30 #include "hugin_config.h"
32 #include <vigra/inspectimage.hxx>
33 #include <vigra/accessor.hxx>
34 #include <vigra/functorexpression.hxx>
35 #include <vigra/sized_int.hxx>
43 template <
class SrcIMG>
44 void convertTo8Bit(SrcIMG& src,
const std::string& origType, vigra::BRGBImage& dest,
int desiredMapping = -1)
49 dest.resize(src.size());
57 if (origType ==
"FLOAT" || origType ==
"DOUBLE" || origType ==
"INT16" || origType ==
"UINT32" || origType ==
"INT32")
59 vigra::RGBToGrayAccessor<vigra::RGBValue<float> > ga;
60 vigra::FindAverageAndVariance<float> mean;
62 min =
std::max(mean.average() - 3 * sqrt(mean.variance()), 1e-6f);
63 max = mean.average() + 3 * sqrt(mean.variance());
75 }
else if (
image16->width() > 0) {
93 std::map<std::string, EntryPtr>::iterator it =
images.find(filename);
98 std::string sfilename = filename + std::string(
":small");
99 it =
images.find(sfilename);
109 std::map<std::string, vigra::BImage*>::iterator it =
pyrImages.find(key.
toString());
121 std::ostringstream s;
122 s << filename << level;
130 for (std::map<std::string, vigra::BImage*>::iterator it =
pyrImages.begin();
145 const unsigned long long purgeToSize =
static_cast<unsigned long long>(0.75 *
upperBound);
148 unsigned long long imgMem = 0;
150 std::map<std::string, EntryPtr>::iterator imgIt;
151 for(imgIt=
images.begin(); imgIt !=
images.end(); ++imgIt) {
153 std::cout <<
"Image: " << imgIt->first << std::endl;
154 std::cout <<
"CacheEntry: " << imgIt->second.use_count() <<
"last access: " << imgIt->second->lastAccess;
156 if (imgIt->second->image8) {
157 imgMem += imgIt->second->image8->width() * imgIt->second->image8->height() * 3;
159 std::cout <<
" 8bit: " << imgIt->second->image8.use_count();
162 if (imgIt->second->image16) {
163 imgMem += imgIt->second->image16->width() * imgIt->second->image16->height() * 3*2;
165 std::cout <<
" 16bit: " << imgIt->second->image8.use_count();
168 if (imgIt->second->imageFloat) {
169 imgMem += imgIt->second->imageFloat->width() * imgIt->second->imageFloat->height() * 3 * 4;
171 std::cout <<
" float: " << imgIt->second->imageFloat.use_count() ;
174 if (imgIt->second->mask) {
175 imgMem += imgIt->second->mask->width() * imgIt->second->mask->height();
177 std::cout <<
" mask: " << imgIt->second->mask.use_count() << std::endl;
182 unsigned long long pyrMem = 0;
183 std::map<std::string, vigra::BImage*>::iterator pyrIt;
185 pyrMem += pyrIt->second->width() * pyrIt->second->height();
188 const unsigned long long usedMem = imgMem + pyrMem;
190 DEBUG_DEBUG(
"total: " << (usedMem>>20) <<
" MB upper bound: " << (purgeToSize>>20) <<
" MB");
194 const unsigned long long purgeAmount = usedMem - purgeToSize;
195 unsigned long long purgedMem = 0;
201 std::map<int,std::string> accessMap;
202 for (std::map<std::string, EntryPtr>::iterator it =
images.begin();
206 if (it->first.substr(it->first.size()-6) !=
":small") {
208 if (it->second.unique()) {
209 DEBUG_DEBUG(
"Considering " << it->first <<
" for deletion");
210 accessMap.insert(make_pair(it->second->lastAccess, it->first));
212 DEBUG_DEBUG(it->first <<
", usecount: " << it->second.use_count());
216 while (purgeAmount > purgedMem) {
217 bool deleted =
false;
219 vigra::BImage * imgPtr = (*(
pyrImages.begin())).second;
220 purgedMem += imgPtr->width() * imgPtr->height();
224 }
else if (!accessMap.empty()) {
225 std::map<int,std::string>::iterator accIt = accessMap.begin();
226 std::map<std::string, EntryPtr>::iterator it =
images.find(accIt->second);
229 DEBUG_DEBUG(
"soft flush: removing image: " << it->first);
230 if (it->second->image8) {
231 purgedMem += it->second->image8->width() * it->second->image8->height() * 3;
233 if (it->second->image16) {
234 purgedMem += it->second->image16->width() * it->second->image16->height() * 3 * 2;
236 if (it->second->imageFloat) {
237 purgedMem += it->second->imageFloat->width() * it->second->imageFloat->height()*3*4;
239 if (it->second->mask) {
240 purgedMem += it->second->mask->width() * it->second->mask->height();
243 accessMap.erase(accIt);
253 DEBUG_DEBUG(
"purged: " << (purgedMem>>20) <<
" MB, memory used for images: " << ((usedMem - purgedMem)>>20) <<
" MB");
267 template <
class SrcPixelType,
268 class DestIterator,
class DestAccessor>
270 vigra::pair<DestIterator, DestAccessor> dest,
271 const std::string & type)
273 if (type ==
"FLOAT" || type ==
"DOUBLE" ) {
275 vigra::importImage(info, dest);
277 vigra::importImage(info, dest);
280 vigra::transformImage(dest.first, dest.first + vigra::Diff2D(info.width(), info.height()), dest.second,
281 dest.first, dest.second,
282 vigra::functor::Arg1()*vigra::functor::Param(scale));
286 template <
class SrcPixelType,
287 class DestIterator,
class DestAccessor,
288 class MaskIterator,
class MaskAccessor>
290 vigra::pair<DestIterator, DestAccessor> dest,
291 vigra::pair<MaskIterator, MaskAccessor> mask,
292 const std::string & type)
294 if (type ==
"FLOAT" || type ==
"DOUBLE" ) {
301 vigra::transformImage(dest.first, dest.first + vigra::Diff2D(info.width(), info.height()), dest.second,
302 dest.first, dest.second,
303 vigra::functor::Arg1()*vigra::functor::Param(scale));
311 std::map<std::string, EntryPtr>::iterator it;
312 it =
images.find(filename);
330 throw std::exception();
342 std::string pixelTypeStr;
350 vigra::ImageImportInfo
info(filename.c_str());
352 if (!
info.getICCProfile().empty())
354 *iccProfile =
info.getICCProfile();
356 int bands =
info.numBands();
357 int extraBands =
info.numExtraBands();
358 const char * pixelType =
info.getPixelType();
359 pixelTypeStr = pixelType;
361 DEBUG_DEBUG(filename <<
": bands: " << bands <<
" extra bands: " << extraBands <<
" type: " << pixelType);
363 if (pixelTypeStr ==
"UINT8") {
364 img8->resize(
info.size());
365 }
else if (pixelTypeStr ==
"UINT16" ) {
366 img16->resize(
info.size());
368 imgFloat->resize(
info.size());
373 if (strcmp(pixelType,
"UINT8") == 0 ) {
375 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)));
377 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(1)));
379 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(2)));
380 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
382 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)));
384 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(1)));
386 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(2)));
388 if (strcmp(pixelType,
"INT16") == 0 ) {
389 importAndConvertImage<vigra::Int16> (
info,
destImage(*imgFloat,
390 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
391 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
392 importAndConvertImage<vigra::UInt32>(
info,
destImage(*imgFloat,
393 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
394 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
395 importAndConvertImage<vigra::Int32>(
info,
destImage(*imgFloat,
396 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
397 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
399 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
400 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
402 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
404 DEBUG_ERROR(
"Unsupported pixel type: " << pixelType);
408 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(1)));
410 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(2)));
412 }
else if ( bands == 2 && extraBands==1) {
413 mask->resize(
info.size());
415 if (strcmp(pixelType,
"UINT8") == 0 ) {
417 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)),
420 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(1)));
422 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(2)));
423 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
425 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)),
428 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(1)));
430 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(2)));
432 if (strcmp(pixelType,
"INT16") == 0 ) {
433 importAndConvertAlphaImage<vigra::Int16> (
info,
destImage(*imgFloat,
434 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
435 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
436 importAndConvertAlphaImage<vigra::UInt32>(
info,
destImage(*imgFloat,
437 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
438 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
439 importAndConvertAlphaImage<vigra::Int32>(
info,
destImage(*imgFloat,
440 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
441 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
443 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
444 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
445 importAndConvertAlphaImage<double>(
info,
destImage(*imgFloat,
446 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
448 DEBUG_ERROR(
"Unsupported pixel type: " << pixelType);
452 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(1)));
454 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(2)));
456 }
else if (bands == 3 && extraBands == 0) {
459 if (strcmp(pixelType,
"UINT8") == 0 ) {
461 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
463 }
else if (strcmp(pixelType,
"INT16") == 0 ) {
464 importAndConvertImage<vigra::RGBValue<vigra::Int16> > (
info,
destImage(*imgFloat), pixelType);
465 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
466 importAndConvertImage<vigra::RGBValue<vigra::UInt32> >(
info,
destImage(*imgFloat), pixelType);
467 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
468 importAndConvertImage<vigra::RGBValue<vigra::Int32> >(
info,
destImage(*imgFloat), pixelType);
469 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
472 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
476 DEBUG_ERROR(
"Unsupported pixel type: " << pixelType);
479 }
else if ( bands == 4 && extraBands == 1) {
480 mask->resize(
info.size());
482 if (strcmp(pixelType,
"UINT8") == 0 ) {
484 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
486 }
else if (strcmp(pixelType,
"INT16") == 0 ) {
488 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
490 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
492 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
494 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
497 DEBUG_FATAL(
"Unsupported pixel type: " << pixelType);
501 DEBUG_ERROR(
"unsupported depth, only images with 1 or 3 channel images are supported.");
504 }
catch (std::exception & e) {
506 DEBUG_ERROR(
"Error during image reading: " << e.what());
510 return EntryPtr(
new Entry(img8, img16, imgFloat, mask, iccProfile, pixelTypeStr));
515 std::map<std::string, EntryPtr>::iterator it;
516 it =
images.find(filename);
531 std::map<std::string, EntryPtr>::iterator it;
533 std::string name = filename + std::string(
":small");
547 images[name] = small_entry;
548 DEBUG_INFO (
"created small image: " << name);
561 if (entry->image8->width() > 0) {
562 w = entry->image8->width();
563 h = entry->image8->height();
564 }
else if (entry->image16->width() > 0) {
565 w = entry->image16->width();
566 h = entry->image16->height();
567 }
else if (entry->imageFloat->width() > 0) {
568 w = entry->imageFloat->width();
569 h = entry->imageFloat->height();
571 vigra_fail(
"Could not load image");
575 size_t smallImageSize = 800 * 800l;
578 while(sz > smallImageSize) {
583 e->origType = entry->origType;
585 if (!entry->iccProfile->empty())
587 *(e->iccProfile) = *(entry->iccProfile);
590 vigra::BImage fullsizeMask = *(entry->mask);
591 if (entry->imageFloat->width() != 0 ) {
593 if (entry->mask->width() != 0) {
599 if (entry->image16->width() != 0 ) {
601 if (entry->mask->width() != 0) {
607 if (entry->image8->width() != 0) {
609 if (entry->mask->width() != 0) {
622 std::map<std::string, EntryPtr>::iterator it;
624 std::string name = filename + std::string(
":small");
637 std::map<std::string, RequestPtr>::iterator it =
m_requests.find(filename);
656 std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.find(filename);
676 bool is_small_request = request->getIsSmall();
677 const std::string & filename = request->getFilename();
679 if (is_small_request) {
680 std::string name = filename+std::string(
":small");
693 for (std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.begin();
696 std::map<std::string, RequestPtr>::iterator next_it = it;
698 if (it->second.unique()) {
706 while (!it->second->ready.empty())
708 it->second->ready.front()(
getSmallImage(it->first), it->first,
true);
709 it->second->ready.erase(it->second->ready.begin());
715 for (std::map<std::string, RequestPtr>::iterator it =
m_requests.begin();
718 std::map<std::string, RequestPtr>::iterator next_it = it;
720 if (it->second.unique()) {
728 while (!it->second->ready.empty())
730 it->second->ready.front()(
getImage(it->first), it->first,
false);
731 it->second->ready.erase(it->second->ready.begin());
753 for (std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.begin();
756 std::map<std::string, RequestPtr>::iterator next_it = it;
758 if (it->second.unique())
767 while (!it->second->ready.empty())
769 it->second->ready.erase(it->second->ready.begin());
775 for (std::map<std::string, RequestPtr>::iterator it =
m_requests.begin();
778 std::map<std::string, RequestPtr>::iterator next_it = it;
780 if (it->second.unique())
790 while (!it->second->ready.empty())
792 it->second->ready.erase(it->second->ready.begin());
810 std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.begin();
815 DEBUG_DEBUG(
"Not staring a thread to load an image, since no images are wanted.");
822 const std::string & filename = it->second->getFilename();
824 if (large.get() == 0)
832 std::thread thread(
loadSafely, it->second, large);
860 DEBUG_ERROR(
"Please set HuginBase::ImageCache::getInstance().asyncLoadCompleteSignal to handle asynchronous image loads.");
RequestPtr requestAsyncImage(const std::string &filename)
Request an image be loaded.
void flush()
release all images in the cache.
double getMaxValForPixelType(const std::string &v)
static EntryPtr loadSmallImageSafely(EntryPtr entry)
Load a small image, in a way that will work in parallel.
AppBase::ProgressDisplay * m_progress
void transformImage(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform an image into the panorama.
Request for an image to load Connect to the ready signal so when the image loads you can respond...
std::shared_ptr< vigra::FRGBImage > ImageCacheRGBFloatPtr
void(* asyncLoadCompleteSignal)(RequestPtr, EntryPtr)
Signal for when a asynchronous load completes.
unsigned long long upperBound
std::shared_ptr< vigra::ImageImportInfo::ICCProfile > ImageCacheICCProfile
static void importAndConvertImage(const vigra::ImageImportInfo &info, vigra::pair< DestIterator, DestAccessor > dest, const std::string &type)
This is a cache for all the images we use.
#define DEBUG_ASSERT(cond)
std::map< std::string, RequestPtr > m_smallRequests
static ImageCache & getInstance()
get the global ImageCache object
void applyMapping(vigra::triple< SrcIterator, SrcIterator, SrcAccessor > img, vigra::pair< DestIterator, DestAccessor > dest, T min, T max, int mapping)
EntryPtr getSmallImageIfAvailable(const std::string &filename)
Get a small image if already loaded.
functions to manage ROI's
information about an image inside the cache
std::shared_ptr< vigra::BImage > ImageCache8Ptr
RequestPtr requestAsyncSmallImage(const std::string &filename)
Request a small image be loaded.
void taskFinished()
call when a task has finished and the status message should be cleared
static EntryPtr loadImageSafely(const std::string &filename)
Load a full size image, in a way that will work in parallel.
std::shared_ptr< Entry > EntryPtr
a shared pointer to the entry
void postEvent(RequestPtr request, EntryPtr entry)
Pass on a loaded event for any images loaded asynchronously.
std::shared_ptr< vigra::BRGBImage > ImageCacheRGB8Ptr
use reference counted pointers
EntryPtr getImageIfAvailable(const std::string &filename)
Get an image if already loaded.
ImageCacheRGB16Ptr image16
std::map< std::string, RequestPtr > m_requests
std::shared_ptr< Request > RequestPtr
Reference counted request for an image to load.
#define HUGIN_IMGCACHE_MAPPING_INTEGER
void setMessage(const std::string &message, const std::string &filename="")
sets the message to given string
EntryPtr getSmallImage(const std::string &filename)
get an small image.
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
static ImageCache * instance
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
ImageCacheRGBFloatPtr imageFloat
std::map< std::string, EntryPtr > images
void softFlush()
a soft version of flush.
void importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor)
Read the image specified by the given vigra::ImageImportInfo object including its alpha channel...
EntryPtr getImage(const std::string &filename)
get a image.
void removeRequest(RequestPtr request)
Removes the given RequestPtr from queue, Call from main GUI thread when an image could not loaded...
std::map< std::string, vigra::BImage * > pyrImages
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
static void info(const char *fmt,...)
#define HUGIN_IMGCACHE_MAPPING_FLOAT
void removeImage(const std::string &filename)
remove a specific image (and dependant images) from the cache
void reduceNTimes(ImageIn &in, Image &out, int n)
std::shared_ptr< vigra::UInt16RGBImage > ImageCacheRGB16Ptr
static void importAndConvertAlphaImage(const vigra::ImageImportInfo &info, vigra::pair< DestIterator, DestAccessor > dest, vigra::pair< MaskIterator, MaskAccessor > mask, const std::string &type)
void spawnAsyncThread()
Start a background thread to load an image.
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
void convertTo8Bit(SrcIMG &src, const std::string &origType, vigra::BRGBImage &dest, int desiredMapping=-1)
ImageCacheRGB8Ptr get8BitImage(int desiredMapping=-1)
static void loadSafely(RequestPtr request, EntryPtr large=EntryPtr())
Load a requested image in a way that will work in parallel.