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>
54 #define VIGRA_EXT_GETRANGE(T1, MI,MA) \
56 T1 GetRange<T1>::min() \
61 T1 GetRange<T1>::max() \
74 #undef VIGRA_EXT_GETRANGE
77 template <
class SrcIMG>
78 void convertTo8Bit(SrcIMG & src,
const std::string & origType, vigra::BRGBImage & dest)
83 dest.resize(src.size());
91 if (origType ==
"FLOAT" || origType ==
"DOUBLE")
93 vigra::RGBToGrayAccessor<vigra::RGBValue<float> > ga;
94 vigra::FindMinMax<float> minmax;
108 if (
image8->width() > 0) {
110 }
else if (
image16->width() > 0) {
127 std::map<std::string, EntryPtr>::iterator it =
images.find(filename);
132 std::string sfilename = filename + std::string(
":small");
133 it =
images.find(sfilename);
143 std::map<std::string, vigra::BImage*>::iterator it =
pyrImages.find(key.
toString());
155 std::ostringstream s;
156 s << filename << level;
164 for (std::map<std::string, vigra::BImage*>::iterator it =
pyrImages.begin();
179 const unsigned long long purgeToSize =
static_cast<unsigned long long>(0.75 *
upperBound);
182 unsigned long long imgMem = 0;
184 std::map<std::string, EntryPtr>::iterator imgIt;
185 for(imgIt=
images.begin(); imgIt !=
images.end(); ++imgIt) {
187 std::cout <<
"Image: " << imgIt->first << std::endl;
188 std::cout <<
"CacheEntry: " << imgIt->second.use_count() <<
"last access: " << imgIt->second->lastAccess;
190 if (imgIt->second->image8) {
191 imgMem += imgIt->second->image8->width() * imgIt->second->image8->height() * 3;
193 std::cout <<
" 8bit: " << imgIt->second->image8.use_count();
196 if (imgIt->second->image16) {
197 imgMem += imgIt->second->image16->width() * imgIt->second->image16->height() * 3*2;
199 std::cout <<
" 16bit: " << imgIt->second->image8.use_count();
202 if (imgIt->second->imageFloat) {
203 imgMem += imgIt->second->imageFloat->width() * imgIt->second->imageFloat->height() * 3 * 4;
205 std::cout <<
" float: " << imgIt->second->imageFloat.use_count() ;
208 if (imgIt->second->mask) {
209 imgMem += imgIt->second->mask->width() * imgIt->second->mask->height();
211 std::cout <<
" mask: " << imgIt->second->mask.use_count() << std::endl;
216 unsigned long long pyrMem = 0;
217 std::map<std::string, vigra::BImage*>::iterator pyrIt;
219 pyrMem += pyrIt->second->width() * pyrIt->second->height();
222 const unsigned long long usedMem = imgMem + pyrMem;
224 DEBUG_DEBUG(
"total: " << (usedMem>>20) <<
" MB upper bound: " << (purgeToSize>>20) <<
" MB");
228 const unsigned long long purgeAmount = usedMem - purgeToSize;
229 unsigned long long purgedMem = 0;
235 std::map<int,std::string> accessMap;
236 for (std::map<std::string, EntryPtr>::iterator it =
images.begin();
240 if (it->first.substr(it->first.size()-6) !=
":small") {
242 if (it->second.unique()) {
243 DEBUG_DEBUG(
"Considering " << it->first <<
" for deletion");
244 accessMap.insert(make_pair(it->second->lastAccess, it->first));
246 DEBUG_DEBUG(it->first <<
", usecount: " << it->second.use_count());
250 while (purgeAmount > purgedMem) {
251 bool deleted =
false;
253 vigra::BImage * imgPtr = (*(
pyrImages.begin())).second;
254 purgedMem += imgPtr->width() * imgPtr->height();
258 }
else if (!accessMap.empty()) {
259 std::map<int,std::string>::iterator accIt = accessMap.begin();
260 std::map<std::string, EntryPtr>::iterator it =
images.find(accIt->second);
263 DEBUG_DEBUG(
"soft flush: removing image: " << it->first);
264 if (it->second->image8) {
265 purgedMem += it->second->image8->width() * it->second->image8->height() * 3;
267 if (it->second->image16) {
268 purgedMem += it->second->image16->width() * it->second->image16->height() * 3 * 2;
270 if (it->second->imageFloat) {
271 purgedMem += it->second->imageFloat->width() * it->second->imageFloat->height()*3*4;
273 if (it->second->mask) {
274 purgedMem += it->second->mask->width() * it->second->mask->height();
277 accessMap.erase(accIt);
287 DEBUG_DEBUG(
"purged: " << (purgedMem>>20) <<
" MB, memory used for images: " << ((usedMem - purgedMem)>>20) <<
" MB");
379 template <
class SrcPixelType,
380 class DestIterator,
class DestAccessor>
382 vigra::pair<DestIterator, DestAccessor> dest,
383 const std::string & type)
385 if (type ==
"FLOAT" || type ==
"DOUBLE" ) {
387 vigra::importImage(info, dest);
389 vigra::importImage(info, dest);
392 vigra::transformImage(dest.first, dest.first + vigra::Diff2D(info.width(), info.height()), dest.second,
393 dest.first, dest.second,
394 vigra::functor::Arg1()*vigra::functor::Param(scale));
398 template <
class SrcPixelType,
399 class DestIterator,
class DestAccessor,
400 class MaskIterator,
class MaskAccessor>
402 vigra::pair<DestIterator, DestAccessor> dest,
403 vigra::pair<MaskIterator, MaskAccessor> mask,
404 const std::string & type)
406 if (type ==
"FLOAT" || type ==
"DOUBLE" ) {
413 vigra::transformImage(dest.first, dest.first + vigra::Diff2D(info.width(), info.height()), dest.second,
414 dest.first, dest.second,
415 vigra::functor::Arg1()*vigra::functor::Param(scale));
423 std::map<std::string, EntryPtr>::iterator it;
424 it =
images.find(filename);
442 throw std::exception();
454 std::string pixelTypeStr;
462 vigra::ImageImportInfo
info(filename.c_str());
464 if (!
info.getICCProfile().empty())
466 *iccProfile =
info.getICCProfile();
468 int bands =
info.numBands();
469 int extraBands =
info.numExtraBands();
470 const char * pixelType =
info.getPixelType();
471 pixelTypeStr = pixelType;
473 DEBUG_DEBUG(filename <<
": bands: " << bands <<
" extra bands: " << extraBands <<
" type: " << pixelType);
475 if (pixelTypeStr ==
"UINT8") {
476 img8->resize(
info.size());
477 }
else if (pixelTypeStr ==
"UINT16" ) {
478 img16->resize(
info.size());
480 imgFloat->resize(
info.size());
485 if (strcmp(pixelType,
"UINT8") == 0 ) {
487 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)));
489 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(1)));
491 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(2)));
492 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
494 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)));
496 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(1)));
498 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(2)));
500 if (strcmp(pixelType,
"INT16") == 0 ) {
501 importAndConvertImage<vigra::Int16> (
info,
destImage(*imgFloat,
502 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
503 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
504 importAndConvertImage<vigra::UInt32>(
info,
destImage(*imgFloat,
505 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
506 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
507 importAndConvertImage<vigra::Int32>(
info,
destImage(*imgFloat,
508 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
509 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
511 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
512 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
514 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)), pixelType);
516 DEBUG_ERROR(
"Unsupported pixel type: " << pixelType);
520 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(1)));
522 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(2)));
524 }
else if ( bands == 2 && extraBands==1) {
525 mask->resize(
info.size());
527 if (strcmp(pixelType,
"UINT8") == 0 ) {
529 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(0)),
532 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(1)));
534 destImage(*img8, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt8> >(2)));
535 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
537 vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(0)),
540 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(1)));
542 destImage(*img16, vigra::VectorComponentAccessor<vigra::RGBValue<vigra::UInt16> >(2)));
544 if (strcmp(pixelType,
"INT16") == 0 ) {
545 importAndConvertAlphaImage<vigra::Int16> (
info,
destImage(*imgFloat,
546 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
547 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
548 importAndConvertAlphaImage<vigra::UInt32>(
info,
destImage(*imgFloat,
549 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
550 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
551 importAndConvertAlphaImage<vigra::Int32>(
info,
destImage(*imgFloat,
552 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
553 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
555 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
556 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
557 importAndConvertAlphaImage<double>(
info,
destImage(*imgFloat,
558 vigra::VectorComponentAccessor<vigra::RGBValue<float> >(0)),
destImage(*mask), pixelType);
560 DEBUG_ERROR(
"Unsupported pixel type: " << pixelType);
564 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(1)));
566 destImage(*imgFloat, vigra::VectorComponentAccessor<vigra::RGBValue<float> >(2)));
568 }
else if (bands == 3 && extraBands == 0) {
571 if (strcmp(pixelType,
"UINT8") == 0 ) {
573 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
575 }
else if (strcmp(pixelType,
"INT16") == 0 ) {
576 importAndConvertImage<vigra::RGBValue<vigra::Int16> > (
info,
destImage(*imgFloat), pixelType);
577 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
578 importAndConvertImage<vigra::RGBValue<vigra::UInt32> >(
info,
destImage(*imgFloat), pixelType);
579 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
580 importAndConvertImage<vigra::RGBValue<vigra::Int32> >(
info,
destImage(*imgFloat), pixelType);
581 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
584 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
588 DEBUG_ERROR(
"Unsupported pixel type: " << pixelType);
591 }
else if ( bands == 4 && extraBands == 1) {
592 mask->resize(
info.size());
594 if (strcmp(pixelType,
"UINT8") == 0 ) {
596 }
else if (strcmp(pixelType,
"UINT16") == 0 ) {
598 }
else if (strcmp(pixelType,
"INT16") == 0 ) {
600 }
else if (strcmp(pixelType,
"UINT32") == 0 ) {
602 }
else if (strcmp(pixelType,
"INT32") == 0 ) {
604 }
else if (strcmp(pixelType,
"FLOAT") == 0 ) {
606 }
else if (strcmp(pixelType,
"DOUBLE") == 0 ) {
609 DEBUG_FATAL(
"Unsupported pixel type: " << pixelType);
613 DEBUG_ERROR(
"unsupported depth, only images with 1 or 3 channel images are supported.");
616 }
catch (std::exception & e) {
618 DEBUG_ERROR(
"Error during image reading: " << e.what());
622 return EntryPtr(
new Entry(img8, img16, imgFloat, mask, iccProfile, pixelTypeStr));
627 std::map<std::string, EntryPtr>::iterator it;
628 it =
images.find(filename);
643 std::map<std::string, EntryPtr>::iterator it;
645 std::string name = filename + std::string(
":small");
659 images[name] = small_entry;
660 DEBUG_INFO (
"created small image: " << name);
673 if (entry->image8->width() > 0) {
674 w = entry->image8->width();
675 h = entry->image8->height();
676 }
else if (entry->image16->width() > 0) {
677 w = entry->image16->width();
678 h = entry->image16->height();
679 }
else if (entry->imageFloat->width() > 0) {
680 w = entry->imageFloat->width();
681 h = entry->imageFloat->height();
683 vigra_fail(
"Could not load image");
687 size_t smallImageSize = 800 * 800l;
690 while(sz > smallImageSize) {
695 e->origType = entry->origType;
697 if (!entry->iccProfile->empty())
699 *(e->iccProfile) = *(entry->iccProfile);
702 vigra::BImage fullsizeMask = *(entry->mask);
703 if (entry->imageFloat->width() != 0 ) {
705 if (entry->mask->width() != 0) {
711 if (entry->image16->width() != 0 ) {
713 if (entry->mask->width() != 0) {
719 if (entry->image8->width() != 0) {
721 if (entry->mask->width() != 0) {
734 std::map<std::string, EntryPtr>::iterator it;
736 std::string name = filename + std::string(
":small");
749 std::map<std::string, RequestPtr>::iterator it =
m_requests.find(filename);
768 std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.find(filename);
788 bool is_small_request = request->getIsSmall();
789 const std::string & filename = request->getFilename();
791 if (is_small_request) {
792 std::string name = filename+std::string(
":small");
805 for (std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.begin();
808 std::map<std::string, RequestPtr>::iterator next_it = it;
810 if (it->second.unique()) {
818 while (!it->second->ready.empty())
820 it->second->ready.front()(
getSmallImage(it->first), it->first,
true);
821 it->second->ready.erase(it->second->ready.begin());
827 for (std::map<std::string, RequestPtr>::iterator it =
m_requests.begin();
830 std::map<std::string, RequestPtr>::iterator next_it = it;
832 if (it->second.unique()) {
840 while (!it->second->ready.empty())
842 it->second->ready.front()(
getImage(it->first), it->first,
false);
843 it->second->ready.erase(it->second->ready.begin());
865 for (std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.begin();
868 std::map<std::string, RequestPtr>::iterator next_it = it;
870 if (it->second.unique())
879 while (!it->second->ready.empty())
881 it->second->ready.erase(it->second->ready.begin());
887 for (std::map<std::string, RequestPtr>::iterator it =
m_requests.begin();
890 std::map<std::string, RequestPtr>::iterator next_it = it;
892 if (it->second.unique())
902 while (!it->second->ready.empty())
904 it->second->ready.erase(it->second->ready.begin());
922 std::map<std::string, RequestPtr>::iterator it =
m_smallRequests.begin();
927 DEBUG_DEBUG(
"Not staring a thread to load an image, since no images are wanted.");
934 const std::string & filename = it->second->getFilename();
936 if (large.get() == 0)
944 std::thread thread(
loadSafely, it->second, large);
972 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
VIGRA_EXT_GETRANGE(vigra::UInt8, 0, 255)
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
ImageCacheRGB8Ptr get8BitImage()
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
void convertTo8Bit(SrcIMG &src, const std::string &origType, vigra::BRGBImage &dest)
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)
static void loadSafely(RequestPtr request, EntryPtr large=EntryPtr())
Load a requested image in a way that will work in parallel.