Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ComputeImageROI.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
26 #include "ComputeImageROI.h"
27 
28 #include <algorithm>
29 #include <nona/RemappedPanoImage.h>
30 #include <nona/RemappedPanoImage.h>
31 
32 
33 
34 namespace HuginBase {
35 
42 template <class TRANSFORM>
44  const PanoramaOptions & dest,
45  TRANSFORM & transf,
46  vigra::Rect2D & imgRect,
47  vigra::BImage & alpha,
48  double & scale,
49  double maxLength = 180.0)
50 {
51  hugin_utils::FDiff2D ul, lr;
52  ul.x = DBL_MAX;
53  ul.y = DBL_MAX;
54  lr.x = -DBL_MAX;
55  lr.y = -DBL_MAX;
56 
57  // remap into a miniature version of the pano and use
58  // that to check for boundaries. This should be much more
59  // robust than the old code that tried to trace the boundaries
60  // of the images using the inverse transform, which could be fooled
61  // easily by fisheye images.
62 
63  scale = std::min(maxLength/dest.getSize().x, maxLength/dest.getSize().y);
64 
65  // take dest roi into account...
66  vigra::Size2D destSz;
67  destSz.x = hugin_utils::ceili(dest.getSize().x * scale);
68  destSz.y = hugin_utils::ceili(dest.getSize().y * scale);
69  vigra::Rect2D destRect;
70  destRect.setUpperLeft(vigra::Point2D (hugin_utils::floori(dest.getROI().left() * scale),
71  hugin_utils::floori(dest.getROI().top() * scale)));
72  destRect.setLowerRight(vigra::Point2D (hugin_utils::ceili(dest.getROI().right() * scale),
73  hugin_utils::ceili(dest.getROI().bottom() * scale)));
74  destRect = destRect & vigra::Rect2D(destSz);
75 
76  DEBUG_DEBUG("scale " << scale);
77  DEBUG_DEBUG("dest roi " << dest.getROI());
78  DEBUG_DEBUG("dest Sz: " << destSz);
79  DEBUG_DEBUG("dest rect: " << destRect);
80 
81  hugin_utils::FDiff2D cropCenter;
82  double radius2=0;
83  if (src.getCropMode() == SrcPanoImage::CROP_CIRCLE) {
84  cropCenter.x = src.getCropRect().left() + src.getCropRect().width()/2.0;
85  cropCenter.y = src.getCropRect().top() + src.getCropRect().height()/2.0;
86  radius2 = std::min(src.getCropRect().width()/2.0, src.getCropRect().height()/2.0);
87  radius2 = radius2 * radius2;
88  }
89 
90  // remap image
91  vigra::BImage img(destSz.x, destSz.y, (unsigned char)0);
92  for (int y=destRect.top(); y < destRect.bottom(); y++) {
93  for (int x=destRect.left(); x < destRect.right(); x++) {
94  // sample image
95  // coordinates in real image pixels
96  double sx,sy;
97  transf.transformImgCoord(sx,sy, x/scale, y/scale);
98  bool valid=true;
99  if (src.getCropMode() == SrcPanoImage::CROP_CIRCLE) {
100  double dx = sx - cropCenter.x;
101  double dy = sy - cropCenter.y;
102  if (dx*dx + dy*dy > radius2) {
103  valid = false;
104  }
105  } else if (!src.getCropRect().contains(vigra::Point2D(hugin_utils::roundi(sx), hugin_utils::roundi(sy))) ) {
106  valid = false;
107  }
108  if(valid && src.hasActiveMasks())
109  valid=!src.isInsideMasks(vigra::Point2D(hugin_utils::roundi(sx), hugin_utils::roundi(sy)));
110 
111  if (valid) {
112  img(x,y) = 255;
113 /* if ( ul.x > (x-1)/scale ) {
114  ul.x = (x-1)/scale;
115  }
116  if ( ul.y > (y-1)/scale ) {
117  ul.y = (y-1)/scale;
118  }
119 
120  if ( lr.x < (x+1)/scale ) {
121  lr.x = (x+1)/scale;
122  }
123  if ( lr.y < (y+1)/scale ) {
124  lr.y = (y+1)/scale;
125  }
126 */
127  } else {
128  img(x,y) = 0;
129  }
130  }
131  }
132 
133  alpha.resize(img.size());
134 
135  // dilate alpha image, to cover neighbouring pixels,
136  // that may be valid in the full resolution image
137  vigra::discDilation(vigra::srcImageRange(img),
138  vigra::destImage(alpha), 1);
139 
140  ul.x = destRect.right();
141  ul.y = destRect.bottom();
142  lr.x = destRect.left();
143  lr.y = destRect.top();
144 
145  for (int y=destRect.top(); y < destRect.bottom(); y++) {
146  for (int x=destRect.left(); x < destRect.right(); x++) {
147  if (alpha(x,y)) {
148  if ( ul.x > x ) {
149  ul.x = x;
150  }
151  if ( ul.y > y ) {
152  ul.y = y;
153  }
154 
155  if ( lr.x < x ) {
156  lr.x = x;
157  }
158  if ( lr.y < y ) {
159  lr.y = y;
160  }
161  }
162  }
163  }
164 
165  // check if we have found some pixels..
166  if ( ul.x == destRect.right() || ul.y == destRect.bottom()
167  || lr.x == destRect.left()|| lr.y == destRect.top() ) {
168 
169  // no valid pixel found. return empty ROI
170  imgRect = vigra::Rect2D();
171 
172  initImage(img.upperLeft()+destRect.upperLeft(),
173  img.upperLeft()+destRect.lowerRight(),
174  img.accessor(),0);
175  /*
176  // no valid pixel.. strange.. either there is no image here, or we have
177  // overlooked some pixel.. to be on the safe side. remap the whole image here...
178  imgRect = dest.getROI();
179  alpha.resize(img.size().x, img.size().y, 0);
180  initImage(img.upperLeft()+destRect.upperLeft(),
181  img.upperLeft()+destRect.lowerRight(),
182  img.accessor(),255);
183  */
184  } else {
185  // bounding rect after scan
186  DEBUG_DEBUG("ul: " << ul << " lr: " << lr);
187  ul.x = (ul.x)/scale;
188  ul.y = (ul.y)/scale;
189  lr.x = (lr.x+1)/scale;
190  lr.y = (lr.y+1)/scale;
191  imgRect.setUpperLeft(vigra::Point2D(hugin_utils::roundi(ul.x), hugin_utils::roundi(ul.y)));
192  imgRect.setLowerRight(vigra::Point2D(hugin_utils::roundi(lr.x), hugin_utils::roundi(lr.y)));
193  // ensure that the roi is inside the destination rect
194  imgRect = dest.getROI() & imgRect;
195  DEBUG_DEBUG("bounding box: " << imgRect);
196  }
197 
198 }
199 
206 template <class TRANSFORM>
207 void estimateImageRect(const SrcPanoImage & src, const PanoramaOptions & dest,
208  TRANSFORM & transf, vigra::Rect2D & imgRect, double maxLength = 180.0)
209 {
210  vigra::BImage img;
211  double scale;
212  estimateImageAlpha(src, dest, transf, imgRect, img, scale, maxLength);
213 }
214 
215  vigra::Rect2D estimateOutputROI(const PanoramaData & pano, const PanoramaOptions & opts, unsigned i, const double maxLength)
216  {
217  vigra::Rect2D imageRect;
218  SrcPanoImage srcImg = pano.getSrcImage(i);
219  PTools::Transform transf;
220  transf.createTransform(srcImg, opts);
221  estimateImageRect(srcImg, opts, transf, imageRect, maxLength);
222  return imageRect;
223  }
224 
225  std::vector<vigra::Rect2D> ComputeImageROI::computeROIS(const PanoramaData& panorama,
226  const PanoramaOptions & opts,
227  const UIntSet & images)
228  {
229  std::vector<vigra::Rect2D> res;
230  for (UIntSet::const_iterator it = images.begin();
231  it != images.end(); ++it)
232  {
233  res.push_back(estimateOutputROI(panorama, opts, *it));
234  }
235  return res;
236  }
237 
238 }
int floori(double x)
Definition: hugin_math.h:65
int roundi(T x)
Definition: hugin_math.h:73
vigra::Rect2D estimateOutputROI(const PanoramaData &pano, const PanoramaOptions &opts, unsigned i, const double maxLength)
bool hasActiveMasks() const
returns true, if image has active masks
Contains functions to transform whole images.
void estimateImageAlpha(const SrcPanoImage &src, const PanoramaOptions &dest, TRANSFORM &transf, vigra::Rect2D &imgRect, vigra::BImage &alpha, double &scale, double maxLength=180.0)
calculate the outline of the image
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
const vigra::Rect2D & getROI() const
int ceili(double x)
Definition: hugin_math.h:60
Model for a panorama.
Definition: PanoramaData.h:81
static std::vector< vigra::Rect2D > computeROIS(const PanoramaData &panorama, const PanoramaOptions &opts, const UIntSet &images)
void estimateImageRect(const SrcPanoImage &src, const PanoramaOptions &dest, TRANSFORM &transf, vigra::Rect2D &imgRect, double maxLength=180.0)
calculate the outline of the image
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
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
Definition: ROIImage.h:287
Holds transformations for Image -&gt; Pano and the other way.
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
virtual SrcPanoImage getSrcImage(unsigned imgNr) const =0
get a complete description of a source image
bool isInsideMasks(vigra::Point2D p) const
returns true, if point p is inside of one mask polygon
All variables of a source image.
Definition: SrcPanoImage.h:194
Panorama image options.
vigra::Size2D getSize() const
get size of output image
static T min(T x, T y)
Definition: svm.cpp:62
void createTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
initialize pano-&gt;image transformation