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