2 * folded-ctf is an implementation of the folded hierarchy of
3 * classifiers for object detection, developed by Francois Fleuret
6 * Copyright (c) 2008 Idiap Research Institute, http://www.idiap.ch/
7 * Written by Francois Fleuret <francois.fleuret@idiap.ch>
9 * This file is part of folded-ctf.
11 * folded-ctf is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published
13 * by the Free Software Foundation, either version 3 of the License,
14 * or (at your option) any later version.
16 * folded-ctf is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with folded-ctf. If not, see <http://www.gnu.org/licenses/>.
29 #include <libpng/png.h>
30 #include "jpeg_misc.h"
32 #include "rgb_image.h"
34 void RGBImage::allocate() {
35 _bit_plans = new unsigned char **[RGB_DEPTH];
36 _bit_lines = new unsigned char *[RGB_DEPTH * _height];
37 _bit_map = new unsigned char [_width * _height * RGB_DEPTH];
38 for(int k = 0; k < RGB_DEPTH; k++) _bit_plans[k] = _bit_lines + k * _height;
39 for(int k = 0; k < RGB_DEPTH * _height; k++) _bit_lines[k] = _bit_map + k * _width;
42 void RGBImage::deallocate() {
48 RGBImage::RGBImage() : _bit_plans(0), _bit_lines(0), _bit_map(0) { }
50 RGBImage::RGBImage(int width, int height) : _width(width), _height(height) {
52 memset(_bit_map, 0, _width * _height * RGB_DEPTH * sizeof(unsigned char));
55 RGBImage::RGBImage(RGBImage *image, scalar_t scale) {
56 _width = int(scale * image->_width);
57 _height = int(scale * image->_height);
61 for(int y = 0; y < _height; y++) {
62 for(int x = 0; x < _width; x++) {
65 int sr = 0, sg = 0, sb = 0, t = 0;
68 for(int yy = y * delta; yy < (y + 1) * delta; yy++) {
69 for(int xx = x * delta; xx < (x + 1) * delta; xx++) {
70 xo = (image->_width * xx)/(_width * delta);
71 yo = (image->_height * yy)/(_height * delta);
72 if(xo >= 0 && xo < image->_width && yo >= 0 && yo < image->_height) {
73 sr += image->_bit_plans[RED][yo][xo];
74 sg += image->_bit_plans[GREEN][yo][xo];
75 sb += image->_bit_plans[BLUE][yo][xo];
82 _bit_plans[RED][y][x] = sr / t;
83 _bit_plans[GREEN][y][x] = sg / t;
84 _bit_plans[BLUE][y][x] = sb / t;
86 _bit_plans[RED][y][x] = 0;
87 _bit_plans[GREEN][y][x] = 0;
88 _bit_plans[BLUE][y][x] = 0;
95 RGBImage::~RGBImage() {
99 void RGBImage::read_png(const char *name) {
100 // This is the number of bytes the read_png routine will read to
101 // decide if the file is a PNG or not. According to the png
102 // documentation, it can be 1 to 8 bytes, 8 being the max and the
105 const int header_size = 8;
107 png_byte header[header_size];
108 png_bytep *row_pointers;
113 FILE *fp = fopen(name, "rb");
115 cerr << "Unable to open file " << name << " for reading.\n";
120 fread(header, 1, header_size, fp);
121 if (png_sig_cmp(header, 0, header_size)) {
122 cerr << "File " << name << " does not look like PNG.\n";
127 // create png pointer
128 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
130 cerr << "png_create_read_struct failed\n";
135 // create png info struct
136 png_infop info_ptr = png_create_info_struct(png_ptr);
138 png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0);
139 cerr << "png_create_info_struct failed\n";
145 png_init_io(png_ptr, fp);
146 png_set_sig_bytes(png_ptr, header_size);
147 png_read_info(png_ptr, info_ptr);
149 _width = info_ptr->width;
150 _height = info_ptr->height;
152 png_byte bit_depth, color_type, channels;
153 color_type = info_ptr->color_type;
154 bit_depth = info_ptr->bit_depth;
155 channels = info_ptr->channels;
158 cerr << "Can only read 8-bits PNG images." << endl;
162 // allocate image pointer
163 row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
164 for (int y = 0; y < _height; y++)
165 row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
170 png_read_image(png_ptr, row_pointers);
172 // send image to red, green and blue buffers
173 switch (color_type) {
174 case PNG_COLOR_TYPE_GRAY:
176 unsigned char pixel = 0;
177 for (int y = 0; y < _height; y++) for (int x = 0; x < _width; x++) {
178 pixel = row_pointers[y][x];
179 _bit_plans[RED][y][x] = pixel;
180 _bit_plans[GREEN][y][x] = pixel;
181 _bit_plans[BLUE][y][x] = pixel;
186 case PNG_COLOR_TYPE_GRAY_ALPHA:
187 cerr << "PNG type GRAY_ALPHA not supported.\n";
191 case PNG_COLOR_TYPE_PALETTE:
192 cerr << "PNG type PALETTE not supported.\n";
196 case PNG_COLOR_TYPE_RGB:
198 if(channels != RGB_DEPTH) {
199 cerr << "Unsupported number of channels for RGB type\n";
203 for (int y = 0; y < _height; y++) {
205 for (int x = 0; x < _width; x++) {
206 _bit_plans[RED][y][x] = row_pointers[y][k++];
207 _bit_plans[GREEN][y][x] = row_pointers[y][k++];
208 _bit_plans[BLUE][y][x] = row_pointers[y][k++];
214 case PNG_COLOR_TYPE_RGB_ALPHA:
215 cerr << "PNG type RGB_ALPHA not supported.\n";
220 cerr << "Unknown PNG type\n";
225 png_destroy_read_struct(&png_ptr, &info_ptr, 0);
227 for (int y = 0; y < _height; y++) free(row_pointers[y]);
233 void RGBImage::write_png(const char *name) {
234 png_bytep *row_pointers;
237 FILE *fp = fopen(name, "wb");
240 cerr << "Unable to create image '" << name << "'\n";
244 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
247 cerr << "png_create_write_struct failed\n";
252 png_infop info_ptr = png_create_info_struct(png_ptr);
254 cerr << "png_create_info_struct failed\n";
259 png_init_io(png_ptr, fp);
261 png_set_IHDR(png_ptr, info_ptr, _width, _height,
262 8, 2, PNG_INTERLACE_NONE,
263 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
265 png_write_info(png_ptr, info_ptr);
268 row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
269 for (int y = 0; y < _height; y++)
270 row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
273 for (int y = 0; y < _height; y++) {
275 for (int x = 0; x < _width; x++) {
276 row_pointers[y][k++] = _bit_map[x + _width * (y + _height * RED)];
277 row_pointers[y][k++] = _bit_map[x + _width * (y + _height * GREEN)];
278 row_pointers[y][k++] = _bit_map[x + _width * (y + _height * BLUE)];
282 png_write_image(png_ptr, row_pointers);
283 png_write_end(png_ptr, 0);
285 png_destroy_write_struct(&png_ptr, &info_ptr);
287 // cleanup heap allocation
288 for (int y = 0; y < _height; y++) free(row_pointers[y]);
294 void RGBImage::write_jpg(const char *filename, int quality) {
295 struct jpeg_compress_struct cinfo;
296 struct my_error_mgr jerr;
297 FILE *outfile; /* target file */
298 JSAMPARRAY buffer; /* Output row buffer */
300 jpeg_create_compress (&cinfo);
302 if ((outfile = fopen (filename, "wb")) == 0) {
303 fprintf (stderr, "Can't open %s\n", filename);
307 cinfo.err = jpeg_std_error (&jerr.pub);
308 jerr.pub.error_exit = my_error_exit;
310 if (setjmp (jerr.setjmp_buffer)) {
311 jpeg_destroy_compress (&cinfo);
316 jpeg_stdio_dest (&cinfo, outfile);
318 cinfo.image_width = _width;
319 cinfo.image_height = _height;
320 cinfo.input_components = RGB_DEPTH;
322 cinfo.in_color_space = JCS_RGB;
324 jpeg_set_defaults (&cinfo);
325 jpeg_set_quality (&cinfo, quality, TRUE);
326 jpeg_start_compress (&cinfo, TRUE);
329 (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE,
330 _width * RGB_DEPTH, 1);
331 while (int(cinfo.next_scanline) < _height) {
332 for(int d = 0; d < RGB_DEPTH; d++)
333 for(int x = 0; x < _width; x++)
334 buffer[0][x * RGB_DEPTH + d] =
335 (JSAMPLE) ((_bit_map[x + _width * (y + _height * d)] * (MAXJSAMPLE + 1)) / 255);
336 jpeg_write_scanlines (&cinfo, buffer, 1);
340 jpeg_finish_compress (&cinfo);
343 jpeg_destroy_compress (&cinfo);
346 void RGBImage::read_jpg(const char *filename) {
347 struct jpeg_decompress_struct cinfo;
348 struct my_error_mgr jerr;
354 if ((infile = fopen (filename, "rb")) == 0) {
355 fprintf (stderr, "can't open %s\n", filename);
359 cinfo.err = jpeg_std_error (&jerr.pub);
360 jerr.pub.error_exit = my_error_exit;
362 if (setjmp (jerr.setjmp_buffer)) {
363 jpeg_destroy_decompress (&cinfo);
372 jpeg_create_decompress (&cinfo);
373 jpeg_stdio_src (&cinfo, infile);
374 jpeg_read_header (&cinfo, TRUE);
375 jpeg_start_decompress (&cinfo);
377 _width = cinfo.output_width;
378 _height = cinfo.output_height;
379 int depth = cinfo.output_components;
384 (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE,
388 while (cinfo.output_scanline < cinfo.output_height) {
389 jpeg_read_scanlines (&cinfo, buffer, 1);
391 for(int d = 0; d < RGB_DEPTH; d++)
392 for(int x = 0; x < _width; x++)
393 _bit_plans[d][y][x] =
394 (unsigned char) ((buffer[0][x * depth] * 255) / (MAXJSAMPLE + 1));
396 for(int d = 0; d < depth; d++)
397 for(int x = 0; x < _width; x++)
398 _bit_plans[d][y][x] =
399 (unsigned char) ((buffer[0][x * depth + d] * 255) / (MAXJSAMPLE + 1));
404 jpeg_finish_decompress (&cinfo);
405 jpeg_destroy_decompress (&cinfo);
410 void RGBImage::draw_line(int thickness,
411 unsigned char r, unsigned char g, unsigned char b,
412 scalar_t x0, scalar_t y0, scalar_t x1, scalar_t y1) {
415 int ix0 = int(x0 + 0.5), iy0 = int(y0 + 0.5), ix1 = int(x1 + 0.5), iy1 = int(y1 + 0.5);
417 if(ix0 < ix1) { dx = 1; h = ix1 - ix0; } else { dx = -1; h = ix0 - ix1; }
418 if(iy0 < iy1) { dy = 1; v = iy1 - iy0; } else { dy = -1; v = iy0 - iy1; }
420 int x = ix0, y = iy0;
423 for(int i = 0; i < h + 1; i++) {
424 for(int ex = - thickness / 2 - 1; ex < (thickness + 1) / 2 + 1; ex++) {
425 for(int ey = - thickness / 2 - 1; ey < (thickness + 1) / 2 + 1; ey++) {
426 if(ex * ex + ey * ey <= thickness * thickness / 4) {
427 int xx = x + ex, yy = y + ey;
428 if(xx >= 0 && xx < _width && yy >= 0 && yy < _height)
429 set_pixel(xx, yy, r, g, b);
435 if(l > 0) { y += dy; l -= h; }
440 for(int i = 0; i < v + 1; i++) {
441 for(int ex = - thickness / 2 - 1; ex < (thickness + 1) / 2 + 1; ex++) {
442 for(int ey = - thickness / 2 - 1; ey < (thickness + 1) / 2 + 1; ey++) {
443 if(ex * ex + ey * ey <= thickness * thickness / 4) {
444 int xx = x + ex, yy = y + ey;
445 if(xx >= 0 && xx < _width && yy >= 0 && yy < _height)
446 set_pixel(xx, yy, r, g, b);
452 if(l < 0) { x += dx; l += v; }
459 void RGBImage::draw_ellipse(int thickness,
460 unsigned char r, unsigned char g, unsigned char b,
461 scalar_t xc, scalar_t yc, scalar_t radius_1, scalar_t radius_2, scalar_t tilt) {
462 scalar_t ux1 = cos(tilt) * radius_1, uy1 = sin(tilt) * radius_1;
463 scalar_t ux2 = - sin(tilt) * radius_2, uy2 = cos(tilt) * radius_2;
465 const int nb_points_to_draw = 80;
466 scalar_t x, y, px = 0, py = 0;
468 for(int i = 0; i <= nb_points_to_draw; i++) {
469 scalar_t alpha = (M_PI * 2 * scalar_t(i)) / scalar_t(nb_points_to_draw);
471 x = xc + cos(alpha) * ux1 + sin(alpha) * ux2;
472 y = yc + cos(alpha) * uy1 + sin(alpha) * uy2;
475 draw_line(thickness, r, g, b, px, py, x, y);