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
00026
00027
00028
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
00042 file_header->FileID = 0x7000;
00043 file_header->HeaderSize = 68;
00044 file_header->HeaderVersion = 100;
00045 file_header->FileSize = 524388;
00046 file_header->ImageHeaderSize = 32;
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;
00052 file_header->Correction = 0;
00053 file_header->IntegrationTime = 0;
00054 file_header->TypeOfNumbers = 4;
00055 }
00056
00057
00058 }
00059
00060 bild16::bild16 (unsigned short *data) THROWSPEC : bild16_base ()
00061 {
00062 file_header = new header_t;
00063
00064 file_header->FileID = 0x7000;
00065 file_header->HeaderSize = 68;
00066 file_header->HeaderVersion = 100;
00067 file_header->FileSize = 524388;
00068 file_header->ImageHeaderSize = 32;
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;
00074 file_header->Correction = 0;
00075 file_header->IntegrationTime = 0;
00076 file_header->TypeOfNumbers = 4;
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';
00093 datei << SIZEX << " " << SIZEY << "\n" << intensity_max << "\n";
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
00102
00103 }
00104
00105
00106 void bild16::write_pgm8 (const char *name) const
00107 {
00108 ofstream datei (name, ios::binary);
00109 datei << "P5" << endl;
00110 datei << SIZEX << " " << SIZEY << "\n" << 0xFF << "\n";
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
00118
00119
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;
00127 datei << SIZEX << " " << SIZEY << "\n" << 0xFF << "\n";
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
00140
00141
00142 }
00143
00144 bild16& bild16::read_his (const char *name) THROWSPEC
00145 {
00146 ifstream his;
00147 his.open (name, ios::binary | ios::in);
00148 if (!his) STHROW(name<<" not found!\n");
00149
00150
00151 his.read ((char *) file_header, sizeof (*file_header));
00152
00153
00154
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 ();
00161 return *this;
00162 }
00163
00164 void bild16::write_his (const char *name) const
00165 {
00166 ofstream his;
00167 his.open (name, ios::binary);
00168 if (!his) {
00169 STHROW("Cannot write to "<<name);
00170 }
00171
00172 his.write ((char *) file_header, sizeof (*file_header));
00173
00174
00175 for (streamoff i=sizeof(*file_header); i<HIS_START; i++)
00176 his.put(char(0));
00177
00178
00179 his.seekp (HIS_START);
00180
00181
00182 for (int y = 0; y < SIZEY; y++) {
00183 his.write ((char *) bild[y], sizeof (unsigned short) * SIZEX);
00184 }
00185
00186 his.close ();
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
00211
00212 eatwhite(is);
00213 while (is.peek()=='#') {
00214
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
00221
00222 const int maxlen=10;
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;
00245 pgm.open (name, ios::binary | ios::in);
00246 if (!pgm) STHROW(name<<" not found!");
00247 try {
00248
00249
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();
00261 switch (maxval)
00262 {
00263 case 255:
00264
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
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 ();
00289 } catch (const string& msg) {
00290 STHROW(name<<": "<<msg);
00291
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
00311 double denom = gain(y,x)-offset(y,x);
00312 if (denom <= epsilon) continue;
00313
00314 double nomin = bild[y][x] - offset(y,x);
00315 if (nomin < 0) continue;
00316
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
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
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
00365
00366
00367 eichkurve::eichkurve ()
00368 {
00369
00370 lookup= new double[0x10000];
00371 }
00372
00373 eichkurve::~eichkurve() {
00374
00375 delete[] lookup;
00376 }
00377
00378 const char eichkurve::magic[]="EICHTABELLE";
00379
00380 void eichkurve::table_init(double hmin, double hmax) {
00381
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;
00391 double vmin=eichfun(hmin);
00392 double vmax=eichfun(hmax);
00393 int signum=1;
00394 if (vmin<vmax) {
00395
00396 signum=1;
00397 if (val<vmin) return hmin;
00398 if (val>vmax) return hmax;
00399 } else {
00400
00401 signum=-1;
00402 if (val>vmin) return hmin;
00403 if (val<vmax) return hmax;
00404 }
00405
00406
00407 double h;
00408 double vh;
00409 do {
00410 h = (val-vmin)/(vmax-vmin) * (hmax-hmin) + hmin;
00411 vh = eichfun(h);
00412
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
00428 #if 0
00429 double eichkurve::fsolve(bild16::data_t val, double hmin, double hmax) const
00430 {
00431 const double epsilon=0.5;
00432 double vmin=eichfun(hmin);
00433 double vmax=eichfun(hmax);
00434 if (vmin<vmax) {
00435
00436 if (val<vmin) return hmin;
00437 if (val>vmax) return hmax;
00438 } else {
00439
00440 if (val>vmin) return hmin;
00441 if (val<vmax) return hmax;
00442 }
00443 double x = initguess(val);
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
00450
00451
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
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
00491 exp4kurve::exp4kurve (double sA, double sa1, double sa2, double sa3,
00492
00493 double sb1, double sb2, double sb3, double sb4 ) :
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
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
00538
00539
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
00576
00577
00578
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
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
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);
00620
00621 for (int y = 0; y < SIZEY; y++) {
00622 datfile >> irawfloat (dummy);
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)
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
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;
00681 } else
00682
00683 {
00684 (*this) (y, x) = 0;
00685 }
00686
00687
00688 }
00689 }
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
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
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
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
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;
00821 }
00822
00823
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
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
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
00854 }
00855
00856
00857
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
00883
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
00950
00951
00952 if ((*this)(y,x)[refindex+1]==(*this)(y,x)[refindex]) {
00953 return val;
00954 }
00955
00956
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
00990
00991 }
00992 }
00993 delete[] bw;
00994 }
00995
00996 QRfit::QRfit(const char *fname) : interpol_base() {
00997
00998
00999
01000
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
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
01049 char c;
01050 datei.get(c);
01051 nref=c;
01052
01053 datei.get(c);
01054 order=c;
01055
01056
01057 refwerte.resize(nref);
01058 for (int r=0; r<nref; r++)
01059 datei>>irawfloat(refwerte[r]);
01060
01061
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
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
01093
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
01105 for (int nr=0; nr<nref; nr++)
01106 b[nr]=refwerte[nr];
01107
01108
01109
01110
01111 if (QR(nref, order, R, d, b, 1e-10)) {
01112
01113
01114
01115 cerr<<".";
01116 double offset=refwerte[0];
01117 double gain=refwerte[nref-1];
01118 if (offset==gain) {
01119
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
01127 }
01128 for (int o=2; o<order; o++) koeff[o]=0.0;
01129
01130 } else {
01131
01132
01133 rdsolve(order, R, d, b, koeff);
01134
01135 }
01136 }
01137
01138