ComputeImageROI.cpp

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

Generated on 31 Aug 2015 for Hugintrunk by  doxygen 1.4.7