00001
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
00077
00078
00079
00080
00081
00082 double maxLength = 180;
00083 scale = std::min(maxLength/dest.getSize().x, maxLength/dest.getSize().y);
00084
00085
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
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
00115
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
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 } else {
00148 img(x,y) = 0;
00149 }
00150 }
00151 }
00152
00153 alpha.resize(img.size());
00154
00155
00156
00157 vigra::discDilation(vigra::srcImageRange(img),
00158 vigra::destImage(alpha), 1);
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
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
00197 if ( ul.x == destRect.right() || ul.y == destRect.bottom()
00198 || lr.x == destRect.left()|| lr.y == destRect.top() ) {
00199
00200
00201 imgRect = vigra::Rect2D();
00202
00203 initImage(img.upperLeft()+destRect.upperLeft(),
00204 img.upperLeft()+destRect.lowerRight(),
00205 img.accessor(),0);
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 } else {
00216
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
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 }