3 * \brief Adaptive Homogeneity-Directed Bayer array conversion routine.
5 * \author Copyright March 12, 2008 Theodore Kilgore <kilgota@auburn.edu>
8 * gp_ahd_interpolate() from Eero Salminen <esalmine@gmail.com>
9 * and Theodore Kilgore. The work of Eero Salminen is for partial completion
10 * of a Diploma in Information and Computer Science,
11 * Helsinki University of Technology, Finland.
14 * The algorithm is based upon the paper
17 * Adaptive Homogeneity-Directed Democsaicing Algoritm,
18 * Keigo Hirakawa and Thomas W. Parks, presented in the
19 * IEEE Transactions on Image Processing, vol. 14, no. 3, March 2005.
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Lesser General Public
24 * License as published by the Free Software Foundation; either
25 * version 2 of the License, or (at your option) any later version.
28 * This library is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31 * Lesser General Public License for more details.
34 * You should have received a copy of the GNU Lesser General Public
35 * License along with this library; if not, write to the
36 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
37 * Boston, MA 02111-1307, USA.
50 #include <gphoto2/gphoto2-result.h>
51 #include <gphoto2/gphoto2-port-log.h>
53 #define GP_MODULE "ahd_bayer"
55 #define MAX(x,y) ((x < y) ? (y) : (x))
56 #define MIN(x,y) ((x > y) ? (y) : (x))
57 #define CLAMP(x) MAX(MIN(x,0xff),0)
63 int dRGB(int i1, int i2, unsigned char *RGB);
65 int do_rb_ctr_row(unsigned char *image_h, unsigned char *image_v, int w,
66 int h, int y, int *pos_code);
68 int do_green_ctr_row(unsigned char *image, unsigned char *image_h,
69 unsigned char *image_v, int w, int h, int y, int *pos_code);
71 int get_diffs_row2(unsigned char * hom_buffer_h, unsigned char *hom_buffer_v,
72 unsigned char * buffer_h, unsigned char *buffer_v, int w);
74 #define AD(x, y, w) ((y)*(w)*3+3*(x))
76 * \brief This function computes distance^2 between two sets of pixel data.
77 * \param i1 location of a pixel
78 * \param i2 location of another pixel
79 * \param RGB some RGB data.
82 int dRGB(int i1, int i2, unsigned char *RGB) {
84 dR=RGB[i1+RED]-RGB[i2+RED];
85 dG=RGB[i1+GREEN]-RGB[i2+GREEN];
86 dB=RGB[i1+BLUE]-RGB[i2+BLUE];
87 return dR*dR+dG*dG+dB*dB;
90 * \brief Missing reds and/or blues are reconstructed on a single row
91 * \param image_h three-row window, horizontal interpolation of row 1 is done
92 * \param image_v three-row window, vertical interpolation of row 1 is done
93 * \param w width of image
94 * \param h height of image.
95 * \param y row number from image which is under construction
96 * \param pos_code position code related to Bayer tiling in use
99 int do_rb_ctr_row(unsigned char *image_h, unsigned char *image_v, int w,
100 int h, int y, int *pos_code)
103 int value,value2,div,color;
105 * pos_code[0] = red. green lrtb, blue diagonals
106 * pos_code[1] = green. red lr, blue tb
107 * pos_code[2] = green. blue lr, red tb
108 * pos_code[3] = blue. green lrtb, red diagonals
110 * The Red channel reconstruction is R=G+L(Rs-Gs), in which
111 * G = interpolated & known Green
113 * Gs = values of G at the positions of Rs
114 * L()= should be a 2D lowpass filter, now we'll check
115 * them from a 3x3 square
116 * L-functions' convolution matrix is
117 * [1/4 1/2 1/4;1/2 1 1/2; 1/4 1/2 1/4]
119 * The Blue channel reconstruction uses exactly the same methods.
121 for (x = 0; x < w; x++)
123 bayer = (x&1?0:1) + (y&1?0:2);
124 for (color=0; color < 3; color+=2) {
125 if ((color==RED && bayer == pos_code[3])
127 && bayer == pos_code[0])) {
129 if (x > 0 && y > 0) {
130 value += image_h[AD(x-1,0,w)+color]
131 -image_h[AD(x-1,0,w)+GREEN];
132 value2+= image_v[AD(x-1,0,w)+color]
133 -image_v[AD(x-1,0,w)+GREEN];
136 if (x > 0 && y < h-1) {
137 value += image_h[AD(x-1,2,w)+color]
138 -image_h[AD(x-1,2,w)+GREEN];
139 value2+= image_v[AD(x-1,2,w)+color]
140 -image_v[AD(x-1,2,w)+GREEN];
143 if (x < w-1 && y > 0) {
144 value += image_h[AD(x+1,0,w)+color]
145 -image_h[AD(x+1,0,w)+GREEN];
146 value2+= image_v[AD(x+1,0,w)+color]
147 -image_v[AD(x+1,0,w)+GREEN];
150 if (x < w-1 && y < h-1) {
151 value += image_h[AD(x+1,2,w)+color]
152 -image_h[AD(x+1,2,w)+GREEN];
153 value2+= image_v[AD(x+1,2,w)+color]
154 -image_v[AD(x+1,2,w)+GREEN];
157 image_h[AD(x,1,w)+color]=
159 image_h[AD(x,1,w)+GREEN]
161 image_v[AD(x,1,w)+color]=
162 CLAMP(image_v[AD(x,1,w)+GREEN]
164 } else if ((color==RED && bayer == pos_code[2])
166 && bayer == pos_code[1])) {
169 value += image_h[AD(x,0,w)+color]
170 -image_h[AD(x,0,w)+GREEN];
171 value2+= image_v[AD(x,0,w)+color]
172 -image_v[AD(x,0,w)+GREEN];
176 value += image_h[AD(x,2,w)+color]
177 -image_h[AD(x,2,w)+GREEN];
178 value2+= image_v[AD(x,2,w)+color]
179 -image_v[AD(x,2,w)+GREEN];
182 image_h[AD(x,1,w)+color]=
184 image_h[AD(x,1,w)+GREEN]
186 image_v[AD(x,1,w)+color]=
188 image_v[AD(x,1,w)+GREEN]
190 } else if ((color==RED && bayer == pos_code[1])
192 && bayer == pos_code[2])) {
195 value += image_h[AD(x-1,1,w)+color]
196 -image_h[AD(x-1,1,w)+GREEN];
197 value2+= image_v[AD(x-1,1,w)+color]
198 -image_v[AD(x-1,1,w)+GREEN];
202 value += image_h[AD(x+1,1,w)+color]
203 -image_h[AD(x+1,1,w)+GREEN];
204 value2+= image_v[AD(x+1,1,w)+color]
205 -image_v[AD(x+1,1,w)+GREEN];
208 image_h[AD(x,1,w)+color]=
210 image_h[AD(x,1,w)+GREEN]
212 image_v[AD(x,1,w)+color]=
214 image_v[AD(x,1,w)+GREEN]
224 * \brief Missing greens are reconstructed on a single row
225 * \param image the image which is being reconstructed
226 * \param image_h three-row window, horizontal interpolation of row 1 is done
227 * \param image_v three-row window, vertical interpolation of row 1 is done
228 * \param w width of image
229 * \param h height of image.
230 * \param y row number from image which is under construction
231 * \param pos_code position code related to Bayer tiling in use
235 int do_green_ctr_row(unsigned char *image, unsigned char *image_h,
236 unsigned char *image_v, int w, int h, int y, int *pos_code)
241 * The horizontal green estimation on a red-green row is
242 * G(x) = (2*R(x)+2*G(x+1)+2*G(x-1)-R(x-2)-R(x+2))/4
243 * The estimation on a green-blue row works in the same
246 for (x = 0; x < w; x++) {
247 bayer = (x&1?0:1) + (y&1?0:2);
248 /* pos_code[0] = red. green lrtb, blue diagonals */
249 /* pos_code[3] = blue. green lrtb, red diagonals */
250 if ( bayer == pos_code[0] || bayer == pos_code[3]) {
252 if (bayer==pos_code[0])
253 value += 2*image[AD(x,y,w)+RED];
255 value += 2*image[AD(x,y,w)+BLUE];
258 value += 2*image[AD(x+1,y,w)+GREEN];
262 if (bayer==pos_code[0])
263 value -= image[AD(x+2,y,w)+RED];
265 value -= image[AD(x+2,y,w)+BLUE];
269 value += 2*image[AD(x-1,y,w)+GREEN];
273 if (bayer==pos_code[0])
274 value -= image[AD(x-2,y,w)+RED];
276 value -= image[AD(x-2,y,w)+BLUE];
279 image_h[AD(x,1,w)+GREEN] = CLAMP(value / div);
280 /* The method for vertical estimation is just like
281 * what is done for horizontal estimation, with only
282 * the obvious difference that it is done vertically.
285 if (bayer==pos_code[0])
286 value += 2*image[AD(x,y,w)+RED];
288 value += 2*image[AD(x,y,w)+BLUE];
291 value += 2*image[AD(x,y+1,w)+GREEN];
295 if (bayer==pos_code[0])
296 value -= image[AD(x,y+2,w)+RED];
298 value -= image[AD(x,y+2,w)+BLUE];
302 value += 2*image[AD(x,y-1,w)+GREEN];
306 if (bayer==pos_code[0])
307 value -= image[AD(x,y-2,w)+RED];
309 value -= image[AD(x,y-2,w)+BLUE];
312 image_v[AD(x,1,w)+GREEN] = CLAMP(value / div);
320 * \brief Differences are assigned scores across row 2 of buffer_v, buffer_h
321 * \param hom_buffer_h tabulation of scores for buffer_h
322 * \param hom_buffer_v tabulation of scores for buffer_v
323 * \param buffer_h three-row window, scores assigned for pixels in row 2
324 * \param buffer_v three-row window, scores assigned for pixels in row 2
325 * \param w pixel width of image and buffers
328 int get_diffs_row2(unsigned char * hom_buffer_h, unsigned char *hom_buffer_v,
329 unsigned char * buffer_h, unsigned char *buffer_v, int w)
333 unsigned char Usize_h, Usize_v;
335 for (j = 1; j < w-1; j++) {
341 * Data collected here for adaptive estimates. First we take
342 * at the given pixel vertical diffs if working in window_v;
343 * left and right diffs if working in window_h. We then choose
344 * of these two diffs as a permissible epsilon-radius within
345 * which to work. Checking within this radius, we will
346 * compute scores for the various possibilities. The score
347 * added in each step is either 1, if the directional change
348 * is within the prescribed epsilon, or 0 if it is not.
352 MAX(dRGB(i,i-3,buffer_h),dRGB(i,i+3,buffer_h)),
353 MAX(dRGB(i,i-3*w,buffer_v),dRGB(i,i+3*w,buffer_v))
356 * The scores for the homogeneity mapping. These will be used
357 * in the choice algorithm to choose the best value.
360 if (dRGB(i,i-3,buffer_h) <= RGBeps)
362 if (dRGB(i,i-3,buffer_v) <= RGBeps)
364 if (dRGB(i,i+3,buffer_h) <= RGBeps)
366 if (dRGB(i,i+3,buffer_v) <= RGBeps)
368 if (dRGB(i,i-3*w,buffer_h)<= RGBeps)
370 if (dRGB(i,i-3*w,buffer_v) <= RGBeps)
372 if (dRGB(i,i+3*w,buffer_h) <= RGBeps)
374 if (dRGB(i,i+3*w,buffer_v) <= RGBeps)
376 hom_buffer_h[j+2*w]=Usize_h;
377 hom_buffer_v[j+2*w]=Usize_v;
383 * \brief Interpolate a expanded bayer array into an RGB image.
385 * \param image the linear RGB array as both input and output
386 * \param w width of the above array
387 * \param h height of the above array
388 * \param tile how the 2x2 bayer array is layed out
390 * This function interpolates a bayer array which has been pre-expanded
391 * by gp_bayer_expand() to an RGB image. It applies the method of adaptive
392 * homogeneity-directed demosaicing.
394 * \return a gphoto error code
397 * In outline, the interpolation algorithm used here does the
401 * In principle, the first thing which is done is to split off from the
402 * image two copies. In one of these, interpolation will be done in the
403 * vertical direction only, and in the other copy only in the
404 * horizontal direction. "Cross-color" data is used throughout, on the
405 * principle that it can be used as a corrector for brightness even if it is
406 * derived from the "wrong" color. Finally, at each pixel there is a choice
407 * criterion to decide whether to use the result of the vertical
408 * interpolation, the horizontal interpolation, or an average of the two.
411 * Memory use and speed are optimized by using two sliding windows, one
412 * for the vertical interpolation and the other for the horizontal
413 * interpolation instead of using two copies of the entire input image. The
414 * nterpolation and the choice algorithm are then implemented entirely within
415 * these windows, too. When this has been done, a completed row is written back
416 * to the image. Then the windows are moved, and the process repeats.
419 int gp_ahd_interpolate (unsigned char *image, int w, int h, BayerTile tile)
424 unsigned char *window_h, *window_v, *cur_window_h, *cur_window_v;
425 unsigned char *homo_h, *homo_v;
426 unsigned char *homo_ch, *homo_cv;
428 window_h = calloc (w * 18, 1);
431 GP_DEBUG("Out of memory\n");
432 return GP_ERROR_NO_MEMORY;
434 window_v = calloc(w * 18, 1);
437 GP_DEBUG("Out of memory\n");
438 return GP_ERROR_NO_MEMORY;
440 homo_h = calloc(w*3, 1);
443 GP_DEBUG("Out of memory\n");
444 return GP_ERROR_NO_MEMORY;
446 homo_v = calloc(w*3, 1);
449 GP_DEBUG("Out of memory\n");
450 return GP_ERROR_NO_MEMORY;
452 homo_ch = calloc (w, 1);
455 GP_DEBUG("Out of memory\n");
456 return GP_ERROR_NO_MEMORY;
458 homo_cv = calloc (w, 1);
461 GP_DEBUG("Out of memory\n");
462 return GP_ERROR_NO_MEMORY;
466 case BAYER_TILE_RGGB:
467 case BAYER_TILE_RGGB_INTERLACED:
468 p[0] = 0; p[1] = 1; p[2] = 2; p[3] = 3;
470 case BAYER_TILE_GRBG:
471 case BAYER_TILE_GRBG_INTERLACED:
472 p[0] = 1; p[1] = 0; p[2] = 3; p[3] = 2;
474 case BAYER_TILE_BGGR:
475 case BAYER_TILE_BGGR_INTERLACED:
476 p[0] = 3; p[1] = 2; p[2] = 1; p[3] = 0;
478 case BAYER_TILE_GBRG:
479 case BAYER_TILE_GBRG_INTERLACED:
480 p[0] = 2; p[1] = 3; p[2] = 0; p[3] = 1;
485 * Once the algorithm is initialized and running, one cycle of the
486 * algorithm can be described thus:
489 * Write from row y+3 of the image to row 5 in window_v and in
493 * Interpolate missing green data on row 5 in each window. Data from
494 * the image only is needed for this, not data from the windows.
497 * Now interpolate the missing red or blue data on row 4 in both
498 * windows. We need to do this inside the windows; what is required
499 * is the real or interpolated green data from rows 3 and 5, and the
500 * real data on rows 3 and 5 about the color being interpolated on
501 * row 4, so all of this information is available in the two windows.
502 * Note that for this operation we are interpolating the center row
503 * of cur_window_v and cur_window_h.
506 * Now we have five completed rows in each window, 0 through 4 (rows
507 * 0 - 3 having been done in previous cycles). Completed rows 0 - 4
508 * are what is required in order to run the choice algorithm at
509 * each pixel location across row 2, to decide whether to choose the
510 * data for that pixel from window_v or from window_h. We run the
511 * choice algorithm, sending the data from row 2 over to row y of the
512 * image, pixel by pixel.
515 * Move the windows down (or the data in them up) by one row.
516 * Increment y, the row counter for the image. Go to Step 1.
518 * Initialization of the algorithm clearly requires some special
519 * steps, which are described below as they occur.
521 cur_window_h = window_h+9*w;
522 cur_window_v = window_v+9*w;
524 * Getting started. Copy row 0 from image to line 4 of windows
525 * and row 1 from image to line 5 of windows.
527 memcpy (window_h+12*w, image, 6*w);
528 memcpy (window_v+12*w, image, 6*w);
530 * Now do the green interpolation in row 4 of the windows, the
531 * "center" row of cur_window_v and _h, with the help of image row 0
534 do_green_ctr_row(image, cur_window_h, cur_window_v, w, h, 0, p);
535 /* this does the green interpolation in row 5 of the windows */
536 do_green_ctr_row(image, cur_window_h+3*w, cur_window_v+3*w, w, h, 1, p);
538 * we are now ready to do the rb interpolation on row 4 of the
539 * windows, which relates to row 0 of the image.
541 do_rb_ctr_row(cur_window_h, cur_window_v, w, h, 0, p);
543 * Row row 4, which will be mapped to image row 0, is finished in both
544 * windows. Row 5 has had only the green interpolation.
546 memmove(window_h, window_h+3*w,15*w);
547 memmove(window_v, window_v+3*w,15*w);
548 memcpy (window_h+15*w, image+6*w, 3*w);
549 memcpy (window_v+15*w, image+6*w, 3*w);
551 * now we have shifted backwards and we have row 0 of the image in
552 * row 3 of the windows. Row 4 of the window contains row 1 of image
553 * and needs the rb interpolation. We have copied row 2 of the image
554 * into row 5 of the windows and need to do green interpolation.
556 do_green_ctr_row(image, cur_window_h+3*w, cur_window_v+3*w, w, h, 2, p);
557 do_rb_ctr_row(cur_window_h, cur_window_v, w, h, 1, p);
558 memmove (window_h, window_h+3*w, 15*w);
559 memmove(window_v, window_v+3*w,15*w);
561 * We have shifted one more time. Row 2 of the two windows is
562 * the original row 0 of the image, now fully interpolated. Rows 3
563 * and 4 of the windows contain the original rows 1 and 2 of the
564 * image, also fully interpolated. They will be used while applying
565 * the choice algorithm on row 2, in order to write it back to row
566 * 0 of the image. The algorithm is now fully initialized. We enter
567 * the loop which will complete the algorithm for the whole image.
570 for (y = 0; y < h; y++) {
572 memcpy (window_v+15*w,image+3*y*w+9*w, 3*w);
573 memcpy (window_h+15*w,image+3*y*w+9*w, 3*w);
575 memset(window_v+15*w, 0, 3*w);
576 memset(window_h+15*w, 0, 3*w);
579 do_green_ctr_row(image, cur_window_h+3*w,
580 cur_window_v+3*w, w, h, y+3, p);
582 do_rb_ctr_row(cur_window_h, cur_window_v, w, h, y+2, p);
584 * The next function writes row 2 of diffs, which is the set of
585 * diff scores for row y+1 of the image, which is row 3 of our
586 * windows. When starting with row 0 of the image, this is all
587 * we need. As we continue, the results of this calculation
588 * will also be rotated; in general we need the diffs for rows
589 * y-1, y, and y+1 in order to carry out the choice algorithm
592 get_diffs_row2(homo_h, homo_v, window_h, window_v, w);
593 memset(homo_ch, 0, w);
594 memset(homo_cv, 0, w);
596 /* The choice algorithm now will use the sum of the nine diff
597 * scores computed at the pixel location and at its eight
598 * nearest neighbors. The direction with highest score will
599 * be used; if the scores are equal an average is used.
601 for (x=0; x < w; x++) {
602 for (i=-1; i < 2;i++) {
603 for (k=0; k < 3;k++) {
605 homo_ch[x]+=homo_h[j];
606 homo_cv[x]+=homo_v[j];
609 for (color=0; color < 3; color++) {
610 if (homo_ch[x] > homo_cv[x])
611 image[3*y*w+3*x+color]
612 = window_h[3*x+6*w+color];
613 else if (homo_ch[x] < homo_cv[x])
614 image[3*y*w+3*x+color]
615 = window_v[3*x+6*w+color];
617 image[3*y*w+3*x+color]
618 = (window_v[3*x+6*w+color]+
619 window_h[3*x+6*w+color])/2;
622 /* Move the windows; loop back if not finished. */
623 memmove(window_v, window_v+3*w, 15*w);
624 memmove(window_h, window_h+3*w, 15*w);
625 memmove (homo_h,homo_h+w,2*w);
626 memmove (homo_v,homo_v+w,2*w);
638 * \brief Convert a bayer raster style image to a RGB raster.
640 * \param input the bayer CCD array as linear input
641 * \param w width of the above array
642 * \param h height of the above array
643 * \param output RGB output array (linear, 3 bytes of R,G,B for every pixel)
644 * \param tile how the 2x2 bayer array is layed out
646 * A regular CCD uses a raster of 2 green, 1 blue and 1 red components to
647 * cover a 2x2 pixel area. The camera or the driver then interpolates a
648 * 2x2 RGB pixel set out of this data.
650 * This function expands and interpolates the bayer array to 3 times larger
651 * bitmap with RGB values interpolated. It does the same job as
652 * gp_bayer_decode() but it calls gp_ahd_interpolate() instead of calling
653 * gp_bayer_interpolate(). Use this instead of gp_bayer_decode() if you
654 * want to use or to test AHD interpolation in a camera library.
655 * \return a gphoto error code
659 gp_ahd_decode (unsigned char *input, int w, int h, unsigned char *output,
662 gp_bayer_expand (input, w, h, output, tile);
663 gp_ahd_interpolate (output, w, h, tile);