/** \file ahd_bayer.c
*
* \brief Adaptive Homogeneity-Directed Bayer array conversion routine.
*
* \author Copyright March 12, 2008 Theodore Kilgore <kilgota@auburn.edu>
*
* \par
* gp_ahd_interpolate() from Eero Salminen <esalmine@gmail.com>
* and Theodore Kilgore. The work of Eero Salminen is for partial completion
* of a Diploma in Information and Computer Science,
* Helsinki University of Technology, Finland.
*
* \par
* The algorithm is based upon the paper
*
* \par
* Adaptive Homogeneity-Directed Democsaicing Algoritm,
* Keigo Hirakawa and Thomas W. Parks, presented in the
* IEEE Transactions on Image Processing, vol. 14, no. 3, March 2005.
*
* \par License
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* \par
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* \par
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
/*
#include "config.h"
*/
#include "bayer.h"
/*
#include <gphoto2/gphoto2-result.h>
#include <gphoto2/gphoto2-port-log.h>
*/
#define GP_MODULE "ahd_bayer"
#define MAX(x,y) ((x < y) ? (y) : (x))
#define MIN(x,y) ((x > y) ? (y) : (x))
#define CLAMP(x) MAX(MIN(x,0xff),0)
#define RED 0
#define GREEN 1
#define BLUE 2
static
int dRGB(int i1, int i2, unsigned char *RGB);
static
void do_rb_ctr_row(unsigned char *image_h, unsigned char *image_v, int w,
int h, int y, int *pos_code);
static
void do_green_ctr_row(unsigned char *image, unsigned char *image_h,
unsigned char *image_v, int w, int h, int y, int *pos_code);
static
void get_diffs_row2(unsigned char * hom_buffer_h, unsigned char *hom_buffer_v,
unsigned char * buffer_h, unsigned char *buffer_v, int w);
#define AD(x, y, w) ((y)*(w)*3+3*(x))
/**
* \brief This function computes distance^2 between two sets of pixel data.
* \param i1 location of a pixel
* \param i2 location of another pixel
* \param RGB some RGB data.
*/
static
int dRGB(int i1, int i2, unsigned char *RGB) {
int dR,dG,dB;
dR=RGB[i1+RED]-RGB[i2+RED];
dG=RGB[i1+GREEN]-RGB[i2+GREEN];
dB=RGB[i1+BLUE]-RGB[i2+BLUE];
return dR*dR+dG*dG+dB*dB;
}
/**
* \brief Missing reds and/or blues are reconstructed on a single row
* \param image_h three-row window, horizontal interpolation of row 1 is done
* \param image_v three-row window, vertical interpolation of row 1 is done
* \param w width of image
* \param h height of image.
* \param y row number from image which is under construction
* \param pos_code position code related to Bayer tiling in use
*/
static
void do_rb_ctr_row(unsigned char *image_h, unsigned char *image_v, int w,
int h, int y, int *pos_code)
{
int x, bayer;
int value,value2,div,color;
/*
* pos_code[0] = red. green lrtb, blue diagonals
* pos_code[1] = green. red lr, blue tb
* pos_code[2] = green. blue lr, red tb
* pos_code[3] = blue. green lrtb, red diagonals
*
* The Red channel reconstruction is R=G+L(Rs-Gs), in which
* G = interpolated & known Green
* Rs = known Red
* Gs = values of G at the positions of Rs
* L()= should be a 2D lowpass filter, now we'll check
* them from a 3x3 square
* L-functions' convolution matrix is
* [1/4 1/2 1/4;1/2 1 1/2; 1/4 1/2 1/4]
*
* The Blue channel reconstruction uses exactly the same methods.
*/
for (x = 0; x < w; x++)
{
bayer = (x&1?0:1) + (y&1?0:2);
for (color=0; color < 3; color+=2) {
if ((color==RED && bayer == pos_code[3])
|| (color==BLUE
&& bayer == pos_code[0])) {
value=value2=div=0;
if (x > 0 && y > 0) {
value += image_h[AD(x-1,0,w)+color]
-image_h[AD(x-1,0,w)+GREEN];
value2+= image_v[AD(x-1,0,w)+color]
-image_v[AD(x-1,0,w)+GREEN];
div++;
}
if (x > 0 && y < h-1) {
value += image_h[AD(x-1,2,w)+color]
-image_h[AD(x-1,2,w)+GREEN];
value2+= image_v[AD(x-1,2,w)+color]
-image_v[AD(x-1,2,w)+GREEN];
div++;
}
if (x < w-1 && y > 0) {
value += image_h[AD(x+1,0,w)+color]
-image_h[AD(x+1,0,w)+GREEN];
value2+= image_v[AD(x+1,0,w)+color]
-image_v[AD(x+1,0,w)+GREEN];
div++;
}
if (x < w-1 && y < h-1) {
value += image_h[AD(x+1,2,w)+color]
-image_h[AD(x+1,2,w)+GREEN];
value2+= image_v[AD(x+1,2,w)+color]
-image_v[AD(x+1,2,w)+GREEN];
div++;
}
image_h[AD(x,1,w)+color]=
CLAMP(
image_h[AD(x,1,w)+GREEN]
+value/div);
image_v[AD(x,1,w)+color]=
CLAMP(image_v[AD(x,1,w)+GREEN]
+value2/div);
} else if ((color==RED && bayer == pos_code[2])
|| (color==BLUE
&& bayer == pos_code[1])) {
value=value2=div=0;
if (y > 0) {
value += image_h[AD(x,0,w)+color]
-image_h[AD(x,0,w)+GREEN];
value2+= image_v[AD(x,0,w)+color]
-image_v[AD(x,0,w)+GREEN];
div++;
}
if (y < h-1) {
value += image_h[AD(x,2,w)+color]
-image_h[AD(x,2,w)+GREEN];
value2+= image_v[AD(x,2,w)+color]
-image_v[AD(x,2,w)+GREEN];
div++;
}
image_h[AD(x,1,w)+color]=
CLAMP(
image_h[AD(x,1,w)+GREEN]
+value/div);
image_v[AD(x,1,w)+color]=
CLAMP(
image_v[AD(x,1,w)+GREEN]
+value2/div);
} else if ((color==RED && bayer == pos_code[1])
|| (color==BLUE
&& bayer == pos_code[2])) {
value=value2=div=0;
if (x > 0) {
value += image_h[AD(x-1,1,w)+color]
-image_h[AD(x-1,1,w)+GREEN];
value2+= image_v[AD(x-1,1,w)+color]
-image_v[AD(x-1,1,w)+GREEN];
div++;
}
if (x < w-1) {
value += image_h[AD(x+1,1,w)+color]
-image_h[AD(x+1,1,w)+GREEN];
value2+= image_v[AD(x+1,1,w)+color]
-image_v[AD(x+1,1,w)+GREEN];
div++;
}
image_h[AD(x,1,w)+color]=
CLAMP(
image_h[AD(x,1,w)+GREEN]
+value/div);
image_v[AD(x,1,w)+color]=
CLAMP(
image_v[AD(x,1,w)+GREEN]
+value2/div);
}
}
}
}
/**
* \brief Missing greens are reconstructed on a single row
* \param image the image which is being reconstructed
* \param image_h three-row window, horizontal interpolation of row 1 is done
* \param image_v three-row window, vertical interpolation of row 1 is done
* \param w width of image
* \param h height of image.
* \param y row number from image which is under construction
* \param pos_code position code related to Bayer tiling in use
*/
static
void do_green_ctr_row(unsigned char *image, unsigned char *image_h,
unsigned char *image_v, int w, int h, int y, int *pos_code)
{
int x, bayer;
int value,div;
/*
* The horizontal green estimation on a red-green row is
* G(x) = (2*R(x)+2*G(x+1)+2*G(x-1)-R(x-2)-R(x+2))/4
* The estimation on a green-blue row works in the same
* way.
*/
for (x = 0; x < w; x++) {
bayer = (x&1?0:1) + (y&1?0:2);
/* pos_code[0] = red. green lrtb, blue diagonals */
/* pos_code[3] = blue. green lrtb, red diagonals */
if ( bayer == pos_code[0] || bayer == pos_code[3]) {
div=value=0;
if (bayer==pos_code[0])
value += 2*image[AD(x,y,w)+RED];
else
value += 2*image[AD(x,y,w)+BLUE];
div+=2;
if (x < (w-1)) {
value += 2*image[AD(x+1,y,w)+GREEN];
div+=2;
}
if (x < (w-2)) {
if (bayer==pos_code[0])
value -= image[AD(x+2,y,w)+RED];
else
value -= image[AD(x+2,y,w)+BLUE];
div--;
}
if (x > 0) {
value += 2*image[AD(x-1,y,w