Stitcher.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00030 #include "Stitcher.h"
00031 
00032 #include <vigra/stdimage.hxx>
00033 
00034 namespace HuginBase {
00035 namespace Nona {
00036 
00037 using namespace std;
00038 using namespace vigra;
00039 using namespace vigra_ext;
00040 
00041 
00046 void estimateBlendingOrder(const PanoramaData & pano, UIntSet images, vector<unsigned int> & blendOrder)
00047 {
00048     unsigned int nImg = images.size();
00049     DEBUG_ASSERT(nImg > 0);
00050 
00051     typedef RemappedPanoImage<vigra::BRGBImage, vigra::BImage> RPImg;
00052 
00053     PanoramaOptions opts = pano.getOptions();
00054     // small area, for alpha mask overlap analysis.
00055     opts.setWidth(400);
00056     Size2D size(opts.getWidth(), opts.getHeight());
00057     Rect2D completeAlphaROI(size);
00058     // find intersecting regions, on a small version of the panorama.
00059     std::map<unsigned int, RemappedPanoImage<vigra::BRGBImage, vigra::BImage> * > rimg;
00060         std::map<unsigned int, RemappedPanoImage<vigra::BRGBImage, vigra::BImage> * >::iterator rimgIter;
00061 
00062     BImage alpha(size);
00063     Rect2D alphaROI;
00064 
00065     for (UIntSet::iterator it = images.begin(); it != images.end(); ++it)
00066     {
00067         // calculate alpha channel
00068         rimg[*it] = new RPImg;
00069         rimg[*it]->setPanoImage(pano.getSrcImage(*it), opts, vigra::Rect2D(size));
00070         rimg[*it]->calcAlpha();
00071 #ifdef DEBUG
00072 //      vigra::exportImage(rimg[*it].alpha(), vigra::ImageExportInfo("debug_alpha.tif"));
00073 #endif
00074     }
00075 
00076     int firstImg = *(images.begin());
00077     // copy first alpha channel
00078     alphaROI = rimg[firstImg]->boundingBox();
00079     // restrict to output pano size
00080     alphaROI = alphaROI & completeAlphaROI;
00081     DEBUG_DEBUG("alphaROI: " << alphaROI);
00082     DEBUG_DEBUG("alpha size: " << alpha.size());
00083     copyImage(applyRect(alphaROI, vigra_ext::srcMaskRange(*(rimg[firstImg]))),
00084 //    copyImage(vigra_ext::srcMaskRange(rimg[firstImg]),
00085               applyRect(alphaROI, destImage(alpha)));
00086 
00087     Rect2D overlap;
00088     // intersect ROI's & masks of all images
00089     while (images.size() > 0) {
00090         unsigned int maxSize = 0;
00091         unsigned int choosenImg = *(images.begin());
00092         // search for maximum overlap
00093         for (UIntSet::iterator it = images.begin(); it != images.end(); ++it) {
00094             // check for possible overlap
00095             DEBUG_DEBUG("examing overlap with image " << *it);
00096             // overlapping images..
00097             overlap = alphaROI & rimg[*it]->boundingBox();
00098             if (!overlap.isEmpty()) {
00099               DEBUG_DEBUG("ROI intersects: " << overlap.upperLeft()
00100                           << " to " << overlap.lowerRight());
00101                 // if the overlap ROI is smaller than the current maximum,
00102                 // ignore.
00103                 if (overlap.area() > (int) maxSize) {
00104                     OverlapSizeCounter counter;
00105                     inspectTwoImages(applyRect(overlap, srcMaskRange(*(rimg[*it]))),
00106                                      applyRect(overlap, srcImage(alpha)),
00107                                      counter);
00108                     DEBUG_DEBUG("overlap size in pixel: " << counter.getSize());
00109                     if (counter.getSize() > maxSize) {
00110                         choosenImg = *it;
00111                         maxSize = counter.getSize();
00112                     }
00113                 }
00114             }
00115         }
00116         // add to the blend list
00117         blendOrder.push_back(choosenImg);
00118         images.erase(choosenImg);
00119         // update alphaROI, to new roi.
00120         alphaROI = alphaROI | rimg[choosenImg]->boundingBox();
00121         alphaROI = alphaROI & completeAlphaROI;
00122     }
00123         // All images have been erased so just iterate through the map
00124     for (rimgIter = rimg.begin(); rimgIter != rimg.end(); rimgIter++) {
00125         delete rimgIter->second;
00126     }
00127 }
00128 
00129 
00137 void stitchPanorama(const PanoramaData & pano,
00138                         const PanoramaOptions & opt,
00139                         AppBase::MultiProgressDisplay & progress,
00140                         const std::string & basename,
00141                         const UIntSet & usedImgs)
00142 {
00143     DEBUG_ASSERT(pano.getNrOfImages() > 0);
00144 
00145     // probe the first image to determine a suitable image type for stitching
00146     unsigned int imgNr = *(usedImgs.begin());
00147     string fname =  pano.getImage(imgNr).getFilename().c_str();
00148     DEBUG_DEBUG("Probing image: " << fname);
00149     vigra::ImageImportInfo info(fname.c_str());
00150     std::string pixelType = info.getPixelType();
00151     int bands = info.numBands();
00152     int extraBands = info.numExtraBands();
00153 
00154     // check if all other relevant images have the same type
00155     for (UIntSet::const_iterator it = usedImgs.begin()++; it != usedImgs.end(); ++it) {
00156         vigra::ImageImportInfo info2(pano.getImage(*it).getFilename().c_str());
00157         if ( pixelType != info2.getPixelType() ) {
00158             UTILS_THROW(std::runtime_error, "image " <<
00159                     pano.getImage(*it).getFilename() << " uses " <<
00160                     info2.getPixelType() << " valued pixel, while " <<
00161                     pano.getImage(0).getFilename() << " uses: " << pixelType);
00162             return;
00163         }
00164 
00165         if (info2.numBands() - info2.numExtraBands() != bands - extraBands) {
00166             UTILS_THROW(std::runtime_error, "image " <<
00167                     pano.getImage(*it).getFilename() << " has " <<
00168                     info2.numBands() << " channels, while " <<
00169                     pano.getImage(0).getFilename() << " uses: " << bands);
00170             return;
00171         }
00172     }
00173 //    DEBUG_DEBUG("Output pixel type: " << pixelType);
00174     PanoramaOptions opts = opt;
00175     if (opts.outputMode == PanoramaOptions::OUTPUT_HDR) {
00176         if (opts.outputPixelType.size() == 0) {
00177             opts.outputPixelType = "FLOAT";
00178         }
00179     } else {
00180         // get the emor parameters.
00181         opts.outputEMoRParams = pano.getSrcImage(0).getEMoRParams();
00182         if (opts.outputPixelType.size() == 0) {
00183             opts.outputPixelType = pixelType;
00184         } else {
00185             // if output format is specified, use output format as stitching format
00186             // TODO: this will fail when going down in precision: UINT16 -> UINT8
00187             pixelType = opts.outputPixelType;
00188         }
00189     }
00190 
00191 #if 1
00192     if (opts.outputMode == PanoramaOptions::OUTPUT_HDR) {
00193         if (bands == 1 || bands == 2 && extraBands == 1) {
00194             stitchPanoIntern<FImage,BImage>(pano, opts, progress, basename, usedImgs);
00195         } else if (bands == 3 || bands == 4 && extraBands == 1) {
00196             stitchPanoIntern<FRGBImage,BImage>(pano, opts, progress, basename, usedImgs);
00197         } else {
00198             DEBUG_ERROR("unsupported depth, only images with 1 and 3 channel images are supported");
00199             throw std::runtime_error("unsupported depth, only images with 1 and 3 channel images are supported");
00200             return;
00201         }
00202     } else {
00203         // stitch the pano with a suitable image type
00204         if (bands == 1 || bands == 2 && extraBands == 1) {
00205             if (pixelType ==  "UINT8"||
00206                 pixelType == "INT16" ||
00207                 pixelType == "UINT16" )
00208             {
00209                 stitchPanoGray_8_16(pano, opts, progress, basename, usedImgs, pixelType.c_str());
00210             } else {
00211                 stitchPanoGray_32_float(pano, opts, progress, basename, usedImgs, pixelType.c_str());
00212             }
00213         } else if (bands == 3 || bands == 4 && extraBands == 1) {
00214             if (pixelType == "UINT8" ||
00215                 pixelType == "INT16" ||
00216                 pixelType == "UINT16" )
00217             {
00218                 stitchPanoRGB_8_16(pano, opts, progress, basename, usedImgs, pixelType.c_str());
00219             } else {
00220                 stitchPanoRGB_32_float(pano, opts, progress, basename, usedImgs, pixelType.c_str());
00221             }
00222         }
00223     }
00224 #else
00225     // always stitch with float images.
00226     if (bands == 1 || bands == 2 && extraBands == 1) {
00227         stitchPanoIntern<FImage,BImage>(pano, opts, progress, basename, usedImgs);
00228     } else if (bands == 3 || bands == 4 && extraBands == 1) {
00229         stitchPanoIntern<FRGBImage,BImage>(pano, opts, progress, basename, usedImgs);
00230     } else {
00231         DEBUG_ERROR("unsupported depth, only images with 1 and 3 channel images are supported");
00232         throw std::runtime_error("unsupported depth, only images with 1 and 3 channel images are supported");
00233         return;
00234     }
00235 #endif
00236 }
00237 
00238 
00239 } // namespace
00240 } // namespace
00241 

Generated on 26 Nov 2014 for Hugintrunk by  doxygen 1.4.7