libgphoto2 photo camera library (libgphoto2) Internals  2.5.23
ahd_bayer.c
Go to the documentation of this file.
1 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <math.h>
46 #include <time.h>
47 
48 #include "config.h"
49 #include "bayer.h"
50 #include <gphoto2/gphoto2-result.h>
52 
53 #define MAX(x,y) ((x < y) ? (y) : (x))
54 #define MIN(x,y) ((x > y) ? (y) : (x))
55 #define CLAMP(x) MAX(MIN(x,0xff),0)
56 #define RED 0
57 #define GREEN 1
58 #define BLUE 2
59 
60 static
61 int dRGB(int i1, int i2, unsigned char *RGB);
62 static
63 int do_rb_ctr_row(unsigned char *image_h, unsigned char *image_v, int w,
64  int h, int y, int *pos_code);
65 static
66 int do_green_ctr_row(unsigned char *image, unsigned char *image_h,
67  unsigned char *image_v, int w, int h, int y, int *pos_code);
68 static
69 int get_diffs_row2(unsigned char * hom_buffer_h, unsigned char *hom_buffer_v,
70  unsigned char * buffer_h, unsigned char *buffer_v, int w);
71 
72 #define AD(x, y, w) ((y)*(w)*3+3*(x))
73 
79 static
80 int dRGB(int i1, int i2, unsigned char *RGB) {
81  int dR,dG,dB;
82  dR=RGB[i1+RED]-RGB[i2+RED];
83  dG=RGB[i1+GREEN]-RGB[i2+GREEN];
84  dB=RGB[i1+BLUE]-RGB[i2+BLUE];
85  return dR*dR+dG*dG+dB*dB;
86 }
96 static
97 int do_rb_ctr_row(unsigned char *image_h, unsigned char *image_v, int w,
98  int h, int y, int *pos_code)
99 {
100  int x, bayer;
101  int value,value2,div,color;
102  /*
103  * pos_code[0] = red. green lrtb, blue diagonals
104  * pos_code[1] = green. red lr, blue tb
105  * pos_code[2] = green. blue lr, red tb
106  * pos_code[3] = blue. green lrtb, red diagonals
107  *
108  * The Red channel reconstruction is R=G+L(Rs-Gs), in which
109  * G = interpolated & known Green
110  * Rs = known Red
111  * Gs = values of G at the positions of Rs
112  * L()= should be a 2D lowpass filter, now we'll check
113  * them from a 3x3 square
114  * L-functions' convolution matrix is
115  * [1/4 1/2 1/4;1/2 1 1/2; 1/4 1/2 1/4]
116  *
117  * The Blue channel reconstruction uses exactly the same methods.
118  */
119  for (x = 0; x < w; x++)
120  {
121  bayer = (x&1?0:1) + (y&1?0:2);
122  for (color=0; color < 3; color+=2) {
123  if ((color==RED && bayer == pos_code[3])
124  || (color==BLUE
125  && bayer == pos_code[0])) {
126  value=value2=div=0;
127  if (x > 0 && y > 0) {
128  value += image_h[AD(x-1,0,w)+color]
129  -image_h[AD(x-1,0,w)+GREEN];
130  value2+= image_v[AD(x-1,0,w)+color]
131  -image_v[AD(x-1,0,w)+GREEN];
132  div++;
133  }
134  if (x > 0 && y < h-1) {
135  value += image_h[AD(x-1,2,w)+color]
136  -image_h[AD(x-1,2,w)+GREEN];
137  value2+= image_v[AD(x-1,2,w)+color]
138  -image_v[AD(x-1,2,w)+GREEN];
139  div++;
140  }
141  if (x < w-1 && y > 0) {
142  value += image_h[AD(x+1,0,w)+color]
143  -image_h[AD(x+1,0,w)+GREEN];
144  value2+= image_v[AD(x+1,0,w)+color]
145  -image_v[AD(x+1,0,w)+GREEN];
146  div++;
147  }
148  if (x < w-1 && y < h-1) {
149  value += image_h[AD(x+1,2,w)+color]
150  -image_h[AD(x+1,2,w)+GREEN];
151  value2+= image_v[AD(x+1,2,w)+color]
152  -image_v[AD(x+1,2,w)+GREEN];
153  div++;
154  }
155  image_h[AD(x,1,w)+color]=
156  CLAMP(
157  image_h[AD(x,1,w)+GREEN]
158  +value/div);
159  image_v[AD(x,1,w)+color]=
160  CLAMP(image_v[AD(x,1,w)+GREEN]
161  +value2/div);
162  } else if ((color==RED && bayer == pos_code[2])
163  || (color==BLUE
164  && bayer == pos_code[1])) {
165  value=value2=div=0;
166  if (y > 0) {
167  value += image_h[AD(x,0,w)+color]
168  -image_h[AD(x,0,w)+GREEN];
169  value2+= image_v[AD(x,0,w)+color]
170  -image_v[AD(x,0,w)+GREEN];
171  div++;
172  }
173  if (y < h-1) {
174  value += image_h[AD(x,2,w)+color]
175  -image_h[AD(x,2,w)+GREEN];
176  value2+= image_v[AD(x,2,w)+color]
177  -image_v[AD(x,2,w)+GREEN];
178  div++;
179  }
180  image_h[AD(x,1,w)+color]=
181  CLAMP(
182  image_h[AD(x,1,w)+GREEN]
183  +value/div);
184  image_v[AD(x,1,w)+color]=
185  CLAMP(
186  image_v[AD(x,1,w)+GREEN]
187  +value2/div);
188  } else if ((color==RED && bayer == pos_code[1])
189  || (color==BLUE
190  && bayer == pos_code[2])) {
191  value=value2=div=0;
192  if (x > 0) {
193  value += image_h[AD(x-1,1,w)+color]
194  -image_h[AD(x-1,1,w)+GREEN];
195  value2+= image_v[AD(x-1,1,w)+color]
196  -image_v[AD(x-1,1,w)+GREEN];
197  div++;
198  }
199  if (x < w-1) {
200  value += image_h[AD(x+1,1,w)+color]
201  -image_h[AD(x+1,1,w)+GREEN];
202  value2+= image_v[AD(x+1,1,w)+color]
203  -image_v[AD(x+1,1,w)+GREEN];
204  div++;
205  }
206  image_h[AD(x,1,w)+color]=
207  CLAMP(
208  image_h[AD(x,1,w)+GREEN]
209  +value/div);
210  image_v[AD(x,1,w)+color]=
211  CLAMP(
212  image_v[AD(x,1,w)+GREEN]
213  +value2/div);
214  }
215  }
216  }
217  return GP_OK;
218 }
219 
220 
232 static
233 int do_green_ctr_row(unsigned char *image, unsigned char *image_h,
234  unsigned char *image_v, int w, int h, int y, int *pos_code)
235 {
236  int x, bayer;
237  int value,div;
238  /*
239  * The horizontal green estimation on a red-green row is
240  * G(x) = (2*R(x)+2*G(x+1)+2*G(x-1)-R(x-2)-R(x+2))/4
241  * The estimation on a green-blue row works in the same
242  * way.
243  */
244  for (x = 0; x < w; x++) {
245  bayer = (x&1?0:1) + (y&1?0:2);
246  /* pos_code[0] = red. green lrtb, blue diagonals */
247  /* pos_code[3] = blue. green lrtb, red diagonals */
248  if ( bayer == pos_code[0] || bayer == pos_code[3]) {
249  div=value=0;
250  if (bayer==pos_code[0])
251  value += 2*image[AD(x,y,w)+RED];
252  else
253  value += 2*image[AD(x,y,w)+BLUE];
254  div+=2;
255  if (x < (w-1)) {
256  value += 2*image[AD(x+1,y,w)+GREEN];
257  div+=2;
258  }
259  if (x < (w-2)) {
260  if (bayer==pos_code[0])
261  value -= image[AD(x+2,y,w)+RED];
262  else
263  value -= image[AD(x+2,y,w)+BLUE];
264  div--;
265  }
266  if (x > 0) {
267  value += 2*image[AD(x-1,y,w)+GREEN];
268  div+=2;
269  }
270  if (x > 1) {
271  if (bayer==pos_code[0])
272  value -= image[AD(x-2,y,w)+RED];
273  else
274  value -= image[AD(x-2,y,w)+BLUE];
275  div--;
276  }
277  image_h[AD(x,1,w)+GREEN] = CLAMP(value / div);
278  /* The method for vertical estimation is just like
279  * what is done for horizontal estimation, with only
280  * the obvious difference that it is done vertically.
281  */
282  div=value=0;
283  if (bayer==pos_code[0])
284  value += 2*image[AD(x,y,w)+RED];
285  else
286  value += 2*image[AD(x,y,w)+BLUE];
287  div+=2;
288  if (y < (h-1)) {
289  value += 2*image[AD(x,y+1,w)+GREEN];
290  div+=2;
291  }
292  if (y < (h-2)) {
293  if (bayer==pos_code[0])
294  value -= image[AD(x,y+2,w)+RED];
295  else
296  value -= image[AD(x,y+2,w)+BLUE];
297  div--;
298  }
299  if (y > 0) {
300  value += 2*image[AD(x,y-1,w)+GREEN];
301  div+=2;
302  }
303  if (y > 1) {
304  if (bayer==pos_code[0])
305  value -= image[AD(x,y-2,w)+RED];
306  else
307  value -= image[AD(x,y-2,w)+BLUE];
308  div--;
309  }
310  image_v[AD(x,1,w)+GREEN] = CLAMP(value / div);
311 
312  }
313  }
314  return GP_OK;
315 }
316 
326 static
327 int get_diffs_row2(unsigned char * hom_buffer_h, unsigned char *hom_buffer_v,
328  unsigned char * buffer_h, unsigned char *buffer_v, int w)
329 {
330  int i,j;
331  int RGBeps;
332  unsigned char Usize_h, Usize_v;
333 
334  for (j = 1; j < w-1; j++) {
335  i=3*j+9*w;
336  Usize_h=0;
337  Usize_v=0;
338 
339  /*
340  * Data collected here for adaptive estimates. First we take
341  * at the given pixel vertical diffs if working in window_v;
342  * left and right diffs if working in window_h. We then choose
343  * of these two diffs as a permissible epsilon-radius within
344  * which to work. Checking within this radius, we will
345  * compute scores for the various possibilities. The score
346  * added in each step is either 1, if the directional change
347  * is within the prescribed epsilon, or 0 if it is not.
348  */
349 
350  RGBeps=MIN(
351  MAX(dRGB(i,i-3,buffer_h),dRGB(i,i+3,buffer_h)),
352  MAX(dRGB(i,i-3*w,buffer_v),dRGB(i,i+3*w,buffer_v))
353  );
354  /*
355  * The scores for the homogeneity mapping. These will be used
356  * in the choice algorithm to choose the best value.
357  */
358 
359  if (dRGB(i,i-3,buffer_h) <= RGBeps)
360  Usize_h++;
361  if (dRGB(i,i-3,buffer_v) <= RGBeps)
362  Usize_v++;
363  if (dRGB(i,i+3,buffer_h) <= RGBeps)
364  Usize_h++;
365  if (dRGB(i,i+3,buffer_v) <= RGBeps)
366  Usize_v++;
367  if (dRGB(i,i-3*w,buffer_h)<= RGBeps)
368  Usize_h++;
369  if (dRGB(i,i-3*w,buffer_v) <= RGBeps)
370  Usize_v++;
371  if (dRGB(i,i+3*w,buffer_h) <= RGBeps)
372  Usize_h++;
373  if (dRGB(i,i+3*w,buffer_v) <= RGBeps)
374  Usize_v++;
375  hom_buffer_h[j+2*w]=Usize_h;
376  hom_buffer_v[j+2*w]=Usize_v;
377  }
378  return GP_OK;
379 }
380 
418 int gp_ahd_interpolate (unsigned char *image, int w, int h, BayerTile tile)
419 {
420  int i, j, k, x, y;
421  int p[4];
422  int color;
423  unsigned char *window_h, *window_v, *cur_window_h, *cur_window_v;
424  unsigned char *homo_h, *homo_v;
425  unsigned char *homo_ch, *homo_cv;
426 
427  window_h = calloc (w * 18, 1);
428  window_v = calloc (w * 18, 1);
429  homo_h = calloc (w*3, 1);
430  homo_v = calloc (w*3, 1);
431  homo_ch = calloc (w, 1);
432  homo_cv = calloc (w, 1);
433  if (!window_h || !window_v || !homo_h || !homo_v || !homo_ch || !homo_cv) {
434  free (window_h);
435  free (window_v);
436  free (homo_h);
437  free (homo_v);
438  free (homo_ch);
439  free (homo_cv);
440  GP_LOG_E ("Out of memory");
441  return GP_ERROR_NO_MEMORY;
442  }
443  switch (tile) {
444  default:
445  case BAYER_TILE_RGGB:
447  p[0] = 0; p[1] = 1; p[2] = 2; p[3] = 3;
448  break;
449  case BAYER_TILE_GRBG:
451  p[0] = 1; p[1] = 0; p[2] = 3; p[3] = 2;
452  break;
453  case BAYER_TILE_BGGR:
455  p[0] = 3; p[1] = 2; p[2] = 1; p[3] = 0;
456  break;
457  case BAYER_TILE_GBRG:
459  p[0] = 2; p[1] = 3; p[2] = 0; p[3] = 1;
460  break;
461  }
462 
463  /*
464  * Once the algorithm is initialized and running, one cycle of the
465  * algorithm can be described thus:
466  *
467  * Step 1
468  * Write from row y+3 of the image to row 5 in window_v and in
469  * window_h.
470  *
471  * Step 2
472  * Interpolate missing green data on row 5 in each window. Data from
473  * the image only is needed for this, not data from the windows.
474  *
475  * Step 3
476  * Now interpolate the missing red or blue data on row 4 in both
477  * windows. We need to do this inside the windows; what is required
478  * is the real or interpolated green data from rows 3 and 5, and the
479  * real data on rows 3 and 5 about the color being interpolated on
480  * row 4, so all of this information is available in the two windows.
481  * Note that for this operation we are interpolating the center row
482  * of cur_window_v and cur_window_h.
483  *
484  * Step 4
485  * Now we have five completed rows in each window, 0 through 4 (rows
486  * 0 - 3 having been done in previous cycles). Completed rows 0 - 4
487  * are what is required in order to run the choice algorithm at
488  * each pixel location across row 2, to decide whether to choose the
489  * data for that pixel from window_v or from window_h. We run the
490  * choice algorithm, sending the data from row 2 over to row y of the
491  * image, pixel by pixel.
492  *
493  * Step 5
494  * Move the windows down (or the data in them up) by one row.
495  * Increment y, the row counter for the image. Go to Step 1.
496  *
497  * Initialization of the algorithm clearly requires some special
498  * steps, which are described below as they occur.
499  */
500  cur_window_h = window_h+9*w;
501  cur_window_v = window_v+9*w;
502  /*
503  * Getting started. Copy row 0 from image to line 4 of windows
504  * and row 1 from image to line 5 of windows.
505  */
506  memcpy (window_h+12*w, image, 6*w);
507  memcpy (window_v+12*w, image, 6*w);
508  /*
509  * Now do the green interpolation in row 4 of the windows, the
510  * "center" row of cur_window_v and _h, with the help of image row 0
511  * and image row 1.
512  */
513  do_green_ctr_row(image, cur_window_h, cur_window_v, w, h, 0, p);
514  /* this does the green interpolation in row 5 of the windows */
515  do_green_ctr_row(image, cur_window_h+3*w, cur_window_v+3*w, w, h, 1, p);
516  /*
517  * we are now ready to do the rb interpolation on row 4 of the
518  * windows, which relates to row 0 of the image.
519  */
520  do_rb_ctr_row(cur_window_h, cur_window_v, w, h, 0, p);
521  /*
522  * Row row 4, which will be mapped to image row 0, is finished in both
523  * windows. Row 5 has had only the green interpolation.
524  */
525  memmove(window_h, window_h+3*w,15*w);
526  memmove(window_v, window_v+3*w,15*w);
527  memcpy (window_h+15*w, image+6*w, 3*w);
528  memcpy (window_v+15*w, image+6*w, 3*w);
529  /*
530  * now we have shifted backwards and we have row 0 of the image in
531  * row 3 of the windows. Row 4 of the window contains row 1 of image
532  * and needs the rb interpolation. We have copied row 2 of the image
533  * into row 5 of the windows and need to do green interpolation.
534  */
535  do_green_ctr_row(image, cur_window_h+3*w, cur_window_v+3*w, w, h, 2, p);
536  do_rb_ctr_row(cur_window_h, cur_window_v, w, h, 1, p);
537  memmove (window_h, window_h+3*w, 15*w);
538  memmove(window_v, window_v+3*w,15*w);
539  /*
540  * We have shifted one more time. Row 2 of the two windows is
541  * the original row 0 of the image, now fully interpolated. Rows 3
542  * and 4 of the windows contain the original rows 1 and 2 of the
543  * image, also fully interpolated. They will be used while applying
544  * the choice algorithm on row 2, in order to write it back to row
545  * 0 of the image. The algorithm is now fully initialized. We enter
546  * the loop which will complete the algorithm for the whole image.
547  */
548 
549  for (y = 0; y < h; y++) {
550  if(y<h-3) {
551  memcpy (window_v+15*w,image+3*y*w+9*w, 3*w);
552  memcpy (window_h+15*w,image+3*y*w+9*w, 3*w);
553  } else {
554  memset(window_v+15*w, 0, 3*w);
555  memset(window_h+15*w, 0, 3*w);
556  }
557  if (y<h-3)
558  do_green_ctr_row(image, cur_window_h+3*w,
559  cur_window_v+3*w, w, h, y+3, p);
560  if (y<h-2)
561  do_rb_ctr_row(cur_window_h, cur_window_v, w, h, y+2, p);
562  /*
563  * The next function writes row 2 of diffs, which is the set of
564  * diff scores for row y+1 of the image, which is row 3 of our
565  * windows. When starting with row 0 of the image, this is all
566  * we need. As we continue, the results of this calculation
567  * will also be rotated; in general we need the diffs for rows
568  * y-1, y, and y+1 in order to carry out the choice algorithm
569  * for writing row y.
570  */
571  get_diffs_row2(homo_h, homo_v, window_h, window_v, w);
572  memset(homo_ch, 0, w);
573  memset(homo_cv, 0, w);
574 
575  /* The choice algorithm now will use the sum of the nine diff
576  * scores computed at the pixel location and at its eight
577  * nearest neighbors. The direction with highest score will
578  * be used; if the scores are equal an average is used.
579  */
580  for (x=0; x < w; x++) {
581  for (i=-1; i < 2;i++) {
582  for (k=0; k < 3;k++) {
583  j=i+x+w*k;
584  homo_ch[x]+=homo_h[j];
585  homo_cv[x]+=homo_v[j];
586  }
587  }
588  for (color=0; color < 3; color++) {
589  if (homo_ch[x] > homo_cv[x])
590  image[3*y*w+3*x+color]
591  = window_h[3*x+6*w+color];
592  else if (homo_ch[x] < homo_cv[x])
593  image[3*y*w+3*x+color]
594  = window_v[3*x+6*w+color];
595  else
596  image[3*y*w+3*x+color]
597  = (window_v[3*x+6*w+color]+
598  window_h[3*x+6*w+color])/2;
599  }
600  }
601  /* Move the windows; loop back if not finished. */
602  memmove(window_v, window_v+3*w, 15*w);
603  memmove(window_h, window_h+3*w, 15*w);
604  memmove (homo_h,homo_h+w,2*w);
605  memmove (homo_v,homo_v+w,2*w);
606  }
607  free(window_v);
608  free(window_h);
609  free(homo_h);
610  free(homo_v);
611  free(homo_ch);
612  free(homo_cv);
613  return GP_OK;
614 }
615 
637 int
638 gp_ahd_decode (unsigned char *input, int w, int h, unsigned char *output,
639  BayerTile tile)
640 {
641  gp_bayer_expand (input, w, h, output, tile);
642  gp_ahd_interpolate (output, w, h, tile);
643  return GP_OK;
644 }
do_rb_ctr_row
static int do_rb_ctr_row(unsigned char *image_h, unsigned char *image_v, int w, int h, int y, int *pos_code)
Missing reds and/or blues are reconstructed on a single row.
Definition: ahd_bayer.c:97
GP_ERROR_NO_MEMORY
#define GP_ERROR_NO_MEMORY
Out of memory.
Definition: gphoto2-port-result.h:42
BAYER_TILE_RGGB
@ BAYER_TILE_RGGB
raster is RG,GN
Definition: bayer.h:33
BAYER_TILE_RGGB_INTERLACED
@ BAYER_TILE_RGGB_INTERLACED
scanline order: R1,G1,R2,G2,...,G1,B1,G2,B2,...
Definition: bayer.h:37
AD
#define AD(x, y, w)
Definition: ahd_bayer.c:72
get_diffs_row2
static int get_diffs_row2(unsigned char *hom_buffer_h, unsigned char *hom_buffer_v, unsigned char *buffer_h, unsigned char *buffer_v, int w)
Differences are assigned scores across row 2 of buffer_v, buffer_h.
Definition: ahd_bayer.c:327
BAYER_TILE_GRBG
@ BAYER_TILE_GRBG
raster is GR,BG
Definition: bayer.h:34
gphoto2-result.h
BAYER_TILE_GBRG_INTERLACED
@ BAYER_TILE_GBRG_INTERLACED
scanline order: G1,B1,G2,B2,...,R1,G1,R2,G2,...
Definition: bayer.h:40
GP_OK
#define GP_OK
Everything is OK.
Definition: gphoto2-port-result.h:30
BAYER_TILE_GBRG
@ BAYER_TILE_GBRG
raster is RG,GB
Definition: bayer.h:36
BAYER_TILE_BGGR
@ BAYER_TILE_BGGR
raster is BG,GR
Definition: bayer.h:35
MIN
#define MIN(x, y)
Definition: ahd_bayer.c:54
do_green_ctr_row
static int do_green_ctr_row(unsigned char *image, unsigned char *image_h, unsigned char *image_v, int w, int h, int y, int *pos_code)
Missing greens are reconstructed on a single row.
Definition: ahd_bayer.c:233
RED
#define RED
Definition: ahd_bayer.c:56
MAX
#define MAX(x, y)
Definition: ahd_bayer.c:53
BAYER_TILE_BGGR_INTERLACED
@ BAYER_TILE_BGGR_INTERLACED
scanline order: B1,G1,R2,G2,...,G1,R1,G2,R2,...
Definition: bayer.h:39
BayerTile
BayerTile
how the bayer CCD array is layed out
Definition: bayer.h:32
BLUE
#define BLUE
Definition: ahd_bayer.c:58
gp_bayer_expand
int gp_bayer_expand(unsigned char *input, int w, int h, unsigned char *output, BayerTile tile)
Expand a bayer raster style image to a RGB raster.
Definition: bayer.c:74
gp_ahd_decode
int gp_ahd_decode(unsigned char *input, int w, int h, unsigned char *output, BayerTile tile)
Convert a bayer raster style image to a RGB raster.
Definition: ahd_bayer.c:638
gp_ahd_interpolate
int gp_ahd_interpolate(unsigned char *image, int w, int h, BayerTile tile)
Interpolate a expanded bayer array into an RGB image.
Definition: ahd_bayer.c:418
GREEN
#define GREEN
Definition: ahd_bayer.c:57
gphoto2-port-log.h
BAYER_TILE_GRBG_INTERLACED
@ BAYER_TILE_GRBG_INTERLACED
scanline order: G1,R1,R2,G2,...,B1,G1,B2,G2,...
Definition: bayer.h:38
CLAMP
#define CLAMP(x)
Definition: ahd_bayer.c:55
bayer.h
dRGB
static int dRGB(int i1, int i2, unsigned char *RGB)
This function computes distance^2 between two sets of pixel data.
Definition: ahd_bayer.c:80