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