.badpixels file support for X-Trans sensor, Issue 2543

This commit is contained in:
Ingo
2014-11-06 14:49:32 +01:00
parent e61e1b6e50
commit 55815038b4
2 changed files with 165 additions and 7 deletions

View File

@@ -456,10 +456,10 @@ void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* interpolateBadPixels: correct raw pixels looking at the bitmap
/* interpolateBadPixelsBayer: correct raw pixels looking at the bitmap
* takes into consideration if there are multiple bad pixels in the neighborhood
*/
int RawImageSource::interpolateBadPixels( PixelsMap &bitmapBads )
int RawImageSource::interpolateBadPixelsBayer( PixelsMap &bitmapBads )
{
static const float eps=1.f;
int counter=0;
@@ -556,7 +556,162 @@ int RawImageSource::interpolateBadPixels( PixelsMap &bitmapBads )
}
return counter; // Number of interpolated pixels.
}
/* interpolateBadPixelsXtrans: correct raw pixels looking at the bitmap
* takes into consideration if there are multiple bad pixels in the neighborhood
*/
int RawImageSource::interpolateBadPixelsXtrans( PixelsMap &bitmapBads )
{
static const float eps=1.f;
int counter=0;
#pragma omp parallel for reduction(+:counter) schedule(dynamic,16)
for( int row = 2; row < H-2; row++ ){
for(int col = 2; col <W-2; col++ ){
int skip = bitmapBads.skipIfZero(col,row); //optimization for a stripe all zero
if( skip ){
col +=skip-1; //-1 is because of col++ in cycle
continue;
}
if(!bitmapBads.get(col,row))
continue;
float wtdsum=0.f,norm=0.f;
int pixelColor = ri->XTRANSFC(row,col);
float oldval = rawData[row][col];
if(pixelColor==1) {
// green channel. A green pixel can either be a solitary green pixel or a member of a 2x2 square of green pixels
if(ri->XTRANSFC(row,col-1)==ri->XTRANSFC(row,col+1)) {
// If left and right neighbour have same color, then this is a solitary green pixel
// For these the following pixels will be used for interpolation. Pixel to be interpolated is in center and marked with a P.
// Pairs of pixels used in this step are numbered. A pair will be used if none of the pixels of the pair is marked bad
// 0 means, the pixel has a different color and will not be used
// 0 1 0 2 0
// 3 5 0 6 4
// 0 0 P 0 0
// 4 6 0 5 3
// 0 2 0 1 0
for( int dx=-1;dx<=1;dx+=2){ // pixels marked 5 or 6 in above example. Distance to P is sqrt(2) => weighting is 0.70710678f
if( bitmapBads.get(col+dx,row-1) || bitmapBads.get(col-dx,row+1))
continue;
float dirwt = 0.70710678f/( fabsf( rawData[row-1][col+dx]- rawData[row+1][col-dx])+eps);
wtdsum += dirwt * (rawData[row-1][col+dx] + rawData[row+1][col-dx]);
norm += dirwt;
}
for( int dx=-1;dx<=1;dx+=2){ // pixels marked 1 or 2 on above example. Distance to P is sqrt(5) => weighting is 0.44721359f
if( bitmapBads.get(col+dx,row-2) || bitmapBads.get(col-dx,row+2))
continue;
float dirwt = 0.44721359f/( fabsf( rawData[row-2][col+dx]- rawData[row+2][col-dx])+eps);
wtdsum += dirwt * (rawData[row-2][col+dx] + rawData[row+2][col-dx]);
norm += dirwt;
}
for( int dx=-2;dx<=2;dx+=4){ // pixels marked 3 or 4 on above example. Distance to P is sqrt(5) => weighting is 0.44721359f
if( bitmapBads.get(col+dx,row-1) || bitmapBads.get(col-dx,row+1))
continue;
float dirwt = 0.44721359f/( fabsf( rawData[row-1][col+dx]- rawData[row+1][col-dx])+eps);
wtdsum += dirwt * (rawData[row-1][col+dx] + rawData[row+1][col-dx]);
norm += dirwt;
}
} else {
// this is a member of a 2x2 square of green pixels
// For these the following pixels will be used for interpolation. Pixel to be interpolated is at position P in the example.
// Pairs of pixels used in this step are numbered. A pair will be used if none of the pixels of the pair is marked bad
// 0 means, the pixel has a different color and will not be used
// 1 0 0 3
// 0 P 2 0
// 0 2 1 0
// 3 0 0 0
int offset1 = ri->XTRANSFC(row-1,col-1) == ri->XTRANSFC(row+1,col+1) ? 1 : -1; // pixels marked 1 in above example. Distance to P is sqrt(2) => weighting is 0.70710678f
if( !(bitmapBads.get(col-offset1,row-1) || bitmapBads.get(col+offset1,row+1))) {
float dirwt = 0.70710678f/( fabsf( rawData[row-1][col-offset1]- rawData[row+1][col+offset1])+eps);
wtdsum += dirwt * (rawData[row-1][col-offset1] + rawData[row+1][col+offset1]);
norm += dirwt;
}
int offsety = (ri->XTRANSFC(row-1,col) != 1 ? 1 : -1);
int offsetx = offset1 * offsety;
if( !(bitmapBads.get(col+offsetx,row) || bitmapBads.get(col,row+offsety))) {
float dirwt = 1.f/( fabsf( rawData[row][col+offsetx]- rawData[row+offsety][col])+eps);
wtdsum += dirwt * (rawData[row][col+offsetx] + rawData[row+offsety][col]);
norm += dirwt;
}
int offsety2 = -offsety;
int offsetx2 = -offsetx;
offsetx *=2;
offsety *=2;
// pixels marked 3 in above example. Distance to P is sqrt(5) => weighting is 0.44721359f
if( !(bitmapBads.get(col+offsetx,row+offsety2) || bitmapBads.get(col+offsetx2,row+offsety))) {
float dirwt = 0.44721359f/( fabsf( rawData[row+offsety2][col+offsetx]- rawData[row+offsety][col+offsetx2])+eps);
wtdsum += dirwt * (rawData[row+offsety2][col+offsetx] + rawData[row+offsety][col+offsetx2]);
norm += dirwt;
}
}
} else {
// red and blue channel.
// Each red or blue pixel has exactly one neigbour of same color in distance 2 and four neighbours of same color which can be reached by a move of a knight in chess.
// For the distance 2 pixel (marked with an X) we generate a virtual counterpart (marked with a V)
// For red and blue channel following pixels will be used for interpolation. Pixel to be interpolated is in center and marked with a P.
// Pairs of pixels used in this step are numbered except for distance 2 pixels which are marked X and V. A pair will be used if none of the pixels of the pair is marked bad
// 0 1 0 0 0 0 0 X 0 0 remaining cases are symmetric
// 0 0 0 0 2 1 0 0 0 2
// X 0 P 0 V 0 0 P 0 0
// 0 0 0 0 1 0 0 0 0 0
// 0 2 0 0 0 0 2 V 1 0
// Find two knight moves landing on a pixel of same color as the pixel to be interpolated.
// If we look at first and last row of 5x5 square, we will find exactly two knight pixels.
// Additionally we know that the column of this pixel has 1 or -1 horizontal distance to the center pixel
// When we find a knight pixel, we get its counterpart, which has distance (+-3,+-3), where the signs of distance depend on the corner of the found knight pixel.
// These pixels are marked 1 or 2 in above examples. Distance to P is sqrt(5) => weighting is 0.44721359f
// The following loop simply scans the four possible places. To keep things simple, it doesn't stop after finding two knight pixels, because it will not find more than two
for(int d1=-2,offsety=3;d1<=2;d1+=4,offsety-=6) {
for(int d2=-1,offsetx=3;d2<1;d2+=2,offsetx-=6) {
if(ri->XTRANSFC(row+d1,col+d2) == pixelColor) {
if( !(bitmapBads.get(col+d2,row+d1) || bitmapBads.get(col+d2+offsetx,row+d1+offsety))) {
float dirwt = 0.44721359f/( fabsf( rawData[row+d1][col+d2]- rawData[row+d1+offsety][col+d2+offsetx])+eps);
wtdsum += dirwt * (rawData[row+d1][col+d2] + rawData[row+d1+offsety][col+d2+offsetx]);
norm += dirwt;
}
}
}
}
// now scan for the pixel of same colour in distance 2 in each direction (marked with an X in above examples).
bool distance2PixelFound = false;
int dx,dy;
// check horizontal
for(dx=-2,dy=0;dx<=2 && !distance2PixelFound;dx+=4)
if(ri->XTRANSFC(row,col+dx) == pixelColor)
distance2PixelFound = true;
if(!distance2PixelFound)
// no distance 2 pixel on horizontal, check vertical
for(dx=0,dy=-2;dy<=2 && !distance2PixelFound;dy+=4)
if(ri->XTRANSFC(row+dy,col) == pixelColor)
distance2PixelFound = true;
// calculate the value of its virtual counterpart (marked with a V in above examples)
float virtualPixel;
if(dy==0) {
virtualPixel = 0.5f*(rawData[row-1][col-dx] + rawData[row+1][col-dx]);
}
else {
virtualPixel = 0.5f*(rawData[row-dy][col-1] + rawData[row-dy][col+1]);
}
// and weight as usual. Distance to P is 2 => weighting is 0.5f
float dirwt = 0.5f/( fabsf( virtualPixel- rawData[row+dy][col+dx])+eps);
wtdsum += dirwt * (virtualPixel + rawData[row+dy][col+dx]);
norm += dirwt;
}
if (LIKELY(norm > 0.f)){ // This means, we found at least one pair of valid pixels in the steps above, likelyhood of this case is about 99.999%
rawData[row][col]= wtdsum / (2.f * norm);//gradient weighted average, Factor of 2.f is an optimization to avoid multiplications in former steps
//#pragma omp critical
// printf("%s Pixel at (col/row) : (%4d/%4d) : Original : %f, interpolated: %f\n",pixelColor == 0 ? "Red " : pixelColor==1 ? "Green" : "Blue ", col-7,row-7,oldval, rawData[row][col]);
counter++;
}
}
}
return counter; // Number of interpolated pixels.
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* Search for hot or dead pixels in the image and update the map
@@ -1162,7 +1317,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le
defGain = 0.0;//log(initialGain) / log(2.0);
if ( raw.hotPixelFilter>0 || raw.deadPixelFilter>0) {
if ( ri->getSensorType()==ST_BAYER && (raw.hotPixelFilter>0 || raw.deadPixelFilter>0)) {
if (plistener) {
plistener->setProgressStr ("Hot/Dead Pixel Filter...");
plistener->setProgress (0.0);
@@ -1216,8 +1371,10 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le
if( totBP )
interpolateBadPixels( bitmapBads );
if ( ri->getSensorType()==ST_BAYER )
interpolateBadPixelsBayer( bitmapBads );
else
interpolateBadPixelsXtrans( bitmapBads );
if ( ri->getSensorType()==ST_BAYER && raw.bayersensor.linenoise >0 ) {
if (plistener) {