ComputeImageROI.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00026 #include "ComputeImageROI.h"
00027 
00028 #include <algorithm>
00029 #include <vigra/impex.hxx>
00030 #include <nona/RemappedPanoImage.h>
00031 #include <nona/RemappedPanoImage.h>
00032 
00033 
00034 
00035 namespace HuginBase {
00036 
00037 using namespace hugin_utils;
00038 
00045 template <class TRANSFORM>
00046 void estimateImageRect(const SrcPanoImage & src,
00047                        const PanoramaOptions & dest,
00048                        TRANSFORM & transf,
00049                        vigra::Rect2D & imgRect);
00050     
00052 template <class TRANSFORM>
00053 void estimateImageAlpha(const SrcPanoImage & src,
00054                         const PanoramaOptions & dest,
00055                         TRANSFORM & transf,
00056                         vigra::Rect2D & imgRect,
00057                          vigra::BImage & alpha,
00058                          double & scale);
00059                          
00060         
00061     
00062 template <class TRANSFORM>
00063 void estimateImageAlpha(const SrcPanoImage & src,
00064                         const PanoramaOptions & dest,
00065                        TRANSFORM & transf,
00066                        vigra::Rect2D & imgRect,
00067                        vigra::BImage & alpha,
00068                        double & scale)
00069 {
00070     FDiff2D ul,lr;
00071     ul.x = DBL_MAX;
00072     ul.y = DBL_MAX;
00073     lr.x = -DBL_MAX;
00074     lr.y = -DBL_MAX;
00075 
00076     // remap into a miniature version of the pano and use
00077     // that to check for boundaries. This should be much more
00078     // robust than the old code that tried to trace the boundaries
00079     // of the images using the inverse transform, which could be fooled
00080     // easily by fisheye images.
00081 
00082     double maxLength = 180;
00083     scale = std::min(maxLength/dest.getSize().x, maxLength/dest.getSize().y);
00084 
00085     // take dest roi into account...
00086     vigra::Size2D destSz;
00087     destSz.x = hugin_utils::ceili(dest.getSize().x * scale);
00088     destSz.y = hugin_utils::ceili(dest.getSize().y * scale);
00089     vigra::Rect2D destRect;
00090     destRect.setUpperLeft(vigra::Point2D (hugin_utils::floori(dest.getROI().left() * scale),
00091                           hugin_utils::floori(dest.getROI().top() * scale)));
00092     destRect.setLowerRight(vigra::Point2D (hugin_utils::ceili(dest.getROI().right() * scale),
00093                    hugin_utils::ceili(dest.getROI().bottom() * scale)));
00094     destRect = destRect & vigra::Rect2D(destSz);
00095 
00096     DEBUG_DEBUG("scale " << scale);
00097     DEBUG_DEBUG("dest roi " << dest.getROI());
00098     DEBUG_DEBUG("dest Sz: " << destSz);
00099     DEBUG_DEBUG("dest rect: " << destRect);
00100 
00101     FDiff2D cropCenter;
00102     double radius2=0;
00103     if (src.getCropMode() == SrcPanoImage::CROP_CIRCLE) {
00104         cropCenter.x = src.getCropRect().left() + src.getCropRect().width()/2.0;
00105         cropCenter.y = src.getCropRect().top() + src.getCropRect().height()/2.0;
00106         radius2 = std::min(src.getCropRect().width()/2.0, src.getCropRect().height()/2.0);
00107         radius2 = radius2 * radius2;
00108     }
00109 
00110     // remap image
00111     vigra::BImage img(destSz.x, destSz.y, (unsigned char)0);
00112     for (int y=destRect.top(); y < destRect.bottom(); y++) {
00113         for (int x=destRect.left(); x < destRect.right(); x++) {
00114             // sample image
00115             // coordinates in real image pixels
00116             double sx,sy;
00117             transf.transformImgCoord(sx,sy, x/scale, y/scale);
00118             bool valid=true;
00119             if (src.getCropMode() == SrcPanoImage::CROP_CIRCLE) {
00120                 double dx = sx - cropCenter.x;
00121                 double dy = sy - cropCenter.y;
00122                 if (dx*dx + dy*dy > radius2) {
00123                         valid = false;
00124                 }
00125             } else if (!src.getCropRect().contains(vigra::Point2D(hugin_utils::roundi(sx), hugin_utils::roundi(sy))) ) {
00126                 valid = false;
00127             }
00128             if(valid && src.hasActiveMasks())
00129                 valid=!src.isInsideMasks(vigra::Point2D(hugin_utils::roundi(sx), hugin_utils::roundi(sy)));
00130 
00131             if (valid) {
00132                 img(x,y) = 255;
00133 /*                if ( ul.x > (x-1)/scale ) {
00134                     ul.x = (x-1)/scale;
00135                 }
00136                 if ( ul.y > (y-1)/scale ) {
00137                     ul.y = (y-1)/scale;
00138                 }
00139 
00140                 if ( lr.x < (x+1)/scale ) {
00141                     lr.x = (x+1)/scale;
00142                 }
00143                 if ( lr.y < (y+1)/scale ) {
00144                     lr.y = (y+1)/scale;
00145                 }
00146 */
00147             } else {
00148                 img(x,y) = 0;
00149             }
00150         }
00151     }
00152 
00153     alpha.resize(img.size());
00154 
00155         // dilate alpha image, to cover neighbouring pixels,
00156         // that may be valid in the full resolution image
00157     vigra::discDilation(vigra::srcImageRange(img),
00158                         vigra::destImage(alpha), 1);
00159     /*
00160 #ifdef DEBUG
00161     {
00162         vigra::ImageExportInfo exinfo( DEBUG_FILE_PREFIX "mask.png");
00163         vigra::exportImage(srcImageRange(img), exinfo);
00164     }
00165     {
00166         vigra::ImageExportInfo exinfo( DEBUG_FILE_PREFIX "mask_dilated.png");
00167         vigra::exportImage(srcImageRange(alpha), exinfo);
00168     }
00169 #endif
00170     */
00171     ul.x = destRect.right();
00172     ul.y = destRect.bottom();
00173     lr.x = destRect.left();
00174     lr.y = destRect.top();
00175 
00176     for (int y=destRect.top(); y < destRect.bottom(); y++) {
00177         for (int x=destRect.left(); x < destRect.right(); x++) {
00178             if (alpha(x,y)) {
00179                 if ( ul.x > x ) {
00180                     ul.x = x;
00181                 }
00182                 if ( ul.y > y ) {
00183                     ul.y = y;
00184                 }
00185 
00186                 if ( lr.x < x ) {
00187                     lr.x = x;
00188                 }
00189                 if ( lr.y < y ) {
00190                     lr.y = y;
00191                 }
00192             }
00193         }
00194     }
00195 
00196     // check if we have found some pixels..
00197     if ( ul.x == destRect.right() || ul.y == destRect.bottom() 
00198          || lr.x == destRect.left()|| lr.y == destRect.top() ) {
00199 
00200         // no valid pixel found. return empty ROI
00201         imgRect = vigra::Rect2D();
00202 
00203         initImage(img.upperLeft()+destRect.upperLeft(), 
00204                   img.upperLeft()+destRect.lowerRight(),
00205                   img.accessor(),0);
00206         /*
00207         // no valid pixel.. strange.. either there is no image here, or we have
00208         // overlooked some pixel.. to be on the safe side. remap the whole image here...
00209         imgRect = dest.getROI();
00210         alpha.resize(img.size().x, img.size().y, 0);
00211         initImage(img.upperLeft()+destRect.upperLeft(), 
00212                   img.upperLeft()+destRect.lowerRight(),
00213                   img.accessor(),255);
00214         */
00215     } else {
00216         // bounding rect after scan
00217         DEBUG_DEBUG("ul: " << ul << "  lr: " << lr);
00218         ul.x = (ul.x)/scale;
00219         ul.y = (ul.y)/scale;
00220         lr.x = (lr.x+1)/scale;
00221         lr.y = (lr.y+1)/scale;
00222         imgRect.setUpperLeft(vigra::Point2D(hugin_utils::roundi(ul.x), hugin_utils::roundi(ul.y)));
00223         imgRect.setLowerRight(vigra::Point2D(hugin_utils::roundi(lr.x), hugin_utils::roundi(lr.y)));
00224         // ensure that the roi is inside the destination rect
00225         imgRect = dest.getROI() & imgRect;
00226         DEBUG_DEBUG("bounding box: " << imgRect);
00227     }
00228 
00229 }
00230 
00237 template <class TRANSFORM>
00238 void estimateImageRect(const SrcPanoImage & src, const PanoramaOptions & dest,
00239                        TRANSFORM & transf, vigra::Rect2D & imgRect)
00240 {
00241     vigra::BImage img;
00242     double scale;
00243     estimateImageAlpha(src, dest, transf, imgRect, img, scale);
00244 }
00245 
00246     vigra::Rect2D estimateOutputROI(const PanoramaData & pano, const PanoramaOptions & opts, unsigned i)
00247     {
00248         vigra::Rect2D imageRect;
00249         SrcPanoImage srcImg = pano.getSrcImage(i);
00250         PTools::Transform transf;
00251         transf.createTransform(srcImg, opts);
00252         estimateImageRect(srcImg, opts, transf, imageRect);
00253         return imageRect;
00254     }
00255 
00256     std::vector<vigra::Rect2D> ComputeImageROI::computeROIS(const PanoramaData& panorama,
00257                                                             const PanoramaOptions & opts,
00258                                                             const UIntSet & images)
00259     {
00260         std::vector<vigra::Rect2D> res;
00261         for (UIntSet::const_iterator it = images.begin(); 
00262              it != images.end(); ++it)
00263         {
00264             res.push_back(estimateOutputROI(panorama, panorama.getOptions(), *it));
00265         }
00266         return res;
00267     }
00268 
00269 }

Generated on 23 Oct 2014 for Hugintrunk by  doxygen 1.4.7