Hugin trunk 0.1
Loading...
Searching...
No Matches
CalculateOptimalROI.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
25#include "CalculateOptimalROI.h"
26#include <algorithm>
27#include "LayerStacks.h"
29
30namespace HuginBase {
31// uncomment the follow line to print more progress
32//#define PRINT_DEBUG_VALUES
33
36{
37 activeImages=panorama.getActiveImages();
38 if (activeImages.empty())
39 {
40 return false;
41 };
42 // check that all images are visible
43 const HuginBase::UIntSet visibleImages = HuginBase::getImagesinROI(panorama, activeImages, vigra::Rect2D(vigra::Point2D(0, 0), panorama.getOptions().getSize()));
44 if (visibleImages.size() != activeImages.size())
45 {
46 // ignore invisible images
48 std::set_intersection(activeImages.begin(), activeImages.end(), visibleImages.begin(), visibleImages.end(), std::inserter(updatedImages, updatedImages.begin()));
50 if (activeImages.empty())
51 {
52 return false;
53 };
54 };
55
56 PanoramaOptions opt = panorama.getOptions();
58 if (o_optimalSize.x == 0 || o_optimalSize.y == 0)
59 {
60 return false;
61 };
62 m_bestRect = vigra::Rect2D();
63 try
64 {
65 testedPixels.resize(static_cast<long long>(o_optimalSize.x) * o_optimalSize.y,false);
66 pixels.resize(static_cast<long long>(o_optimalSize.x) * o_optimalSize.y,false);
67 }
68 catch(std::bad_alloc&)
69 {
70 //could not allocate enough memory
71 return false;
72 };
73
74 for (UIntSet::const_iterator it=activeImages.begin(); it!=activeImages.end(); ++it)
75 {
76 const SrcPanoImage &img=panorama.getImage(*it);
78 transf->createTransform(img,opt);
79 transfMap.insert(std::pair<unsigned int,PTools::Transform*>(*it,transf));
80 }
81
82 if (!getProgressDisplay()->updateDisplay("Calculate the cropping region"))
83 {
84 CleanUp();
85 return false;
86 };
87 if (!autocrop())
88 {
89 CleanUp();
90 return false;
91 };
92
93 //clean up on demand
94 CleanUp();
95 return true;
96};
97
99{
100 for (std::map<unsigned int, PTools::Transform*>::iterator it = transfMap.begin(); it != transfMap.end(); ++it)
101 {
102 delete (*it).second;
103 };
104};
105
106//now you can do dynamic programming, look thinks up on fly
108{
109 bool inside = intersection; // start with true for intersection mode and with false for union mode
110 //check that pixel at each place
111 for(UIntSet::const_iterator it=stack.begin();it!=stack.end();++it)
112 {
113 double xd,yd;
114 if(transfMap[*it]->transformImgCoord(xd,yd,(double)i,(double)j))
115 {
116 if(o_panorama.getImage(*it).isInside(vigra::Point2D(xd,yd)))
117 {
118 if (!intersection) {
119 //if found in a single image, short cut out
120 inside=true;
121 break;
122 }
123 }
124 else {
125 if (intersection) {
126 //outside of at least one image - return false
127 inside=false;
128 break;
129 }
130 }
131 }
132 }
133
134 return inside;
135}
136
138{
139 if(!testedPixels[static_cast<long long>(j) * o_optimalSize.x + i])
140 {
141 bool inside;
142
143 if (stacks.empty())
144 {
145 // no stacks - test all images on union or intersection
147 }
148 else
149 {
150 inside = false;
151 // pixel must be inside of at least one stack
152 for (unsigned s=0; s < stacks.size(); s++)
153 {
154 // images in each stack are tested on intersection
155 if (stackPixel(i, j, stacks[s]))
156 {
157 inside = true;
158 break;
159 }
160 }
161 }
162
163 testedPixels[static_cast<long long>(j) * o_optimalSize.x + i] = true;
164 pixels[static_cast<long long>(j) * o_optimalSize.x + i] = inside;
165
166 return inside;
167 }
168 //else it is know if this pixel is covered by at least one image
169 else
170 {
171 return pixels[static_cast<long long>(j) * o_optimalSize.x + i];
172 }
173}
174
176void CalculateOptimalROI::AddCheckingRects(std::list<vigra::Rect2D>& testingRects, const vigra::Rect2D& rect, const long maxvalue)
177{
178 if(rect.left()<0 || rect.top()<0 || rect.right()>o_optimalSize.x || rect.bottom()>o_optimalSize.y)
179 {
180 return;
181 }
182
183 if (rect.left() < rect.right() && rect.top() < rect.bottom())
184 {
185 //not big enough
186 if(maxvalue>0 && rect.area()<maxvalue)
187 {
188 return;
189 }
190 // check if rect is already in list
191 std::list<vigra::Rect2D>::iterator it=std::find(testingRects.begin(), testingRects.end(), rect);
192 if (it == testingRects.end())
193 {
194 testingRects.push_back(rect);
195 };
196 }
197}
198
201{
202 for (int i = rect.left(); i<rect.right(); i++)
203 {
204 if (imgPixel(i, rect.top()) == 0 || imgPixel(i, rect.bottom() - 1) == 0)
205 {
206 return false;
207 }
208 }
209
210 for (int j = rect.top(); j<rect.bottom(); j++)
211 {
212 if (imgPixel(rect.left(), j) == 0 || imgPixel(rect.right() - 1, j) == 0)
213 {
214 return false;
215 }
216 }
217 return true;
218};
219
220vigra::Rect2D ModifyRect(const vigra::Rect2D& rect, long deltaLeft, long deltaTop, long deltaRight, long deltaBottom)
221{
222 vigra::Rect2D newRect(rect);
223 newRect.moveBy(deltaLeft, deltaTop);
224 newRect.addSize(vigra::Size2D(deltaRight - deltaLeft, deltaBottom - deltaTop));
225 return newRect;
226};
227
228void CalculateOptimalROI::nonreccheck(const vigra::Rect2D& rect, int acc, int searchStrategy, long& maxvalue)
229{
230 std::list<vigra::Rect2D> testRects;
231 testRects.push_back(rect);
232
233 while(!testRects.empty())
234 {
235 vigra::Rect2D testingRect = *testRects.begin();
237 switch(searchStrategy)
238 {
239 case 1:
240 if(!rectCovers)
241 {
242 //all directions (shrink only)
247 }
248 //it was good, stop recursing
249 else
250 {
251 if(maxvalue<testingRect.area())
252 {
253 maxvalue=testingRect.area();
255 }
256 }
257 break;
258 case 2:
259 if(!rectCovers)
260 {
261 //all directions (shrink only)
264 }
265 //it was good, stop recursing
266 else
267 {
268 if(maxvalue<testingRect.area())
269 {
270 maxvalue = testingRect.area();
272 }
273 }
274 break;
275 case 0:
276 default:
277 if(rectCovers)
278 {
279 //check growth in all 4 directions
284 //check if shrinking in one direction will allow more growth in other direction
297 if(maxvalue<testingRect.area())
298 {
299 maxvalue = testingRect.area();
301 }
302 }
303 };
304 testRects.pop_front();
305 }
306}
307
309{
310 long maxvalue=0;
311
312 //put backwards at the start
313 int startacc = pow(2.0, std::min((int)log2(o_optimalSize.x / 2 - 1), (int)log2(o_optimalSize.y / 2 - 1)) - 1);
314 if (startacc < 1)
315 {
316 startacc = 1;
317 };
318
319 //start smaller to get biggest initial position
320 if(startacc>64)
321 {
322 //we start searching with a symmetric decrease
323 for(int acc=startacc;acc>=64;acc/=2)
324 {
325 nonreccheck(vigra::Rect2D(vigra::Point2D(), o_optimalSize), acc, 2, maxvalue);
326 if (!getProgressDisplay()->updateDisplayValue())
327 {
328 return false;
329 };
330 if(maxvalue>0)
331 {
332#ifdef PRINT_DEBUG_VALUES
333 printf("Inner %d %ld: %d %d - %d %d\n", acc, maxvalue, m_bestRect.left(), m_bestRect.right(), m_bestRect.top(), m_bestRect.bottom());
334#endif
335 break;
336 }
337 }
338 };
339
340 if(maxvalue==0)
341 {
342 // if the rough symmetric search failed we are using also an asymmetric strategy
343 for(int acc=startacc;acc>=1;acc/=2)
344 {
345 nonreccheck(vigra::Rect2D(vigra::Point2D(), o_optimalSize), acc, 1, maxvalue);
346 if (!getProgressDisplay()->updateDisplayValue())
347 {
348 return false;
349 };
350 if (maxvalue>0)
351 {
352#ifdef PRINT_DEBUG_VALUES
353 printf("Inner %d %ld: %d %d - %d %d\n", acc, maxvalue, m_bestRect.left(), m_bestRect.right(), m_bestRect.top(), m_bestRect.bottom());
354#endif
355 break;
356 }
357 }
358 };
359
360 for(int acc=startacc;acc>=1;acc/=2)
361 {
362#ifdef PRINT_DEBUG_VALUES
363 printf("Starting %d: %d %d - %d %d\n", acc, m_bestRect.left(), m_bestRect.right(), m_bestRect.top(), m_bestRect.bottom());
364#endif
366 if (!getProgressDisplay()->updateDisplayValue())
367 {
368 return false;
369 };
370 }
371
372 return true;
373}
374
376{
378 intersection=true;
379};
380
381// implementation of outside crop finding
383{
384 if (hasRunSuccessfully())
385 {
386 return m_bestRect;
387 }
388 else
389 {
390 return vigra::Rect2D();
391 }
392}
393
395{
397 if (activeImgs.empty())
398 {
399 // no image, return false
400 return false;
401 };
403 // reset roi for calculation
404 opts.setROI(vigra::Rect2D(vigra::Point2D(0, 0), opts.getSize()));
405 m_bestRect = vigra::Rect2D();
406 progress->setMaximum(activeImgs.size());
407 for (auto& img : activeImgs)
408 {
409 // calculate boundary of all images, use a miniatur scale of 800 px for speed reasons
410 m_bestRect |= HuginBase::estimateOutputROI(pano, opts, img, 800);
411 progress->updateDisplayValue();
412 if (progress->wasCancelled())
413 {
414 m_bestRect = vigra::Rect2D();
415 return false;
416 };
417 };
418 return !m_bestRect.isEmpty();
419}
420
421} //namespace
declaration of functions to handle stacks and layers
virtual vigra::Rect2D getResultOptimalROI()
returns the found crop rect
bool CalcOutsideCrop(PanoramaData &pano, AppBase::ProgressDisplay *progress)
the main crop finding algorithm
std::map< unsigned int, PTools::Transform * > transfMap
bool calcOptimalROI(PanoramaData &panorama)
bool CheckRectCoversPano(const vigra::Rect2D &rect)
check if given rect covers the whole pano
void setStacks(std::vector< UIntSet > hdr_stacks)
sets the stack vector
void AddCheckingRects(std::list< vigra::Rect2D > &testingRects, const vigra::Rect2D &rect, const long maxvalue)
add new rect to list of rects to be check, do some checks before
void nonreccheck(const vigra::Rect2D &rect, int acc, int searchStrategy, long &maxvalue)
bool stackPixel(int i, int j, UIntSet &stack)
Holds transformations for Image -> Pano and the other way.
Model for a panorama.
virtual const PanoramaOptions & getOptions() const =0
returns the options for this panorama
virtual UIntSet getActiveImages() const =0
get active images
virtual const SrcPanoImage & getImage(std::size_t nr) const =0
get a panorama image, counting starts with 0
Panorama image options.
void setROI(const vigra::Rect2D &val)
vigra::Size2D getSize() const
get size of output image
All variables of a source image.
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
virtual AppBase::ProgressDisplay * getProgressDisplay() const
mainly consists of wrapper around the pano tools library, to assist in ressource management and to pr...
Definition wxcms.cpp:39
vigra::Rect2D estimateOutputROI(const PanoramaData &pano, const PanoramaOptions &opts, unsigned i, const double maxLength)
vigra::Rect2D ModifyRect(const vigra::Rect2D &rect, long deltaLeft, long deltaTop, long deltaRight, long deltaBottom)
UIntSet getImagesinROI(const PanoramaData &pano, const UIntSet activeImages)
returns set of images which are visible in output ROI
std::set< unsigned int > UIntSet
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41