imgclass.cpp

Go to the documentation of this file.
00001 #include <iostream>
00002 #include <iomanip>
00003 #include <fstream>
00004 #include <cmath>
00005 #include <cstdlib>
00006 #include <cstring>
00007 using namespace std;
00008 
00009 #include "imgclass.hpp"
00010 #include "matrixutil.hpp"
00011 
00012 
00013 namespace NaN {
00014   const float fnan = nanf("");
00015 }
00016 
00017 using NaN::fnan;
00018 
00019 
00020 inline double clip(double x, double limit) {
00021   return (x>limit)?limit:x;
00022 }
00023 
00024 //-----------------------------------------------
00025 // alles mit bild16
00026 // 16-Bit Graustufenbilder
00027 // aus der Röntgenanlage
00028 // Ausgabe als pgm-Bitmap möglich
00029 //---------------------------------------------------
00030 
00031 const bild16::data_t bild16::intensity_max=0xFFFF;
00032 const bild16::data_t bild16::intensity_min=0x0000;
00033 const streamoff bild16::HIS_START=100;  
00034 
00035 bild16::bild16 (const char *fname) THROWSPEC : bild16_base () 
00036 {
00037   file_header = new header_t;
00038   if (fname) {
00039     read_his (fname);
00040   } else {
00041     //initialise header
00042     file_header->FileID = 0x7000;       //1
00043     file_header->HeaderSize = 68;
00044     file_header->HeaderVersion = 100;
00045     file_header->FileSize = 524388;
00046     file_header->ImageHeaderSize = 32;  //5
00047     file_header->ULX = 1;
00048     file_header->ULY = 1;
00049     file_header->BRX = 512;
00050     file_header->BRY = 512;
00051     file_header->NrOfFrames = 1;        //10
00052     file_header->Correction = 0;
00053     file_header->IntegrationTime = 0;
00054     file_header->TypeOfNumbers = 4;     //13
00055   }
00056 
00057 
00058 }
00059 
00060 bild16::bild16 (unsigned short *data) THROWSPEC : bild16_base ()
00061 {
00062     file_header = new header_t;
00063     //initialise header
00064     file_header->FileID = 0x7000;       //1
00065     file_header->HeaderSize = 68;
00066     file_header->HeaderVersion = 100;
00067     file_header->FileSize = 524388;
00068     file_header->ImageHeaderSize = 32;  //5
00069     file_header->ULX = 1;
00070     file_header->ULY = 1;
00071     file_header->BRX = 512;
00072     file_header->BRY = 512;
00073     file_header->NrOfFrames = 1;        //10
00074     file_header->Correction = 0;
00075     file_header->IntegrationTime = 0;
00076     file_header->TypeOfNumbers = 4;     //13
00077     
00078     MAP ((*this)) {
00079       bild[y][x]=data[SIZEX*y+x];
00080     }  
00081          
00082 }
00083 
00084 bild16::~bild16() 
00085 {
00086   delete file_header;  
00087 }
00088 
00089 void bild16::write_pgm16 (const char *name) const 
00090 {
00091   ofstream datei (name, ios::binary);
00092   datei << "P5" << '\n';        //magic number für PGM
00093   datei << SIZEX << " " << SIZEY << "\n" << intensity_max << "\n";      //Breite, Höhe und größter Wert für Weiß, 16 Bit 
00094 
00095   for (int y = 0; y < SIZEY; y++)
00096     for (int x = 0; x < SIZEX; x++) {
00097       datei << static_cast <unsigned char>(bild[y][x] / 0x100) 
00098       << static_cast <unsigned char>(bild[y][x] % 0x100);
00099     }
00100 
00101   // Daten als Block, byte-weise
00102   // MSB first
00103  }
00104 
00105 
00106 void bild16::write_pgm8 (const char *name) const 
00107 {
00108   ofstream datei (name, ios::binary);
00109   datei << "P5" << endl;        //magic number für PGM
00110   datei << SIZEX << " " << SIZEY << "\n" << 0xFF << "\n";       //Breite, Höhe und größter Wert für Weiß, 8 Bit 
00111 
00112   for (int y = 0; y < SIZEY; y++)
00113     for (int x = 0; x < SIZEX; x++) {
00114       datei << static_cast < unsigned char >(bild[y][x] / 0x100);
00115     }
00116 
00117   // Daten als Block, byte-weise
00118   // Koordinatensystem nicht mathematisch, sondern
00119   // bildschirmorientiert: y geht nach unten
00120 }
00121 
00122 void bild16::write_pgm8_bounds (const char *name, bild16::data_t low, bild16::data_t high) const 
00123 {  if (low==high) STHROW("Error: Zero range (write_pgm8_bounds), low==high=="<<low);
00124    if (low>high) swap(low,high);
00125   ofstream datei (name, ios::binary);
00126   datei << "P5" << endl;        //magic number für PGM
00127   datei << SIZEX << " " << SIZEY << "\n" << 0xFF << "\n";       //Breite, Höhe und größter Wert für Weiß, 8 Bit 
00128 
00129   for (int y = 0; y < SIZEY; y++)
00130     for (int x = 0; x < SIZEX; x++) {
00131       unsigned char byte;
00132       data_t wert=(*this)(y,x);
00133       if (wert>high) byte=0xFF;
00134       else if (wert<low) byte=0x00;
00135       else byte = static_cast < unsigned char >(0xFF*double((*this)(y,x)-low)/double(high-low));
00136       datei << byte;
00137     }
00138 
00139   // Daten als Block, byte-weise
00140   // Koordinatensystem nicht mathematisch, sondern
00141   // bildschirmorientiert: y geht nach unten
00142 }
00143 
00144 bild16& bild16::read_his (const char *name) THROWSPEC
00145 {
00146   ifstream his;                 //Unsere Datei-Streams
00147   his.open (name, ios::binary | ios::in);       // öffnen des hisfiles
00148   if (!his) STHROW(name<<" not found!\n");
00149   
00150   // Einlesen des Fileheaders
00151   his.read ((char *) file_header, sizeof (*file_header));
00152 
00153 
00154   // Einlesen der Daten
00155   his.seekg (HIS_START);
00156   for (int y = 0; y < SIZEY; y++) {
00157     his.read ((char *) bild[y], sizeof (unsigned short) * SIZEX);       
00158   }
00159 
00160   his.close ();                 //Schliesst das hisfile
00161   return *this;
00162 }
00163 
00164 void bild16::write_his (const char *name) const
00165 {
00166   ofstream his;         
00167   his.open (name, ios::binary); // öffnen des hisfiles
00168   if (!his) {
00169     STHROW("Cannot write to "<<name); 
00170   }
00171   // Schreiben des Fileheaders
00172   his.write ((char *) file_header, sizeof (*file_header));
00173   
00174   // padding 
00175   for (streamoff i=sizeof(*file_header); i<HIS_START; i++)
00176     his.put(char(0));
00177 
00178   // Schreiben der Daten
00179   his.seekp (HIS_START);
00180   // nur zur Sicherheit ein seek, die Position 
00181   // sollte eigentlich schon stimmen!
00182   for (int y = 0; y < SIZEY; y++) {
00183     his.write ((char *) bild[y], sizeof (unsigned short) * SIZEX);      
00184   }
00185 
00186   his.close ();                 //Schliesst das hisfile
00187 }
00188 
00189 inline int isdecdigit(char dig) {
00190   return (dig>='0' && dig<='9');
00191 }
00192 
00193 inline void eatwhite(istream& is) {
00194  bool yet=true;
00195  do {
00196    switch (is.peek()) {
00197      case '\n': 
00198      case '\r':
00199      case ' ' :
00200      case '\t':
00201        is.get();
00202        break;
00203      default:
00204        yet=false;
00205    }
00206  } while(yet && !is.eof());
00207 }
00208 
00209 static int getpgmnumber(istream &is) THROWSPEC{
00210   // Eat whitespace, ignore comments, then read decimal number
00211   
00212   eatwhite(is);
00213   while (is.peek()=='#') {
00214     // Comment, ignore to eol or eof
00215     int c=is.get();
00216     while ((c!='\n') && (!is.eof())) c=is.get();
00217     if (is.eof()) STHROW ("Expected number (PGM)");
00218     eatwhite(is);
00219   }
00220   // next char is no #, should read number
00221 
00222   const int maxlen=10; // maximum tendigits
00223   char digitbuf[maxlen+1];
00224   int dnum=0;
00225   do {
00226     
00227     char c=is.get();
00228     if (is.eof()) STHROW("Premature EOF (PGM)");
00229 
00230     if (isdecdigit(c)) digitbuf[dnum++]=c;
00231     else {
00232       is.putback(c);
00233       break;
00234     }  
00235   } while (dnum < maxlen);
00236 
00237   digitbuf[dnum]='\0';
00238 
00239   return atoi(digitbuf);
00240 }
00241     
00242 bild16& bild16::read_pgm (const char *name) THROWSPEC 
00243 {
00244   ifstream pgm;                 //Unsere Datei-Streams
00245   pgm.open (name, ios::binary | ios::in);       // öffnen des hisfiles
00246   if (!pgm) STHROW(name<<" not found!");
00247   try {
00248     // PGM format: P5<whitespace>
00249     // Dann Breite und Höhe, evtl Kommentare dazwischen
00250     if (pgm.get()!='P') STHROW("Not a PPM file");
00251     if (pgm.get()!='5') STHROW("Not a PGM Graymap");
00252   
00253     int width=getpgmnumber(pgm);
00254     if (width!=SIZEX) STHROW("Width doesn't match. Expected"<<SIZEX<<", got"<<width);
00255     
00256     int height=getpgmnumber(pgm);
00257     if (height!=SIZEY) STHROW("Height doesn't match. Expected"<<SIZEY<<", got"<<height);
00258     
00259     int maxval=getpgmnumber(pgm);
00260     pgm.get(); // ein einzelnes Whitespace ist nach Maxval erlaubt
00261     switch (maxval)
00262     {
00263        case 255:
00264         // 8bit PGM
00265          for (int y=0; y < SIZEY; y++) {
00266            for (int x=0; x< SIZEX; x++) {
00267            unsigned int val8=pgm.get();
00268            (*this)(y,x)=val8*0x100;
00269          }
00270          }
00271          if (!pgm) STHROW("PGM corrupt");
00272          break;
00273        case 65535:
00274          // 16bit PGM
00275          for (int y=0; y < SIZEY; y++) {
00276            for (int x=0; x< SIZEX; x++) {
00277            unsigned int hi8=pgm.get();
00278            unsigned int lo8=pgm.get();
00279            (*this)(y,x)=(hi8 & 0xFF)*0x100+(lo8 & 0xFF);
00280          }
00281          }
00282          if (!pgm) STHROW("PGM corrupt");
00283          break;
00284        default:
00285          STHROW("Can only read 8bit or 16bit PGM (maxval=="<<maxval<<")");
00286     }     
00287   
00288     pgm.close ();                       //Schliesst das hisfile
00289   } catch (const string& msg) {
00290       STHROW(name<<": "<<msg);
00291       // prefix every error by the name
00292   }    
00293      
00294   return *this;
00295 }
00296 
00297 void bild16::fromfloat(const bildfloat& bf, float max) {
00298   MAP (bf) {
00299       if (bf(y,x)>max) (*this)(y,x)=intensity_max;
00300       else if (bf(y,x)<0) (*this)(y,x)=intensity_min;
00301       else (*this)(y,x)=intensity_min+static_cast<data_t>(intensity_max*bf(y,x)/max);
00302     }  
00303 }
00304 
00305       
00306 bild16& bild16::og_correct(const bild16& offset, const bild16& gain) {
00307   const double epsilon=1.0; 
00308   for (int y=0; y<SIZEY; y++) 
00309     for (int x=0; x<SIZEX; x++) {
00310        // Offset-Gain-Korrektur
00311        double denom = gain(y,x)-offset(y,x);
00312        if (denom <= epsilon) continue;
00313          //vermeide Division durch Null
00314        double nomin = bild[y][x] - offset(y,x);
00315        if (nomin < 0) continue;
00316          // dunkler als Offset = kaputter Pixel
00317        bild[y][x] = data_t(clip(double(intensity_max)*nomin/denom, intensity_max));
00318     }
00319     return *this;
00320 }    
00321 
00322 
00323 bild16& bild16::drawx(int x, int y1, int y2) THROWSPEC {
00324         
00325   if (y1>y2) swap(y1,y2);
00326   
00327   if ((x<0) || (x>=SIZEX)) STHROW("drawx: x out of range (x="<<x<<")");
00328   if ((y2<0) || (y1>=SIZEY)) STHROW("drawx: line outside image (y1="<<y1<<", y2="<<y2<<")");
00329   
00330   /* clip line on border */
00331   if (y1<0) y1=0;
00332   if (y2>=SIZEY) y2=SIZEY-1;
00333   
00334   for (int y=y1; y<=y2; y++)
00335     bild[y][x]^=0xFFFF;
00336   return *this;
00337 }
00338 
00339 bild16& bild16::drawy(int y, int x1, int x2) THROWSPEC {
00340   if (x1>x2) swap(x1,x2);
00341   
00342   if ((y<0) || (y>=SIZEY)) STHROW("drawy: y out of range (y="<<y<<")");
00343   if ((x2<0) || (x1>=SIZEX)) STHROW("drawy: line outside image (x1="<<x1<<", x2="<<x2<<")");
00344   
00345   /* clip line on border */
00346 
00347   if (x1<0) x1=0;
00348   if (x2>=SIZEX) x2=SIZEX-1;
00349   
00350   for (int x=x1; x<=x2; x++)
00351     bild[y][x]^=0xFFFF;
00352   return *this;  
00353 }
00354 
00355 bild16& bild16::kreuz (int x, int y) THROWSPEC {
00356 
00357   if ((x<0) || (x>=SIZEX) || (y<0) || (y>=SIZEY)) STHROW("kreuz: Outside of the image, x="<<x<<", y="<<y<<")");
00358   
00359   drawx(x, y-10, y+10);
00360   drawy(y, x-10, x+10);
00361   return *this;
00362 } 
00363 //---------------------------------------------------
00364 // Eichkurven
00365 //---------------------------------------------------
00366 
00367 eichkurve::eichkurve ()
00368 {
00369   // reserve memory for the lookup-table
00370   lookup= new double[0x10000];
00371 }
00372 
00373 eichkurve::~eichkurve() {
00374   // release memory
00375   delete[] lookup;
00376 }
00377   
00378 const char eichkurve::magic[]="EICHTABELLE";
00379 
00380 void eichkurve::table_init(double hmin, double hmax) {
00381  //solve the function for all possible input values;
00382   for (int i=0; i<0x10000; i++) {
00383     lookup[i]=fsolve(i, hmin, hmax);
00384   }  
00385 
00386 }
00387 
00388 double eichkurve::fsolve(bild16::data_t val, double hmin, double hmax) const
00389 {
00390   const double epsilon=0.1;            // nicht genauer als 1 Bit Höhen-Auflösung
00391   double vmin=eichfun(hmin);
00392   double vmax=eichfun(hmax);
00393   int signum=1;
00394   if (vmin<vmax) { 
00395     // Funktion (monoton) steigend
00396     signum=1; 
00397     if (val<vmin) return hmin;
00398     if (val>vmax) return hmax;
00399   } else {
00400      //Funktion (monoton) fallend
00401      signum=-1;
00402      if (val>vmin) return hmin;
00403      if (val<vmax) return hmax;
00404   } 
00405   //Wert ist zwischen vmin und vmax eingeschlossen
00406   //Sekantenverfahren (Regula falsi)
00407   double h;
00408   double vh;
00409   do {
00410     h  = (val-vmin)/(vmax-vmin) * (hmax-hmin) + hmin;
00411     vh = eichfun(h);
00412    // cout<<hmax<<"  "<<hmin<<"  "<<h<<"  "<<vh<<"  "<<val<<endl;
00413     if (signum*(vh-val)>0) {
00414         vmax = vh;
00415         hmax = h;
00416     } else {
00417         vmin = vh;
00418         hmin = h;
00419     }   
00420     
00421   } while (abs(vh-val)>epsilon);
00422   
00423   return h; 
00424 }  
00425 
00426 
00427 // Newton-Raphson; konvergiert nicht immer
00428 #if 0 
00429 double eichkurve::fsolve(bild16::data_t val, double hmin, double hmax) const
00430 {
00431   const double epsilon=0.5;            // nicht genauer als 1 Bit Höhen-Auflösung
00432   double vmin=eichfun(hmin);
00433   double vmax=eichfun(hmax);
00434   if (vmin<vmax) { 
00435     // Funktion (monoton) steigend
00436     if (val<vmin) return hmin;
00437     if (val>vmax) return hmax;
00438   } else {
00439      //Funktion (monoton) fallend
00440      if (val>vmin) return hmin;
00441      if (val<vmax) return hmax;
00442   } 
00443   double x = initguess(val); //Startwert schätzen
00444   double xalt;
00445   do {
00446     xalt = x;
00447     x = xalt + (val - eichfun(xalt))/deichfun_dx(xalt);
00448   } while (abs(eichfun(xalt)-eichfun(x))>epsilon);
00449   //Newton-Raphson Iteration
00450   
00451   // Beschränkung, falls Newton außerhalb des erlaubten Bereichs landet
00452   if (x>hmax) { 
00453            cout<<"Zu groß: "<<x<<"  "<<val<<endl;
00454            return hmax;
00455   }        
00456   if (x<hmin)  return hmin;
00457   return x; 
00458 }  
00459 #endif 
00460 
00461 
00462 void eichkurve::table_write(const char *fname) const {
00463   ofstream datei(fname, ios::out|ios::binary);
00464   datei.write(magic, sizeof(magic));
00465   for (int i=0; i<0x10000; i++)
00466     datei<<rawfloat(lookup[i]);
00467 }       
00468 //
00469 // Exponentialabschwächung, versch. char. Zeiten
00470 expkurve::expkurve (double  sA, double sg1, double sg2, double sg3, 
00471                       double sf1, double sf2) :
00472   eichkurve(), A(sA), g1(sg1), g2(sg2), g3(sg3), f1(sf1), f2(sf2) { 
00473 
00474   table_init(0.0, 40.0);
00475 } 
00476  
00477 double expkurve::eichfun(double x) const {
00478     return  A*(f1*exp(-g1*x)+f2*exp(-g2*x)+(1-f1-f2)*exp(-g3*x));
00479 }
00480   
00481 double expkurve::deichfun_dx(double x) const {
00482     return -A*(f1*g1*exp(-g1*x)+f2*g2*exp(-g2*x)+(1-f1-f2)*g3*exp(-g3*x));
00483   
00484 }
00485 
00486 double expkurve::initguess(bild16::data_t val) const {
00487   return - log(double(val)/A)/g1;
00488 }  
00489 
00490 // 4 überlagerte Exponentialkurven
00491 exp4kurve::exp4kurve (double sA, double sa1, double sa2, double sa3,
00492                 // rel. Anteile
00493                 double sb1, double sb2, double sb3, double sb4 ) : // charakteristische Tiefen
00494   eichkurve(), A(sA), a1(sa1), a2(sa2), a3(sa3), b1(sb1), b2(sb2), b3(sb3), b4(sb4) { 
00495 
00496   table_init(0.0, 35.0);
00497 } 
00498  
00499 double exp4kurve::eichfun(double x) const {
00500     return A*(a1*exp(-b1*x)+a2*exp(-b2*x)+a3*exp(-b3*x)+(1.0-a1-a2-a3)*exp(-b4*x));
00501 }
00502   
00503 double exp4kurve::deichfun_dx(double x) const {
00504     return -A*(a1*b1*exp(-b1*x)+a2*b2*exp(-b2*x)+a3*b3*exp(-b3*x)+(1.0-a1-a2-a3)*b4*exp(-b4*x));
00505   
00506 }
00507 
00508 double exp4kurve::initguess(bild16::data_t val) const {
00509   return -log(val/(A*a3))/b3;
00510 }  
00511 
00512 
00513 //
00514 // flatkurve
00515 
00516 flatkurve::flatkurve (bool normalize_) : eichkurve(), normalize(normalize_) {
00517 
00518   for (int i=bild16::intensity_min; i<=bild16::intensity_max; i++)
00519     lookup[i]=initguess(i);
00520 }
00521 
00522 double flatkurve::initguess(bild16::data_t  val) const {
00523   if (normalize) return static_cast<double>(val)/bild16::intensity_max;
00524   else return static_cast<double>(val);
00525 }
00526 
00527 double flatkurve::eichfun(double x) const {
00528   if (normalize) return x*bild16::intensity_max;
00529   else return x;
00530 }
00531 
00532 double flatkurve::deichfun_dx(double x) const  {
00533   if (normalize) return static_cast<double>(bild16::intensity_max);
00534   else return 1.0;
00535 }
00536 
00537 // tablekurve schlägt einfach in der Tabelle nach und
00538 // benutzt Dateien, die vorher von anderen Kurven geschrieben wurden
00539 // Das spart die aufwendigen Newton-Iterationen am Anfang
00540 tablekurve::tablekurve (const char *fname) THROWSPEC {
00541   ifstream datei(fname, ios::binary);
00542   if (!datei) STHROW(fname<<" not found.");
00543   char magictest[sizeof(magic)];
00544   
00545   for (size_t i=0; i<sizeof(magic); i++) 
00546     datei.get(magictest[i]);
00547   
00548   if (strncmp(magic, magictest, sizeof(magic))!=0)
00549     STHROW(fname<<" is not a tablekurve file.");
00550   
00551   for (int i=0; i< 0x10000; i++) {
00552     float temp;
00553     datei>>irawfloat(temp);
00554     lookup[i]=temp;
00555   }  
00556 }    
00557 
00558 
00559 double tablekurve::eichfun (double x) const 
00560 {
00561   STHROW ("Tablekurve pseudo-function called");
00562 }
00563 double tablekurve::deichfun_dx (double x) const
00564 {
00565   STHROW ("Tablekurve pseudo-function called");
00566 }
00567 
00568 double tablekurve::initguess (bild16::data_t val) const 
00569 {
00570   STHROW ("Tablekurve pseudo-function called");
00571 }
00572 
00573 
00574 //---------------------------------------------------
00575 // bildfloat
00576 // 512x512-Bilder in single precision floats
00577 // für alle Rechnungen gut
00578 // Ein/Ausgabe als gnuplot binary file möglich
00579 //---------------------------------------------------
00580 
00581 
00582 
00583 
00584 const float bildfloat::pix_size  = static_cast<float>(1606.0 / 1765 * 0.4);
00585 
00586 bildfloat::bildfloat(const region_t& regio) : bildfloat_base() {
00587   MAP (regio)
00588    if (regio(y,x)) (*this)(y,x)=1.0f;
00589    else (*this)(y,x) = fnan; 
00590 }      
00591   
00592 void bildfloat::write_gnuplot (const char *name) const
00593 {
00594   // write binary gnuplot data file
00595   ofstream datfile (name, ios::binary);
00596   datfile << rawfloat (SIZEY);
00597   for (int y = 0; y < SIZEY; y++)
00598     datfile << rawfloat (y * pix_size);
00599     
00600   for (int y = 0; y < SIZEY; y++) {
00601     datfile << rawfloat (y * pix_size);
00602     
00603     for (int x = 0; x < SIZEX; x++) {
00604       datfile << rawfloat ((*this)(y, x));
00605     }  
00606   }
00607   datfile.close();
00608 }
00609 
00610 bildfloat& bildfloat::read_gnuplot (const char *name) THROWSPEC
00611 {
00612   // read binary gnuplot data file
00613   ifstream datfile (name, ios::binary);
00614   if (!datfile) STHROW (name<<" not readable");
00615   float dummy;
00616   datfile >> irawfloat (dummy);
00617   if (dummy != SIZEY) STHROW ("Not a known gnuplot binary format");
00618   for (int y = 0; y < SIZEY; y++)
00619     datfile >> irawfloat (dummy); //ignore these values (y0..yn)
00620     
00621   for (int y = 0; y < SIZEY; y++) {
00622     datfile >> irawfloat (dummy); //ignore x value
00623     
00624     for (int x = 0; x < SIZEX; x++) {
00625       datfile >> irawfloat ((*this)(y, x));
00626     }  
00627   }
00628   datfile.close();
00629   return *this;
00630 }
00631      
00632 bildfloat& bildfloat::from_bild16(const bild16& aufnahme) {
00633 
00634   MAP (aufnahme) 
00635       bild[y][x]=static_cast<float>(aufnahme(y,x))/static_cast<float>(bild16::intensity_max);
00636   return *this;    
00637 }
00638 
00639 bildfloat& bildfloat::from_bild16(const bild16& aufnahme, const eichkurve& ek) {
00640 
00641   MAP (aufnahme) 
00642       bild[y][x]=ek(aufnahme(y,x));
00643   return *this;    
00644 }
00645 
00646 
00656 bildfloat& bildfloat::badpix_correct (const bild16 & bpmap, bild16::data_t threshold)   //badpixel correction
00657 {
00658 #define GOODPIX(Y,X)    if (bpmap((Y),(X)) < threshold) \
00659         { \
00660           mean += (*this)((Y),(X)); \
00661           mean_i++;  \
00662         }
00663 
00664   for (int y = 1; y < SIZEY - 1; y++)
00665     for (int x = 1; x < SIZEX - 1; x++) {
00666       float mean = 0;
00667       int mean_i = 0;
00668       if (bpmap(y,x) > threshold)
00669         //ersetze durch mittelwert der 8 nachbarn, wenn diese ok
00670       {
00671           GOODPIX (y - 1, x - 1)
00672           GOODPIX (y - 1, x)
00673           GOODPIX (y - 1, x + 1)
00674           GOODPIX (y, x - 1)
00675           GOODPIX (y, x + 1)
00676           GOODPIX (y + 1, x - 1)
00677           GOODPIX (y + 1, x)
00678           GOODPIX (y + 1, x + 1)
00679           if (mean_i > 0) {
00680             (*this) (y, x) = mean / mean_i;     // mittelwert der nicht defekten Nachbarpix
00681           } else                        //wenn alle 8 nachbarpix defekt sind?
00682           //es muss div durch null vermieden werden
00683           {
00684             (*this) (y, x) = 0;
00685           }
00686 
00687 
00688       }                         //if-zu
00689     }                           // for-zu
00690 
00691     return *this;
00692 }
00693 
00696 bildfloat& bildfloat::gamma_correct (const bildfloat& gammabild) {
00697  for (int y = 1; y < SIZEY - 1; y++)
00698     for (int x = 1; x < SIZEX - 1; x++) {
00699        if ((*this)(y,x)<=0.0) { 
00700          (*this)(y,x)=0.0; 
00701          continue;
00702        }
00703 
00704        if ((*this)(y,x)>=1.0) {
00705          (*this)(y,x)=1.0;
00706          continue;
00707        }         
00708        (*this)(y,x)=pow((*this)(y,x), gammabild(y,x));
00709  }
00710  return *this;
00711 } 
00712 
00716 bildfloat& bildfloat::bquad_correct (const bildfloat& bquadbild) {
00717  for (int y = 1; y < SIZEY - 1; y++)
00718     for (int x = 1; x < SIZEX - 1; x++) {
00719        if ((*this)(y,x)<=0.0) { 
00720          (*this)(y,x)=0.0; 
00721          continue;
00722        }
00723 
00724        if ((*this)(y,x)>=1.0) {
00725          (*this)(y,x)=1.0;
00726          continue;
00727        }         
00728        (*this)(y,x)=((*this)(y,x)+bquadbild(y,x)*SQR((*this)(y,x)))/(1.0+bquadbild(y,x));
00729     }
00730     return *this;
00731 } 
00732 
00733 
00738 bildfloat& bildfloat::polyfit_correct (const QRfit& korrektor) {
00739     /* interpoliere durch das Ausgleichspolynom */
00740      for (int y=0; y<SIZEY; y++) {
00741        for (int x=0; x<SIZEX; x++) {
00742         (*this)(y,x)=korrektor(y, x, ((*this)(y,x)) );
00743        }
00744      }
00745    return *this;
00746 }
00747 
00750 bildfloat& bildfloat::apply_eichkurve(const eichkurve& ek) {
00751    MAP ((*this)) {
00752        float val = (*this)(y,x);
00753        // ensure we are not out of range
00754        if (val>1.0) (*this)(y,x)=ek(bild16::intensity_max);
00755        else if (val<0.0) (*this)(y,x)=ek(bild16::intensity_min);
00756        else (*this)(y,x)=ek(static_cast<bild16::data_t>(bild16::intensity_max*val));
00757    }     
00758   return *this;    
00759 }
00760 
00761 void bildfloat::shutter_detect(int &y0, int &y1, float thresh, int radius ) const {
00762   // looks for the dark shadow 
00763   const int xmitte=SIZEX/2; const int ymitte=SIZEY/2;
00764   y0=-1; y1=-1;
00765   for (int y=SIZEY/2; y < SIZEY-1; y ++) {
00766      float sum=0; float diffsum=0;
00767      for (int x=0; x<SIZEX; x++) 
00768        if ((SQR(x-xmitte)+SQR(y-ymitte))<SQR(radius)) {
00769        sum+=(*this)(y,x)+(*this)(y+1,x);
00770        diffsum+=(*this)(y,x)-(*this)(y+1,x);
00771      }
00772      if (sum<=0) continue;
00773      if (fabs(diffsum/sum)>thresh) {
00774        y1 = y+1;
00775        break;
00776      }  
00777    }
00778 
00779    for (int y=SIZEY/2; y; y--) {
00780      float sum=0; float diffsum=0;
00781      for (int x=0; x< SIZEX; x++) 
00782        if ((SQR(x-xmitte)+SQR(y-ymitte))<SQR(radius)){
00783        sum+=(*this)(y,x)+(*this)(y+1,x);
00784        diffsum+=(*this)(y-1,x)-(*this)(y,x);
00785      }
00786      
00787      if (sum<=0) continue;
00788      if (fabs(diffsum/sum)>thresh) {
00789        y0 = y-1;
00790        break;
00791      } 
00792    }
00793  
00794 }
00795 
00796 bildfloat& bildfloat::shutter_correct(int y0, int y1, float shadingfactor) {
00797   for (int y=0; y<=y0; y++) 
00798       for (int x=0; x< (*this).SIZEX; x++)
00799         (*this)(y,x)*=shadingfactor;
00800 
00801     for (int y=y1; y<(*this).SIZEY; y++) 
00802       for (int x=0; x< (*this).SIZEX; x++)
00803         (*this)(y,x)*=shadingfactor;
00804 
00805    return *this;        
00806 }
00807 
00808 bildfloat& bildfloat::convolve (const float * kernel, int sx, int sy, bool normalize) const  THROWSPEC  {
00809   if ( (sx %2 ==0) || (sy %2 ==0) || (sx<=0) || (sy<=0)) 
00810       STHROW("Sizes of kernel must be odd (convolve) and positive, sx="<<sx<<", sy="<<sy);
00811 
00812   float *newkernel=NULL;
00813   if (normalize) {
00814     // normalize kernel
00815     float norm=0;
00816     for (int k=0; k<sx*sy; k++) norm+=kernel[k];
00817     if (norm==0.0) STHROW("Kernel may not be zero (convolve)");
00818     newkernel = new float[sx*sy];
00819     for (int k=0; k<sx*sy; k++) newkernel[k]=kernel[k]/norm;
00820     kernel=newkernel; // Pointer umbiegen erlaubt
00821   }
00822   
00823   // construct convoluted image
00824   bildfloat* newbild = new bildfloat;
00825   
00826   for (int y=0; y<SIZEY; y++)
00827     for (int x=0; x<SIZEX; x++) {
00828       if ((x< sx/2) || (y < sy/2) || (x>= SIZEX - sx/2) || (y>=SIZEY - sy/2)) {
00829         (*newbild)(y,x)=(*this)(y,x);
00830         continue;
00831       } 
00832       // Randpunkte ausschließen
00833       float value=0.0;
00834       for (int ky=0; ky<sy; ky++)
00835         for (int kx=0; kx<sx; kx++)
00836           value+=(*this)(y+ky-sy/2,x+kx-sx/2)*kernel[ky*sx+kx];
00837       (*newbild)(y,x)=value;
00838     }
00839   if (normalize) delete[] newkernel;
00841   //Smart pointers could help, but confuse EP5 people...
00842   return *newbild;
00843 }  
00844        
00846 bildfloat& bildfloat::gaussian (float radius) {
00847    const int size=2*static_cast<int>(radius)+1;
00848    const int middle=size/2;
00849    float *kernel= new float[SQR(size)];
00850    for (int y=0; y<size; y++)   
00851     for (int x=0; x<size; x++) {
00852       kernel[y*size+x] = exp(-(SQR(x-middle)+SQR(y-middle))/radius);
00853      // cerr<<kernel[y*size+x]<<"  ";
00854     }  
00855     
00856     //ugly and SLOW
00857     //need to copy temporary unnecessarily
00858     bildfloat *p=&convolve(kernel, size, size, true);
00859    (*this)=*p;
00860    delete p;
00861    delete [] kernel;
00862    return *this;
00863  
00864  } 
00865 
00866 bildfloat& bildfloat::mask(const region_t& reg) {
00867   for (int y=0; y<static_cast<signed>(SIZEY); y++)
00868     for (int x=0; x<static_cast<signed>(SIZEX); x++)
00869       if (!reg(y,x)) (*this)(y,x)=fnan;
00870   return *this;
00871 }
00872 
00873 const char interpol::magic[]="INTERREF";
00874 
00875 interpol::interpol(const char *fname) : interpol_base() {
00876   read(fname);
00877 }  
00878 
00879 interpol::interpol(bild16 * refbilder, float* refw, int nrefimg): 
00880   interpol_base(), nref(nrefimg), refwerte(refw, nrefimg) {
00881 
00882   /* Kopiere die Referenzbilder in eine "transponierte" Struktur */
00883   /* eine Matrix 512x512 von valarrays, die die Kurve enthält */
00884   for (int y=0; y<SIZEY; y++) {
00885     for (int x=0; x<SIZEX; x++) {
00886       (*this)(y,x).resize(nref);
00887 
00888       for (int r=0; r<nref; r++)
00889           (*this)(y,x)[r] = static_cast<float>(refbilder[r] (y,x))/bild16::intensity_max;
00890      }    
00891    }
00892 
00893 }  
00894 
00895 void interpol::write (const char* fname) {
00896   ofstream datei(fname, ios::out|ios::binary);
00897   datei.write(magic, sizeof(magic));
00898   datei.put(static_cast<char>(nref));
00899   for (int r=0; r<nref; r++) {
00900     datei<<rawfloat(refwerte[r]);
00901   }
00902 
00903   for (int y=0; y<SIZEY; y++)
00904     for (int x=0; x<SIZEX; x++)
00905       for (int r=0; r<nref; r++)
00906         datei<<rawfloat((*this)(y,x)[r]);
00907 }       
00908     
00909   
00910 
00911 void interpol::read(const char* fname) throw(const char*){
00912   ifstream datei(fname, ios::binary);
00913   if (!datei) throw("Nicht gefunden.");
00914   char magictest[sizeof(magic)];
00915   
00916   for (size_t i=0; i<sizeof(magic); i++) 
00917     datei.get(magictest[i]);
00918   
00919   if (strncmp(magic, magictest, sizeof(magic))!=0)
00920     throw("Kein Interpol-Reffile");
00921   
00922   char c;
00923   datei.get(c);
00924   nref=c;
00925   
00926   refwerte.resize(nref);
00927   for (int r=0; r<nref; r++)
00928     datei>>irawfloat(refwerte[r]);
00929   
00930   for (int y=0; y<SIZEY; y++)
00931     for (int x=0; x<SIZEX; x++) {
00932       (*this)(y,x).resize(nref);
00933       for (int r=0; r<nref; r++) 
00934         datei>>irawfloat((*this)(y,x)[r]);
00935     }
00936     
00937 }    
00938   
00939 float interpol::operator () (int y, int x, float val) {
00940    if (val>=(*this)(y,x)[nref-1]) {
00941      return 1.0;
00942    }
00943    if (val<=(*this)(y,x)[0]) {
00944      return 0.0;
00945    }
00946    int refindex=0;
00947    while (val > (*this)(y,x)[refindex+1]) refindex++;
00948    
00949    /* zu interpolierender Wert liegt zwischen refindex und refindex+1 */
00950 
00951    /* vermeide Division durch Null */
00952    if ((*this)(y,x)[refindex+1]==(*this)(y,x)[refindex]) {
00953       return val;
00954    }     
00955 
00956    /* interpoliere linear */
00957    return  refwerte[refindex] + (refwerte[refindex+1] - refwerte[refindex]) * 
00958                 (val-(*this)(y,x)[refindex])/((*this)(y,x)[refindex+1]-(*this)(y,x)[refindex]);
00959 }               
00960 
00961 
00962 const char QRfit::magic[]="QRfit";
00963 
00964 QRfit::QRfit(bild16 *refbilder, float *refw, int nrefimg, int order_) :
00965    interpol_base(), nref(nrefimg), order(order_), refwerte(refw, nrefimg) {
00966   
00967   reserve_2D(R, order, nref);
00968   d=new double[order];
00969   b=new double[nref];
00970   koeff=new double[order];
00971   double *bw = new double[nref];
00972   for (int y=0; y<SIZEY; y++) {
00973     for (int x=0; x<SIZEX; x++) {
00974       (*this)(y,x).resize(order);
00975 
00976       for (int k=0; k<nref; k++)
00977         bw[k]=double((refbilder[k])(y,x))/double(bild16::intensity_max);
00978         
00979       polyfit(bw);
00980 
00981       for (int k=0; k<order; k++)
00982         (*this)(y,x)[k]=koeff[k];
00983       
00984       if ((x==100) && (y==100)) {
00985         for (int r=0; r<order; r++)
00986            cout<<koeff[r]<<"  ";
00987          cout<<endl; 
00988       }
00989       // Fitte ein Polynom an die gewünschte Übertragungskurve
00990       // und speichere in dem valarray ab
00991     }  
00992   }
00993   delete[] bw;
00994 } 
00995 
00996 QRfit::QRfit(const char *fname) : interpol_base() {
00997 /*  reserve_2D(R, order, nref);
00998   d=new double[order];
00999   b=new double[nref];
01000   koeff=new double[order];
01001   */
01002   R=NULL;
01003   d=NULL;
01004   b=NULL;
01005   koeff=NULL;
01006   read(fname);
01007 }
01008 
01009 QRfit::~QRfit() {
01010   if (R) delete_2D(R);
01011   if (d) delete[] d;
01012   if (b) delete[] b;
01013   if (koeff) delete[] koeff;
01014 }
01015 
01016 void QRfit::write (const char* fname) const {
01017   ofstream datei(fname, ios::out|ios::binary);
01018   datei.write(magic, sizeof(magic));
01019 
01020   datei.put(static_cast<char>(nref));
01021   datei.put(static_cast<char>(order));
01022   
01023   for (int r=0; r<nref; r++) {
01024     datei<<rawfloat(refwerte[r]);
01025   }
01026 
01027   for (int y=0; y<SIZEY; y++)
01028     for (int x=0; x<SIZEX; x++)
01029       for (int k=0; k<order; k++)
01030         datei<<rawfloat((*this)(y,x)[k]);
01031 }       
01032     
01033   
01034 
01035 void QRfit::read(const char* fname) THROWSPEC {
01036   ifstream datei(fname, ios::binary);
01037   if (!datei) STHROW(fname<<" not found.");
01038   char magictest[sizeof(magic)];
01039  
01040   /* Testen, ob die Datei mit dem Magicstring beginnt */
01041   
01042   for (size_t i=0; i<sizeof(magic); i++) 
01043     datei.get(magictest[i]);
01044   
01045   if (strncmp(magic, magictest, sizeof(magic))!=0)
01046     STHROW(fname<<" is not a QRfit file");
01047   
01048   /* Anzahl der Referenzwerte und Ordnung des Polynoms lesen */
01049   char c;
01050   datei.get(c);
01051   nref=c;
01052   
01053   datei.get(c);
01054   order=c;
01055   
01056   /* Referenzwerte lesen */
01057   refwerte.resize(nref);
01058   for (int r=0; r<nref; r++)
01059     datei>>irawfloat(refwerte[r]);
01060   
01061   /* Koeffizienten lesen */
01062   for (int y=0; y<SIZEY; y++)
01063     for (int x=0; x<SIZEX; x++) {
01064       (*this)(y,x).resize(order);
01065       for (int k=0; k<order; k++) 
01066         datei>>irawfloat((*this)(y,x)[k]);
01067     }
01068     
01069 }    
01070  
01071 float QRfit::operator () (int y, int x, float val) const {
01072   float sum=(*this)(y,x)[0];
01073   float var=1.0;
01074   /* werte Polynom aus */
01075   for (int k=1; k<order; k++) {
01076     var*=val;
01077     sum+=var*(*this)(y,x)[k];
01078   }
01079    if (sum<0.0) return 0.0;
01080    if (sum>1.0) return 1.0;
01081   return sum;
01082 }
01083 
01084 float QRfit::get_coeff(int x, int y, int n) const {
01085   if (n<0 || n>order) STHROW("Index must be positive and < "<<order);
01086   return (*this)(y,x)[n];
01087 }
01088 
01089 
01090 void QRfit::polyfit(double *bildwerte) {
01091   
01092   // Fülle die Matrix mit den Bildwerten^ordnung
01093   // Für Polynomfit
01094   for (int nr=0; nr<nref; nr++) {
01095     double r=bildwerte[nr];
01096     R[nr][0]=1;
01097     
01098     for (int o=1; o<order; o++) {
01099        R[nr][o]=R[nr][o-1]*r;
01100     }
01101 
01102   }
01103 
01104   // Fülle die rechte Seite mit den Referenzwerten
01105   for (int nr=0; nr<nref; nr++)
01106     b[nr]=refwerte[nr];
01107   
01108   // Nun löse mit dem QR-Algorithmus
01109   // || R x - b || = minimal nach x
01110 
01111   if (QR(nref, order, R, d, b, 1e-10))  {
01112     //  STHROW("Singuläre Matrix");
01113     // Nicht gleich Exception werfen
01114     // "Notlösung" Offset-Gain für diesen Pixel
01115     cerr<<".";
01116     double offset=refwerte[0]; 
01117     double gain=refwerte[nref-1];
01118     if (offset==gain) {
01119       // jetzt ist wirklich alles singulär
01120       cerr<<":";
01121       koeff[0]=0.0;
01122       koeff[1]=1.0;
01123     } else {  
01124       koeff[0]=- offset/(gain-offset);
01125       koeff[1]=1.0/(gain-offset);
01126       // Standard Offset-Gain
01127     }
01128     for (int o=2; o<order; o++) koeff[o]=0.0;
01129 
01130   }  else  { 
01131    
01132     // Fit war nichtsingulär -- löse das QR-Ergebnis auf
01133     rdsolve(order, R, d, b, koeff);
01134 
01135   }  
01136 }    
01137 
01138 

Generated on Fri Jul 24 12:49:17 2009 for Xgrayimg Library by  doxygen 1.5.5