1 /*
2 * Copyright (C) 2009-2016 Christoph L. Spiel
3 *
4 * This file is part of Enblend.
5 *
6 * Enblend is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Enblend is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Enblend; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #ifndef __NEAREST_H__
21 #define __NEAREST_H__
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <iostream>
28 #ifdef _WIN32
29 #include <cmath>
30 #else
31 #include <math.h>
32 #endif
33 #include <stdlib.h>
34 #include <utility>
35
36 #include <vigra/functorexpression.hxx>
37 #include <vigra/inspectimage.hxx>
38 #include <vigra/numerictraits.hxx>
39
40 #include "timer.h"
41 #include "opencl_vigra.h"
42
43
44 #ifdef OPENCL
45 namespace GPU
46 {
47 extern std::unique_ptr<vigra::ocl::DistanceTransformFH> DistanceTransform;
48 }
49 #endif
50
51
52 namespace vigra
53 {
54 namespace ocl
55 {
56 template <class SrcImageIterator, class SrcAccessor,
57 class DestImageIterator, class DestAccessor,
58 class ValueType>
59 inline void
distanceTransform(SrcImageIterator src_upperleft,SrcImageIterator src_lowerright,SrcAccessor src_acc,DestImageIterator dest_upperleft,DestAccessor dest_acc,ValueType background,int norm)60 distanceTransform(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc,
61 DestImageIterator dest_upperleft, DestAccessor dest_acc,
62 ValueType background, int norm)
63 {
64 timer::WallClock wall_clock;
65
66 wall_clock.start();
67
68 #ifdef OPENCL
69 const bool enable_kernel = parameter::as_boolean("gpu-kernel-dt", true);
70
71 if (GPUContext && GPU::DistanceTransform && enable_kernel)
72 {
73 #ifdef DEBUG
74 std::cerr <<
75 command << ": info: choose OpenCL accelaration for Distance Transform" << std::endl;
76 #endif // DEBUG
77
78 GPU::DistanceTransform->run(src_upperleft, src_lowerright, src_acc,
79 dest_upperleft, dest_acc,
80 background, norm);
81 }
82 else
83 {
84 if (UseGPU && enable_kernel)
85 {
86 std::cerr <<
87 command << ": warning: missing GPUContext or OpenCL DistanceTransform\n" <<
88 command << ": warning: falling back to CPU path" << std::endl;
89 }
90
91 vigra::omp::distanceTransform(src_upperleft, src_lowerright, src_acc,
92 dest_upperleft, dest_acc,
93 background, norm);
94 }
95 #else
96 vigra::omp::distanceTransform(src_upperleft, src_lowerright, src_acc,
97 dest_upperleft, dest_acc,
98 background, norm);
99 #endif // OPENCL
100
101 wall_clock.stop();
102 if (parameter::as_boolean("time-distance-transform", false))
103 {
104 const std::ios::fmtflags flags(std::cerr.flags());
105 vigra::Size2D size(src_lowerright - src_upperleft);
106 std::cerr <<
107 "\n" <<
108 command << ": timing: wall-clock runtime of `Distance Transform': " <<
109 std::setprecision(3) << 1000.0 * wall_clock.value() << " ms\n" <<
110 command << ": timing: speed according to wall-clock: " <<
111 size.area() / (1048576.0 * wall_clock.value()) << " MPixel/s\n" <<
112 std::endl;
113 std::cerr.flags(flags);
114 }
115 }
116
117
118 template <class SrcImageIterator, class SrcAccessor,
119 class DestImageIterator, class DestAccessor,
120 class ValueType>
121 inline static void
distanceTransform(vigra::triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,vigra::pair<DestImageIterator,DestAccessor> dest,ValueType background,int norm)122 distanceTransform(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
123 vigra::pair<DestImageIterator, DestAccessor> dest,
124 ValueType background, int norm)
125 {
126 vigra::ocl::distanceTransform(src.first, src.second, src.third,
127 dest.first, dest.second,
128 background, norm);
129 }
130 } // namespace ocl
131 } // namespace vigra
132
133
134 namespace enblend {
135
136 template <class SrcImageIterator, class SrcAccessor,
137 class DestImageIterator, class DestAccessor>
138 void
quadruple_image(SrcImageIterator src_upperleft,SrcImageIterator src_lowerright,SrcAccessor sa,DestImageIterator dest_upperleft,DestAccessor da,boundary_t boundary)139 quadruple_image(SrcImageIterator src_upperleft,
140 SrcImageIterator src_lowerright, SrcAccessor sa,
141 DestImageIterator dest_upperleft, DestAccessor da,
142 boundary_t boundary)
143 {
144 const vigra::Diff2D size_x(src_lowerright.x - src_upperleft.x, 0);
145 const vigra::Diff2D size_y(0, src_lowerright.y - src_upperleft.y);
146
147 switch (boundary)
148 {
149 case OpenBoundaries:
150 vigra::copyImage(src_upperleft, src_lowerright, sa,
151 dest_upperleft, da);
152 break;
153
154 case HorizontalStrip:
155 vigra::copyImage(src_upperleft, src_lowerright, sa,
156 dest_upperleft, da); // 11
157 vigra::copyImage(src_upperleft, src_lowerright, sa,
158 dest_upperleft + size_x, da); // 12
159 break;
160
161 case VerticalStrip:
162 vigra::copyImage(src_upperleft, src_lowerright, sa,
163 dest_upperleft, da); // 11
164 vigra::copyImage(src_upperleft, src_lowerright, sa,
165 dest_upperleft + size_y, da); // 21
166 break;
167
168 case DoubleStrip:
169 vigra::copyImage(src_upperleft, src_lowerright, sa,
170 dest_upperleft, da); // 11
171 vigra::copyImage(src_upperleft, src_lowerright, sa,
172 dest_upperleft + size_x, da); // 12
173 vigra::copyImage(src_upperleft, src_lowerright, sa,
174 dest_upperleft + size_y, da); // 21
175 vigra::copyImage(src_upperleft, src_lowerright, sa,
176 dest_upperleft + size_x + size_y, da); // 22
177 break;
178
179 default:
180 NEVER_REACHED("switch control expression \"boundary\" out of range");
181 }
182 }
183
184
185 template <class SrcImageIterator, class SrcAccessor,
186 class DestImageIterator, class DestAccessor>
187 inline void
quadruple_image(vigra::triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,vigra::pair<DestImageIterator,DestAccessor> dest,boundary_t boundary)188 quadruple_image(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
189 vigra::pair<DestImageIterator, DestAccessor> dest,
190 boundary_t boundary)
191 {
192 quadruple_image(src.first, src.second, src.third,
193 dest.first, dest.second,
194 boundary);
195 }
196
197
198 template <class SrcImageIterator, class SrcAccessor,
199 class DestImageIterator, class DestAccessor>
200 void
quater_image(SrcImageIterator src_upperleft,SrcImageIterator src_lowerright,SrcAccessor sa,DestImageIterator dest_upperleft,DestAccessor da,boundary_t boundary)201 quater_image(SrcImageIterator src_upperleft,
202 SrcImageIterator src_lowerright, SrcAccessor sa,
203 DestImageIterator dest_upperleft, DestAccessor da,
204 boundary_t boundary)
205 {
206 const vigra::Diff2D size_x(src_lowerright.x - src_upperleft.x, 0);
207 const vigra::Diff2D size_y(0, src_lowerright.y - src_upperleft.y);
208 const vigra::Diff2D size_x2(size_x / 2);
209 const vigra::Diff2D size_y2(size_y / 2);
210 const vigra::Diff2D size_x4(size_x2 / 2);
211 const vigra::Diff2D size_y4(size_y2 / 2);
212
213 // destination image
214 // | 11 12 |
215 // | |
216 // | 21 22 |
217
218 switch (boundary)
219 {
220 case OpenBoundaries:
221 vigra::copyImage(src_upperleft, src_lowerright, sa,
222 dest_upperleft, da);
223 break;
224
225 case HorizontalStrip:
226 vigra::copyImage(src_upperleft + size_x2,
227 src_upperleft + size_x2 + size_x4 + size_y,
228 sa,
229 dest_upperleft,
230 da); // 11
231 vigra::copyImage(src_upperleft + size_x4,
232 src_upperleft + size_x2 + size_y,
233 sa,
234 dest_upperleft + size_x4,
235 da); // 12
236 break;
237
238 case VerticalStrip:
239 vigra::copyImage(src_upperleft + size_y2,
240 src_upperleft + size_y2 + size_y4 + size_x,
241 sa,
242 dest_upperleft,
243 da); // 21
244 vigra::copyImage(src_upperleft + size_y4,
245 src_upperleft + size_y2 + size_x,
246 sa,
247 dest_upperleft + size_y4,
248 da); // 22
249 break;
250
251 case DoubleStrip:
252 vigra::copyImage(src_upperleft + size_x2 + size_y2,
253 src_upperleft + size_x2 + size_y2 + size_x4 + size_y4,
254 sa,
255 dest_upperleft,
256 da); // 11
257 vigra::copyImage(src_upperleft + size_x4 + size_y2,
258 src_upperleft + size_x2 + size_y2 + size_y4,
259 sa,
260 dest_upperleft + size_x4,
261 da); // 12
262 vigra::copyImage(src_upperleft + size_x2 + size_y4,
263 src_upperleft + size_x2 + size_x4 + size_y2,
264 sa,
265 dest_upperleft + size_y4,
266 da); // 21
267 vigra::copyImage(src_upperleft + size_x4 + size_y4,
268 src_upperleft + size_x2 + size_y2,
269 sa,
270 dest_upperleft + size_x4 + size_y4,
271 da); // 22
272 break;
273
274 default:
275 NEVER_REACHED("switch control expression \"boundary\" out of range");
276 }
277 }
278
279
280 template <class SrcImageIterator, class SrcAccessor,
281 class DestImageIterator, class DestAccessor>
282 inline void
quater_image(vigra::triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,vigra::pair<DestImageIterator,DestAccessor> dest,boundary_t boundary)283 quater_image(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
284 vigra::pair<DestImageIterator, DestAccessor> dest,
285 boundary_t boundary)
286 {
287 quater_image(src.first, src.second, src.third,
288 dest.first, dest.second,
289 boundary);
290 }
291
292
293 template <class SrcImageIterator, class SrcAccessor,
294 class DestImageIterator, class DestAccessor,
295 class ValueType>
296 void
periodicDistanceTransform(SrcImageIterator src_upperleft,SrcImageIterator src_lowerright,SrcAccessor sa,DestImageIterator dest_upperleft,DestAccessor da,ValueType background,int norm,boundary_t boundary)297 periodicDistanceTransform(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor sa,
298 DestImageIterator dest_upperleft, DestAccessor da,
299 ValueType background, int norm, boundary_t boundary)
300 {
301 typedef typename SrcImageIterator::value_type SrcValueType;
302 typedef typename DestImageIterator::value_type DestValueType;
303
304 const vigra::Diff2D size(src_lowerright.x - src_upperleft.x,
305 src_lowerright.y - src_upperleft.y);
306 int size_x;
307 int size_y;
308
309 switch (boundary)
310 {
311 case OpenBoundaries:
312 size_x = size.x;
313 size_y = size.y;
314 break;
315
316 case HorizontalStrip:
317 size_x = 2 * size.x;
318 size_y = size.y;
319 break;
320
321 case VerticalStrip:
322 size_x = size.x;
323 size_y = 2 * size.y;
324 break;
325
326 case DoubleStrip:
327 size_x = 2 * size.x;
328 size_y = 2 * size.y;
329 break;
330
331 default:
332 NEVER_REACHED("switch control expression \"boundary\" out of range");
333 }
334
335 vigra::BasicImage<SrcValueType> periodic(size_x, size_y);
336 vigra::BasicImage<DestValueType> distance(periodic.size());
337
338 quadruple_image(src_upperleft, src_lowerright, sa, periodic.upperLeft(), periodic.accessor(), boundary);
339 vigra::ocl::distanceTransform(srcImageRange(periodic), destImage(distance), background, norm);
340 quater_image(srcImageRange(distance), destIter(dest_upperleft, da), boundary);
341 }
342
343
344 template <class SrcImageIterator, class SrcAccessor,
345 class DestImageIterator, class DestAccessor,
346 class ValueType>
347 inline void
periodicDistanceTransform(vigra::triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,vigra::pair<DestImageIterator,DestAccessor> dest,ValueType background,int norm,boundary_t boundary)348 periodicDistanceTransform(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
349 vigra::pair<DestImageIterator, DestAccessor> dest,
350 ValueType background, int norm, boundary_t boundary)
351 {
352 periodicDistanceTransform(src.first, src.second, src.third,
353 dest.first, dest.second,
354 background, norm, boundary);
355 }
356
357
358 template <class ValueType>
359 struct saturating_subtract
360 {
361 typedef ValueType first_argument_type;
362 typedef ValueType second_argument_type;
363 typedef ValueType result_type;
364
operatorsaturating_subtract365 result_type operator()(const first_argument_type& v1,
366 const second_argument_type& v2) const
367 {
368 typedef vigra::NumericTraits<result_type> traits;
369
370 return v2 < v1 ? v1 - v2 : traits::zero();
371 }
372 };
373
374
375 template <class SrcImageIterator, class SrcAccessor>
376 inline unsigned
quick_tally(SrcImageIterator begin,SrcImageIterator end,SrcAccessor acc,unsigned threshold)377 quick_tally(SrcImageIterator begin, SrcImageIterator end, SrcAccessor acc,
378 unsigned threshold)
379 {
380 typedef typename SrcAccessor::value_type SrcValueType;
381
382 unsigned count = 0U;
383 SrcImageIterator i = begin;
384 while (count < threshold && i != end)
385 {
386 if (acc(i) != SrcValueType())
387 {
388 ++count;
389 }
390 ++i;
391 }
392
393 return count;
394 }
395
396
397 template <class SrcImageIterator, class SrcAccessor>
398 inline unsigned
quick_tally(vigra::triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,unsigned threshold)399 quick_tally(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
400 unsigned threshold)
401 {
402 return quick_tally(src.first, src.second, src.third, threshold);
403 }
404
405
406 // Compute a mask (dest) that defines the seam line given the
407 // blackmask (src1) and the whitemask (src2) of the overlapping
408 // images.
409 //
410 // The idea of the algorithm is from
411 // Yalin Xiong, Ken Turkowski
412 // "Registration, Calibration and Blending in Creating High Quality Panoramas"
413 // Proceedings of the 4th IEEE Workshop on Applications of Computer Vision (WACV'98)
414 // where we find:
415 // "To locate the mask boundary, we perform the grassfire
416 // transform on two images individually. The resulting distance
417 // maps represent how far away each pixel is from its nearest
418 // boundary. The pixel values of the blend mask is then set to
419 // either 0 or 1 by comparing the distance values at each pixel
420 // in the two distance maps."
421 //
422 // Though we prefer the Distance Transform to the Grassfire Transform.
423
424 template <class SrcImageIterator, class SrcAccessor,
425 class DestImageIterator, class DestAccessor>
426 void
nearestFeatureTransform(SrcImageIterator src1_upperleft,SrcImageIterator src1_lowerright,SrcAccessor sa1,SrcImageIterator src2_upperleft,SrcAccessor sa2,DestImageIterator dest_upperleft,DestAccessor da,nearest_neighbor_metric_t norm,boundary_t boundary)427 nearestFeatureTransform(SrcImageIterator src1_upperleft, SrcImageIterator src1_lowerright, SrcAccessor sa1,
428 SrcImageIterator src2_upperleft, SrcAccessor sa2,
429 DestImageIterator dest_upperleft, DestAccessor da,
430 nearest_neighbor_metric_t norm, boundary_t boundary)
431 {
432 typedef typename SrcAccessor::value_type SrcPixelType;
433 typedef vigra::NumericTraits<SrcPixelType> SrcPixelTraits;
434
435 typedef typename DestAccessor::value_type DestPixelType;
436 typedef vigra::NumericTraits<DestPixelType> DestPixelTraits;
437
438 const SrcPixelType background = SrcPixelTraits::zero();
439 const vigra::Size2D size(src1_lowerright.x - src1_upperleft.x, src1_lowerright.y - src1_upperleft.y);
440
441 IMAGETYPE<float> dist12(size);
442 IMAGETYPE<float> dist21(size);
443 if (Verbose >= VERBOSE_NFT_MESSAGES)
444 {
445 std::cerr << command << ": info: creating ";
446 if (CoarseMask) {
447 std::cerr << "coarse/" << CoarsenessFactor;
448 } else {
449 std::cerr << "fine";
450 }
451 std::cerr << " blend mask: 1/3";
452 std::cerr.flush();
453 }
454
455 const unsigned overlap_threshold =
456 // Arbitrary threshold of overlapping pixels below which we
457 // consider the overlap of the masks to be complete, i.e. the
458 // image pair as useless.
459 //
460 // The current parameter default is two times the
461 // circumference of the overlap rectangle.
462 parameter::as_unsigned("overlap-check-threshold", 2U) * //< overlap-check-threshold 2
463 2U * (static_cast<unsigned>(size.height()) + static_cast<unsigned>(size.width()));
464 IMAGETYPE<SrcPixelType> diff12(size);
465 vigra::omp::combineTwoImages(src1_upperleft, src1_lowerright, sa1,
466 src2_upperleft, sa2,
467 diff12.upperLeft(), diff12.accessor(),
468 saturating_subtract<SrcPixelType>());
469
470 const unsigned tally12 = quick_tally(diff12.begin(), diff12.end(), diff12.accessor(), overlap_threshold);
471
472 switch (boundary)
473 {
474 case OpenBoundaries:
475 vigra::ocl::distanceTransform(srcImageRange(diff12), destImage(dist12), background, norm);
476 break;
477
478 case HorizontalStrip: // FALLTHROUGH
479 case VerticalStrip: // FALLTHROUGH
480 case DoubleStrip:
481 periodicDistanceTransform(srcImageRange(diff12), destImage(dist12),
482 background, norm, boundary);
483 break;
484
485 default:
486 NEVER_REACHED("switch control expression \"boundary\" out of range");
487 }
488
489 if (Verbose >= VERBOSE_NFT_MESSAGES)
490 {
491 std::cerr << " 2/3";
492 std::cerr.flush();
493 }
494 IMAGETYPE<SrcPixelType> diff21(size);
495 vigra::omp::combineTwoImages(src2_upperleft, src2_upperleft + size, sa2,
496 src1_upperleft, sa1,
497 diff21.upperLeft(), diff21.accessor(),
498 saturating_subtract<SrcPixelType>());
499
500 const unsigned tally21 = quick_tally(diff21.begin(), diff21.end(), diff21.accessor(), overlap_threshold);
501
502 switch (boundary)
503 {
504 case OpenBoundaries:
505 vigra::ocl::distanceTransform(srcImageRange(diff21), destImage(dist21), background, norm);
506 break;
507
508 case HorizontalStrip: // FALLTHROUGH
509 case VerticalStrip: // FALLTHROUGH
510 case DoubleStrip:
511 periodicDistanceTransform(srcImageRange(diff21), destImage(dist21),
512 background, norm, boundary);
513 break;
514
515 default:
516 NEVER_REACHED("switch control expression \"boundary\" out of range");
517 }
518
519 if (Verbose >= VERBOSE_NFT_MESSAGES)
520 {
521 std::cerr << " 3/3";
522 std::cerr.flush();
523 }
524
525 const unsigned overlap_tally = std::max(tally12, tally21);
526 if (overlap_tally < overlap_threshold)
527 {
528 std::cerr << "\n" <<
529 command << ": excessive image overlap detected; too high risk of defective seam line\n" <<
530 command << ": note: remove at least one of the images" << std::endl;
531 #ifdef DEBUG
532 std::cerr <<
533 command << ": note: overlap area size is " << size << " > " << overlap_threshold << ", but only\n" <<
534 command << ": note: " << overlap_tally << " of " << size.x * size.y << " pixels do not overlap" <<
535 std::endl;
536 #endif
537 exit(1);
538 }
539
540 vigra::omp::combineTwoImages(dist12.upperLeft(), dist12.lowerRight(), dist12.accessor(),
541 dist21.upperLeft(), dist21.accessor(),
542 dest_upperleft, da,
543 ifThenElse(vigra::functor::Arg1() < vigra::functor::Arg2(),
544 vigra::functor::Param(DestPixelTraits::max()),
545 vigra::functor::Param(DestPixelTraits::zero())));
546
547 if (Verbose >= VERBOSE_NFT_MESSAGES)
548 {
549 std::cerr << std::endl;
550 }
551 }
552
553
554 template <class SrcImageIterator, class SrcAccessor,
555 class DestImageIterator, class DestAccessor>
556 inline void
nearestFeatureTransform(vigra::triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src1,vigra::pair<SrcImageIterator,SrcAccessor> src2,vigra::pair<DestImageIterator,DestAccessor> dest,nearest_neighbor_metric_t norm,boundary_t boundary)557 nearestFeatureTransform(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src1,
558 vigra::pair<SrcImageIterator, SrcAccessor> src2,
559 vigra::pair<DestImageIterator, DestAccessor> dest,
560 nearest_neighbor_metric_t norm, boundary_t boundary)
561 {
562 nearestFeatureTransform(src1.first, src1.second, src1.third,
563 src2.first, src2.second,
564 dest.first, dest.second,
565 norm, boundary);
566 }
567
568 } // namespace enblend
569
570 #endif /* __NEAREST_H__ */
571
572 // Local Variables:
573 // mode: c++
574 // End:
575