37 #ifndef VIGRA_EDGEDETECTION_HXX
38 #define VIGRA_EDGEDETECTION_HXX
43 #include "utilities.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);
629 typename TMPIMG::Iterator ix = iy;
630 typename TMPIMG::Iterator tx = ty;
631 DestIterator dx = dy;
633 for(x=0; x<w-1; ++x, ++ix.x, ++tx.x, dx.x+=2)
635 TMPTYPE diff = *tx - *ix;
636 TMPTYPE gx = tx[right] - *tx;
638 if((gx * gx > thresh) &&
639 (diff * (tx[right] - ix[right]) < zero))
641 da.set(edge_marker, dx, right);
645 iy = smooth.upperLeft() + Diff2D(0,1);
646 ty = tmp.upperLeft() + Diff2D(0,1);
647 dy = dul + Diff2D(1,2);
649 const Diff2D topleft(-1,-1);
650 const Diff2D topright(1,-1);
651 const Diff2D bottomleft(-1,1);
652 const Diff2D bottomright(1,1);
655 for(y=0; y<h-2; ++y, ++iy.y, ++ty.y, dy.y+=2)
657 typename TMPIMG::Iterator ix = iy;
658 typename TMPIMG::Iterator tx = ty;
659 DestIterator dx = dy;
661 for(
int x=0; x<w-2; ++x, ++ix.x, ++tx.x, dx.x+=2)
663 if(da(dx) == edge_marker)
continue;
665 TMPTYPE diff = *tx - *ix;
667 if((diff * (tx[right] - ix[right]) < zero) &&
668 (((da(dx, bottomright) == edge_marker) &&
669 (da(dx, topleft) == edge_marker)) ||
670 ((da(dx, bottomleft) == edge_marker) &&
671 (da(dx, topright) == edge_marker))))
674 da.set(edge_marker, dx);
679 iy = smooth.upperLeft() + Diff2D(1,0);
680 ty = tmp.upperLeft() + Diff2D(1,0);
681 dy = dul + Diff2D(2,1);
684 for(y=0; y<h-2; ++y, ++iy.y, ++ty.y, dy.y+=2)
686 typename TMPIMG::Iterator ix = iy;
687 typename TMPIMG::Iterator tx = ty;
688 DestIterator dx = dy;
690 for(
int x=0; x<w-2; ++x, ++ix.x, ++tx.x, dx.x+=2)
692 if(da(dx) == edge_marker)
continue;
694 TMPTYPE diff = *tx - *ix;
696 if((diff * (tx[bottom] - ix[bottom]) < zero) &&
697 (((da(dx, bottomright) == edge_marker) &&
698 (da(dx, topleft) == edge_marker)) ||
699 ((da(dx, bottomleft) == edge_marker) &&
700 (da(dx, topright) == edge_marker))))
703 da.set(edge_marker, dx);
708 dy = dul + Diff2D(1,1);
711 for(y=0; y<h-1; ++y, dy.y+=2)
713 DestIterator dx = dy;
715 for(
int x=0; x<w-1; ++x, dx.x+=2)
717 const Diff2D dist[] = {right, top, left, bottom };
722 if(da(dx, dist[i]) == edge_marker)
break;
725 if(i < 4) da.set(edge_marker, dx);
730 template <
class SrcIterator,
class SrcAccessor,
731 class DestIterator,
class DestAccessor,
732 class GradValue,
class DestValue>
735 pair<DestIterator, DestAccessor> dest,
736 double scale, GradValue gradient_threshold,
737 DestValue edge_marker)
740 dest.first, dest.second,
741 scale, gradient_threshold, edge_marker);
744 template <
class T1,
class S1,
746 class GradValue,
class DestValue>
749 MultiArrayView<2, T2, S2> dest,
751 GradValue gradient_threshold,
752 DestValue edge_marker)
754 vigra_precondition(2*src.shape() -
Shape2(1) == dest.shape(),
755 "differenceOfExponentialCrackEdgeImage(): shape mismatch between input and output.");
758 scale, gradient_threshold, edge_marker);
868 template <
class Iterator,
class Accessor,
class Value>
870 Iterator sul, Iterator slr, Accessor sa,
871 unsigned int min_edge_length, Value non_edge_marker)
873 int w = slr.x - sul.x;
874 int h = slr.y - sul.y;
880 int number_of_regions =
882 destImage(labels),
true, non_edge_marker);
884 ArrayOfRegionStatistics<FindROISize<int> >
885 region_stats(number_of_regions);
892 for(y=0; y<h; ++y, ++oy.y, ++ly.y)
897 for(x=0; x<w; ++x, ++ox.x, ++lx.x)
899 if(sa(ox) == non_edge_marker)
continue;
900 if((region_stats[*lx].count) < min_edge_length)
902 sa.set(non_edge_marker, ox);
908 template <
class Iterator,
class Accessor,
class Value>
911 unsigned int min_edge_length, Value non_edge_marker)
914 min_edge_length, non_edge_marker);
917 template <
class T,
class S,
class Value>
920 unsigned int min_edge_length, Value non_edge_marker)
923 min_edge_length, non_edge_marker);
1037 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1039 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1040 SrcValue edge_marker)
1042 int w = slr.x - sul.x;
1043 int h = slr.y - sul.y;
1045 vigra_precondition(w % 2 == 1 && h % 2 == 1,
1046 "closeGapsInCrackEdgeImage(): Input is not a crack edge image (must have odd-numbered shape).");
1048 int w2 = w / 2, h2 = h / 2, x, y;
1050 int count1, count2, count3;
1052 const Diff2D right(1,0);
1053 const Diff2D bottom(0,1);
1054 const Diff2D left(-1,0);
1055 const Diff2D top(0,-1);
1057 const Diff2D leftdist[] = { Diff2D(0, 0), Diff2D(-1, 1), Diff2D(-2, 0), Diff2D(-1, -1)};
1058 const Diff2D rightdist[] = { Diff2D(2, 0), Diff2D(1, 1), Diff2D(0, 0), Diff2D(1, -1)};
1059 const Diff2D topdist[] = { Diff2D(1, -1), Diff2D(0, 0), Diff2D(-1, -1), Diff2D(0, -2)};
1060 const Diff2D bottomdist[] = { Diff2D(1, 1), Diff2D(0, 2), Diff2D(-1, 1), Diff2D(0, 0)};
1064 SrcIterator sy = sul + Diff2D(0,1);
1068 for(y=0; y<h2; ++y, sy.y+=2)
1070 sx = sy + Diff2D(2,0);
1072 for(x=2; x<w2; ++x, sx.x+=2)
1074 if(sa(sx) == edge_marker)
continue;
1076 if(sa(sx, left) != edge_marker)
continue;
1077 if(sa(sx, right) != edge_marker)
continue;
1085 if(sa(sx, leftdist[i]) == edge_marker)
1090 if(sa(sx, rightdist[i]) == edge_marker)
1097 if(count1 <= 1 || count2 <= 1 || count3 == 15)
1099 sa.set(edge_marker, sx);
1104 sy = sul + Diff2D(1,2);
1107 for(y=2; y<h2; ++y, sy.y+=2)
1111 for(x=0; x<w2; ++x, sx.x+=2)
1113 if(sa(sx) == edge_marker)
continue;
1115 if(sa(sx, top) != edge_marker)
continue;
1116 if(sa(sx, bottom) != edge_marker)
continue;
1124 if(sa(sx, topdist[i]) == edge_marker)
1129 if(sa(sx, bottomdist[i]) == edge_marker)
1136 if(count1 <= 1 || count2 <= 1 || count3 == 15)
1138 sa.set(edge_marker, sx);
1144 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1147 SrcValue edge_marker)
1153 template <
class T,
class S,
class Value>
1282 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1284 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1285 SrcValue edge_marker, SrcValue background_marker)
1287 int w = slr.x - sul.x;
1288 int h = slr.y - sul.y;
1290 vigra_precondition(w % 2 == 1 && h % 2 == 1,
1291 "beautifyCrackEdgeImage(): Input is not a crack edge image (must have odd-numbered shape).");
1293 int w2 = w / 2, h2 = h / 2, x, y;
1295 SrcIterator sy = sul + Diff2D(1,1);
1298 const Diff2D right(1,0);
1299 const Diff2D bottom(0,1);
1300 const Diff2D left(-1,0);
1301 const Diff2D top(0,-1);
1304 for(y=0; y<h2; ++y, sy.y+=2)
1308 for(x=0; x<w2; ++x, sx.x+=2)
1310 if(sa(sx) != edge_marker)
continue;
1312 if(sa(sx, right) == edge_marker && sa(sx, left) == edge_marker)
continue;
1313 if(sa(sx, bottom) == edge_marker && sa(sx, top) == edge_marker)
continue;
1315 sa.set(background_marker, sx);
1320 template <
class SrcIterator,
class SrcAccessor,
class SrcValue>
1323 SrcValue edge_marker, SrcValue background_marker)
1326 edge_marker, background_marker);
1329 template <
class T,
class S,
class Value>
1332 Value edge_marker, Value background_marker)
1335 edge_marker, background_marker);
1404 template <
class SrcIterator,
class SrcAccessor,
1405 class MagnitudeImage,
class BackInsertable,
class GradValue>
1406 void internalCannyFindEdgels(SrcIterator ul, SrcAccessor grad,
1407 MagnitudeImage
const & magnitude,
1408 BackInsertable & edgels, GradValue grad_thresh)
1410 typedef typename SrcAccessor::value_type PixelType;
1411 typedef typename PixelType::value_type ValueType;
1413 vigra_precondition(grad_thresh >= NumericTraits<GradValue>::zero(),
1414 "cannyFindEdgels(): gradient threshold must not be negative.");
1419 for(
int y=1; y<magnitude.height()-1; ++y, ++ul.y)
1421 SrcIterator ix = ul;
1422 for(
int x=1; x<magnitude.width()-1; ++x, ++ix.x)
1424 double mag = magnitude(x, y);
1425 if(mag <= grad_thresh)
1427 ValueType gradx = grad.getComponent(ix, 0);
1428 ValueType grady = grad.getComponent(ix, 1);
1438 double m1 = magnitude(x1, y1);
1439 double m3 = magnitude(x2, y2);
1441 if(m1 < mag && m3 <= mag)
1446 double del = 0.5 * (m1 - m3) / (m1 + m3 - 2.0*mag);
1451 if(orientation < 0.0)
1452 orientation += 2.0*M_PI;
1454 edgels.push_back(edgel);
1587 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1590 BackInsertable & edgels,
double scale)
1592 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
1593 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
1599 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1602 BackInsertable & edgels)
1604 using namespace functor;
1606 typedef typename SrcAccessor::value_type SrcType;
1607 typedef typename NumericTraits<typename SrcType::value_type>::RealPromote TmpType;
1608 BasicImage<TmpType> magnitude(lr-ul);
1612 internalCannyFindEdgels(ul, src, magnitude, edgels, NumericTraits<TmpType>::zero());
1615 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1617 cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1618 BackInsertable & edgels,
double scale)
1623 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
1625 cannyEdgelList(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1626 BackInsertable & edgels)
1631 template <
class T,
class S,
class BackInsertable>
1634 BackInsertable & edgels,
double scale)
1639 template <
class T,
class S,
class BackInsertable>
1641 cannyEdgelList(MultiArrayView<2, TinyVector<T, 2>, S>
const & src,
1642 BackInsertable & edgels)
1771 template <
class SrcIterator,
class SrcAccessor,
1772 class BackInsertable,
class GradValue>
1775 BackInsertable & edgels,
double scale, GradValue grad_threshold)
1777 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
1778 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
1784 template <
class SrcIterator,
class SrcAccessor,
1785 class BackInsertable,
class GradValue>
1788 BackInsertable & edgels, GradValue grad_threshold)
1790 using namespace functor;
1792 typedef typename SrcAccessor::value_type SrcType;
1793 typedef typename NumericTraits<typename SrcType::value_type>::RealPromote TmpType;
1794 BasicImage<TmpType> magnitude(lr-ul);
1798 internalCannyFindEdgels(ul, src, magnitude, edgels, grad_threshold);
1801 template <
class SrcIterator,
class SrcAccessor,
1802 class BackInsertable,
class GradValue>
1805 BackInsertable & edgels,
double scale, GradValue grad_threshold)
1810 template <
class SrcIterator,
class SrcAccessor,
1811 class BackInsertable,
class GradValue>
1814 BackInsertable & edgels, GradValue grad_threshold)
1819 template <
class T,
class S,
1820 class BackInsertable,
class GradValue>
1823 BackInsertable & edgels,
1825 GradValue grad_threshold)
1830 template <
class T,
class S,
1831 class BackInsertable,
class GradValue>
1834 BackInsertable & edgels,
1835 GradValue grad_threshold)
1944 template <
class SrcIterator,
class SrcAccessor,
1945 class DestIterator,
class DestAccessor,
1946 class GradValue,
class DestValue>
1948 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
1949 DestIterator dul, DestAccessor da,
1950 double scale, GradValue gradient_threshold, DestValue edge_marker)
1952 std::vector<Edgel> edgels;
1956 int w = slr.x - sul.x;
1957 int h = slr.y - sul.y;
1959 for(
unsigned int i=0; i<edgels.size(); ++i)
1961 Diff2D pix((
int)(edgels[i].x + 0.5), (
int)(edgels[i].y + 0.5));
1963 if(pix.x < 0 || pix.x >= w || pix.y < 0 || pix.y >= h)
1966 da.set(edge_marker, dul, pix);
1970 template <
class SrcIterator,
class SrcAccessor,
1971 class DestIterator,
class DestAccessor,
1972 class GradValue,
class DestValue>
1974 cannyEdgeImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1975 pair<DestIterator, DestAccessor> dest,
1976 double scale, GradValue gradient_threshold, DestValue edge_marker)
1979 dest.first, dest.second,
1980 scale, gradient_threshold, edge_marker);
1983 template <
class T1,
class S1,
1985 class GradValue,
class DestValue>
1988 MultiArrayView<2, T2, S2> dest,
1989 double scale, GradValue gradient_threshold, DestValue edge_marker)
1991 vigra_precondition(src.shape() == dest.shape(),
1992 "cannyEdgeImage(): shape mismatch between input and output.");
1995 scale, gradient_threshold, edge_marker);
2002 template <
class DestIterator>
2003 int neighborhoodConfiguration(DestIterator dul)
2007 for(
int i=0; i<8; ++i, --c)
2009 v = (v << 1) | ((*c != 0) ? 1 : 0);
2015 template <
class GradValue>
2021 SimplePoint(Diff2D
const & p, GradValue g)
2025 bool operator<(SimplePoint
const & o)
const
2027 return grad < o.grad;
2030 bool operator>(SimplePoint
const & o)
const
2032 return grad > o.grad;
2036 template <
class SrcIterator,
class SrcAccessor,
2037 class DestIterator,
class DestAccessor,
2038 class GradValue,
class DestValue>
2039 void cannyEdgeImageFromGrad(
2040 SrcIterator sul, SrcIterator slr, SrcAccessor grad,
2041 DestIterator dul, DestAccessor da,
2042 GradValue gradient_threshold, DestValue edge_marker)
2044 typedef typename SrcAccessor::value_type PixelType;
2045 typedef typename NormTraits<PixelType>::SquaredNormType NormType;
2047 NormType zero = NumericTraits<NormType>::zero();
2048 double tan22_5 = M_SQRT2 - 1.0;
2049 typename NormTraits<GradValue>::SquaredNormType g2thresh =
squaredNorm(gradient_threshold);
2051 int w = slr.x - sul.x;
2052 int h = slr.y - sul.y;
2058 for(
int y = 1; y < h-1; ++y, ++sul.y, ++dul.y)
2060 SrcIterator sx = sul;
2061 DestIterator dx = dul;
2062 for(
int x = 1; x < w-1; ++x, ++sx.x, ++dx.x)
2064 PixelType g = grad(sx);
2069 NormType g2n1, g2n3;
2071 if(
abs(g[1]) < tan22_5*
abs(g[0]))
2077 else if(
abs(g[0]) < tan22_5*
abs(g[1]))
2083 else if(g[0]*g[1] < zero)
2096 if(g2n1 < g2n && g2n3 <= g2n)
2098 da.set(edge_marker, dx);
2230 template <
class SrcIterator,
class SrcAccessor,
2231 class DestIterator,
class DestAccessor,
2232 class GradValue,
class DestValue>
2234 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
2235 DestIterator dul, DestAccessor da,
2236 GradValue gradient_threshold,
2237 DestValue edge_marker,
bool addBorder =
true)
2239 int w = slr.x - sul.x;
2240 int h = slr.y - sul.y;
2247 detail::cannyEdgeImageFromGrad(sul, slr, sa, eul, ea, gradient_threshold, 1);
2249 bool isSimplePoint[256] = {
2250 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
2251 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
2252 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
2253 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
2254 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1,
2255 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
2256 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0,
2257 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
2258 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
2259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2260 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
2261 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
2262 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0,
2263 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1,
2271 typedef detail::SimplePoint<GradValue> SP;
2273 std::priority_queue<SP, std::vector<SP>, std::greater<SP> > pqueue;
2276 for(; p.y < h2; ++p.y)
2278 for(p.x = 0; p.x < w2; ++p.x)
2283 int v = detail::neighborhoodConfiguration(e);
2284 if(isSimplePoint[v])
2286 pqueue.push(SP(p,
norm(sa(sul+p))));
2292 const Diff2D dist[] = { Diff2D(-1,0), Diff2D(0,-1), Diff2D(1,0), Diff2D(0,1) };
2294 while(pqueue.size())
2296 p = pqueue.top().point;
2300 int v = detail::neighborhoodConfiguration(e);
2301 if(!isSimplePoint[v])
2306 for(
int i=0; i<4; ++i)
2308 Diff2D pneu = p + dist[i];
2309 if(pneu.x == -1 || pneu.y == -1 || pneu.x == w2 || pneu.y == h2)
2315 int v = detail::neighborhoodConfiguration(eneu);
2316 if(isSimplePoint[v])
2318 pqueue.push(SP(pneu,
norm(sa(sul+pneu))));
2325 initImageIf(destIterRange(dul, dul+Diff2D(w,h), da),
2326 maskImage(edgeImage), edge_marker);
2329 template <
class SrcIterator,
class SrcAccessor,
2330 class DestIterator,
class DestAccessor,
2331 class GradValue,
class DestValue>
2333 triple<SrcIterator, SrcIterator, SrcAccessor> src,
2334 pair<DestIterator, DestAccessor> dest,
2335 GradValue gradient_threshold,
2336 DestValue edge_marker,
bool addBorder =
true)
2339 dest.first, dest.second,
2340 gradient_threshold, edge_marker, addBorder);
2343 template <
class T1,
class S1,
2345 class GradValue,
class DestValue>
2348 MultiArrayView<2, T2, S2> dest,
2349 GradValue gradient_threshold,
2350 DestValue edge_marker,
bool addBorder =
true)
2352 vigra_precondition(src.shape() == dest.shape(),
2353 "cannyEdgeImageFromGradWithThinning(): shape mismatch between input and output.");
2356 gradient_threshold, edge_marker, addBorder);
2463 template <
class SrcIterator,
class SrcAccessor,
2464 class DestIterator,
class DestAccessor,
2465 class GradValue,
class DestValue>
2467 SrcIterator sul, SrcIterator slr, SrcAccessor sa,
2468 DestIterator dul, DestAccessor da,
2469 double scale, GradValue gradient_threshold,
2470 DestValue edge_marker,
bool addBorder =
true)
2473 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
2474 BasicImage<TinyVector<TmpType, 2> > grad(slr-sul);
2477 gradient_threshold, edge_marker, addBorder);
2480 template <
class SrcIterator,
class SrcAccessor,
2481 class DestIterator,
class DestAccessor,
2482 class GradValue,
class DestValue>
2485 pair<DestIterator, DestAccessor> dest,
2486 double scale, GradValue gradient_threshold,
2487 DestValue edge_marker,
bool addBorder =
true)
2490 dest.first, dest.second,
2491 scale, gradient_threshold, edge_marker, addBorder);
2494 template <
class T1,
class S1,
2496 class GradValue,
class DestValue>
2499 MultiArrayView<2, T2, S2> dest,
2500 double scale, GradValue gradient_threshold,
2501 DestValue edge_marker,
bool addBorder =
true)
2503 vigra_precondition(src.shape() == dest.shape(),
2504 "cannyEdgeImageWithThinning(): shape mismatch between input and output.");
2507 scale, gradient_threshold, edge_marker, addBorder);
2512 template <
class SrcIterator,
class SrcAccessor,
2513 class MaskImage,
class BackInsertable,
class GradValue>
2514 void internalCannyFindEdgels3x3(SrcIterator ul, SrcAccessor grad,
2515 MaskImage
const & mask,
2516 BackInsertable & edgels,
2517 GradValue grad_thresh)
2519 typedef typename SrcAccessor::value_type PixelType;
2520 typedef typename PixelType::value_type ValueType;
2522 vigra_precondition(grad_thresh >= NumericTraits<GradValue>::zero(),
2523 "cannyFindEdgels3x3(): gradient threshold must not be negative.");
2526 for(
int y=1; y<mask.height()-1; ++y, ++ul.y)
2528 SrcIterator ix = ul;
2529 for(
int x=1; x<mask.width()-1; ++x, ++ix.x)
2534 ValueType gradx = grad.getComponent(ix, 0);
2535 ValueType grady = grad.getComponent(ix, 1);
2536 double mag =
hypot(gradx, grady);
2537 if(mag <= grad_thresh)
2539 double c = gradx / mag,
2542 Matrix<double> ml(3,3), mr(3,1), l(3,1), r(3,1);
2545 for(
int yy = -1; yy <= 1; ++yy)
2547 for(
int xx = -1; xx <= 1; ++xx)
2549 double u = c*xx + s*yy;
2550 double v =
norm(grad(ix, Diff2D(xx, yy)));
2563 double del = -r(1,0) / 2.0 / r(2,0);
2564 if(std::fabs(del) > 1.5)
2570 if(orientation < 0.0)
2571 orientation += 2.0*M_PI;
2573 edgels.push_back(edgel);
2701 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2704 BackInsertable & edgels,
double scale)
2706 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
2707 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
2713 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2716 BackInsertable & edgels)
2718 typedef typename NormTraits<typename SrcAccessor::value_type>::NormType NormType;
2725 internalCannyFindEdgels3x3(ul, src,
edges, edgels, NumericTraits<NormType>::zero());
2728 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2731 BackInsertable & edgels,
double scale)
2736 template <
class SrcIterator,
class SrcAccessor,
class BackInsertable>
2739 BackInsertable & edgels)
2744 template <
class T,
class S,
class BackInsertable>
2747 BackInsertable & edgels,
double scale)
2752 template <
class T,
class S,
class BackInsertable>
2755 BackInsertable & edgels)
2881 template <
class SrcIterator,
class SrcAccessor,
2882 class BackInsertable,
class GradValue>
2885 BackInsertable & edgels,
double scale, GradValue grad_thresh)
2887 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
2888 BasicImage<TinyVector<TmpType, 2> > grad(lr-ul);
2894 template <
class SrcIterator,
class SrcAccessor,
2895 class BackInsertable,
class GradValue>
2898 BackInsertable & edgels, GradValue grad_thresh)
2905 internalCannyFindEdgels3x3(ul, src,
edges, edgels, grad_thresh);
2908 template <
class SrcIterator,
class SrcAccessor,
2909 class BackInsertable,
class GradValue>
2912 BackInsertable & edgels,
double scale, GradValue grad_thresh)
2917 template <
class SrcIterator,
class SrcAccessor,
2918 class BackInsertable,
class GradValue>
2921 BackInsertable & edgels, GradValue grad_thresh)
2926 template <
class T,
class S,
2927 class BackInsertable,
class GradValue>
2930 BackInsertable & edgels,
double scale, GradValue grad_thresh)
2935 template <
class T,
class S,
2936 class BackInsertable,
class GradValue>
2939 BackInsertable & edgels,
2940 GradValue grad_thresh)
2994 #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:1351
void gaussianGradient(...)
Calculate the gradient vector by means of a 1st derivatives of Gaussian filter.
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
IteratorTraits< traverser >::DefaultAccessor Accessor
Definition: basicimage.hxx:571
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:1355
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:1393
BasicImage< UInt8 > UInt8Image
Definition: stdimage.hxx:71
void cannyEdgelListThreshold(...)
Canny's edge detector with thresholding.
BasicImageIterator< PIXELTYPE, PIXELTYPE ** > traverser
Definition: basicimage.hxx:526
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:530
void cannyEdgeImageFromGradWithThinning(...)
Detect and mark edges in an edge image using Canny's algorithm.
void cannyEdgelList3x3(...)
Improved implementation of Canny's edge detector.
void recursiveSmoothX(...)
Performs 1 dimensional recursive smoothing in x direction.
value_type strength
Definition: edgedetection.hxx:1359
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:1457
MultiArrayShape< 2 >::type Shape2
shape type for MultiArray<2, T>
Definition: multi_shape.hxx:241
float value_type
Definition: edgedetection.hxx:1347
bool operator<(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r)
less than
Definition: fixedpoint.hxx:512
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
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:2809
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:1341
PIXELTYPE value_type
Definition: basicimage.hxx:479
void initImageIf(...)
Write value to pixel in the image if mask is true.
BasicImage< Int32 > IImage
Definition: stdimage.hxx:116