00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef NEARESTFEATURETRANSFORM_H
00025 #define NEARESTFEATURETRANSFORM_H
00026
00027 #include <iostream>
00028 #include <list>
00029 #include <math.h>
00030 #include <vigra/basicimage.hxx>
00031 #include <vigra/functorexpression.hxx>
00032 #include <vigra/combineimages.hxx>
00033
00034 #include <hugin_utils/utils.h>
00035 #include <appbase/ProgressDisplayOld.h>
00036
00037
00038 #include <tiff.h>
00039 #include <tiffio.h>
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 namespace vigra_ext {
00059
00060 #define EUCLIDEAN_METRIC
00061
00062 #ifdef EUCLIDEAN_METRIC
00063
00064
00065 typedef float dist_t;
00066 #define DIST_MAX (1e20)
00067 #define DIST_MIN 0
00068 inline dist_t distance(uint32 deltaX, dist_t *deltaY) {
00069 return (*deltaY == DIST_MAX) ? DIST_MAX : *deltaY + deltaX * deltaX;
00070 }
00071 inline dist_t distance(uint32 deltaY) {
00072 return deltaY * deltaY;
00073 }
00074 #else
00075 #ifdef CHESSBOARD_METRIC
00076 typedef uint32 dist_t;
00077 #define DIST_MAX ((dist_t)-1)
00078 #define DIST_MIN 0
00079 inline dist_t distance(uint32 deltaX, dist_t *deltaY) {
00080 return max(deltaX, *deltaY);
00081 }
00082 inline dist_t distance(uint32 deltaY) {
00083 return deltaY;
00084 }
00085 #else
00086 #ifdef MANHATTAN_METRIC
00087 typedef uint32 dist_t;
00088 #define DIST_MAX ((dist_t)-1)
00089 #define DIST_MIN 0
00090 inline dist_t distance(uint32 deltaX, dist_t *deltaY) {
00091 return (*deltaY == DIST_MAX) ? DIST_MAX : deltaX + *deltaY;
00092 }
00093 inline dist_t distance(uint32 deltaY) {
00094 return deltaY;
00095 }
00096 #endif
00097 #endif
00098 #endif
00099
00100
00101 #ifdef DEBUG_NEAREST
00102 static inline void saveDist(dist_t *ptr, uint32 w, uint32 h, const char * filename)
00103 {
00104
00105 TIFF *outputTIFF = TIFFOpen(filename, "w");
00106 if (outputTIFF == NULL) {
00107 std::cerr << "enblend: error opening TIFF file \""
00108 << filename << "\"" << std::endl;
00109 exit(1);
00110 }
00111
00112 TIFFSetField(outputTIFF, TIFFTAG_ORIENTATION, 1);
00113 TIFFSetField(outputTIFF, TIFFTAG_SAMPLEFORMAT, 3);
00114 TIFFSetField(outputTIFF, TIFFTAG_SAMPLESPERPIXEL, 1);
00115 TIFFSetField(outputTIFF, TIFFTAG_BITSPERSAMPLE, 32);
00116 TIFFSetField(outputTIFF, TIFFTAG_IMAGEWIDTH, w);
00117 TIFFSetField(outputTIFF, TIFFTAG_IMAGELENGTH, h);
00118 TIFFSetField(outputTIFF, TIFFTAG_PHOTOMETRIC, 1);
00119 TIFFSetField(outputTIFF, TIFFTAG_PLANARCONFIG, 1);
00120
00121 for (uint32 scan = 0; scan < h; scan++) {
00122 TIFFWriteScanline(outputTIFF,
00123 &(ptr[scan * w]),
00124 scan,
00125 1);
00126 }
00127 TIFFClose(outputTIFF);
00128 }
00129
00130 static void saveDistRaw(void * ptr, uint32 w, uint32 h, const char * file)
00131 {
00132 FILE * f = fopen(file,"wb+");
00133 if (f == NULL) {
00134 std::cerr << "enblend: error creating temporary file." << std::endl;
00135 exit(1);
00136 }
00137 size_t size = w*h;
00138 size_t itemsWritten = fwrite(ptr, sizeof(dist_t), size, f);
00139 if (itemsWritten < size) {
00140 std::cerr << "enblend: error writing to temporary file." << std::endl;
00141 perror("reason");
00142 exit(1);
00143 }
00144 }
00145 #endif
00146
00155 template <typename Feat1Iter, typename Feat1Accessor,
00156 typename Feat2Iter, typename Feat2Accessor,
00157 typename Mask1Iter, typename Mask1Accessor,
00158 typename Mask2Iter, typename Mask2Accessor>
00159 void nearestFeatureTransform(vigra::triple<Feat1Iter, Feat1Iter, Feat1Accessor> feat1,
00160 std::pair<Feat2Iter, Feat2Accessor> feat2,
00161 std::pair<Mask1Iter, Mask1Accessor> mask1,
00162 std::pair<Mask2Iter, Mask2Accessor> mask2,
00163 AppBase::MultiProgressDisplay & progress)
00164 {
00165 typedef typename Mask1Accessor::value_type MaskType;
00166 typedef vigra::BasicImage<MaskType> FeatImage;
00167 typedef typename FeatImage::Iterator FeatIter;
00168 progress.pushTask(AppBase::ProgressTask("blend mask", "creating blend line",1/4));
00169
00170 vigra::Diff2D ubbSize = feat1.second - feat1.first;
00171
00172 uint32 ubbWidth = ubbSize.x;
00173 uint32 ubbHeight = ubbSize.y;
00174 uint32 ubbPixels = ubbWidth * ubbHeight;
00175
00176
00177
00178 FeatImage feature(ubbSize);
00179
00180
00181
00182 dist_t *dnfColumn = (dist_t*)malloc(ubbPixels * sizeof(dist_t));
00183
00184 if (dnfColumn == NULL) {
00185 std::cerr << std::endl
00186 << "enblend: out of memory (in nearestFeatureTransform for dnfColumn)" << std::endl;
00187 exit(1);
00188 }
00189
00190
00191
00192 dist_t *dnfLeft = (dist_t*)malloc(ubbPixels * sizeof(dist_t));
00193 if (dnfLeft == NULL) {
00194 std::cerr << "enblend: out of memory (in nearestFeatureTransform for dnfLeft)" << std::endl;
00195 exit(1);
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 Mask1Iter m1x(mask1.first);
00210 Mask2Iter m2x(mask2.first);
00211
00212 Feat1Iter f1x(feat1.first);
00213 Feat2Iter f2x(feat2.first);
00214
00215
00216
00217
00218 for (uint32 x = 0; x < ubbWidth; x++, ++m1x.x, ++m2x.x, ++f1x.x, ++f2x.x) {
00219 dist_t *dnfColumnP = &dnfColumn[x];
00220
00221
00222
00223 MaskType lastFeature2 = 0;
00224 MaskType lastFeature1 = 0;
00225
00226 uint32 lastFeatureDeltaY = 0;
00227 bool foundFirstFeature = false;
00228
00229 Mask1Iter m1y(m1x);
00230 Mask2Iter m2y(m2x);
00231 Feat1Iter f1y(f1x);
00232 Feat2Iter f2y(f2x);
00233 for (uint32 y = 0; y < ubbHeight; y++, ++m1y.y, ++m2y.y, ++f1y.y, ++f2y.y) {
00234
00235 if ((*f2y) != (*f1y)) {
00236
00237
00238 *dnfColumnP = DIST_MIN;
00239 lastFeatureDeltaY = 0;
00240
00241
00242 lastFeature2 = *f2y;
00243 lastFeature1 = *f1y;
00244 *m1y = lastFeature1;
00245 *m2y = lastFeature2;
00246 foundFirstFeature = true;
00247 } else if (foundFirstFeature) {
00248
00249 *dnfColumnP = distance(lastFeatureDeltaY);
00250
00251
00252 *m1y = lastFeature1;
00253 *m2y = lastFeature2;
00254 } else {
00255 *dnfColumnP = DIST_MAX;
00256 }
00257
00258 lastFeatureDeltaY++;
00259
00260
00261 dnfColumnP += ubbWidth;
00262
00263 }
00264 }
00265
00266 #ifdef DEBUG_NEAREST
00267 vigra::exportImage(vigra::srcImageRange(feature), vigra::ImageExportInfo("nona_0_featuremask.tif"));
00268 vigra::exportImage(srcIterRange(mask1.first, mask1.first + ubbSize), vigra::ImageExportInfo("nona_1_mask1.tif"));
00269 vigra::exportImage(srcIterRange(mask2.first, mask2.first + ubbSize), vigra::ImageExportInfo("nona_1_mask2.tif"));
00270 saveDist(dnfColumn, ubbWidth, ubbHeight, "nona_1_dnfColumn.tif");
00271 saveDist(dnfLeft, ubbWidth, ubbHeight, "nona_1_dnfLeft.tif");
00272 #endif
00273
00274
00275
00276
00277
00278 progress.increase();
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 m1x = mask1.first + ubbSize - vigra::Diff2D(1,1);
00289 m2x = mask2.first + ubbSize - vigra::Diff2D(1,1);
00290 f1x = feat1.first + ubbSize - vigra::Diff2D(1,1);
00291 f2x = feat2.first + ubbSize - vigra::Diff2D(1,1);
00292
00293 dist_t *lastDNFColumnP = &dnfColumn[ubbPixels - 1];
00294 for (uint32 x = 0; x < ubbWidth; x++, --m1x.x, --m2x.x, --f1x.x, --f2x.x) {
00295 dist_t *dnfColumnP = lastDNFColumnP - x;
00296
00297
00298
00299 MaskType lastFeatureG = 0;
00300 MaskType lastFeatureB = 0;
00301
00302 uint32 lastFeatureDeltaY = 0;
00303 bool foundFirstFeature = false;
00304
00305 Mask1Iter m1y(m1x);
00306 Mask2Iter m2y(m2x);
00307 Feat1Iter f1y(f1x);
00308 Feat2Iter f2y(f2x);
00309 for (uint32 y = 0; y < ubbHeight; y++, --m1y.y, --m2y.y, --f1y.y, --f2y.y)
00310 {
00311
00312 if ((*f2y) != (*f1y)) {
00313
00314
00315 lastFeatureDeltaY = 0;
00316
00317
00318 lastFeatureG = *m2y;
00319 lastFeatureB = *m1y;
00320 foundFirstFeature = true;
00321 } else if (foundFirstFeature) {
00322
00323 dist_t distLastFeature = distance(lastFeatureDeltaY);
00324
00325
00326 if (distLastFeature < *dnfColumnP) {
00327 *dnfColumnP = distLastFeature;
00328
00329
00330 *m1y = lastFeatureB;
00331 *m2y = lastFeatureG;
00332 }
00333 }
00334
00335 lastFeatureDeltaY++;
00336
00337
00338 dnfColumnP -= ubbWidth;
00339
00340 }
00341 }
00342
00343 #ifdef DEBUG_NEAREST
00344 vigra::exportImage(srcIterRange(mask1.first, mask1.first + ubbSize), vigra::ImageExportInfo("nona_2_mask1.tif"));
00345 vigra::exportImage(srcIterRange(mask2.first, mask2.first + ubbSize), vigra::ImageExportInfo("nona_2_mask2.tif"));
00346 saveDist(dnfColumn, ubbWidth, ubbHeight, "nona_2_dnfColumn.tif");
00347 saveDist(dnfLeft, ubbWidth, ubbHeight, "nona_2_dnfLeft.tif");
00348 #endif
00349
00350
00351
00352
00353 progress.increase();
00354
00355
00356
00357
00358
00359
00360
00361 Mask1Iter m1y(mask1.first);
00362 Mask2Iter m2y(mask2.first);
00363 for (uint32 y = 0; y < ubbHeight; y++, ++m1y.y, ++m2y.y) {
00364 dist_t *dnfLeftP = &dnfLeft[y * ubbWidth];
00365 dist_t *dnfColumnP = &dnfColumn[y * ubbWidth];
00366
00367
00368
00369
00370 std::list<dist_t*> potentialFeatureList;
00371
00372 Mask1Iter m1x(m1y);
00373 Mask2Iter m2x(m2y);
00374 for (uint32 x = 0; x < ubbWidth; x++, ++m1x.x, ++m2x.x) {
00375
00376 potentialFeatureList.push_back(dnfColumnP);
00377
00378
00379
00380
00381
00382 std::list<dist_t*>::iterator potentialFeature =
00383 --(potentialFeatureList.end());
00384
00385
00386
00387 dist_t distPotentialFeature = *dnfColumnP;
00388 while (potentialFeature != potentialFeatureList.begin()) {
00389
00390 std::list<dist_t*>::iterator previousFeature = potentialFeature;
00391 previousFeature--;
00392
00393
00394 uint32 deltaX = dnfColumnP - *previousFeature;
00395
00396
00397 dist_t distPreviousFeature = distance(deltaX, *previousFeature);
00398
00399 if (distPreviousFeature >= distPotentialFeature) {
00400
00401
00402 potentialFeatureList.erase(previousFeature);
00403 } else {
00404
00405 potentialFeature = previousFeature;
00406 distPotentialFeature = distPreviousFeature;
00407 }
00408 }
00409
00410
00411
00412 *dnfLeftP = distPotentialFeature;
00413
00414
00415
00416 int dx = (dnfColumnP - *potentialFeature);
00417 Mask1Iter m1l(m1x);
00418 m1l.x -= dx;
00419 *m1x = *m1l;
00420 Mask1Iter m2l(m2x);
00421 m2l.x -= dx;
00422 *m2x = *m2l;
00423
00424
00425 dnfLeftP++;
00426 dnfColumnP++;
00427
00428
00429
00430 }
00431 }
00432
00433
00434
00435
00436
00437 #ifdef DEBUG_NEAREST
00438 vigra::exportImage(vigra::srcIterRange(mask1.first, mask1.first + ubbSize), vigra::ImageExportInfo("nona_3_mask1.tif"));
00439 vigra::exportImage(vigra::srcIterRange(mask2.first, mask2.first + ubbSize), vigra::ImageExportInfo("nona_3_mask2.tif"));
00440 saveDist(dnfColumn, ubbWidth, ubbHeight, "nona_3_dnfColumn.tif");
00441 saveDist(dnfLeft, ubbWidth, ubbHeight, "nona_3_dnfLeft.tif");
00442 #endif
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 dist_t *lastDNFLeftP = &dnfLeft[ubbPixels - 1];
00454 m1y = mask1.first + (ubbSize - vigra::Diff2D(1,1));
00455 m2y = mask2.first + (ubbSize - vigra::Diff2D(1,1));
00456 for (uint32 y = 0; y < ubbHeight; y++, --m1y.y, --m2y.y) {
00457 dist_t *dnfColumnP = lastDNFColumnP - (y * ubbWidth);
00458 dist_t *dnfLeftP = lastDNFLeftP - (y * ubbWidth);
00459
00460
00461
00462
00463 std::list<dist_t*> potentialFeatureList;
00464
00465 Mask1Iter m1x(m1y);
00466 Mask2Iter m2x(m2y);
00467 for (uint32 x = 0; x < ubbWidth; x++, --m1x.x, --m2x.x) {
00468
00469 potentialFeatureList.push_back(dnfColumnP);
00470
00471
00472 std::list<dist_t*>::iterator potentialFeature =
00473 --(potentialFeatureList.end());
00474 dist_t distPotentialFeature = *dnfColumnP;
00475 while (potentialFeature != potentialFeatureList.begin()) {
00476
00477 std::list<dist_t*>::iterator previousFeature = potentialFeature;
00478 previousFeature--;
00479
00480
00481 uint32 deltaX = *previousFeature - dnfColumnP;
00482
00483
00484 dist_t distPreviousFeature = distance(deltaX, *previousFeature);
00485
00486 if (distPreviousFeature >= distPotentialFeature) {
00487
00488 potentialFeatureList.erase(previousFeature);
00489 } else {
00490
00491 potentialFeature = previousFeature;
00492 distPotentialFeature = distPreviousFeature;
00493 }
00494 }
00495
00496
00497 if (*dnfLeftP > distPotentialFeature) {
00498
00499
00500 Mask1Iter m1r(m1x);
00501 int dx = (*potentialFeature - dnfColumnP);
00502 m1r.x += dx;
00503 *m1x = *m1r;
00504 Mask2Iter m2r(m2x);
00505 m2r.x += dx;
00506 *m2x = *m2r;
00507 }
00508
00509
00510 dnfLeftP--;
00511 dnfColumnP--;
00512
00513
00514
00515 }
00516 }
00517
00518
00519
00520
00521
00522 vigra::combineTwoImages(feat1, mask1, mask1,
00523 vigra::functor::ifThenElse( vigra::functor::Arg1() > vigra::functor::Param(0),
00524 vigra::functor::Arg2(),
00525 vigra::functor::Param(0) ) );
00526 vigra::combineTwoImages(srcIterRange(feat2.first, feat2.first + ubbSize),
00527 mask2, mask2,
00528 vigra::functor::ifThenElse( vigra::functor::Arg1() > vigra::functor::Param(0),
00529 vigra::functor::Arg2(),
00530 vigra::functor::Param(0) ) );
00531
00532 #ifdef DEBUG_NEAREST
00533 vigra::exportImage(vigra::srcIterRange(mask1.first, mask1.first + ubbSize), vigra::ImageExportInfo("nona_4_mask1.tif"));
00534 vigra::exportImage(vigra::srcIterRange(mask2.first, mask2.first + ubbSize), vigra::ImageExportInfo("nona_4_mask2.tif"));
00535 saveDist(dnfColumn, ubbWidth, ubbHeight, "nona_4_dnfColumn.tif");
00536 saveDist(dnfLeft, ubbWidth, ubbHeight, "nona_4_dnfLeft.tif");
00537 #endif
00538
00539 progress.increase();
00540
00541 free(dnfColumn);
00542 free(dnfLeft);
00543
00544 progress.popTask();
00545 return;
00546 }
00547
00548 }
00549
00550 #endif // NEARESTFEATURETRANSFORM_H