37 #ifndef VIGRA_EDGEDETECTION_HXX
38 #define VIGRA_EDGEDETECTION_HXX
44 #include "numerictraits.hxx"
45 #include "stdimage.hxx"
46 #include "stdimagefunctions.hxx"
47 #include "recursiveconvolution.hxx"
48 #include "separableconvolution.hxx"
49 #include "convolution.hxx"
50 #include "labelimage.hxx"
51 #include "mathutil.hxx"
52 #include "pixelneighborhood.hxx"
53 #include "linear_solve.hxx"
54 #include "functorexpression.hxx"
55 #include "multi_shape.hxx"
207 template <
class SrcIterator,
class SrcAccessor,
208 class DestIterator,
class DestAccessor,
209 class GradValue,
class DestValue>
211 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
212 DestIterator dul, DestAccessor da,
213 double scale, GradValue gradient_threshold, DestValue edge_marker)
215 vigra_precondition(scale > 0,
216 "differenceOfExponentialEdgeImage(): scale > 0 required.");
218 vigra_precondition(gradient_threshold > 0,
219 "differenceOfExponentialEdgeImage(): "
220 "gradient_threshold > 0 required.");
222 int w = slr.x - sul.x;
223 int h = slr.y - sul.y;
227 NumericTraits<typename SrcAccessor::value_type>::RealPromote
229 typedef BasicImage<TMPTYPE> TMPIMG;
240 typename TMPIMG::Iterator iy = smooth.upperLeft();
241 typename TMPIMG::Iterator ty = tmp.upperLeft();
242 DestIterator dy = dul;
244 const Diff2D right(1, 0);
245 const Diff2D bottom(0, 1);
248 TMPTYPE thresh = detail::RequiresExplicitCast<TMPTYPE>::cast((gradient_threshold * gradient_threshold) *
249 NumericTraits<TMPTYPE>::one());
250 TMPTYPE zero = NumericTraits<TMPTYPE>::zero();
252 for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, ++dy.y)
254 typename TMPIMG::Iterator ix = iy;
255 typename TMPIMG::Iterator tx = ty;
256 DestIterator dx = dy;
258 for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, ++dx.x)
260 TMPTYPE diff = *tx - *ix;
261 TMPTYPE gx = tx[right] - *tx;
262 TMPTYPE gy = tx[bottom] - *tx;
264 if((gx * gx > thresh) &&
265 (diff * (tx[right] - ix[right]) < zero))
269 da.set(edge_marker, dx, right);
273 da.set(edge_marker, dx);
276 if(((gy * gy > thresh) &&
277 (diff * (tx[bottom] - ix[bottom]) < zero)))
281 da.set(edge_marker, dx, bottom);
285 da.set(edge_marker, dx);
291 typename TMPIMG::Iterator ix = iy;
292 typename TMPIMG::Iterator tx = ty;
293 DestIterator dx = dy;
295 for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, ++dx.x)
297 TMPTYPE diff = *tx - *ix;
298 TMPTYPE gx = tx[right] - *tx;
300 if((gx * gx > thresh) &&
301 (diff * (tx[right] - ix[right]) < zero))
305 da.set(edge_marker, dx, right);
309 da.set(edge_marker, dx);
315 template <
class SrcIterator,
class SrcAccessor,
316 class DestIterator,
class DestAccessor,
320 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
321 DestIterator dul, DestAccessor da,
322 double scale, GradValue gradient_threshold)
325 scale, gradient_threshold, 1);
328 template <
class SrcIterator,
class SrcAccessor,
329 class DestIterator,
class DestAccessor,
330 class GradValue,
class DestValue>
333 pair<DestIterator, DestAccessor> dest,
334 double scale, GradValue gradient_threshold,
335 DestValue edge_marker)
338 dest.first, dest.second,
339 scale, gradient_threshold, edge_marker);
342 template <
class SrcIterator,
class SrcAccessor,
343 class DestIterator,
class DestAccessor,
347 pair<DestIterator, DestAccessor> dest,
348 double scale, GradValue gradient_threshold)
351 dest.first, dest.second,
352 scale, gradient_threshold, 1);
355 template <
class T1,
class S1,
357 class GradValue,
class DestValue>
360 MultiArrayView<2, T2, S2> dest,
362 GradValue gradient_threshold,
363 DestValue edge_marker)
365 vigra_precondition(src.shape() == dest.shape(),
366 "differenceOfExponentialEdgeImage(): shape mismatch between input and output.");
369 scale, gradient_threshold, edge_marker);
372 template <
class T1,
class S1,
377 MultiArrayView<2, T2, S2> dest,
378 double scale, GradValue gradient_threshold)
380 vigra_precondition(src.shape() == dest.shape(),
381 "differenceOfExponentialEdgeImage(): shape mismatch between input and output.");
384 scale, gradient_threshold, T2(1));
546 template <
class SrcIterator,
class SrcAccessor,
547 class DestIterator,
class DestAccessor,
548 class GradValue,
class DestValue>
550 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
551 DestIterator dul, DestAccessor da,
552 double scale, GradValue gradient_threshold,
553 DestValue edge_marker)
555 vigra_precondition(scale > 0,
556 "differenceOfExponentialCrackEdgeImage(): scale > 0 required.");
558 vigra_precondition(gradient_threshold > 0,
559 "differenceOfExponentialCrackEdgeImage(): "
560 "gradient_threshold > 0 required.");
562 int w = slr.x - sul.x;
563 int h = slr.y - sul.y;
567 NumericTraits<typename SrcAccessor::value_type>::RealPromote
569 typedef BasicImage<TMPTYPE> TMPIMG;
574 TMPTYPE zero = NumericTraits<TMPTYPE>::zero();
576 const Diff2D right(1,0);
577 const Diff2D bottom(0,1);
578 const Diff2D left(-1,0);
579 const Diff2D top(0,-1);
587 typename TMPIMG::Iterator iy = smooth.upperLeft();
588 typename TMPIMG::Iterator ty = tmp.upperLeft();
589 DestIterator dy = dul;
591 TMPTYPE thresh = detail::RequiresExplicitCast<TMPTYPE>::cast((gradient_threshold * gradient_threshold) *
592 NumericTraits<TMPTYPE>::one());
595 for(y=0; y<h-1; ++y, ++iy.y, ++ty.y, dy.y+=2)
597 typename TMPIMG::Iterator ix = iy;
598 typename TMPIMG::Iterator tx = ty;
599 DestIterator dx = dy;
601 for(
int x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2)
603 TMPTYPE diff = *tx - *ix;
604 TMPTYPE gx = tx[right] - *tx;
605 TMPTYPE gy = tx[bottom] - *tx;
607 if((gx * gx > thresh) &&
608 (diff * (tx[right] - ix[right]) < zero))
610 da.set(edge_marker, dx, right);
612 if((gy * gy > thresh) &&
613 (diff * (tx[bottom] - ix[bottom]) < zero))
615 da.set(edge_marker, dx, bottom);
619 TMPTYPE diff = *tx - *ix;
620 TMPTYPE gy = tx[bottom] - *tx;
622 if((gy * gy > thresh) &&
623 (diff * (tx[bottom] - ix[bottom]) < zero))
625 da.set(edge_marker, dx, bottom);
630 typename TMPIMG::Iterator ix = iy;
631 typename TMPIMG::Iterator tx = ty;
632 DestIterator dx = dy;
634 for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2)
636 TMPTYPE diff = *tx - *ix;
637 TMPTYPE gx = tx[right] - *tx;
639 if((gx * gx > thresh) &&
640 (diff * (tx[right] - ix[right]) < zero))
642 da.set(edge_marker, dx, right);
647 iy = smooth.upperLeft() + Diff2D(0,1);
648 ty = tmp.upperLeft() + Diff2D(0,1);
649 dy = dul + Diff2D(1,2);
651 const Diff2D topleft(-1,-1);
652 const Diff2D topright(1,-1);
653 const Diff2D bottomleft(-1,1);
654 const Diff2D bottomright(1,1);
657 for(y=0; y<h-2; ++y, ++iy.y, ++ty.y, dy.y+=2)
659 typename TMPIMG::Iterator ix = iy;
660 typename TMPIMG::Iterator tx = ty;
661 DestIterator dx = dy;
663 for(
int x=0; x<w-2; ++x, ++ix.x, ++tx.x, dx.x+=2)
665 if(da(dx) == edge_marker)
continue;
667 TMPTYPE diff = *tx - *ix;
669 if((diff * (tx[right] - ix[right]) < zero) &&
670 (((da(dx, bottomright) == edge_marker) &&
671 (da(dx, topleft) == edge_marker)) ||
672 ((da(dx, bottomleft) == edge_marker) &&
673 (da(dx, topright) == edge_marker))))
676 da.set(edge_marker, dx);
681 iy = smooth.upperLeft() + Diff2D(1,0);
682 ty = tmp.upperLeft() + Diff2D(1,0);
683 dy = dul + Diff2D(2,1);
686 for(y=0; y<h-2; ++y, ++iy.y, ++ty.y, dy.y+=2)
688 typename TMPIMG::Iterator ix = iy;
689 typename TMPIMG::Iterator tx = ty;
690 DestIterator dx = dy;
692 for(
int x=0; x<w-2; ++x, ++ix.x, ++tx.x, dx.x+=2)
694 if(da(dx) == edge_marker)
continue;
696 TMPTYPE diff = *tx - *ix;
698 if((diff * (tx[bottom] - ix[bottom]) < zero) &&
699 (((da(dx, bottomright) == edge_marker) &&
700 (da(dx, topleft) == edge_marker)) ||
701 ((da(dx, bottomleft) == edge_marker) &&
702 (da(dx, topright) == edge_marker))))
705 da.set(edge_marker, dx);
710 dy = dul + Diff2D(1,1);
713 for(y=0; y<h-1; ++y, dy.y+=2)
715 DestIterator dx = dy;
717 for(
int x=0; x<w-1; ++x, dx.x+=2)
719 const Diff2D dist[] = {right, top, left, bottom };
724 if(da(dx, dist[i]) == edge_marker)
break;
727 if(i < 4) da.set(edge_marker, dx);
732 template <
class SrcIterator,
class SrcAccessor,
733 class DestIterator,
class DestAccessor,
734 class GradValue,
class DestValue>
737 pair<DestIterator, DestAccessor> dest,
738 double scale, GradValue gradient_threshold,
739 DestValue edge_marker)
742 dest.first, dest.second,
743 scale, gradient_threshold, edge_marker);
746 template <
class T1,
class S1,
748 class GradValue,
class DestValue>
751 MultiArrayView<2, T2, S2> dest,
753 GradValue gradient_threshold,
754 DestValue edge_marker)
756 vigra_precondition(2*src.shape() - Shape2(1) == dest.shape(),
757 "differenceOfExponentialCrackEdgeImage(): shape mismatch between input and output.");
760 scale, gradient_threshold, edge_marker);
870 template <
class Iterator,
class Accessor,
class Value>
872 Iterator sul, Iterator slr, Accessor sa,
873 unsigned int min_edge_length, Value non_edge_marker)
875 int w = slr.x - sul.x;
876 int h = slr.y - sul.y;
882 int number_of_regions =
884 destImage(labels),
true, non_edge_marker);
886 ArrayOfRegionStatistics<FindROISize<int> >
887 region_stats(number_of_regions);
894 for(y=0; y<h; ++y, ++oy.y, ++ly.y)
899 for(x=0; x<w; ++x, ++ox.x, ++lx.x)
901 if(sa(ox) == non_edge_marker)
continue;
902 if((region_stats[*lx].count) < min_edge_length)
904 sa.set(non_edge_marker, ox);
910 template <
class Iterator,
class Accessor,
class Value>
913 unsigned int min_edge_length, Value non_edge_marker)
916 min_edge_length, non_edge_marker);
919 template <
class T,
class S,
class Value>
922 unsigned int min_edge_length, Value non_edge_marker)
925 min_edge_length, non_edge_marker);
1039 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1041 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1042 SrcValue edge_marker)
1044 int w = slr.x - sul.x;
1045 int h = slr.y - sul.y;
1047 vigra_precondition(w % 2 == 1 && h % 2 == 1,
1048 "closeGapsInCrackEdgeImage(): Input is not a crack edge image (must have odd-numbered shape).");
1050 int w2 = w / 2, h2 = h / 2, x, y;
1052 int count1, count2, count3;
1054 const Diff2D right(1,0);
1055 const Diff2D bottom(0,1);
1056 const Diff2D left(-1,0);
1057 const Diff2D top(0,-1);
1059 const Diff2D leftdist[] = { Diff2D(0, 0), Diff2D(-1, 1), Diff2D(-2, 0), Diff2D(-1, -1)};
1060 const Diff2D rightdist[] = { Diff2D(2, 0), Diff2D(1, 1), Diff2D(0, 0), Diff2D(1, -1)};
1061 const Diff2D topdist[] = { Diff2D(1, -1), Diff2D(0, 0), Diff2D(-1, -1), Diff2D(0, -2)};
1062 const Diff2D bottomdist[] = { Diff2D(1, 1), Diff2D(0, 2), Diff2D(-1, 1), Diff2D(0, 0)};
1066 SrcIterator sy = sul + Diff2D(0,1);
1070 for(y=0; y<h2; ++y, sy.y+=2)
1072 sx = sy + Diff2D(2,0);
1074 for(x=2; x<w2; ++x, sx.x+=2)
1076 if(sa(sx) == edge_marker)
continue;
1078 if(sa(sx, left) != edge_marker)
continue;
1079 if(sa(sx, right) != edge_marker)
continue;
1087 if(sa(sx, leftdist[i]) == edge_marker)
1092 if(sa(sx, rightdist[i]) == edge_marker)
1099 if(count1 <= 1 || count2 <= 1 || count3 == 15)
1101 sa.set(edge_marker, sx);
1106 sy = sul + Diff2D(1,2);
1109 for(y=2; y<h2; ++y, sy.y+=2)
1113 for(x=0; x<w2; ++x, sx.x+=2)
1115 if(sa(sx) == edge_marker)
continue;
1117 if(sa(sx, top) != edge_marker)
continue;
1118 if(sa(sx, bottom) != edge_marker)
continue;
1126 if(sa(sx, topdist[i]) == edge_marker)
1131 if(sa(sx, bottomdist[i]) == edge_marker)
1138 if(count1 <= 1 || count2 <= 1 || count3 == 15)
1140 sa.set(edge_marker, sx);
1146 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1149 SrcValue edge_marker)
1155 template <
class T,
class S,
class Value>
1284 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1286 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1287 SrcValue edge_marker, SrcValue background_marker)
1289 int w = slr.x - sul.x;
1290 int h = slr.y - sul.y;
1292 vigra_precondition(w % 2 == 1 && h % 2 == 1,
1293 "beautifyCrackEdgeImage(): Input is not a crack edge image (must have odd-numbered shape).");
1295 int w2 = w / 2, h2 = h / 2, x, y;
1297 SrcIterator sy = sul + Diff2D(1,1);
1300 const Diff2D right(1,0);
1301 const Diff2D bottom(0,1);
1302 const Diff2D left(-1,0);
1303 const Diff2D top(0,-1);
1306 for(y=0; y<h2; ++y, sy.y+=2)
1310 for(x=0; x<w2; ++x, sx.x+=2)
1312 if(sa(sx) != edge_marker)
continue;
1314 if(sa(sx, right) == edge_marker && sa(sx, left) == edge_marker)
continue;
1315 if(sa(sx, bottom) == edge_marker && sa(sx, top) == edge_marker)
continue;
1317 sa.set(background_marker, sx);
1322 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1325 SrcValue edge_marker, SrcValue background_marker)
1328 edge_marker, background_marker);
1331 template <
class T,
class S,
class Value>
1334 Value edge_marker, Value background_marker)
1337 edge_marker, background_marker);
1406 template <
class SrcIterator,
class SrcAccessor,
1407 class MagnitudeImage,
class BackInsertable,
class GradValue>
1408 void internalCannyFindEdgels(SrcIterator ul, SrcAccessor grad,
1409 MagnitudeImage
const & magnitude,
1410 BackInsertable & edgels, GradValue grad_thresh)
1412 typedef typename SrcAccessor::value_type PixelType;
1413 typedef typename PixelType::value_type ValueType;
1415 vigra_precondition(grad_thresh >= NumericTraits<GradValue>::zero(),
1416 "cannyFindEdgels(): gradient threshold must not be negative.");
1421 for(
int y=1; y<magnitude.height()-1; ++y, ++ul.y)
1423 SrcIterator ix = ul;
1424 for(
int x=1; x<magnitude.width()-1; ++x, ++ix.x)
1426 double mag = magnitude(x, y);
1427 if(mag <= grad_thresh)
1429 ValueType gradx = grad.getComponent(ix, 0);
1430 ValueType grady = grad.getComponent(ix, 1);
1440 double m1 = magnitude(x1, y1);
1441 double m3 = magnitude(x2, y2);
1443 if(m1 < mag && m3 <= mag)
1448 double del = 0.5 * (m1 - m3) / (m1 + m3 - 2.0*mag);
1453 if(orientation < 0.0)
1454 orientation += 2.0*M_PI;
1456 edgels.push_back(edgel);
1589 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1592 BackInsertable & edgels,
double scale)
1594 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
1595 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
1601 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1604 BackInsertable & edgels)
1606 using namespace functor;
1608 typedef typename SrcAccessor::value_type SrcType;
1609 typedef typename NumericTraits<typename SrcType::value_type>::RealPromote TmpType;
1610 BasicImage<TmpType> magnitude(lr-ul);
1614 internalCannyFindEdgels(ul, src, magnitude, edgels, NumericTraits<TmpType>::zero());
1617 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1619 cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1620 BackInsertable & edgels,
double scale)
1625 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1627 cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1628 BackInsertable & edgels)
1633 template <
class T,
class S,
class BackInsertable>
1636 BackInsertable & edgels,
double scale)
1641 template <
class T,
class S,
class BackInsertable>
1643 cannyEdgelList(MultiArrayView<2, TinyVector<T, 2>, S>
const & src,
1644 BackInsertable & edgels)
1773 template <
class SrcIterator,
class SrcAccessor,
1774 class BackInsertable,
class GradValue>
1777 BackInsertable & edgels,
double scale, GradValue grad_threshold)
1779 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
1780 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
1786 template <
class SrcIterator,
class SrcAccessor,
1787 class BackInsertable,
class GradValue>
1790 BackInsertable & edgels, GradValue grad_threshold)
1792 using namespace functor;
1794 typedef typename SrcAccessor::value_type SrcType;
1795 typedef typename NumericTraits<typename SrcType::value_type>::RealPromote TmpType;
1796 BasicImage<TmpType> magnitude(lr-ul);
1800 internalCannyFindEdgels(ul, src, magnitude, edgels, grad_threshold);
1803 template <
class SrcIterator,
class SrcAccessor,
1804 class BackInsertable,
class GradValue>
1807 BackInsertable & edgels,
double scale, GradValue grad_threshold)
1812 template <
class SrcIterator,
class SrcAccessor,
1813 class BackInsertable,
class GradValue>
1816 BackInsertable & edgels, GradValue grad_threshold)
1821 template <
class T,
class S,
1822 class BackInsertable,
class GradValue>
1825 BackInsertable & edgels,
1827 GradValue grad_threshold)
1832 template <
class T,
class S,
1833 class BackInsertable,
class GradValue>
1836 BackInsertable & edgels,
1837 GradValue grad_threshold)
1946 template <
class SrcIterator,
class SrcAccessor,
1947 class DestIterator,
class DestAccessor,
1948 class GradValue,
class DestValue>
1950 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1951 DestIterator dul, DestAccessor da,
1952 double scale, GradValue gradient_threshold, DestValue edge_marker)
1954 std::vector<Edgel> edgels;
1958 int w = slr.x - sul.x;
1959 int h = slr.y - sul.y;
1961 for(
unsigned int i=0; i<edgels.size(); ++i)
1963 Diff2D pix((
int)(edgels[i].x + 0.5), (
int)(edgels[i].y + 0.5));
1965 if(pix.x < 0 || pix.x >= w || pix.y < 0 || pix.y >= h)
1968 da.set(edge_marker, dul, pix);
1972 template <
class SrcIterator,
class SrcAccessor,
1973 class DestIterator,
class DestAccessor,
1974 class GradValue,
class DestValue>
1976 cannyEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1977 pair<DestIterator, DestAccessor> dest,
1978 double scale, GradValue gradient_threshold, DestValue edge_marker)
1981 dest.first, dest.second,
1982 scale, gradient_threshold, edge_marker);
1985 template <
class T1,
class S1,
1987 class GradValue,
class DestValue>
1990 MultiArrayView<2, T2, S2> dest,
1991 double scale, GradValue gradient_threshold, DestValue edge_marker)
1993 vigra_precondition(src.shape() == dest.shape(),
1994 "cannyEdgeImage(): shape mismatch between input and output.");
1997 scale, gradient_threshold, edge_marker);
2004 template <
class DestIterator>
2005 int neighborhoodConfiguration(DestIterator dul)
2009 for(
int i=0; i<8; ++i, --c)
2011 v = (v << 1) | ((*c != 0) ? 1 : 0);
2017 template <
class GradValue>
2023 SimplePoint(Diff2D
const & p, GradValue g)
2027 bool operator<(SimplePoint
const & o)
const
2029 return grad < o.grad;
2032 bool operator>(SimplePoint
const & o)
const
2034 return grad > o.grad;
2038 template <
class SrcIterator,
class SrcAccessor,
2039 class DestIterator,
class DestAccessor,
2040 class GradValue,
class DestValue>
2041 void cannyEdgeImageFromGrad(
2042 SrcIterator sul, SrcIterator slr, SrcAccessor grad,
2043 DestIterator dul, DestAccessor da,
2044 GradValue gradient_threshold, DestValue edge_marker)
2046 typedef typename SrcAccessor::value_type PixelType;
2047 typedef typename NormTraits<PixelType>::SquaredNormType NormType;
2049 NormType zero = NumericTraits<NormType>::zero();
2050 double tan22_5 = M_SQRT2 - 1.0;
2051 typename NormTraits<GradValue>::SquaredNormType g2thresh =
squaredNorm(gradient_threshold);
2053 int w = slr.x - sul.x;
2054 int h = slr.y - sul.y;
2060 for(
int y = 1; y < h-1; ++y, ++sul.y, ++dul.y)
2062 SrcIterator sx = sul;
2063 DestIterator dx = dul;
2064 for(
int x = 1; x < w-1; ++x, ++sx.x, ++dx.x)
2066 PixelType g = grad(sx);
2071 NormType g2n1, g2n3;
2073 if(
abs(g[1]) < tan22_5*
abs(g[0]))
2079 else if(
abs(g[0]) < tan22_5*
abs(g[1]))
2085 else if(g[0]*g[1] < zero)
2098 if(g2n1 < g2n && g2n3 <= g2n)
2100 da.set(edge_marker, dx);
2232 template <
class SrcIterator,
class SrcAccessor,
2233 class DestIterator,
class DestAccessor,
2234 class GradValue,
class DestValue>
2236 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
2237 DestIterator dul, DestAccessor da,
2238 GradValue gradient_threshold,
2239 DestValue edge_marker,
bool addBorder =
true)
2241 vigra_precondition(gradient_threshold >= NumericTraits<GradValue>::zero(),
2242 "cannyEdgeImageFromGradWithThinning(): gradient threshold must not be negative.");
2244 int w = slr.x - sul.x;
2245 int h = slr.y - sul.y;
2252 detail::cannyEdgeImageFromGrad(sul, slr, sa, eul, ea, gradient_threshold, 1);
2254 bool isSimplePoint[256] = {
2255 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
2256 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
2257 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
2258 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
2259 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1,
2260 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
2261 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0,
2262 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
2263 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
2264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2265 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
2266 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
2267 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0,
2268 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1,
2276 typedef detail::SimplePoint<GradValue> SP;
2278 std::priority_queue<SP, std::vector<SP>, std::greater<SP> > pqueue;
2281 for(; p.y < h2; ++p.y)
2283 for(p.x = 0; p.x < w2; ++p.x)
2288 int v = detail::neighborhoodConfiguration(e);
2289 if(isSimplePoint[v])
2291 pqueue.push(SP(p,
norm(sa(sul+p))));
2297 const Diff2D dist[] = { Diff2D(-1,0), Diff2D(0,-1), Diff2D(1,0), Diff2D(0,1) };
2299 while(pqueue.size())
2301 p = pqueue.top().point;
2305 int v = detail::neighborhoodConfiguration(e);
2306 if(!isSimplePoint[v])
2311 for(
int i=0; i<4; ++i)
2313 Diff2D pneu = p + dist[i];
2314 if(pneu.x == -1 || pneu.y == -1 || pneu.x == w2 || pneu.y == h2)
2320 v = detail::neighborhoodConfiguration(eneu);
2321 if(isSimplePoint[v])
2323 pqueue.push(SP(pneu,
norm(sa(sul+pneu))));
2330 initImageIf(destIterRange(dul, dul+Diff2D(w,h), da),
2331 maskImage(edgeImage), edge_marker);
2334 template <
class SrcIterator,
class SrcAccessor,
2335 class DestIterator,
class DestAccessor,
2336 class GradValue,
class DestValue>
2338 triple<SrcIterator, SrcIterator, SrcAccessor> src,
2339 pair<DestIterator, DestAccessor> dest,
2340 GradValue gradient_threshold,
2341 DestValue edge_marker,
bool addBorder =
true)
2344 dest.first, dest.second,
2345 gradient_threshold, edge_marker, addBorder);
2348 template <
class T1,
class S1,
2350 class GradValue,
class DestValue>
2353 MultiArrayView<2, T2, S2> dest,
2354 GradValue gradient_threshold,
2355 DestValue edge_marker,
bool addBorder =
true)
2357 vigra_precondition(src.shape() == dest.shape(),
2358 "cannyEdgeImageFromGradWithThinning(): shape mismatch between input and output.");
2361 gradient_threshold, edge_marker, addBorder);
2468 template <
class SrcIterator,
class SrcAccessor,
2469 class DestIterator,
class DestAccessor,
2470 class GradValue,
class DestValue>
2472 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
2473 DestIterator dul, DestAccessor da,
2474 double scale, GradValue gradient_threshold,
2475 DestValue edge_marker,
bool addBorder =
true)
2478 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
2479 BasicImage<TinyVector<TmpType, 2> > grad(slr-sul);
2482 gradient_threshold, edge_marker, addBorder);
2485 template <
class SrcIterator,
class SrcAccessor,
2486 class DestIterator,
class DestAccessor,
2487 class GradValue,
class DestValue>
2490 pair<DestIterator, DestAccessor> dest,
2491 double scale, GradValue gradient_threshold,
2492 DestValue edge_marker,
bool addBorder =
true)
2495 dest.first, dest.second,
2496 scale, gradient_threshold, edge_marker, addBorder);
2499 template <
class T1,
class S1,
2501 class GradValue,
class DestValue>
2504 MultiArrayView<2, T2, S2> dest,
2505 double scale, GradValue gradient_threshold,
2506 DestValue edge_marker,
bool addBorder =
true)
2508 vigra_precondition(src.shape() == dest.shape(),
2509 "cannyEdgeImageWithThinning(): shape mismatch between input and output.");
2512 scale, gradient_threshold, edge_marker, addBorder);
2517 template <
class SrcIterator,
class SrcAccessor,
2518 class MaskImage,
class BackInsertable,
class GradValue>
2519 void internalCannyFindEdgels3x3(SrcIterator ul, SrcAccessor grad,
2520 MaskImage
const & mask,
2521 BackInsertable & edgels,
2522 GradValue grad_thresh)
2524 typedef typename SrcAccessor::value_type PixelType;
2525 typedef typename PixelType::value_type ValueType;
2527 vigra_precondition(grad_thresh >= NumericTraits<GradValue>::zero(),
2528 "cannyFindEdgels3x3(): gradient threshold must not be negative.");
2531 for(
int y=1; y<mask.height()-1; ++y, ++ul.y)
2533 SrcIterator ix = ul;
2534 for(
int x=1; x<mask.width()-1; ++x, ++ix.x)
2539 ValueType gradx = grad.getComponent(ix, 0);
2540 ValueType grady = grad.getComponent(ix, 1);
2541 double mag =
hypot(gradx, grady);
2542 if(mag <= grad_thresh)
2544 double c = gradx / mag,
2547 Matrix<double> ml(3,3), mr(3,1), l(3,1), r(3,1);
2550 for(
int yy = -1; yy <= 1; ++yy)
2552 for(
int xx = -1; xx <= 1; ++xx)
2554 double u = c*xx + s*yy;
2555 double v =
norm(grad(ix, Diff2D(xx, yy)));
2568 double del = -r(1,0) / 2.0 / r(2,0);
2569 if(std::fabs(del) > 1.5)
2575 if(orientation < 0.0)
2576 orientation += 2.0*M_PI;
2578 edgels.push_back(edgel);
2706 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2709 BackInsertable & edgels,
double scale)
2711 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
2712 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
2718 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2721 BackInsertable & edgels)
2723 typedef typename NormTraits<typename SrcAccessor::value_type>::NormType NormType;
2730 internalCannyFindEdgels3x3(ul, src,
edges, edgels, NumericTraits<NormType>::zero());
2733 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2736 BackInsertable & edgels,
double scale)
2741 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2744 BackInsertable & edgels)
2749 template <
class T,
class S,
class BackInsertable>
2752 BackInsertable & edgels,
double scale)
2757 template <
class T,
class S,
class BackInsertable>
2760 BackInsertable & edgels)
2886 template <
class SrcIterator,
class SrcAccessor,
2887 class BackInsertable,
class GradValue>
2890 BackInsertable & edgels,
double scale, GradValue grad_thresh)
2892 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
2893 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
2899 template <
class SrcIterator,
class SrcAccessor,
2900 class BackInsertable,
class GradValue>
2903 BackInsertable & edgels, GradValue grad_thresh)
2910 internalCannyFindEdgels3x3(ul, src,
edges, edgels, grad_thresh);
2913 template <
class SrcIterator,
class SrcAccessor,
2914 class BackInsertable,
class GradValue>
2917 BackInsertable & edgels,
double scale, GradValue grad_thresh)
2922 template <
class SrcIterator,
class SrcAccessor,
2923 class BackInsertable,
class GradValue>
2926 BackInsertable & edgels, GradValue grad_thresh)
2931 template <
class T,
class S,
2932 class BackInsertable,
class GradValue>
2935 BackInsertable & edgels,
double scale, GradValue grad_thresh)
2940 template <
class T,
class S,
2941 class BackInsertable,
class GradValue>
2944 BackInsertable & edgels,
2945 GradValue grad_thresh)
2999 #endif // VIGRA_EDGEDETECTION_HXX
FixedPoint16< 2, OverflowHandling > atan2(FixedPoint16< IntBits, OverflowHandling > y, FixedPoint16< IntBits, OverflowHandling > x)
Arctangent. Accuracy better than 1/3 degree (9 significant bits).
Definition: fixedpoint.hxx:1654
Definition: pixelneighborhood.hxx:443
value_type x
Definition: edgedetection.hxx:1353
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
IteratorTraits< traverser >::DefaultAccessor Accessor
Definition: basicimage.hxx:573
void differenceOfExponentialCrackEdgeImage(...)
Detect and mark edges in a crack edge image using the Shen/Castan zero-crossing detector.
void beautifyCrackEdgeImage(...)
Beautify crack edge image for visualization.
FFTWComplex< R >::SquaredNormType squaredNorm(const FFTWComplex< R > &a)
squared norm (= squared magnitude)
Definition: fftw3.hxx:1044
value_type y
Definition: edgedetection.hxx:1357
void removeShortEdges(...)
Remove short edges from an edge image.
void inspectTwoImages(...)
Apply read-only functor to every pixel of both images.
void cannyEdgeImageWithThinning(...)
Detect and mark edges in an edge image using Canny's algorithm.
value_type orientation
The edgel's orientation.
Definition: edgedetection.hxx:1395
BasicImage< UInt8 > UInt8Image
Definition: stdimage.hxx:71
void cannyEdgelListThreshold(...)
Canny's edge detector with thresholding.
BasicImageIterator< PIXELTYPE, PIXELTYPE ** > traverser
Definition: basicimage.hxx:528
FixedPoint16< IntBits, OverflowHandling > hypot(FixedPoint16< IntBits, OverflowHandling > v1, FixedPoint16< IntBits, OverflowHandling > v2)
Length of hypotenuse.
Definition: fixedpoint.hxx:1640
unsigned int labelImageWithBackground(...)
Find the connected components of a segmented image, excluding the background from labeling...
BasicImage< UInt8 > BImage
Definition: stdimage.hxx:62
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
void cannyEdgeImage(...)
Detect and mark edges in an edge image using Canny's algorithm.
void cannyEdgelList(...)
Simple implementation of Canny's edge detector.
void closeGapsInCrackEdgeImage(...)
Close one-pixel wide gaps in a cell grid edge image.
void cannyEdgelList3x3Threshold(...)
Improved implementation of Canny's edge detector with thresholding.
BasicImageIterator< PIXELTYPE, PIXELTYPE ** > Iterator
Definition: basicimage.hxx:532
void cannyEdgeImageFromGradWithThinning(...)
Detect and mark edges in an edge image using Canny's algorithm.
void cannyEdgelList3x3(...)
Improved implementation of Canny's edge detector.
std::pair< typename vigra::GridGraph< N, DirectedTag >::edge_iterator, typename vigra::GridGraph< N, DirectedTag >::edge_iterator > edges(vigra::GridGraph< N, DirectedTag > const &g)
Get a (begin, end) iterator pair for the edges of graph g (API: boost).
Definition: multi_gridgraph.hxx:2966
void recursiveSmoothX(...)
Performs 1 dimensional recursive smoothing in x direction.
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
value_type strength
Definition: edgedetection.hxx:1361
void recursiveSmoothY(...)
Performs 1 dimensional recursive smoothing in y direction.
void outer(const MultiArrayView< 2, T, C1 > &x, const MultiArrayView< 2, T, C2 > &y, MultiArrayView< 2, T, C3 > &r)
Definition: matrix.hxx:1459
float value_type
Definition: edgedetection.hxx:1349
bool operator<(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r)
less than
Definition: fixedpoint.hxx:512
void gaussianGradient(...)
Calculate the gradient vector by means of a 1st derivatives of Gaussian filter.
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
bool operator>(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r)
greater
Definition: fixedpoint.hxx:530
void differenceOfExponentialEdgeImage(...)
Detect and mark edges in an edge image using the Shen/Castan zero-crossing detector.
void initImageBorder(...)
Write value to the specified border pixels in the image.
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition: fixedpoint.hxx:667
Definition: edgedetection.hxx:1343
PIXELTYPE value_type
Definition: basicimage.hxx:481
void initImageIf(...)
Write value to pixel in the image if mask is true.
BasicImage< Int32 > IImage
Definition: stdimage.hxx:116