00001
00002
00027 #include "ImageCache.h"
00028
00029 #include <iostream>
00030 #include <boost/thread/thread.hpp>
00031 #include <vigra/inspectimage.hxx>
00032 #include <vigra/accessor.hxx>
00033 #include <vigra/functorexpression.hxx>
00034 #include <vigra/sized_int.hxx>
00035 #include <vigra_ext/utils.h>
00036 #include <vigra_ext/impexalpha.hxx>
00037 #include <vigra_ext/Pyramid.h>
00038 #include <vigra_ext/FunctorAccessor.h>
00039
00040
00041
00042 namespace HuginBase {
00043
00044 using namespace std;
00045 using namespace vigra::functor;
00046
00047
00048 template <class T1>
00049 class GetRange
00050 {
00051 public:
00052 static T1 min();
00053 static T1 max();
00054 };
00055
00056
00057 #define VIGRA_EXT_GETRANGE(T1, MI,MA) \
00058 template<> \
00059 T1 GetRange<T1>::min() \
00060 { \
00061 return MI; \
00062 } \
00063 template<> \
00064 T1 GetRange<T1>::max() \
00065 { \
00066 return MA; \
00067 } \
00068
00069 VIGRA_EXT_GETRANGE(vigra::UInt8, 0, 255);
00070 VIGRA_EXT_GETRANGE(vigra::Int16, 0, 32767);
00071 VIGRA_EXT_GETRANGE(vigra::UInt16, 0, 65535);
00072 VIGRA_EXT_GETRANGE(vigra::Int32, 0, 2147483647);
00073 VIGRA_EXT_GETRANGE(vigra::UInt32, 0, 4294967295u);
00074 VIGRA_EXT_GETRANGE(float, 0, 1.0f);
00075 VIGRA_EXT_GETRANGE(double, 0, 1.0);
00076
00077 #undef VIGRA_EXT_GETRANGE
00078
00079
00080 template <class SrcIMG>
00081 void convertTo8Bit(SrcIMG & src, const std::string & origType, vigra::BRGBImage & dest)
00082 {
00083
00084
00085
00086 dest.resize(src.size());
00087
00088 double min=0;
00089 double max=vigra_ext::getMaxValForPixelType(origType);
00090 ;
00091
00092 int mapping = HUGIN_IMGCACHE_MAPPING_INTEGER;
00093
00094
00095 if (origType == "FLOAT" || origType == "DOUBLE")
00096 {
00097 vigra::RGBToGrayAccessor<vigra::RGBValue<float> > ga;
00098 vigra::FindMinMax<float> minmax;
00099 vigra::inspectImage(srcImageRange(src, ga),
00100 minmax);
00101 min = minmax.min;
00102 max = minmax.max;
00103 mapping = HUGIN_IMGCACHE_MAPPING_FLOAT;
00104 }
00105 vigra_ext::applyMapping(srcImageRange(src), destImage(dest), min, max, mapping);
00106 }
00107
00108
00109
00110 ImageCache::ImageCacheRGB8Ptr ImageCache::Entry::get8BitImage()
00111 {
00112 if (image8->width() > 0) {
00113 return image8;
00114 } else if (image16->width() > 0) {
00115 convertTo8Bit(*image16,
00116 origType,
00117 *image8);
00118 } else if (imageFloat->width() > 0) {
00119 convertTo8Bit(*imageFloat,
00120 origType,
00121 *image8);
00122 }
00123 return image8;
00124 }
00125
00126 ImageCache * ImageCache::instance = NULL;
00127
00128
00129 void ImageCache::removeImage(const std::string & filename)
00130 {
00131 map<string, EntryPtr>::iterator it = images.find(filename);
00132 if (it != images.end()) {
00133 images.erase(it);
00134 }
00135
00136 string sfilename = filename + string("_small");
00137 it = images.find(sfilename);
00138 if (it != images.end()) {
00139 images.erase(it);
00140 }
00141
00142 int level = 0;
00143 bool found = true;
00144 do {
00145
00146 PyramidKey key(filename,level);
00147 map<string, vigra::BImage*>::iterator it = pyrImages.find(key.toString());
00148 found = (it != pyrImages.end());
00149 if (found) {
00150 delete it->second;
00151 pyrImages.erase(it);
00152 }
00153 level++;
00154 } while (found);
00155 }
00156
00157
00158 void ImageCache::flush()
00159 {
00160 images.clear();
00161
00162 for (map<string, vigra::BImage*>::iterator it = pyrImages.begin();
00163 it != pyrImages.end();
00164 ++it)
00165 {
00166 delete it->second;
00167 }
00168 pyrImages.clear();
00169 }
00170
00171 void ImageCache::softFlush()
00172 {
00173 if(upperBound==0l)
00174 upperBound = 100 * 1024 * 1024l;
00175 long purgeToSize = long(0.75 * upperBound);
00176
00177
00178 long imgMem = 0;
00179
00180 std::map<std::string, EntryPtr>::iterator imgIt;
00181 for(imgIt=images.begin(); imgIt != images.end(); imgIt++) {
00182 #ifdef DEBUG
00183 cout << "Image: " << imgIt->first << std::endl;
00184 cout << "CacheEntry: " << imgIt->second.use_count() << "last access: " << imgIt->second->lastAccess;
00185 #endif
00186 if (imgIt->second->image8) {
00187 imgMem += imgIt->second->image8->width() * imgIt->second->image8->height() * 3;
00188 #ifdef DEBUG
00189 cout << " 8bit: " << imgIt->second->image8.use_count();
00190 #endif
00191 }
00192 if (imgIt->second->image16) {
00193 imgMem += imgIt->second->image16->width() * imgIt->second->image16->height() * 3*2;
00194 #ifdef DEBUG
00195 cout << " 16bit: " << imgIt->second->image8.use_count();
00196 #endif
00197 }
00198 if (imgIt->second->imageFloat) {
00199 imgMem += imgIt->second->imageFloat->width() * imgIt->second->imageFloat->height() * 3 * 4;
00200 #ifdef DEBUG
00201 cout << " float: " << imgIt->second->imageFloat.use_count() ;
00202 #endif
00203 }
00204 if (imgIt->second->mask) {
00205 imgMem += imgIt->second->mask->width() * imgIt->second->mask->height();
00206 #ifdef DEBUG
00207 cout << " mask: " << imgIt->second->mask.use_count() << std:: endl;
00208 #endif
00209 }
00210 }
00211
00212 long pyrMem = 0;
00213 std::map<std::string, vigra::BImage*>::iterator pyrIt;
00214 for(pyrIt=pyrImages.begin(); pyrIt != pyrImages.end(); pyrIt++) {
00215 pyrMem += pyrIt->second->width() * pyrIt->second->height();
00216 }
00217
00218 long usedMem = imgMem + pyrMem;
00219
00220 DEBUG_DEBUG("total: " << (usedMem>>20) << " MB upper bound: " << (purgeToSize>>20) << " MB");
00221 if (usedMem > upperBound)
00222 {
00223
00224 long purgeAmount = usedMem - purgeToSize;
00225 long purgedMem = 0;
00226
00227
00228
00229
00230
00231 std::map<int,std::string> accessMap;
00232 for (map<string, EntryPtr>::iterator it = images.begin();
00233 it != images.end();
00234 ++it)
00235 {
00236 if (it->first.substr(it->first.size()-6) != ":small") {
00237
00238 if (it->second.unique()) {
00239 DEBUG_DEBUG("Considering " << it->first << " for deletion");
00240 accessMap.insert(make_pair(it->second->lastAccess, it->first));
00241 } else {
00242 DEBUG_DEBUG(it->first << ", usecount: " << it->second.use_count());
00243 }
00244 }
00245 }
00246 while (purgeAmount > purgedMem) {
00247 bool deleted = false;
00248 if (pyrImages.size() > 0) {
00249 vigra::BImage * imgPtr = (*(pyrImages.begin())).second;
00250 purgedMem += imgPtr->width() * imgPtr->height();
00251 delete imgPtr;
00252 pyrImages.erase(pyrImages.begin());
00253 deleted = true;
00254 } else if (accessMap.size() > 0) {
00255 std::map<int,std::string>::iterator accIt = accessMap.begin();
00256 map<string, EntryPtr>::iterator it = images.find(accIt->second);
00257
00258 if (it != images.end()) {
00259 DEBUG_DEBUG("soft flush: removing image: " << it->first);
00260 if (it->second->image8) {
00261 purgedMem += it->second->image8->width() * it->second->image8->height() * 3;
00262 }
00263 if (it->second->image16) {
00264 purgedMem += it->second->image16->width() * it->second->image16->height() * 3 * 2;
00265 }
00266 if (it->second->imageFloat) {
00267 purgedMem += it->second->imageFloat->width() * it->second->imageFloat->height()*3*4;
00268 }
00269 if (it->second->mask) {
00270 purgedMem += it->second->mask->width() * it->second->mask->height();
00271 }
00272 images.erase(it);
00273 accessMap.erase(accIt);
00274 deleted = true;
00275 } else {
00276 DEBUG_ASSERT("internal error while purging cache");
00277 }
00278 }
00279 if (!deleted) {
00280 break;
00281 }
00282 }
00283
00284
00285
00286
00287 DEBUG_DEBUG("purged: " << (purgedMem>>20) << " MB, memory used for images: " << ((usedMem - purgedMem)>>20) << " MB");
00288
00289 }
00290 }
00291
00292
00293
00294 ImageCache& ImageCache::getInstance()
00295 {
00296 if (instance == NULL)
00297 {
00298 instance = new ImageCache();
00299 }
00300 return *instance;
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00342
00343
00344
00345
00346
00347
00348
00349
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 template <class SrcPixelType,
00380 class DestIterator, class DestAccessor>
00381 void ImageCache::importAndConvertImage(const vigra::ImageImportInfo & info,
00382 vigra::pair<DestIterator, DestAccessor> dest,
00383 const std::string & type)
00384 {
00385 typedef typename DestAccessor::value_type DestPixelType;
00386
00387 if (type == "FLOAT" || type == "DOUBLE" ) {
00388
00389 vigra::importImage(info, dest);
00390 } else {
00391 vigra::importImage(info, dest);
00392
00393 double scale = 1.0/vigra_ext::LUTTraits<SrcPixelType>::max();
00394
00395 vigra_ext::Multiply<double> f(scale);
00396 transformImage(dest.first, dest.first+ vigra::Diff2D(info.width(), info.height()), dest.second,
00397 dest.first, dest.second,
00398 Arg1()*Param(scale));
00399 }
00400 }
00401
00402 #if 0
00403
00404 template <class SrcPixelType,
00405 class DestIterator, class DestAccessor>
00406 void ImageCache::importAndConvertGrayImage(const ImageImportInfo & info,
00407 vigra::pair<DestIterator, DestAccessor> dest,
00408 wxString type)
00409
00410 {
00411 typedef typename DestAccessor::value_type DestPixelType;
00412 typedef typename DestPixelType::value_type DestComponentType;
00413 typedef SrcPixelType SrcComponentType;
00414
00415
00416 BasicImage<SrcPixelType> tmp(info.width(), info.height());
00417 vigra::importImage(info, destImage(tmp));
00418
00419 SrcComponentType min,max;
00420
00421 int range = wxConfigBase::Get()->Read(wxT("/ImageCache/Range"), HUGIN_IMGCACHE_RANGE);
00422 if (range == 0) {
00423 double t;
00424 wxConfigBase::Get()->Read(wxT("/ImageCache/") + type + wxT("/min"), &t, double(GetRange<SrcComponentType>::min()));
00425 min = SrcComponentType(t);
00426 wxConfigBase::Get()->Read(wxT("/ImageCache/") + type + wxT("/max"), &t, double(GetRange<SrcComponentType>::max()));
00427 max = SrcComponentType(t);
00428 } else if (range == 1) {
00429 vigra::FindMinMax<SrcComponentType> minmax;
00430 vigra::inspectImage(srcImageRange(tmp),
00431 minmax);
00432 min = minmax.min;
00433 max = minmax.max;
00434 } else{
00435 vigra_fail("Unknown image import range mode");
00436 }
00437
00438 int mapping = wxConfigBase::Get()->Read(wxT("/ImageCache/Mapping"), HUGIN_IMGCACHE_MAPPING);
00439 applyMapping(srcImageRange(tmp), dest, min, max, mapping);
00440 }
00441
00442 template <class SrcPixelType,
00443 class DestIterator, class DestAccessor>
00444 void ImageCache::importAndConvertGrayAlphaImage(const ImageImportInfo & info,
00445 vigra::pair<DestIterator, DestAccessor> dest,
00446 wxString type)
00447 {
00448 typedef typename DestAccessor::value_type DestPixelType;
00449 typedef typename DestPixelType::value_type DestComponentType;
00450 typedef SrcPixelType SrcComponentType;
00451
00452
00453 BasicImage<SrcPixelType> tmp(info.width(), info.height());
00454 BImage mask(info.width(), info.height());
00455 vigra::importImageAlpha(info, destImage(tmp), destImage(mask));
00456
00457 SrcComponentType min,max;
00458
00459 int range = wxConfigBase::Get()->Read(wxT("/ImageCache/Range"), HUGIN_IMGCACHE_RANGE);
00460 if (range == 0) {
00461 double t;
00462 wxConfigBase::Get()->Read(wxT("/ImageCache/") + type + wxT("/min"), &t, double(GetRange<SrcComponentType>::min()));
00463 min = SrcComponentType(t);
00464 wxConfigBase::Get()->Read(wxT("/ImageCache/") + type + wxT("/max"), &t, double(GetRange<SrcComponentType>::max()));
00465 max = SrcComponentType(t);
00466 } else if (range == 1) {
00467 vigra::FindMinMax<SrcComponentType> minmax;
00468 vigra::inspectImage(srcImageRange(tmp),
00469 minmax);
00470 min = minmax.min;
00471 max = minmax.max;
00472 } else{
00473 vigra_fail("Unknown image import range mode");
00474 }
00475
00476 int mapping = wxConfigBase::Get()->Read(wxT("/ImageCache/Mapping"), HUGIN_IMGCACHE_MAPPING);
00477 applyMapping(srcImageRange(tmp), dest, min, max, mapping);
00478 }
00479
00480 #endif
00481
00482 template <class SrcPixelType,
00483 class DestIterator, class DestAccessor,
00484 class MaskIterator, class MaskAccessor>
00485 void ImageCache::importAndConvertAlphaImage(const vigra::ImageImportInfo & info,
00486 vigra::pair<DestIterator, DestAccessor> dest,
00487 vigra::pair<MaskIterator, MaskAccessor> mask,
00488 const std::string & type)
00489 {
00490 if (type == "FLOAT" || type == "DOUBLE" ) {
00491
00492 vigra::importImageAlpha(info, dest, mask);
00493 } else {
00494
00495 vigra::importImageAlpha(info, dest, mask);
00496 double scale = 1.0/vigra_ext::LUTTraits<SrcPixelType>::max();
00497 transformImage(dest.first, dest.first+ vigra::Diff2D(info.width(), info.height()), dest.second,
00498 dest.first, dest.second,
00499 Arg1()*Param(scale));
00500 }
00501 }
00502
00503 ImageCache::EntryPtr ImageCache::getImage(const std::string & filename)
00504 {
00505
00506 m_accessCounter++;
00507 std::map<std::string, EntryPtr>::iterator it;
00508 it = images.find(filename);
00509 if (it != images.end()) {
00510 it->second->lastAccess = m_accessCounter;
00511 return it->second;
00512 } else {
00513 if (m_progress) {
00514 m_progress->pushTask(AppBase::ProgressTask("Loading image: "+hugin_utils::stripPath(filename), "", 0));
00515 }
00516
00517 EntryPtr e = loadImageSafely(filename);
00518
00519 if (m_progress) {
00520 m_progress->popTask();
00521 }
00522
00523 if (!e.get())
00524 {
00525
00526 throw std::exception();
00527 }
00528
00529 images[filename] = e;
00530 e->lastAccess = m_accessCounter;
00531 return e;
00532 }
00533 }
00534
00535 ImageCache::EntryPtr ImageCache::loadImageSafely(const std::string & filename)
00536 {
00537
00538 std::string pixelTypeStr;
00539 ImageCacheRGB8Ptr img8(new vigra::BRGBImage);
00540 ImageCacheRGB16Ptr img16(new vigra::UInt16RGBImage);
00541 ImageCacheRGBFloatPtr imgFloat(new vigra::FRGBImage);
00542 ImageCache8Ptr mask(new vigra::BImage);
00543
00544 try {
00545 vigra::ImageImportInfo info(filename.c_str());
00546
00547 int bands = info.numBands();
00548 int extraBands = info.numExtraBands();
00549 const char * pixelType = info.getPixelType();
00550 pixelTypeStr = pixelType;
00551
00552 DEBUG_DEBUG(filename << ": bands: " << bands << " extra bands: " << extraBands << " type: " << pixelType);
00553
00554 if (pixelTypeStr == "UINT8") {
00555 img8->resize(info.size());
00556 } else if (pixelTypeStr == "UINT16" ) {
00557 img16->resize(info.size());
00558 } else {
00559 imgFloat->resize(info.size());
00560 }
00561
00562 if ( bands == 1) {
00563
00564 if (strcmp(pixelType, "UINT8") == 0 ) {
00565 vigra::importImage(info, destImage(*img8,
00566 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)));
00567 copyImage(srcImageRange(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)),
00568 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(1)));
00569 copyImage(srcImageRange(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)),
00570 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(2)));
00571 } else if (strcmp(pixelType, "UINT16") == 0 ) {
00572 vigra::importImage(info, destImage(*img16,
00573 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)));
00574 copyImage(srcImageRange(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)),
00575 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(1)));
00576 copyImage(srcImageRange(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)),
00577 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(2)));
00578 } else {
00579 if (strcmp(pixelType, "INT16") == 0 ) {
00580 importAndConvertImage<vigra::Int16> (info, destImage(*imgFloat,
00581 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
00582 } else if (strcmp(pixelType, "UINT32") == 0 ) {
00583 importAndConvertImage<vigra::UInt32>(info, destImage(*imgFloat,
00584 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
00585 } else if (strcmp(pixelType, "INT32") == 0 ) {
00586 importAndConvertImage<vigra::Int32>(info, destImage(*imgFloat,
00587 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
00588 } else if (strcmp(pixelType, "FLOAT") == 0 ) {
00589 importAndConvertImage<float>(info, destImage(*imgFloat,
00590 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
00591 } else if (strcmp(pixelType, "DOUBLE") == 0 ) {
00592 importAndConvertImage<double>(info, destImage(*imgFloat,
00593 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
00594 } else {
00595 DEBUG_ERROR("Unsupported pixel type: " << pixelType);
00596 return EntryPtr();
00597 }
00598 copyImage(srcImageRange(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
00599 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(1)));
00600 copyImage(srcImageRange(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
00601 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(2)));
00602 }
00603 } else if ( bands == 2 && extraBands==1) {
00604 mask->resize(info.size());
00605
00606 if (strcmp(pixelType, "UINT8") == 0 ) {
00607 vigra::importImageAlpha(info, destImage(*img8,
00608 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)),
00609 destImage(*mask));
00610 copyImage(srcImageRange(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)),
00611 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(1)));
00612 copyImage(srcImageRange(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)),
00613 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(2)));
00614 } else if (strcmp(pixelType, "UINT16") == 0 ) {
00615 vigra::importImageAlpha(info, destImage(*img16,
00616 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)),
00617 destImage(*mask));
00618 copyImage(srcImageRange(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)),
00619 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(1)));
00620 copyImage(srcImageRange(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)),
00621 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(2)));
00622 } else {
00623 if (strcmp(pixelType, "INT16") == 0 ) {
00624 importAndConvertAlphaImage<vigra::Int16> (info, destImage(*imgFloat,
00625 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), destImage(*mask), pixelType);
00626 } else if (strcmp(pixelType, "UINT32") == 0 ) {
00627 importAndConvertAlphaImage<vigra::UInt32>(info, destImage(*imgFloat,
00628 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), destImage(*mask), pixelType);
00629 } else if (strcmp(pixelType, "INT32") == 0 ) {
00630 importAndConvertAlphaImage<vigra::Int32>(info, destImage(*imgFloat,
00631 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), destImage(*mask), pixelType);
00632 } else if (strcmp(pixelType, "FLOAT") == 0 ) {
00633 importAndConvertAlphaImage<float>(info, destImage(*imgFloat,
00634 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), destImage(*mask), pixelType);
00635 } else if (strcmp(pixelType, "DOUBLE") == 0 ) {
00636 importAndConvertAlphaImage<double>(info, destImage(*imgFloat,
00637 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), destImage(*mask), pixelType);
00638 } else {
00639 DEBUG_ERROR("Unsupported pixel type: " << pixelType);
00640 return EntryPtr();
00641 }
00642 copyImage(srcImageRange(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
00643 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(1)));
00644 copyImage(srcImageRange(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
00645 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(2)));
00646 }
00647 } else if (bands == 3 && extraBands == 0) {
00648 DEBUG_DEBUG( pixelType);
00649
00650 if (strcmp(pixelType, "UINT8") == 0 ) {
00651 vigra::importImage(info, destImage(*img8));
00652 } else if (strcmp(pixelType, "UINT16") == 0 ) {
00653 vigra::importImage(info, destImage(*img16));
00654 } else if (strcmp(pixelType, "INT16") == 0 ) {
00655 importAndConvertImage<vigra::RGBValue<vigra::Int16> > (info, destImage(*imgFloat), pixelType);
00656 } else if (strcmp(pixelType, "UINT32") == 0 ) {
00657 importAndConvertImage<vigra::RGBValue<vigra::UInt32> >(info, destImage(*imgFloat), pixelType);
00658 } else if (strcmp(pixelType, "INT32") == 0 ) {
00659 importAndConvertImage<vigra::RGBValue<vigra::Int32> >(info, destImage(*imgFloat), pixelType);
00660 } else if (strcmp(pixelType, "FLOAT") == 0 ) {
00661 vigra::importImage(info, destImage(*imgFloat));
00662
00663 } else if (strcmp(pixelType, "DOUBLE") == 0 ) {
00664 vigra::importImage(info, destImage(*imgFloat));
00665
00666 } else {
00667 DEBUG_ERROR("Unsupported pixel type: " << pixelType);
00668 return EntryPtr();
00669 }
00670 } else if ( bands == 4 && extraBands == 1) {
00671 mask->resize(info.size());
00672
00673 if (strcmp(pixelType, "UINT8") == 0 ) {
00674 vigra::importImageAlpha(info, destImage(*img8), destImage(*mask));
00675 } else if (strcmp(pixelType, "UINT16") == 0 ) {
00676 vigra::importImageAlpha(info, destImage(*img16), destImage(*mask));
00677 } else if (strcmp(pixelType, "INT16") == 0 ) {
00678 importAndConvertAlphaImage<short> (info, destImage(*imgFloat), destImage(*mask), pixelType);
00679 } else if (strcmp(pixelType, "UINT32") == 0 ) {
00680 importAndConvertAlphaImage<unsigned int>(info, destImage(*imgFloat), destImage(*mask), pixelType);
00681 } else if (strcmp(pixelType, "INT32") == 0 ) {
00682 importAndConvertAlphaImage<int>(info, destImage(*imgFloat), destImage(*mask), pixelType);
00683 } else if (strcmp(pixelType, "FLOAT") == 0 ) {
00684 importAndConvertAlphaImage<float>(info, destImage(*imgFloat), destImage(*mask), pixelType);
00685 } else if (strcmp(pixelType, "DOUBLE") == 0 ) {
00686 importAndConvertAlphaImage<double>(info, destImage(*imgFloat), destImage(*mask), pixelType);
00687 } else {
00688 DEBUG_FATAL("Unsupported pixel type: " << pixelType);
00689 return EntryPtr();
00690 }
00691 } else {
00692 DEBUG_ERROR("unsupported depth, only images with 1 or 3 channel images are supported.");
00693 return EntryPtr();
00694 }
00695 } catch (std::exception & e) {
00696
00697 DEBUG_ERROR("Error during image reading: " << e.what());
00698 return EntryPtr();
00699 }
00700
00701 return EntryPtr(new Entry(img8, img16, imgFloat, mask, pixelTypeStr));
00702 }
00703
00704 ImageCache::EntryPtr ImageCache::getImageIfAvailable(const std::string & filename)
00705 {
00706 std::map<std::string, EntryPtr>::iterator it;
00707 it = images.find(filename);
00708 if (it != images.end()) {
00709 m_accessCounter++;
00710 it->second->lastAccess = m_accessCounter;
00711 return it->second;
00712 } else {
00713
00714 return EntryPtr();
00715 }
00716 }
00717
00718 ImageCache::EntryPtr ImageCache::getSmallImage(const std::string & filename)
00719 {
00720 m_accessCounter++;
00721 softFlush();
00722 std::map<std::string, EntryPtr>::iterator it;
00723
00724 string name = filename + string(":small");
00725 it = images.find(name);
00726 if (it != images.end()) {
00727 return it->second;
00728 } else {
00729 if (m_progress)
00730 {
00731 m_progress->pushTask(AppBase::ProgressTask("Scaling image: "+hugin_utils::stripPath(filename), "", 0));
00732 }
00733 DEBUG_DEBUG("creating small image " << name );
00734 EntryPtr entry = getImage(filename);
00735
00736 EntryPtr small_entry = loadSmallImageSafely(entry);
00737 small_entry->lastAccess = m_accessCounter;
00738 images[name] = small_entry;
00739 DEBUG_INFO ( "created small image: " << name);
00740 if (m_progress) {
00741 m_progress->popTask();
00742 }
00743 return small_entry;
00744 }
00745 }
00746
00747 ImageCache::EntryPtr ImageCache::loadSmallImageSafely(EntryPtr entry)
00748 {
00749
00750 size_t w=0;
00751 size_t h=0;
00752 if (entry->image8->width() > 0) {
00753 w = entry->image8->width();
00754 h = entry->image8->height();
00755 } else if (entry->image16->width() > 0) {
00756 w = entry->image16->width();
00757 h = entry->image16->height();
00758 } else if (entry->imageFloat->width() > 0) {
00759 w = entry->imageFloat->width();
00760 h = entry->imageFloat->height();
00761 } else {
00762 vigra_fail("Could not load image");
00763 }
00764
00765 size_t sz = w*h;
00766 size_t smallImageSize = 800 * 800l;
00767
00768 int nLevel=0;
00769 while(sz > smallImageSize) {
00770 sz /=4;
00771 nLevel++;
00772 }
00773 EntryPtr e(new Entry);
00774 e->origType = entry->origType;
00775
00776 vigra::BImage fullsizeMask = *(entry->mask);
00777 if (entry->imageFloat->width() != 0 ) {
00778 e->imageFloat = ImageCacheRGBFloatPtr(new vigra::FRGBImage);
00779 if (entry->mask->width() != 0) {
00780 vigra_ext::reduceNTimes(*(entry->imageFloat), fullsizeMask, *(e->imageFloat), *(e->mask), nLevel);
00781 } else {
00782 vigra_ext::reduceNTimes(*(entry->imageFloat), *(e->imageFloat), nLevel);
00783 }
00784 }
00785 if (entry->image16->width() != 0 ) {
00786 e->image16 = ImageCacheRGB16Ptr(new vigra::UInt16RGBImage);
00787 if (entry->mask->width() != 0) {
00788 vigra_ext::reduceNTimes(*(entry->image16), fullsizeMask, *(e->image16), *(e->mask), nLevel);
00789 } else {
00790 vigra_ext::reduceNTimes(*(entry->image16), *(e->image16), nLevel);
00791 }
00792 }
00793 if (entry->image8->width() != 0) {
00794 e->image8 = ImageCacheRGB8Ptr(new vigra::BRGBImage);
00795 if (entry->mask->width() != 0) {
00796 vigra_ext::reduceNTimes(*(entry->image8), fullsizeMask, *(e->image8), *(e->mask), nLevel);
00797 } else {
00798 vigra_ext::reduceNTimes(*(entry->image8), *(e->image8), nLevel);
00799 }
00800 }
00801 return e;
00802 }
00803
00804 ImageCache::EntryPtr ImageCache::getSmallImageIfAvailable(const std::string & filename)
00805 {
00806 m_accessCounter++;
00807 softFlush();
00808 std::map<std::string, EntryPtr>::iterator it;
00809
00810 string name = filename + string(":small");
00811 it = images.find(name);
00812 if (it != images.end()) {
00813 return it->second;
00814 } else {
00815
00816 return EntryPtr();
00817 }
00818 }
00819
00820 ImageCache::RequestPtr ImageCache::requestAsyncImage(const std::string & filename)
00821 {
00822
00823 std::map<std::string, RequestPtr>::iterator it = m_requests.find(filename);
00824 if (it != m_requests.end()) {
00825
00826 return it->second;
00827 } else {
00828 bool need_thread = m_requests.empty() && m_smallRequests.empty();
00829
00830 RequestPtr request = RequestPtr(new Request(filename, false));
00831 m_requests[filename] = request;
00832 if (need_thread) {
00833 spawnAsyncThread();
00834 }
00835 return request;
00836 }
00837 }
00838
00839 ImageCache::RequestPtr ImageCache::requestAsyncSmallImage(const std::string & filename)
00840 {
00841
00842 std::map<std::string, RequestPtr>::iterator it = m_smallRequests.find(filename);
00843 if (it != m_smallRequests.end()) {
00844
00845 return it->second;
00846 } else {
00847
00848 bool need_thread = m_requests.empty() && m_smallRequests.empty();
00849 RequestPtr request = RequestPtr(new Request(filename, true));
00850 m_smallRequests[filename] = request;
00851 if (need_thread) {
00852 spawnAsyncThread();
00853 }
00854 return request;
00855 }
00856 }
00857
00858 void ImageCache::postEvent(RequestPtr request, EntryPtr entry)
00859 {
00860
00861
00862 bool is_small_request = request->getIsSmall();
00863 const std::string & filename = request->getFilename();
00864
00865 if (is_small_request) {
00866 std::string name = filename+std::string(":small");
00867 images[name] = entry;
00868 } else {
00869 images[filename] = entry;
00870 }
00871 entry->lastAccess = m_accessCounter;
00872
00873
00874
00875
00876
00877
00878
00879 for (std::map<std::string, RequestPtr>::iterator it = m_smallRequests.begin();
00880 it != m_smallRequests.end();)
00881 {
00882 std::map<std::string, RequestPtr>::iterator next_it = it;
00883 next_it++;
00884 if (it->second.unique()) {
00885
00886
00887 m_smallRequests.erase(it);
00888
00889 } else if (getSmallImageIfAvailable(it->first).get()) {
00890
00891
00892 it->second->ready(getSmallImage(it->first), it->first, true);
00893 m_smallRequests.erase(it);
00894 }
00895 it = next_it;
00896 }
00897 for (std::map<std::string, RequestPtr>::iterator it = m_requests.begin();
00898 it != m_requests.end();)
00899 {
00900 std::map<std::string, RequestPtr>::iterator next_it = it;
00901 next_it++;
00902 if (it->second.unique()) {
00903
00904
00905
00906 m_requests.erase(it);
00907 } else if (getImageIfAvailable(it->first).get()) {
00908
00909
00910 it->second->ready(getImage(it->first), it->first, false);
00911 m_requests.erase(it);
00912 }
00913 it = next_it;
00914 }
00915
00916 if (!(m_requests.empty() && m_smallRequests.empty())) {
00917
00918 spawnAsyncThread();
00919 }
00920 }
00921
00922 void ImageCache::spawnAsyncThread()
00923 {
00924
00925
00926 std::map<std::string, RequestPtr>::iterator it = m_smallRequests.begin();
00927 if (it == m_smallRequests.end()) {
00928 it = m_requests.begin();
00929 if (it == m_requests.end())
00930 {
00931 DEBUG_DEBUG("Not staring a thread to load an image, since no images are wanted.");
00932 } else {
00933 boost::thread(loadSafely, it->second, EntryPtr());
00934 }
00935 } else {
00936
00937 const std::string & filename = it->second->getFilename();
00938 EntryPtr large = getImageIfAvailable(filename);
00939 if (large.get() == 0)
00940 {
00941
00942 RequestPtr request(new Request(filename, false));
00943 boost::thread(loadSafely, request, EntryPtr());
00944 } else {
00945
00946 boost::thread(loadSafely, it->second, large);
00947 }
00948 }
00949
00950
00951
00952
00953
00954 }
00955
00956 void ImageCache::loadSafely(ImageCache::RequestPtr request, EntryPtr large)
00957 {
00958
00959 EntryPtr new_entry;
00960 if (large.get())
00961 {
00962 new_entry = loadSmallImageSafely(large);
00963 } else {
00964 new_entry = loadImageSafely(request->getFilename());
00965 }
00966
00967
00968
00969 if (getInstance().asyncLoadCompleteSignal)
00970 {
00971 (*getInstance().asyncLoadCompleteSignal)(request, new_entry);
00972 } else {
00973 DEBUG_ERROR("Please set HuginBase::ImageCache::getInstance().asyncLoadCompleteSignal to handle asynchronous image loads.");
00974 }
00975 }
00976
00977 }