代码
注: 本代码非本人所作, 如他人用于其它任何用途均与本人无关.
/* raw.h */
#ifndef __RAW_H__
#define __RAW_H__
#define GP_OK 1
typedef enum {
BAYER_TILE_RGGB = 0 ,
BAYER_TILE_GRBG = 1 ,
BAYER_TILE_BGGR = 2 ,
BAYER_TILE_GBRG = 3 ,
BAYER_TILE_RGGB_INTERLACED = 4 ,
BAYER_TILE_GRBG_INTERLACED = 5 ,
BAYER_TILE_BGGR_INTERLACED = 6 ,
BAYER_TILE_GBRG_INTERLACED = 7 ,
} BayerTile;
int gp_bayer_expand (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile);
int gp_bayer_decode (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile);
int gp_bayer_interpolate (unsigned char * image, int w, int h, BayerTile tile);
#endif
/* raw.c */
#include " raw.h "
static const int tile_colours[ 8 ][ 4 ] = {
{ 0 , 1 , 1 , 2 },
{ 1 , 0 , 2 , 1 },
{ 2 , 1 , 1 , 0 },
{ 1 , 2 , 0 , 1 },
{ 0 , 1 , 1 , 2 },
{ 1 , 0 , 2 , 1 },
{ 2 , 1 , 1 , 0 },
{ 1 , 2 , 0 , 1 }};
#define RED 0
#define GREEN 1
#define BLUE 2
static int
gp_bayer_accrue (unsigned char * image, int w, int h, int x0, int y0,
int x1, int y1, int x2, int y2, int x3, int y3, int colour);
int
gp_bayer_expand (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile)
{
int x, y, i;
int colour, bayer;
unsigned char * ptr = input;
switch (tile) {
case BAYER_TILE_RGGB:
case BAYER_TILE_GRBG:
case BAYER_TILE_BGGR:
case BAYER_TILE_GBRG:
for (y = 0 ; y < h; ++ y)
for (x = 0 ; x < w; ++ x, ++ ptr)
{
bayer = (x & 1 ? 0 : 1 ) + (y & 1 ? 0 : 2 );
colour = tile_colours[tile][bayer];
i = (y * w + x) * 3 ;
output[i + RED] = 0 ;
output[i + GREEN] = 0 ;
output[i + BLUE] = 0 ;
output[i + colour] = * ptr;
}
break ;
case BAYER_TILE_RGGB_INTERLACED:
case BAYER_TILE_GRBG_INTERLACED:
case BAYER_TILE_BGGR_INTERLACED:
case BAYER_TILE_GBRG_INTERLACED:
for (y = 0 ; y < h; ++ y, ptr += w)
for (x = 0 ; x < w; ++ x)
{
bayer = (x & 1 ? 0 : 1 ) + (y & 1 ? 0 : 2 );
colour = tile_colours[tile][bayer];
i = (y * w + x) * 3 ;
output[i + RED] = 0 ;
output[i + GREEN] = 0 ;
output[i + BLUE] = 0 ;
output[i + colour] = (x & 1 ) ? ptr[x >> 1 ]:ptr[(w >> 1 ) + (x >> 1 )];
}
break ;
}
return (GP_OK);
}
#define AD(x, y, w) ((y)*(w)*3+3*(x))
int
gp_bayer_interpolate (unsigned char * image, int w, int h, BayerTile tile)
{
int x, y, bayer;
int p0, p1, p2, p3;
int value, div ;
switch (tile) {
default :
case BAYER_TILE_RGGB:
case BAYER_TILE_RGGB_INTERLACED:
p0 = 0 ; p1 = 1 ; p2 = 2 ; p3 = 3 ;
break ;
case BAYER_TILE_GRBG:
case BAYER_TILE_GRBG_INTERLACED:
p0 = 1 ; p1 = 0 ; p2 = 3 ; p3 = 2 ;
break ;
case BAYER_TILE_BGGR:
case BAYER_TILE_BGGR_INTERLACED:
p0 = 3 ; p1 = 2 ; p2 = 1 ; p3 = 0 ;
break ;
case BAYER_TILE_GBRG:
case BAYER_TILE_GBRG_INTERLACED:
p0 = 2 ; p1 = 3 ; p2 = 0 ; p3 = 1 ;
break ;
}
for (y = 0 ; y < h; y ++ )
for (x = 0 ; x < w; x ++ ) {
bayer = (x & 1 ? 0 : 1 ) + (y & 1 ? 0 : 2 );
if ( bayer == p0 ) {
/* red. green lrtb, blue diagonals */
image[AD(x,y,w) + GREEN] =
gp_bayer_accrue(image, w, h, x - 1 , y, x + 1 , y, x, y - 1 , x, y + 1 , GREEN) ;
image[AD(x,y,w) + BLUE] =
gp_bayer_accrue(image, w, h, x + 1 , y + 1 , x - 1 , y - 1 , x - 1 , y + 1 , x + 1 , y - 1 , BLUE) ;
} else if (bayer == p1) {
/* green. red lr, blue tb */
div = value = 0 ;
if (x < (w - 1 )) {
value += image[AD(x + 1 ,y,w) + RED];
div ++ ;
}
if (x) {
value += image[AD(x - 1 ,y,w) + RED];
div ++ ;
}
image[AD(x,y,w) + RED] = value / div;
div = value = 0 ;
if (y < (h - 1 )) {
value += image[AD(x,y + 1 ,w) + BLUE];
div ++ ;
}
if (y) {
value += image[AD(x,y - 1 ,w) + BLUE];
div ++ ;
}
image[AD(x,y,w) + BLUE] = value / div;
} else if ( bayer == p2 ) {
/* green. blue lr, red tb */
div = value = 0 ;
if (x < (w - 1 )) {
value += image[AD(x + 1 ,y,w) + BLUE];
div ++ ;
}
if (x) {
value += image[AD(x - 1 ,y,w) + BLUE];
div ++ ;
}
image[AD(x,y,w) + BLUE] = value / div;
div = value = 0 ;
if (y < (h - 1 )) {
value += image[AD(x,y + 1 ,w) + RED];
div ++ ;
}
if (y) {
value += image[AD(x,y - 1 ,w) + RED];
div ++ ;
}
image[AD(x,y,w) + RED] = value / div;
} else {
/* blue. green lrtb, red diagonals */
image[AD(x,y,w) + GREEN] =
gp_bayer_accrue (image, w, h, x - 1 , y, x + 1 , y, x, y - 1 , x, y + 1 , GREEN) ;
image[AD(x,y,w) + RED] =
gp_bayer_accrue (image, w, h, x + 1 , y + 1 , x - 1 , y - 1 , x - 1 , y + 1 , x + 1 , y - 1 , RED) ;
}
}
return (GP_OK);
}
static int
gp_bayer_accrue (unsigned char * image, int w, int h, int x0, int y0,
int x1, int y1, int x2, int y2, int x3, int y3, int colour)
{ int x [ 4 ] ;
int y [ 4 ] ;
int value [ 4 ] ;
int above [ 4 ] ;
int counter ;
int sum_of_values;
int average ;
int i ;
x[ 0 ] = x0 ; x[ 1 ] = x1 ; x[ 2 ] = x2 ; x[ 3 ] = x3 ;
y[ 0 ] = y0 ; y[ 1 ] = y1 ; y[ 2 ] = y2 ; y[ 3 ] = y3 ;
counter = sum_of_values = 0 ;
if (colour == GREEN)
{
for (i = 0 ; i < 4 ; i ++ )
{ if ((x[i] >= 0 ) && (x[i] < w) && (y[i] >= 0 ) && (y[i] < h))
{
value [i] = image[AD(x[i],y[i],w) + colour] ;
counter ++ ;
}
else
{
value [i] = - 1 ;
}
}
if (counter == 4 )
{
int hdiff ;
int vdiff ;
hdiff = value [ 1 ] - value [ 0 ] ;
hdiff *= hdiff ; /* Make value positive by squaring */
vdiff = value [ 3 ] - value [ 2 ] ;
vdiff *= vdiff ; /* Make value positive by squaring */
if (hdiff > 2 * vdiff)
{
return (value [ 3 ] + value [ 2 ]) / 2 ;
}
if (vdiff > 2 * hdiff)
{
return (value [ 1 ] + value [ 0 ]) / 2 ;
}
}
}
/* for blue and red */
counter = sum_of_values = 0 ;
for (i = 0 ; i < 4 ; i ++ )
{ if ((x[i] >= 0 ) && (x[i] < w) && (y[i] >= 0 ) && (y[i] < h))
{ value [i] = image[AD(x[i],y[i],w) + colour] ;
sum_of_values += value [i] ;
counter ++ ;
}
}
average = sum_of_values / counter ;
if (counter < 4 ) return average ;
/* Less than four surrounding - just take average */
counter = 0 ;
for (i = 0 ; i < 4 ; i ++ )
{ above[i] = value[i] > average ;
if (above[i]) counter ++ ;
}
/* Note: counter == 0 indicates all values the same */
if ((counter == 2 ) || (counter == 0 )) return average ;
sum_of_values = 0 ;
for (i = 0 ; i < 4 ; i ++ )
{ if ((counter == 3 ) == above[i])
{ sum_of_values += value[i] ; }
}
return sum_of_values / 3 ;
}
int
gp_bayer_decode (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile)
{
gp_bayer_expand (input, w, h, output, tile);
gp_bayer_interpolate (output, w, h, tile);
return (GP_OK);
}
/* raw.h */
#ifndef __RAW_H__
#define __RAW_H__
#define GP_OK 1
typedef enum {
BAYER_TILE_RGGB = 0 ,
BAYER_TILE_GRBG = 1 ,
BAYER_TILE_BGGR = 2 ,
BAYER_TILE_GBRG = 3 ,
BAYER_TILE_RGGB_INTERLACED = 4 ,
BAYER_TILE_GRBG_INTERLACED = 5 ,
BAYER_TILE_BGGR_INTERLACED = 6 ,
BAYER_TILE_GBRG_INTERLACED = 7 ,
} BayerTile;
int gp_bayer_expand (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile);
int gp_bayer_decode (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile);
int gp_bayer_interpolate (unsigned char * image, int w, int h, BayerTile tile);
#endif
/* raw.c */
#include " raw.h "
static const int tile_colours[ 8 ][ 4 ] = {
{ 0 , 1 , 1 , 2 },
{ 1 , 0 , 2 , 1 },
{ 2 , 1 , 1 , 0 },
{ 1 , 2 , 0 , 1 },
{ 0 , 1 , 1 , 2 },
{ 1 , 0 , 2 , 1 },
{ 2 , 1 , 1 , 0 },
{ 1 , 2 , 0 , 1 }};
#define RED 0
#define GREEN 1
#define BLUE 2
static int
gp_bayer_accrue (unsigned char * image, int w, int h, int x0, int y0,
int x1, int y1, int x2, int y2, int x3, int y3, int colour);
int
gp_bayer_expand (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile)
{
int x, y, i;
int colour, bayer;
unsigned char * ptr = input;
switch (tile) {
case BAYER_TILE_RGGB:
case BAYER_TILE_GRBG:
case BAYER_TILE_BGGR:
case BAYER_TILE_GBRG:
for (y = 0 ; y < h; ++ y)
for (x = 0 ; x < w; ++ x, ++ ptr)
{
bayer = (x & 1 ? 0 : 1 ) + (y & 1 ? 0 : 2 );
colour = tile_colours[tile][bayer];
i = (y * w + x) * 3 ;
output[i + RED] = 0 ;
output[i + GREEN] = 0 ;
output[i + BLUE] = 0 ;
output[i + colour] = * ptr;
}
break ;
case BAYER_TILE_RGGB_INTERLACED:
case BAYER_TILE_GRBG_INTERLACED:
case BAYER_TILE_BGGR_INTERLACED:
case BAYER_TILE_GBRG_INTERLACED:
for (y = 0 ; y < h; ++ y, ptr += w)
for (x = 0 ; x < w; ++ x)
{
bayer = (x & 1 ? 0 : 1 ) + (y & 1 ? 0 : 2 );
colour = tile_colours[tile][bayer];
i = (y * w + x) * 3 ;
output[i + RED] = 0 ;
output[i + GREEN] = 0 ;
output[i + BLUE] = 0 ;
output[i + colour] = (x & 1 ) ? ptr[x >> 1 ]:ptr[(w >> 1 ) + (x >> 1 )];
}
break ;
}
return (GP_OK);
}
#define AD(x, y, w) ((y)*(w)*3+3*(x))
int
gp_bayer_interpolate (unsigned char * image, int w, int h, BayerTile tile)
{
int x, y, bayer;
int p0, p1, p2, p3;
int value, div ;
switch (tile) {
default :
case BAYER_TILE_RGGB:
case BAYER_TILE_RGGB_INTERLACED:
p0 = 0 ; p1 = 1 ; p2 = 2 ; p3 = 3 ;
break ;
case BAYER_TILE_GRBG:
case BAYER_TILE_GRBG_INTERLACED:
p0 = 1 ; p1 = 0 ; p2 = 3 ; p3 = 2 ;
break ;
case BAYER_TILE_BGGR:
case BAYER_TILE_BGGR_INTERLACED:
p0 = 3 ; p1 = 2 ; p2 = 1 ; p3 = 0 ;
break ;
case BAYER_TILE_GBRG:
case BAYER_TILE_GBRG_INTERLACED:
p0 = 2 ; p1 = 3 ; p2 = 0 ; p3 = 1 ;
break ;
}
for (y = 0 ; y < h; y ++ )
for (x = 0 ; x < w; x ++ ) {
bayer = (x & 1 ? 0 : 1 ) + (y & 1 ? 0 : 2 );
if ( bayer == p0 ) {
/* red. green lrtb, blue diagonals */
image[AD(x,y,w) + GREEN] =
gp_bayer_accrue(image, w, h, x - 1 , y, x + 1 , y, x, y - 1 , x, y + 1 , GREEN) ;
image[AD(x,y,w) + BLUE] =
gp_bayer_accrue(image, w, h, x + 1 , y + 1 , x - 1 , y - 1 , x - 1 , y + 1 , x + 1 , y - 1 , BLUE) ;
} else if (bayer == p1) {
/* green. red lr, blue tb */
div = value = 0 ;
if (x < (w - 1 )) {
value += image[AD(x + 1 ,y,w) + RED];
div ++ ;
}
if (x) {
value += image[AD(x - 1 ,y,w) + RED];
div ++ ;
}
image[AD(x,y,w) + RED] = value / div;
div = value = 0 ;
if (y < (h - 1 )) {
value += image[AD(x,y + 1 ,w) + BLUE];
div ++ ;
}
if (y) {
value += image[AD(x,y - 1 ,w) + BLUE];
div ++ ;
}
image[AD(x,y,w) + BLUE] = value / div;
} else if ( bayer == p2 ) {
/* green. blue lr, red tb */
div = value = 0 ;
if (x < (w - 1 )) {
value += image[AD(x + 1 ,y,w) + BLUE];
div ++ ;
}
if (x) {
value += image[AD(x - 1 ,y,w) + BLUE];
div ++ ;
}
image[AD(x,y,w) + BLUE] = value / div;
div = value = 0 ;
if (y < (h - 1 )) {
value += image[AD(x,y + 1 ,w) + RED];
div ++ ;
}
if (y) {
value += image[AD(x,y - 1 ,w) + RED];
div ++ ;
}
image[AD(x,y,w) + RED] = value / div;
} else {
/* blue. green lrtb, red diagonals */
image[AD(x,y,w) + GREEN] =
gp_bayer_accrue (image, w, h, x - 1 , y, x + 1 , y, x, y - 1 , x, y + 1 , GREEN) ;
image[AD(x,y,w) + RED] =
gp_bayer_accrue (image, w, h, x + 1 , y + 1 , x - 1 , y - 1 , x - 1 , y + 1 , x + 1 , y - 1 , RED) ;
}
}
return (GP_OK);
}
static int
gp_bayer_accrue (unsigned char * image, int w, int h, int x0, int y0,
int x1, int y1, int x2, int y2, int x3, int y3, int colour)
{ int x [ 4 ] ;
int y [ 4 ] ;
int value [ 4 ] ;
int above [ 4 ] ;
int counter ;
int sum_of_values;
int average ;
int i ;
x[ 0 ] = x0 ; x[ 1 ] = x1 ; x[ 2 ] = x2 ; x[ 3 ] = x3 ;
y[ 0 ] = y0 ; y[ 1 ] = y1 ; y[ 2 ] = y2 ; y[ 3 ] = y3 ;
counter = sum_of_values = 0 ;
if (colour == GREEN)
{
for (i = 0 ; i < 4 ; i ++ )
{ if ((x[i] >= 0 ) && (x[i] < w) && (y[i] >= 0 ) && (y[i] < h))
{
value [i] = image[AD(x[i],y[i],w) + colour] ;
counter ++ ;
}
else
{
value [i] = - 1 ;
}
}
if (counter == 4 )
{
int hdiff ;
int vdiff ;
hdiff = value [ 1 ] - value [ 0 ] ;
hdiff *= hdiff ; /* Make value positive by squaring */
vdiff = value [ 3 ] - value [ 2 ] ;
vdiff *= vdiff ; /* Make value positive by squaring */
if (hdiff > 2 * vdiff)
{
return (value [ 3 ] + value [ 2 ]) / 2 ;
}
if (vdiff > 2 * hdiff)
{
return (value [ 1 ] + value [ 0 ]) / 2 ;
}
}
}
/* for blue and red */
counter = sum_of_values = 0 ;
for (i = 0 ; i < 4 ; i ++ )
{ if ((x[i] >= 0 ) && (x[i] < w) && (y[i] >= 0 ) && (y[i] < h))
{ value [i] = image[AD(x[i],y[i],w) + colour] ;
sum_of_values += value [i] ;
counter ++ ;
}
}
average = sum_of_values / counter ;
if (counter < 4 ) return average ;
/* Less than four surrounding - just take average */
counter = 0 ;
for (i = 0 ; i < 4 ; i ++ )
{ above[i] = value[i] > average ;
if (above[i]) counter ++ ;
}
/* Note: counter == 0 indicates all values the same */
if ((counter == 2 ) || (counter == 0 )) return average ;
sum_of_values = 0 ;
for (i = 0 ; i < 4 ; i ++ )
{ if ((counter == 3 ) == above[i])
{ sum_of_values += value[i] ; }
}
return sum_of_values / 3 ;
}
int
gp_bayer_decode (unsigned char * input, int w, int h, unsigned char * output,
BayerTile tile)
{
gp_bayer_expand (input, w, h, output, tile);
gp_bayer_interpolate (output, w, h, tile);
return (GP_OK);
}