Added <cameramodel>.badpixels file support

Rewritten bad pixels correction steps.
This commit is contained in:
ffsup2 2010-09-18 00:44:10 +02:00
parent bafa38e5ed
commit e681354973
4 changed files with 177 additions and 144 deletions

View File

@ -23,6 +23,7 @@
#include <safegtk.h>
#include <common.h>
#include <sstream>
#include <stdio.h>
namespace rtengine{
@ -92,7 +93,7 @@ RawImage* dfInfo::getRawImage()
return ri;
}
std::list<badPix>& dfInfo::getBadPixels()
std::list<badPix>& dfInfo::getHotPixels()
{
if( !ri ){
updateRawImage();
@ -206,8 +207,17 @@ void DFManager::init( Glib::ustring pathname )
safe_build_file_list (dir, names, pathname);
dfList.clear();
bpList.clear();
for (int i=0; i<names.size(); i++) {
int lastdot = names[i].find_last_of ('.');
if (lastdot != Glib::ustring::npos && names[i].substr(lastdot) == ".badpixels" ){
if( scanBadPixelsFile( names[i] ) && settings->verbose)
printf("Loaded badpixels file %s\n",names[i].c_str());
continue;
}
try{
addFileInfo(names[i]);
}catch( std::exception e ){}
}
// Where multiple shots exist for same group, move filename to list
for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){
@ -229,7 +239,7 @@ void DFManager::init( Glib::ustring pathname )
return;
}
bool DFManager::addFileInfo(const Glib::ustring &filename )
dfInfo *DFManager::addFileInfo(const Glib::ustring &filename )
{
Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(filename);
if (!file )
@ -248,7 +258,7 @@ bool DFManager::addFileInfo(const Glib::ustring &filename )
dfList_t::iterator iter = dfList.find( key );
if( iter == dfList.end() ){
dfInfo n(filename, ri.make, ri.model,(int)ri.iso_speed,ri.shutter,ri.timestamp);
dfList.insert(std::pair< std::string,dfInfo>( key,n ) );
iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) );
}else{
while( iter != dfList.end() && iter->second.key() == key && ABS(iter->second.timestamp - ri.timestamp) >60*60*6 ) // 6 hour difference
iter++;
@ -257,14 +267,14 @@ bool DFManager::addFileInfo(const Glib::ustring &filename )
iter->second.pathNames.push_back( filename );
else{
dfInfo n(filename, ri.make, ri.model,(int)ri.iso_speed,ri.shutter,ri.timestamp);
dfList.insert(std::pair< std::string,dfInfo>( key,n ) );
iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) );
}
}
return true;
return &(iter->second);
}
}
}
return false;
return 0;
}
void DFManager::getStat( int &totFiles, int &totTemplates)
@ -285,10 +295,10 @@ void DFManager::getStat( int &totFiles, int &totTemplates)
* if perfect matches for iso and shutter are found, then the list is scanned for lesser distance in time
* otherwise if no match is found, the whole list is searched for lesser distance in iso and shutter
*/
dfInfo& DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t )
dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t )
{
if( dfList.size() == 0 )
throw std::exception();
return 0;
std::string key( dfInfo::key(mak,mod,isospeed,shut) );
dfList_t::iterator iter = dfList.find( key );
@ -302,7 +312,7 @@ dfInfo& DFManager::find( const std::string &mak, const std::string &mod, int iso
bestDeltaTime = d;
}
}
return bestMatch->second;
return &(bestMatch->second);
}else{
iter = dfList.begin();
dfList_t::iterator bestMatch = iter;
@ -314,36 +324,83 @@ dfInfo& DFManager::find( const std::string &mak, const std::string &mod, int iso
bestMatch = iter;
}
}
return bestMatch->second;
return &(bestMatch->second);
}
}
RawImage* DFManager::searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t )
{
try{
dfInfo &df = find( mak, mod, iso, shut, t );
return df.getRawImage();
}catch( std::exception e){
return NULL;
}
dfInfo *df = find( mak, mod, iso, shut, t );
if( df )
return df->getRawImage();
else
return 0;
}
RawImage* DFManager::searchDarkFrame( Glib::ustring filename )
RawImage* DFManager::searchDarkFrame( const Glib::ustring filename )
{
for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){
if( iter->second.pathname.compare( filename )==0 )
return iter->second.getRawImage();
}
dfInfo *df = addFileInfo( filename );
if(df)
return df->getRawImage();
return 0;
}
std::list<badPix> *DFManager::getHotPixels ( const Glib::ustring filename )
{
for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){
if( iter->second.pathname.compare( filename )==0 )
return &iter->second.getHotPixels();
}
return 0;
}
std::list<badPix> *DFManager::getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t )
{
dfInfo *df = find( mak, mod, iso, shut, t );
if( df )
return &df->getHotPixels();
else
return 0;
}
std::list<badPix> DFManager::searchBadPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t )
bool DFManager::scanBadPixelsFile( Glib::ustring filename )
{
try{
dfInfo &df = find( mak, mod, iso, shut, t );
return df.getBadPixels();
}catch( std::exception e){
return std::list<badPix>();
FILE *file = fopen( filename.c_str(),"r" );
if( !file ) return false;
int lastdot = filename.find_last_of ('.');
int dirpos1 = filename.find_last_of ('/');
int dirpos2 = filename.find_last_of ('\\');
if( dirpos1 == Glib::ustring::npos && dirpos2== Glib::ustring::npos )
dirpos1 =0;
else
dirpos1= (dirpos1> dirpos2 ? dirpos1: dirpos2);
std::string makmodel(filename,dirpos1+1,lastdot-(dirpos1+1) );
std::list<badPix> bp;
char line[256];
while( fgets(line,sizeof(line),file ) ){
int x,y;
if( sscanf(line,"%d %d",&x,&y) == 2 )
bp.push_back( badPix(x,y) );
}
if( bp.size()>0 ){
bpList[ makmodel ] = bp;
return true;
}
return false;
}
std::list<badPix> *DFManager::getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial)
{
std::ostringstream s;
s << mak << " " <<mod;
if( serial.size()>0)
s << " " << serial;
bpList_t::iterator iter = bpList.find( s.str() );
if( iter != bpList.end() )
return &(iter->second);
return 0;
}
// Global variable
@ -351,3 +408,4 @@ DFManager dfm;
}

View File

@ -29,7 +29,7 @@ class dfInfo
public:
Glib::ustring pathname; // filename of dark frame
std::list<Glib::ustring> pathNames; // other similar dark frames, used to mediate
std::list<Glib::ustring> pathNames; // other similar dark frames, used for average
std::string maker; ///< manufacturer
std::string model; ///< model
int iso; ///< ISO (gain)
@ -55,11 +55,11 @@ public:
std::string key(){ return key( maker,model,iso,shutter); }
RawImage *getRawImage();
std::list<badPix> &getBadPixels();
std::list<badPix> &getHotPixels();
protected:
RawImage *ri; ///< Dark Frame raw data
std::list<badPix> badPixels; ///< Unreliable pixels
std::list<badPix> badPixels; ///< Extracted hot pixels
void updateBadPixelList( RawImage *df );
void updateRawImage();
@ -72,16 +72,21 @@ public:
Glib::ustring getPathname(){ return currentPath; };
void getStat( int &totFiles, int &totTemplate);
RawImage *searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t );
RawImage *searchDarkFrame( Glib::ustring filename );
std::list<badPix> searchBadPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t );
RawImage *searchDarkFrame( const Glib::ustring filename );
std::list<badPix> *getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t );
std::list<badPix> *getHotPixels ( const Glib::ustring filename );
std::list<badPix> *getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial);
protected:
typedef std::multimap<std::string,dfInfo> dfList_t;
typedef std::map<std::string, std::list<badPix> > bpList_t;
dfList_t dfList;
bpList_t bpList;
bool initialized;
Glib::ustring currentPath;
bool addFileInfo(const Glib::ustring &filename );
dfInfo &find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t );
dfInfo *addFileInfo(const Glib::ustring &filename );
dfInfo *find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t );
bool scanBadPixelsFile( Glib::ustring filename );
};
extern DFManager dfm;

View File

@ -59,7 +59,6 @@ RawImageSource::RawImageSource ()
,border(4)
,rawData(NULL)
,ri(NULL)
,df(NULL)
{
hrmap[0] = NULL;
hrmap[1] = NULL;
@ -76,9 +75,6 @@ RawImageSource::~RawImageSource () {
if (ri) {
delete ri;
}
if(df){
delete df;
}
if (green)
freeArray<unsigned short>(green, H);
@ -328,94 +324,66 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe
isrcMutex.unlock ();
}
void RawImageSource::cfaCleanFromList( const std::list<badPix> &bpList )
/* cfaCleanFromMap: correct raw pixels looking at the bitmap
* takes into consideration if there are multiple bad pixels in the neighborhood
*/
int RawImageSource::cfaCleanFromMap( BYTE* bitmapBads )
{
int rr, cc;
unsigned short gin,g[8];
float eps=1e-10;//tolerance to avoid dividing by zero
float p[8];
const int border=4;
double eps=1e-10;
int bmpW= (W/8+ (W%8?1:0));
int counter=0;
for( int row = 0; row < H; row++ ){
for(int col = 0; col <W; col++ ){
for (std::list<badPix>::const_iterator iter=bpList.begin(); iter != bpList.end(); iter++ ){
rr = iter->y;
if( rr<4 || rr>=H-4 )
continue;
cc = iter->x;
if( cc<4 || cc>=W-4 )
continue;
if( !bitmapBads[ row *bmpW + col/8] ){ col+=7;continue; } //optimization
//pixel neighbor average
gin=rawData[rr][cc];
g[0]=rawData[rr-2][cc-2];
g[1]=rawData[rr-2][cc];
g[2]=rawData[rr-2][cc+2];
g[3]=rawData[rr][cc-2];
g[4]=rawData[rr][cc+2];
g[5]=rawData[rr+2][cc-2];
g[6]=rawData[rr+2][cc];
g[7]=rawData[rr+2][cc+2];
if( !(bitmapBads[ row *bmpW + col/8] & (1<<col%8)) ) continue;
p[0]=1/(eps+fabs(g[0]-gin)+fabs(g[0]-rawData[rr-4][cc-4])+fabs(rawData[rr-1][cc-1]-rawData[rr-3][cc-3]));
p[1]=1/(eps+fabs(g[1]-gin)+fabs(g[1]-rawData[rr-4][cc])+fabs(rawData[rr-1][cc]-rawData[rr-3][cc]));
p[2]=1/(eps+fabs(g[2]-gin)+fabs(g[2]-rawData[rr-4][cc+4])+fabs(rawData[rr-1][cc+1]-rawData[rr-3][cc+3]));
p[3]=1/(eps+fabs(g[3]-gin)+fabs(g[3]-rawData[rr][cc-4])+fabs(rawData[rr][cc-1]-rawData[rr][cc-3]));
p[4]=1/(eps+fabs(g[4]-gin)+fabs(g[4]-rawData[rr][cc+4])+fabs(rawData[rr][cc+1]-rawData[rr][cc+3]));
p[5]=1/(eps+fabs(g[5]-gin)+fabs(g[5]-rawData[rr+4][cc-4])+fabs(rawData[rr+1][cc-1]-rawData[rr+3][cc-3]));
p[6]=1/(eps+fabs(g[6]-gin)+fabs(g[6]-rawData[rr+4][cc])+fabs(rawData[rr+1][cc]-rawData[rr+3][cc]));
p[7]=1/(eps+fabs(g[7]-gin)+fabs(g[7]-rawData[rr+4][cc+4])+fabs(rawData[rr+1][cc+1]-rawData[rr+3][cc+3]));
double wtdsum=0,norm=0;
for( int dy=-2;dy<=2;dy+=2){
for( int dx=-2;dx<=2;dx+=2){
if (dy==0 && dx==0) continue;
if (row+dy<0 || row+dy>=H || col+dx<0 || row+dx>=W ) continue;
if (bitmapBads[ (row+dy) *bmpW + (col+dx)/8] & (1<<(col+dx)%8)) continue;
rawData[rr][cc] = (int)((g[0]*p[0]+g[1]*p[1]+g[2]*p[2]+g[3]*p[3]+g[4]*p[4]+ g[5]*p[5]+g[6]*p[6]+g[7]*p[7])/(p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]));
double dirwt = 1/( ( rawData[row+dy][col+dx]- rawData[row][col])*( rawData[row+dy][col+dx]- rawData[row][col])+eps);
wtdsum += dirwt* rawData[row+dy][col+dx];
norm += dirwt;
}
}
if (norm > 0.){
rawData[row][col]= wtdsum / norm;//low pass filter
counter++;
}
}
}
return counter;
}
void RawImageSource::cfa_clean(float thresh) //Emil's hot/dead pixel removal -- only filters egregiously impulsive pixels
/* Search for hot or dead pixels in the image and update the map
* For each pixel compare its value to the average of similar color surrounding
* (Taken from Emil Martinec idea)
*/
int RawImageSource::findHotDeadPixel( BYTE *bpMap, float thresh)
{
// local variables
int rr, cc;
int gin, g[8];
int bmpW= (W/8+ (W%8?1:0));
float eps=1e-10;//tolerance to avoid dividing by zero
float p[8];
float pixave, pixratio;
int counter=0;
for (int rr=2; rr < H-2; rr++)
for (int cc=2; cc < W-2; cc++) {
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//The cleaning algorithm starts here
for (rr=4; rr < H-4; rr++)
for (cc=4; cc < W-4; cc++) {
//pixel neighbor average
gin=rawData[rr][cc];
g[0]=rawData[rr-2][cc-2];
g[1]=rawData[rr-2][cc];
g[2]=rawData[rr-2][cc+2];
g[3]=rawData[rr][cc-2];
g[4]=rawData[rr][cc+2];
g[5]=rawData[rr+2][cc-2];
g[6]=rawData[rr+2][cc];
g[7]=rawData[rr+2][cc+2];
pixave=(float)(g[0]+g[1]+g[2]+g[3]+g[4]+g[5]+g[6]+g[7])/8;
pixratio=MIN(gin,pixave)/(eps+MAX(gin,pixave));
int gin=rawData[rr][cc];
int pixave = (rawData[rr-2][cc-2]+rawData[rr-2][cc]+rawData[rr-2][cc+2]+rawData[rr][cc-2]+rawData[rr][cc+2]+rawData[rr+2][cc-2]+rawData[rr+2][cc]+rawData[rr+2][cc+2])/8;
float pixratio=MIN(gin,pixave)/(eps+MAX(gin,pixave));
if (pixratio > thresh) continue;
p[0]=1/(eps+fabs(g[0]-gin)+fabs(g[0]-rawData[rr-4][cc-4])+fabs(rawData[rr-1][cc-1]-rawData[rr-3][cc-3]));
p[1]=1/(eps+fabs(g[1]-gin)+fabs(g[1]-rawData[rr-4][cc])+fabs(rawData[rr-1][cc]-rawData[rr-3][cc]));
p[2]=1/(eps+fabs(g[2]-gin)+fabs(g[2]-rawData[rr-4][cc+4])+fabs(rawData[rr-1][cc+1]-rawData[rr-3][cc+3]));
p[3]=1/(eps+fabs(g[3]-gin)+fabs(g[3]-rawData[rr][cc-4])+fabs(rawData[rr][cc-1]-rawData[rr][cc-3]));
p[4]=1/(eps+fabs(g[4]-gin)+fabs(g[4]-rawData[rr][cc+4])+fabs(rawData[rr][cc+1]-rawData[rr][cc+3]));
p[5]=1/(eps+fabs(g[5]-gin)+fabs(g[5]-rawData[rr+4][cc-4])+fabs(rawData[rr+1][cc-1]-rawData[rr+3][cc-3]));
p[6]=1/(eps+fabs(g[6]-gin)+fabs(g[6]-rawData[rr+4][cc])+fabs(rawData[rr+1][cc]-rawData[rr+3][cc]));
p[7]=1/(eps+fabs(g[7]-gin)+fabs(g[7]-rawData[rr+4][cc+4])+fabs(rawData[rr+1][cc+1]-rawData[rr+3][cc+3]));
rawData[rr][cc] = (int)((g[0]*p[0]+g[1]*p[1]+g[2]*p[2]+g[3]*p[3]+g[4]*p[4]+ \
g[5]*p[5]+g[6]*p[6]+g[7]*p[7])/(p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]));
}//now impulsive values have been corrected
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// mark the pixel as "bad"
bpMap[rr*bmpW+cc/8 ] |= 1<<(cc%8);
counter++;
}
return counter;
}
@ -802,31 +770,33 @@ int RawImageSource::load (Glib::ustring fname) {
void RawImageSource::preprocess (const RAWParams &raw)
{
Glib::ustring newDF = raw.dark_frame;
Glib::ustring currentDF = (df ? df->fname : "");
RawImage *rid=NULL;
if (!raw.df_autoselect) {
if (newDF != currentDF) {
if (df)
delete df;
df = NULL;
if (newDF.length() > 0) {
df = new RawImage(newDF);
int res = df->loadRaw();
if (res) {
delete df;
df = NULL;
}
}
}
copyOriginalPixels(ri, df);
if( raw.dark_frame.size()>0)
rid = dfm.searchDarkFrame( raw.dark_frame );
}else{
RawImage *rid = dfm.searchDarkFrame( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp);
rid = dfm.searchDarkFrame( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp);
}
copyOriginalPixels(ri, rid);
size_t widthBitmap = (ri->width/8+ (ri->width%8?1:0));
size_t dimBitmap = widthBitmap*ri->height;
BYTE *bitmapBads = new BYTE [ dimBitmap ];
std::list<badPix> *bp = dfm.getBadPixels( ri->make, ri->model, std::string("") );
if( bp ){
for(std::list<badPix>::iterator iter = bp->begin(); iter != bp->end(); iter++)
bitmapBads[ widthBitmap * (iter->y) + (iter->x)/8] |= 1<<(iter->x%8);
}
if(!raw.hotdeadpix_filt && raw.df_autoselect ){
std::list<badPix> bp = dfm.searchBadPixels( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp);
cfaCleanFromList(bp);
}
bp = 0;
if( raw.df_autoselect )
bp = dfm.getHotPixels( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp);
else if( raw.dark_frame.size()>0 )
bp = dfm.getHotPixels( raw.dark_frame );
if(bp)
for(std::list<badPix>::iterator iter = bp->begin(); iter != bp->end(); iter++)
bitmapBads[ widthBitmap *iter->y + iter->x/8] |= 1<<(iter->x%8);
preInterpolate(false);
scaleColors( false,true);
@ -840,7 +810,7 @@ void RawImageSource::preprocess (const RAWParams &raw)
double tg = icoeff[1][0] * cam_r + icoeff[1][1] * cam_g + icoeff[1][2] * cam_b;
double tb = icoeff[2][0] * cam_r + icoeff[2][1] * cam_g + icoeff[2][2] * cam_b;
defGain = log(ri->defgain) / log(2.0); //\TODO rivedere l'assegnamento di ri->defgain che dovrebbe essere "costante"
defGain = log(ri->defgain) / log(2.0); //\TODO ri->defgain should be "costant"
// check if it is an olympus E camera, if yes, compute G channel pre-compensation factors
if ( raw.greenthresh || (((idata->getMake().size()>=7 && idata->getMake().substr(0,7)=="OLYMPUS" && idata->getModel()[0]=='E') || (idata->getMake().size()>=9 && idata->getMake().substr(0,7)=="Panasonic")) && raw.dmethod != RAWParams::methodstring[ RAWParams::vng4] && ri->filters) ) {
@ -880,9 +850,10 @@ void RawImageSource::preprocess (const RAWParams &raw)
plistener->setProgressStr ("Hot/Dead Pixel Filter...");
plistener->setProgress (0.0);
}
cfa_clean(0.1);
findHotDeadPixel( bitmapBads,0.1 );
}
cfaCleanFromMap( bitmapBads );
delete [] bitmapBads;
if ( raw.linenoise >0 ) {
if (plistener) {

View File

@ -74,7 +74,6 @@ class RawImageSource : public ImageSource {
cmsHPROFILE embProfile;
RawImage* ri; // Copy of raw pixels
RawImage* df; // Darkframe pixels (if present)
// to accelerate CIELAB conversion:
double lc00, lc01, lc02, lc10, lc11, lc12, lc20, lc21, lc22;
@ -148,8 +147,8 @@ class RawImageSource : public ImageSource {
int LinEqSolve( int nDim, float* pfMatr, float* pfVect, float* pfSolution);//Emil's CA auto correction
void CA_correct_RT ();
void cfaCleanFromList( const std::list<badPix> &bpList );
void cfa_clean (float thresh);//Emil's hot/dead pixel filter
int cfaCleanFromMap( BYTE* bitmapBads );
int findHotDeadPixel( BYTE *bpMap, float thresh);
void ddct8x8s(int isgn, float **a);
void cfa_linedn (float linenoiselevel);//Emil's line denoise