Logo Search packages:      
Sourcecode: libgphoto2 version File versions

int gp_ahd_interpolate ( unsigned char *  image,
int  w,
int  h,
BayerTile  tile 
)

Interpolate a expanded bayer array into an RGB image.

Parameters:
image the linear RGB array as both input and output
w width of the above array
h height of the above array
tile how the 2x2 bayer array is layed out
This function interpolates a bayer array which has been pre-expanded by gp_bayer_expand() to an RGB image. It applies the method of adaptive homogeneity-directed demosaicing.

Returns:
a gphoto error code
In outline, the interpolation algorithm used here does the following:
In principle, the first thing which is done is to split off from the image two copies. In one of these, interpolation will be done in the vertical direction only, and in the other copy only in the horizontal direction. "Cross-color" data is used throughout, on the principle that it can be used as a corrector for brightness even if it is derived from the "wrong" color. Finally, at each pixel there is a choice criterion to decide whether to use the result of the vertical interpolation, the horizontal interpolation, or an average of the two.
Memory use and speed are optimized by using two sliding windows, one for the vertical interpolation and the other for the horizontal interpolation instead of using two copies of the entire input image. The nterpolation and the choice algorithm are then implemented entirely within these windows, too. When this has been done, a completed row is written back to the image. Then the windows are moved, and the process repeats.

Definition at line 419 of file ahd_bayer.c.

References BAYER_TILE_BGGR, BAYER_TILE_BGGR_INTERLACED, BAYER_TILE_GBRG, BAYER_TILE_GBRG_INTERLACED, BAYER_TILE_GRBG, BAYER_TILE_GRBG_INTERLACED, BAYER_TILE_RGGB, BAYER_TILE_RGGB_INTERLACED, do_green_ctr_row(), do_rb_ctr_row(), get_diffs_row2(), GP_ERROR_NO_MEMORY, and GP_OK.

Referenced by gp_ahd_decode().

{
      int i, j, k, x, y;
      int p[4];
      int color;
      unsigned char *window_h, *window_v, *cur_window_h, *cur_window_v;
      unsigned char *homo_h, *homo_v;
      unsigned char *homo_ch, *homo_cv;

      window_h = calloc (w * 18, 1);
      if (!window_h) {
            free (window_h);
            GP_DEBUG("Out of memory\n");
            return GP_ERROR_NO_MEMORY;
      }
      window_v = calloc(w * 18, 1);
      if (!window_v) {
            free (window_v);
            GP_DEBUG("Out of memory\n");
            return GP_ERROR_NO_MEMORY;
      }
      homo_h = calloc(w*3, 1);
      if (!homo_h) {
            free (homo_h);
            GP_DEBUG("Out of memory\n");
            return GP_ERROR_NO_MEMORY;
      }
      homo_v = calloc(w*3, 1);
      if (!homo_v) {
            free (homo_v);
            GP_DEBUG("Out of memory\n");
            return GP_ERROR_NO_MEMORY;
      }
      homo_ch = calloc (w, 1);
      if (!homo_ch) {
            free (homo_ch);
            GP_DEBUG("Out of memory\n");
            return GP_ERROR_NO_MEMORY;
      }
      homo_cv = calloc (w, 1);
      if (!homo_cv) {
            free (homo_ch);
            GP_DEBUG("Out of memory\n");
            return GP_ERROR_NO_MEMORY;
      }
      switch (tile) {
      default:
      case BAYER_TILE_RGGB:
      case BAYER_TILE_RGGB_INTERLACED:
            p[0] = 0; p[1] = 1; p[2] = 2; p[3] = 3;
            break;
      case BAYER_TILE_GRBG:
      case BAYER_TILE_GRBG_INTERLACED:
            p[0] = 1; p[1] = 0; p[2] = 3; p[3] = 2;
            break;
      case BAYER_TILE_BGGR:
      case BAYER_TILE_BGGR_INTERLACED:
            p[0] = 3; p[1] = 2; p[2] = 1; p[3] = 0;
            break;
      case BAYER_TILE_GBRG:
      case BAYER_TILE_GBRG_INTERLACED:
            p[0] = 2; p[1] = 3; p[2] = 0; p[3] = 1;
            break;
      }

      /* 
       * Once the algorithm is initialized and running, one cycle of the 
       * algorithm can be described thus:
       * 
       * Step 1
       * Write from row y+3 of the image to row 5 in window_v and in 
       * window_h. 
       *
       * Step 2
       * Interpolate missing green data on row 5 in each window. Data from
       * the image only is needed for this, not data from the windows. 
       *
       * Step 3
       * Now interpolate the missing red or blue data on row 4 in both 
       * windows. We need to do this inside the windows; what is required 
       * is the real or interpolated green data from rows 3 and 5, and the 
       * real data on rows 3 and 5 about the color being interpolated on 
       * row 4, so all of this information is available in the two windows. 
       * Note that for this operation we are interpolating the center row 
       * of cur_window_v and cur_window_h. 
       * 
       * Step 4
       * Now we have five completed rows in each window, 0 through 4 (rows
       * 0 - 3 having been done in previous cycles). Completed rows 0 - 4 
       * are what is required in order to run the choice algorithm at 
       * each pixel location across row 2, to decide whether to choose the 
       * data for that pixel from window_v or from window_h. We run the 
       * choice algorithm, sending the data from row 2 over to row y of the 
       * image, pixel by pixel. 
       *
       * Step 5
       * Move the windows down (or the data in them up) by one row.
       * Increment y, the row counter for the image. Go to Step 1.
       * 
       * Initialization of the algorithm clearly requires some special 
       * steps, which are described below as they occur. 
       */
      cur_window_h = window_h+9*w; 
      cur_window_v = window_v+9*w; 
      /*
       * Getting started. Copy row 0 from image to line 4 of windows
       * and row 1 from image to line 5 of windows. 
       */
      memcpy (window_h+12*w, image, 6*w);
      memcpy (window_v+12*w, image, 6*w);
      /*
       * Now do the green interpolation in row 4 of the windows, the 
       * "center" row of cur_window_v and  _h, with the help of image row 0
       * and image row 1.
       */
      do_green_ctr_row(image, cur_window_h, cur_window_v, w, h, 0, p);
      /* this does the green interpolation in row 5 of the windows */
      do_green_ctr_row(image, cur_window_h+3*w, cur_window_v+3*w, w, h, 1, p);
      /*
       * we are now ready to do the rb interpolation on row 4 of the 
       * windows, which relates to row 0 of the image. 
       */ 
      do_rb_ctr_row(cur_window_h, cur_window_v, w, h, 0, p);
      /*
       * Row row 4, which will be mapped to image row 0, is finished in both
       * windows. Row 5 has had only the green interpolation. 
       */
      memmove(window_h, window_h+3*w,15*w);
      memmove(window_v, window_v+3*w,15*w);
      memcpy (window_h+15*w, image+6*w, 3*w);
      memcpy (window_v+15*w, image+6*w, 3*w);
      /*
       * now we have shifted backwards and we have row 0 of the image in 
       * row 3 of the windows. Row 4 of the window contains row 1 of image
       * and needs the rb interpolation. We have copied row 2 of the image 
       * into row 5 of the windows and need to do green interpolation. 
       */
      do_green_ctr_row(image, cur_window_h+3*w, cur_window_v+3*w, w, h, 2, p);
      do_rb_ctr_row(cur_window_h, cur_window_v, w, h, 1, p);
      memmove (window_h, window_h+3*w, 15*w);
      memmove(window_v, window_v+3*w,15*w); 
      /*
       * We have shifted one more time. Row 2 of the two windows is 
       * the original row 0 of the image, now fully interpolated. Rows 3 
       * and 4 of the windows contain the original rows 1 and 2 of the 
       * image, also fully interpolated. They will be used while applying 
       * the choice algorithm on row 2, in order to write it back to row
       * 0 of the image. The algorithm is now fully initialized. We enter 
       * the loop which will complete the algorithm for the whole image.
       */
       
      for (y = 0; y < h; y++) {
            if(y<h-3) {
                  memcpy (window_v+15*w,image+3*y*w+9*w, 3*w);
                  memcpy (window_h+15*w,image+3*y*w+9*w, 3*w);
            } else {
                  memset(window_v+15*w, 0, 3*w);
                  memset(window_h+15*w, 0, 3*w);
            }
            if (y<h-3) 
                  do_green_ctr_row(image, cur_window_h+3*w, 
                              cur_window_v+3*w, w, h, y+3, p);
            if (y<h-2) 
                  do_rb_ctr_row(cur_window_h, cur_window_v, w, h, y+2, p);
            /*
             * The next function writes row 2 of diffs, which is the set of 
             * diff scores for row y+1 of the image, which is row 3 of our 
             * windows. When starting with row 0 of the image, this is all
             * we need. As we continue, the results of this calculation 
             * will also be rotated; in general we need the diffs for rows
             * y-1, y, and y+1 in order to carry out the choice algorithm
             * for writing row y.
             */
            get_diffs_row2(homo_h, homo_v, window_h, window_v, w);
            memset(homo_ch, 0, w);
            memset(homo_cv, 0, w);

            /* The choice algorithm now will use the sum of the nine diff 
             * scores computed at the pixel location and at its eight 
             * nearest neighbors. The direction with highest score will 
             * be used; if the scores are equal an average is used. 
             */
            for (x=0; x < w; x++) {
                  for (i=-1; i < 2;i++) {
                        for (k=0; k < 3;k++) {
                              j=i+x+w*k; 
                              homo_ch[x]+=homo_h[j];
                              homo_cv[x]+=homo_v[j];
                        }
                  }
                  for (color=0; color < 3; color++) {
                        if (homo_ch[x] > homo_cv[x])
                              image[3*y*w+3*x+color]
                              = window_h[3*x+6*w+color];
                        else if (homo_ch[x] < homo_cv[x])
                              image[3*y*w+3*x+color]
                              = window_v[3*x+6*w+color];
                        else
                              image[3*y*w+3*x+color]
                              = (window_v[3*x+6*w+color]+
                                    window_h[3*x+6*w+color])/2;
                  }
            }
            /* Move the windows; loop back if not finished. */
            memmove(window_v, window_v+3*w, 15*w);
            memmove(window_h, window_h+3*w, 15*w);
            memmove (homo_h,homo_h+w,2*w);
            memmove (homo_v,homo_v+w,2*w);
      }
      free(window_v);
      free(window_h);
      free(homo_h);
      free(homo_v);
      free(homo_ch);
      free(homo_cv);
      return GP_OK;
}


Generated by  Doxygen 1.6.0   Back to index