diff --git a/Article/Fig_york/P1020928.png b/Article/Fig_york/P1020928.png new file mode 100644 index 0000000000000000000000000000000000000000..5402d60c3c8db513195bedb8797e25385aa128f0 Binary files /dev/null and b/Article/Fig_york/P1020928.png differ diff --git a/Article/Fig_york/P1020928_canny.png b/Article/Fig_york/P1020928_canny.png new file mode 100644 index 0000000000000000000000000000000000000000..62e77f2fa88db865ada988aba95cadd4027e1454 Binary files /dev/null and b/Article/Fig_york/P1020928_canny.png differ diff --git a/Article/Fig_york/P1020928_ed.png b/Article/Fig_york/P1020928_ed.png new file mode 100644 index 0000000000000000000000000000000000000000..702ea79a6381fdc0186b36b496cadfded7d98e3a Binary files /dev/null and b/Article/Fig_york/P1020928_ed.png differ diff --git a/Article/Fig_york/P1020928_fbsd.png b/Article/Fig_york/P1020928_fbsd.png new file mode 100644 index 0000000000000000000000000000000000000000..70f919ced3165fe69a29f5bbef2898965f93fe68 Binary files /dev/null and b/Article/Fig_york/P1020928_fbsd.png differ diff --git a/Article/Fig_york/P1020928_lsd.png b/Article/Fig_york/P1020928_lsd.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc13967819a1ee83240288eae1498de42c3b941 Binary files /dev/null and b/Article/Fig_york/P1020928_lsd.png differ diff --git a/Article/Fig_york/P1020928_york.png b/Article/Fig_york/P1020928_york.png new file mode 100644 index 0000000000000000000000000000000000000000..1a87585ab0b9d171818f52f15c9f0c371ffa3929 Binary files /dev/null and b/Article/Fig_york/P1020928_york.png differ diff --git a/Article/conclusion.tex b/Article/conclusion.tex index 745866d30a8bd05ee1e063e263ab5fa3dec0e148..de85fc7a811e0f90665b212349796f01897c44f0 100755 --- a/Article/conclusion.tex +++ b/Article/conclusion.tex @@ -4,7 +4,7 @@ This paper introduced a new straight edge detector based on a local analysis of the image gradient and on the use of blurred segments to embed an -estimation of the detected edge thickness. +estimation of the detected edge width. It relies on directional scans of the input image around maximal values of the gradient magnitude, and on %that have previously been presented in \cite{KerautretEven09}. @@ -17,13 +17,14 @@ gradient magnitude, and on %The main limitations of the former approach were solved through the integration of two new concepts: adaptive directional scans that continuously adjust the scan strip -to the detected edge direction; +to the detected edge direction the control of the assigned width based on the observation of the blurred segment growth. -Experiments on synthetic ground truth images show improved accuracy -brought be the new concepts, and a reliable extraction of the line width. -Moreover reached performance are quite comparable to a recent well -established edge detector in the literature. +Experiments on synthetic ground truth images show the better performance +and especially the more accurate estimation of the line width brought by +these concepts. +Moreover reached performance are quite comparable to those of recent well +established edge detectors. A residual weakness of the approach is the sensitivity to the initial conditions. diff --git a/Article/expeV2.tex b/Article/expeV2.tex index b4c2f29c01f6d78a27014d896951754a1aec4b46..ae5503d4014f0c19513156f4405d4adf95c43153 100755 --- a/Article/expeV2.tex +++ b/Article/expeV2.tex @@ -2,15 +2,16 @@ \label{sec:expe} -The main goal of this work is to detect straight segments enriched with a -quality measure through the associated width parameter. -In lack of available reference tool, the evaluation stage first aims -at quantifying the benefits of the new detector compared to the previous -one in unsupervised context on synthetic data considered as a ground truth. -Then comparisons are made with a well established recent detector -\cite{LuAl15} in order to check that global performance (processing time, -ground truth covering, detected lines count and mean length) are not -degraded. +%The main goal of this work is to detect straight segments enriched with a +%quality measure through the associated width parameter. +%In lack of available reference tool (line detector and ground truth data) +%dealing with the thickness parameter, the evaluation stage first aims +%at quantifying the benefits of the new detector compared to the previous +%one in unsupervised context on synthetic data considered as a ground truth. +%Then comparisons are made with a well established recent detector +%\cite{LuAl15} in order to check that global performance (processing time, +%ground truth covering, detected lines count and mean length) are not +%degraded. %The process flow of the former method (initial detection followed by two %refinement steps) is integrated as an option into the code of the new @@ -22,15 +23,18 @@ degraded. %All other tests, sparsity or fragmentation, are disabled. %The segment minimal size is set to 5 pixels, except where precised. -The first test compares the performance of both -detectors on a set of 1000 synthesized images containing 10 randomly +At first, the benefits of introduced concepts are evaluated through a +comparison of the performance of both versions of the detector +on a set of 1000 synthesized images containing 10 randomly placed input segments with random width between 2 and 5 pixels. +As these values are controlled, these images can be considered as a +ground truth. The absolute value of the difference of each found segment to its matched input segment is measured. -On these ground-truth images, the numerical error on the gradient extraction -biases the line width measures. This bias was first estimated using 1000 -images containing only one input segment (no possible interaction) -and the found value (1.4 pixel) was taken into account in the test. +%On these synthetic images, the numerical error on the gradient extraction +%biases the line width measures. This bias was first estimated using 1000 +%images containing only one input segment (no possible interaction) +%and the found value (1.4 pixel) was taken into account in the test. \RefTab{tab:synth} shows slightly better width and angle measurements for the new detector. The new detector shows more precise, with a smaller amount of false @@ -67,36 +71,79 @@ that the new detector is faster and finds more edges than the previous one. \begin{table} \centering \input{Fig_synth/statsTable} -\caption{Measured performance of both detectors on a set of synthesized images. +\caption{Measured performance of both versions of the detector on a set of +synthesized images. +Old refers to the previous version \cite{KerautretEven09}, whereas new is +the present detector augmented with ADS and CAW concepts. $S$ is the set of all the input segments, $D$ the set of all the detected blurred segments.} \label{tab:synth} \end{table} -The next experiments aim at evaluating the performance of the new -detector with respect to CannyLines detector \cite{LuAl15} -on the 102 annotated ground truth images of the York Urban data base -\cite{DenisAl08}. -%One of them is displayed on \RefFig{fig:auto}. +Next experiments aim at comparing the achieved performance of the new +detector with those of well established line detectors : LSD \cite{GioiAl10}, +ED-Lines \cite{AkinlarTopal12} and CannyLines \cite{LuAl15}. +The tests are run on the set of 102 ground truth images of the York Urban +database \cite{DenisAl08}. +As this database was set in the scope of Manhattan-world environments, +only lines in the three main directions are identified. +The results on one image is displayed on \RefFig{fig:york}. Compared measures $M$ are execution time $T$, covering ratio $C$, -Detected lines amount $N$, total lines length $L$ and ratio $L/N$. -To compare the execution times, for each image of the data base we measure -the execution time of 100 detections, gradient extraction included. -The covering ratio compares the length of ground truth lines covered -by the detected lines wrt the total length of ground truth lines. -A eight neighborhood of 8 pixels is added to lines provided by CannyLines. +detected lines amount $N$, cumulated length of detected lines $L$ and +mean length ratio $L/N$. +On each image of the database we measure the execution time of 100 +detections, gradient extraction included; $T$ is the mean value measured on +the whole image set. +If we assume that a pixel of a ground truth line is identified +if there is a detected line in its 8-neighborhood, then the measure $C$ is +the mean ratio of the length of ground truth line pixels identified on the +total amount of ground truth line pixels. +For all these experiments, detected lines smaller than 10 pixels are +discarded for all the detectors. +Found measures are given in \RefTab{tab:comp}. + +\begin{figure}[h] +\center + \begin{tabular}{c@{\hspace{0.2cm}}c@{\hspace{0.2cm}}c} + \includegraphics[width=0.32\textwidth]{Fig_york/P1020928.png} & + \includegraphics[width=0.32\textwidth]{Fig_york/P1020928_york.png} & + \includegraphics[width=0.32\textwidth]{Fig_york/P1020928_lsd.png} \\ + \includegraphics[width=0.32\textwidth]{Fig_york/P1020928_ed.png} & + \includegraphics[width=0.32\textwidth]{Fig_york/P1020928_canny.png} & + \includegraphics[width=0.32\textwidth]{Fig_york/P1020928_fbsd.png} + \begin{picture}(1,1)(0,0) + \put(-320,91.5){\circle{8}} + \put(-202,91.5){\circle{8}} + \put(-85,91.5){\circle{8}} + \put(-322.5,89){a} + \put(-204.5,88.5){b} + \put(-87,89){c} + \put(-320,4.5){\circle{8}} + \put(-202,4.5){\circle{8}} + \put(-85,4.5){\circle{8}} + \put(-322.5,2){d} + \put(-204,2){e} + \put(-87,2){f} + \end{picture} + \end{tabular} + \caption{Comparison of line detectors on one of the 102 ground truth + images of the York Urban database : a) Image P1020928, + b) ground truth lines, c) LSD result, d) ED-Lines result, + e) CannyLines result, f) our detector result.} + \label{fig:york} +\end{figure} -\RefTab{tab:canny} gives the achieved results. \begin{table} \centering -\input{Expe_auto/cannyTable} -\caption{Measured performance of the proposed detector and CannyLines -on standard images.} -\label{tab:canny} +\input{Expe_auto/compTable} + +\caption{Measured performance of recent line detectors and of our detector +on the York Urban Database \cite{DenisAl08}.} +\label{tab:comp} \end{table} -The new detector shows equivalent performance in terms of ground trouth lines -coverture. CannyLines is faster and finds less but longer lines, but these -results remain quite comparble so that we can arg that the global performance -is not degraded. And most of all, our detector provides an indication on the -detected lines quality through the additional thickness parameter. +Globally the performance of the new detector are pretty similar to those +of the other ones, with seemingly a small advantage for the ground truth +cover. CannyLines provides longer lines and LSD is faster. +But additionnaly, our detector provides an indication +on the detected lines quality through the additional width parameter. diff --git a/Article/methodV2.tex b/Article/methodV2.tex index e2fb253ad6a40e247070c63646bd4f5a80942b28..538bba15dc12ca933686dc2d55d752c54a7a1f6b 100755 --- a/Article/methodV2.tex +++ b/Article/methodV2.tex @@ -52,7 +52,7 @@ The workflow of the detection process is summerized in the following figure. \begin{figure}[h] \center \input{Fig_method/workflow} - \caption{The detection process main workflow.} + \caption{The main workflow of the detection process.} \label{fig:workflow} \end{figure} @@ -133,7 +133,7 @@ To overcome this issue, in the former work, an additional refinement step is run in the direction estimated from this longer segment. It is enough to completely detect most of the tested edges, but certainly not all, especially if big size images with much longer edges are processed. -As a solution, this operation could be itered as long as the blurred segment +As a solution, this operation could be iterated as long as the blurred segment escapes from the directional scan using as any fine detection steps as necessary. But at each iteration, already tested points are processed again, @@ -280,25 +280,25 @@ blurred segment extension in the fine tracking step. \subsection{Automatic blurred segment detection} An unsupervised mode is also proposed to automatically detect all the -straight edges in the image. The principle of this automatic detection -is described in Algorithm 2. A stroke that crosses the whole image, is +straight edges in the image. A stroke that crosses the whole image, is swept in both directions, vertical then horizontal, from the center to the borders. At each position, the multi-detection algorithm is run to collect all the segments found under the stroke. -In the present work, the stroke sweeping step $\delta$ is set to 10 pixels. -Then small blurred segments are rejected in order to avoid the formation -of small mis-aligned segments when the sweeping stroke crosses an image edge -near one of its ends. In such situation, any nearby disturbing gradient is +In the present work, the stroke sweeping step $\delta$ is set to 15 pixels. +Then small (less than 10 pixels) blurred segments are rejected in order to +avoid the formation of small mis-aligned segments when the sweeping stroke +crosses an image edge near one of its ends. +In such situation, any nearby disturbing gradient is likely to deviate the blurred segment direction, and the expansion is quickly stopped. A length threshold value of 30 pixels is experimentally set. The automatic detection of blurred segments in a whole image is available -for testing from an online demonstration +for testing from the online demonstration and from a \textit{GitHub} source code repository: \\ \href{https://github.com/evenp/FBSD}{ \small{\url{https://github.com/evenp/FBSD}}} -\input{Fig_method/algoAuto} +%\input{Fig_method/algoAuto} %The behavior of the unsupervised detection is depicted through the two %examples of \RefFig{fig:auto}. diff --git a/Article/notions.tex b/Article/notions.tex index b0599b8e05be31aa57aeacb8fc68d8a198e02f68..0830d85c8bbeb0a07d34bdb196df96f2fefadeb6 100755 --- a/Article/notions.tex +++ b/Article/notions.tex @@ -78,7 +78,7 @@ DS = \left\{ S_i = \mathcal{D} \cap \mathcal{N}_i \cap \mathcal{I} \end{equation} In this definition, the clause $\vec{V}(\mathcal{N}_i) \cdot \vec{V}(\mathcal{D}) = 0$ -expresses the othogonality constraint between the scan lines $\mathcal{N}_i$ +expresses the orthogonality constraint between the scan lines $\mathcal{N}_i$ and the scan strip $\mathcal{D}$. Then the shift of the period $p(\mathcal{D})$ between successive scans guarantees that all points of the scan strip are travelled one and only one diff --git a/Code/FBSD/BSTools/bsidetview.cpp b/Code/FBSD/BSTools/bsidetview.cpp index 0cf49ead4add5fd39f44949762da979ff60aff90..5dd218dd2d3668ec3ddaf2e98c6fc4d37a8ecd1f 100755 --- a/Code/FBSD/BSTools/bsidetview.cpp +++ b/Code/FBSD/BSTools/bsidetview.cpp @@ -57,7 +57,7 @@ bool BSIdetView::processKeyEvent (QKeyEvent *event) // QRect (QPoint (0, 0), // QSize (idet->getWidth(), idet->getHeight())) // ).toImage().save ("firstDetection.png"); - // cout << "First detection window shot in capture.png" << endl; + // cout << "First detection window shot in firstDetection.png" << endl; break; case Qt::Key_Left : diff --git a/Code/FBSD/BSTools/bsyorkitem.cpp b/Code/FBSD/BSTools/bsyorkitem.cpp index 38f7c135842780b7aff61c6b71257ca35912c576..cd0d168622ba3f9a28d67f5ada12c59cf68b577d 100755 --- a/Code/FBSD/BSTools/bsyorkitem.cpp +++ b/Code/FBSD/BSTools/bsyorkitem.cpp @@ -8,14 +8,22 @@ using namespace std; const int BSYorkItem::YORK_ALONE = 0; -const int BSYorkItem::CANNY_ALONE = 1; -const int BSYorkItem::DILATED_CANNY_ALONE = 2; -const int BSYorkItem::YORK_OVER_CANNY = 3; -const int BSYorkItem::YORK_OVER_BS = 4; -const int BSYorkItem::YORK_OVER_DSS = 5; -const int BSYorkItem::YORK_WITH_CANNY = 6; -const int BSYorkItem::YORK_WITH_DSS = 7; -const int BSYorkItem::NO_INFO = 8; +const int BSYorkItem::LSD_ALONE = 1; +const int BSYorkItem::DILATED_LSD_ALONE = 2; +const int BSYorkItem::YORK_OVER_LSD = 3; +const int BSYorkItem::ED_ALONE = 4; +const int BSYorkItem::DILATED_ED_ALONE = 5; +const int BSYorkItem::YORK_OVER_ED = 6; +const int BSYorkItem::CANNY_ALONE = 7; +const int BSYorkItem::DILATED_CANNY_ALONE = 8; +const int BSYorkItem::YORK_OVER_CANNY = 9; +const int BSYorkItem::FBSD_ALONE = 10; +const int BSYorkItem::YORK_OVER_BS = 11; +const int BSYorkItem::YORK_OVER_DSS = 12; +const int BSYorkItem::YORK_WITH_CANNY = 13; +const int BSYorkItem::YORK_WITH_DSS = 14; +const int BSYorkItem::NO_INFO = 15; +const QColor BSYorkItem::ALONE_COLOR = Qt::black; const QColor BSYorkItem::OVER_COLOR = Qt::lightGray; const QColor BSYorkItem::UNDER_COLOR = Qt::yellow; const QColor BSYorkItem::BOTH_COLOR = Qt::black; @@ -33,9 +41,11 @@ BSYorkItem::BSYorkItem (int width, int height, const QImage *im, clmap = new bool[size]; det = detector; type = YORK_ALONE; - cannyDilation = 0; - yorks = new ExtLines ("yorklines.txt", w, h); - cannys = new ExtLines ("cannylines.txt", w, h, 5); + dilationType = 0; + yorks = new ExtLines ("Data/yorklines.txt", w, h); + cannys = new ExtLines ("Data/cannylines.txt", w, h, 5); + lsds = new ExtLines ("Data/lsdlines.txt", w, h, 7); + eds = new ExtLines ("Data/edlines.txt", w, h, 4); } @@ -59,35 +69,50 @@ void BSYorkItem::paint (QPainter *painter, Q_UNUSED (widget); for (int i = 0; i < w * h; i++) bsmap[i] = false; - if (type == YORK_ALONE) drawYorkLines (painter); - else if (type == CANNY_ALONE) drawCannyLines (painter); + if (type == YORK_ALONE) drawYorkLines (painter, true); + else if (type == ED_ALONE) drawEdLines (painter, true); + else if (type == DILATED_ED_ALONE) drawDilatedEdLines (painter); + else if (type == YORK_OVER_ED) + { + drawEdLines (painter, false); + drawYorkLines (painter, false); + } + else if (type == LSD_ALONE) drawLsdLines (painter, true); + else if (type == DILATED_LSD_ALONE) drawDilatedLsdLines (painter); + else if (type == YORK_OVER_LSD) + { + drawLsdLines (painter, false); + drawYorkLines (painter, false); + } + else if (type == CANNY_ALONE) drawCannyLines (painter, true); else if (type == DILATED_CANNY_ALONE) drawDilatedCannyLines (painter); else if (type == YORK_OVER_CANNY) { - drawCannyLines (painter); - drawYorkLines (painter); + drawCannyLines (painter, false); + drawYorkLines (painter, false); } + else if (type == FBSD_ALONE) drawDSS (painter, true); else if (type == YORK_OVER_BS) { - drawBS (painter); - drawYorkLines (painter); + drawBS (painter, false); + drawYorkLines (painter, false); } else if (type == YORK_OVER_DSS) { - drawDSS (painter); - drawYorkLines (painter); + drawDSS (painter, false); + drawYorkLines (painter, false); } else if (type == YORK_WITH_CANNY) { drawCannyLines (painter, false); - drawYorkLines (painter); + drawYorkLines (painter, false); } else if (type == YORK_WITH_DSS) { - drawDSS (painter, false); - drawYorkLines (painter); + drawDSS (painter, false, false); + drawYorkLines (painter, false); } - else drawYorkLines (painter); + else drawYorkLines (painter, true); int nboth = 0, ncl = 0, nbs = 0; for (int i = 0; i < w * h; i++) if (clmap[i]) @@ -98,9 +123,10 @@ void BSYorkItem::paint (QPainter *painter, } -void BSYorkItem::drawBS (QPainter *painter) +void BSYorkItem::drawBS (QPainter *painter, bool alone) { - painter->setPen (QPen (UNDER_COLOR, DEFAULT_PEN_WIDTH, Qt::SolidLine, + painter->setPen (QPen (alone ? ALONE_COLOR : UNDER_COLOR, + DEFAULT_PEN_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); vector<BlurredSegment *> bss = det->getBlurredSegments (); if (! bss.empty ()) @@ -115,9 +141,10 @@ void BSYorkItem::drawBS (QPainter *painter) } -void BSYorkItem::drawDSS (QPainter *painter, bool disp) +void BSYorkItem::drawDSS (QPainter *painter, bool alone, bool disp) { - painter->setPen (QPen (UNDER_COLOR, DEFAULT_PEN_WIDTH, Qt::SolidLine, + painter->setPen (QPen (alone ? ALONE_COLOR : UNDER_COLOR, + DEFAULT_PEN_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); vector<BlurredSegment *> bss = det->getBlurredSegments (); if (! bss.empty ()) @@ -156,7 +183,7 @@ void BSYorkItem::drawPoints (QPainter *painter, vector<Pt2i> pts, bool disp) } -void BSYorkItem::drawYorkLines (QPainter *painter) +void BSYorkItem::drawYorkLines (QPainter *painter, bool alone) { int n = 0; Pt2i *pts = NULL; @@ -170,7 +197,7 @@ void BSYorkItem::drawYorkLines (QPainter *painter) if (pts[i].x () >= 0 && pts[i].x () < w && pts[i].y () >= 0 && pts[i].y () < h) { - painter->setPen (QPen (bsmap[pts[i].y()*w+pts[i].x()] ? + painter->setPen (QPen (alone || bsmap[pts[i].y()*w+pts[i].x()] ? BOTH_COLOR : OVER_COLOR, DEFAULT_PEN_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); @@ -184,7 +211,162 @@ void BSYorkItem::drawYorkLines (QPainter *painter) } -void BSYorkItem::drawCannyLines (QPainter *painter, bool disp) { +void BSYorkItem::drawLsdLines (QPainter *painter, bool alone, bool disp) { + int n = 0; + Pt2i *pts = NULL; + int nb = lsds->countOfLines (); + for (int i = 0; i < nb; i++) + { + pts = Pt2i (lsds->xStart (i), lsds->yStart (i)).drawing ( + Pt2i (lsds->xEnd (i), lsds->yEnd (i)), &n); + for (int i = 0; i < n; i++) + { + if (pts[i].x () >= 0 && pts[i].x () < w + && pts[i].y () >= 0 && pts[i].y () < h) + { + if (disp) + { + painter->setPen (QPen (alone ? ALONE_COLOR : UNDER_COLOR, + DEFAULT_PEN_WIDTH, Qt::SolidLine, + Qt::RoundCap, Qt::RoundJoin)); + painter->drawPoint (QPoint (pts[i].x (), + h - 1 - pts[i].y ())); // dec 1 + } + bsmap[pts[i].y()*w+pts[i].x()] = true; + } + } + delete [] pts; + } +} + + +void BSYorkItem::drawDilatedLsdLines (QPainter *painter, bool disp) +{ + int nb = lsds->countOfLines (); + for (int i = 0; i < nb; i++) + { + int xs = lsds->xStart (i); + int ys = lsds->yStart (i); + int xe = lsds->xEnd (i); + int ye = lsds->yEnd (i); + int minx = (xe < xs ? xe : xs); + int miny = (ye < ys ? ye : ys); + int maxx = (xe < xs ? xs : xe); + int maxy = (ye < ys ? ys : ye); + DigitalStraightSegment *dss = new DigitalStraightSegment ( + Pt2i (xs, ys), Pt2i (xe, ye), + DigitalStraightLine::DSL_NAIVE, minx, miny, maxx, maxy); + vector<Pt2i> points; + if (dilationType > 0) + { + int dil = 0; + if (dilationType == 1) dil = dss->period (); + else if (dilationType == 2) dil = dss->standard (); + else if (dilationType == 3) dil = 2 * dss->period (); +cout << "Dilation of " << dil << endl; + dss->dilate (dil); + } + dss->getPoints (points); + vector<Pt2i>::iterator pit = points.begin (); + while (pit != points.end ()) + { + if (pit->x () >= 0 && pit->x () < w && pit->y () >= 0 && pit->y () < h) + { + if (disp) + { + painter->setPen (QPen (UNDER_COLOR, + DEFAULT_PEN_WIDTH, Qt::SolidLine, + Qt::RoundCap, Qt::RoundJoin)); + painter->drawPoint (QPoint (pit->x (), h - 1 - pit->y ())); + } + bsmap[pit->y()*w+pit->x()] = true; + } + pit ++; + } + delete dss; + } +} + + +void BSYorkItem::drawEdLines (QPainter *painter, bool alone, bool disp) { + int n = 0; + Pt2i *pts = NULL; + int nb = eds->countOfLines (); + for (int i = 0; i < nb; i++) + { + pts = Pt2i (eds->xStart (i), eds->yStart (i)).drawing ( + Pt2i (eds->xEnd (i), eds->yEnd (i)), &n); + for (int i = 0; i < n; i++) + { + if (pts[i].x () >= 0 && pts[i].x () < w + && pts[i].y () >= 0 && pts[i].y () < h) + { + if (disp) + { + painter->setPen (QPen (alone ? ALONE_COLOR : UNDER_COLOR, + DEFAULT_PEN_WIDTH, Qt::SolidLine, + Qt::RoundCap, Qt::RoundJoin)); + painter->drawPoint (QPoint (pts[i].x (), + h - 1 - pts[i].y ())); // dec 1 + } + bsmap[pts[i].y()*w+pts[i].x()] = true; + } + } + delete [] pts; + } +} + + +void BSYorkItem::drawDilatedEdLines (QPainter *painter, bool disp) +{ + int nb = eds->countOfLines (); + for (int i = 0; i < nb; i++) + { + int xs = eds->xStart (i); + int ys = eds->yStart (i); + int xe = eds->xEnd (i); + int ye = eds->yEnd (i); + int minx = (xe < xs ? xe : xs); + int miny = (ye < ys ? ye : ys); + int maxx = (xe < xs ? xs : xe); + int maxy = (ye < ys ? ys : ye); + DigitalStraightSegment *dss = new DigitalStraightSegment ( + Pt2i (xs, ys), Pt2i (xe, ye), + DigitalStraightLine::DSL_NAIVE, minx, miny, maxx, maxy); + vector<Pt2i> points; + if (dilationType > 0) + { + int dil = 0; + if (dilationType == 1) dil = dss->period (); + else if (dilationType == 2) dil = dss->standard (); + else if (dilationType == 3) dil = 2 * dss->period (); +cout << "Dilation of " << dil << endl; + dss->dilate (dil); + } + dss->getPoints (points); + vector<Pt2i>::iterator pit = points.begin (); + while (pit != points.end ()) + { + if (pit->x () >= 0 && pit->x () < w && pit->y () >= 0 && pit->y () < h) + { + if (disp) + { + painter->setPen (QPen (UNDER_COLOR, + DEFAULT_PEN_WIDTH, Qt::SolidLine, + Qt::RoundCap, Qt::RoundJoin)); + painter->drawPoint (QPoint (pit->x (), h - 1 - pit->y ())); + } + bsmap[pit->y()*w+pit->x()] = true; + } + pit ++; + } + delete dss; + } +} + + +void BSYorkItem::drawCannyLines (QPainter *painter, bool alone, bool disp) +{ int n = 0; Pt2i *pts = NULL; int nb = cannys->countOfLines (); @@ -199,7 +381,7 @@ void BSYorkItem::drawCannyLines (QPainter *painter, bool disp) { { if (disp) { - painter->setPen (QPen (UNDER_COLOR, + painter->setPen (QPen (alone ? ALONE_COLOR : UNDER_COLOR, DEFAULT_PEN_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter->drawPoint (QPoint (pts[i].x (), @@ -230,12 +412,12 @@ void BSYorkItem::drawDilatedCannyLines (QPainter *painter, bool disp) Pt2i (xs, ys), Pt2i (xe, ye), DigitalStraightLine::DSL_NAIVE, minx, miny, maxx, maxy); vector<Pt2i> points; - if (cannyDilation > 0) + if (dilationType > 0) { int dil = 0; - if (cannyDilation == 1) dil = dss->period (); - else if (cannyDilation == 2) dil = dss->standard (); - else if (cannyDilation == 3) dil = 2 * dss->period (); + if (dilationType == 1) dil = dss->period (); + else if (dilationType == 2) dil = dss->standard (); + else if (dilationType == 3) dil = 2 * dss->period (); cout << "Dilation of " << dil << endl; dss->dilate (dil); } @@ -268,16 +450,17 @@ void BSYorkItem::computeBScovering () cout << "FBSD covering : " << fbsdCov << endl; int nb; double lg; - double cannyCov = yorks->cannyLineCovering ( - "/home/even/tmp/FBSD/cannylines.txt", + double cannyCov = yorks->covering ( + "/home/even/tmp/FBSD/Data/cannylines.txt", 5, nb, lg, det->finalSpreadMinLength ()); cout << "Canny lines covering : " << cannyCov << endl; } -bool BSYorkItem::toggleCannyDilation () +bool BSYorkItem::toggleDilationType () { - if (++cannyDilation == 4) cannyDilation = 0; - return (type == DILATED_CANNY_ALONE); + if (++dilationType == 4) dilationType = 0; + return (type == DILATED_CANNY_ALONE + || type == DILATED_ED_ALONE || type == DILATED_LSD_ALONE); } diff --git a/Code/FBSD/BSTools/bsyorkitem.h b/Code/FBSD/BSTools/bsyorkitem.h index 694be46e3f82d3d75bd405c35273c681b7c09c1e..f8db92ab55a9a738555fd759483ecc74e7a11f6d 100755 --- a/Code/FBSD/BSTools/bsyorkitem.h +++ b/Code/FBSD/BSTools/bsyorkitem.h @@ -46,28 +46,52 @@ public: else if (++type == NO_INFO) type = 0; } /** - * \brief Toggles canny dilation. + * \brief Toggles dilation type for external lines. * Returns if the display should be updated. */ - bool toggleCannyDilation (); + bool toggleDilationType (); /** - * \brief Cpomputes and displays blurred segment covering. + * \brief Computes and displays blurred segment covering. */ void computeBScovering (); + /** + * \brief Returns the external lines view width. + */ + inline int getWidth () const { return w; } + + /** + * \brief Returns the external lines view height. + */ + inline int getHeight () const { return h; } + /** * \brief Returns the displayed information title. */ inline QString itemTitle () const { if (type == YORK_ALONE) return ("York Urban DB ground truth"); + else if (type == DILATED_LSD_ALONE) + return ("Dilated_LSD lines"); + else if (type == LSD_ALONE) + return ("LSD lines"); + else if (type == YORK_OVER_LSD) + return ("York over LSD lines"); + else if (type == DILATED_ED_ALONE) + return ("Dilated_ED lines"); + else if (type == ED_ALONE) + return ("ED lines"); + else if (type == YORK_OVER_ED) + return ("York over ED lines"); else if (type == DILATED_CANNY_ALONE) return ("Dilated_Canny lines"); else if (type == CANNY_ALONE) return ("Canny lines"); else if (type == YORK_OVER_CANNY) return ("York over Canny lines"); + else if (type == FBSD_ALONE) + return ("FBSD lines"); else if (type == YORK_OVER_BS) return ("York over blurred segments points"); else if (type == YORK_OVER_DSS) @@ -85,12 +109,26 @@ private: /** York lines alone display modality. */ static const int YORK_ALONE; + /** Lsd lines alone display modality. */ + static const int LSD_ALONE; + /** Dilated Lsd lines alone display modality. */ + static const int DILATED_LSD_ALONE; + /** York over Lsd display modality. */ + static const int YORK_OVER_LSD; + /** ED lines alone display modality. */ + static const int ED_ALONE; + /** Dilated ED lines alone display modality. */ + static const int DILATED_ED_ALONE; + /** York over ED display modality. */ + static const int YORK_OVER_ED; /** Canny lines alone display modality. */ static const int CANNY_ALONE; /** Dilated Canny lines alone display modality. */ static const int DILATED_CANNY_ALONE; /** York over Canny display modality. */ static const int YORK_OVER_CANNY; + /** FBSD lines alone display modality. */ + static const int FBSD_ALONE; /** York over BS display modality. */ static const int YORK_OVER_BS; /** York over DSS display modality. */ @@ -101,6 +139,8 @@ private: static const int YORK_WITH_DSS; /** No info display modality. */ static const int NO_INFO; + /** Default color for alone lines. */ + static const QColor ALONE_COLOR; /** Default color for first drawn lines. */ static const QColor UNDER_COLOR; /** Default color for further drawn lines. */ @@ -112,6 +152,10 @@ private: /** Set of York lines. */ ExtLines *yorks; + /** Set of Lsd lines. */ + ExtLines *lsds; + /** Set of ED lines. */ + ExtLines *eds; /** Set of Canny lines. */ ExtLines *cannys; @@ -129,23 +173,35 @@ private: bool *clmap; /** Display modality */ int type; - /** Type of dilation for Canny lines */ - int cannyDilation; + /** Type of dilation for external lines */ + int dilationType; /** Displays blurred segments pixels */ - void drawBS (QPainter *painter); + void drawBS (QPainter *painter, bool alone); /** Displays blurred segments DSS */ - void drawDSS (QPainter *painter, bool disp = true); + void drawDSS (QPainter *painter, bool alone, bool disp = true); /** Displays a set of points */ void drawPoints (QPainter *painter, vector<Pt2i> pts, bool disp = true); /** Displays York lines */ - void drawYorkLines (QPainter *painter); + void drawYorkLines (QPainter *painter, bool alone); + + /** Displays Lsd lines */ + void drawLsdLines (QPainter *painter, bool alone, bool disp = true); + + /** Displays dilated Lsd lines */ + void drawDilatedLsdLines (QPainter *painter, bool disp = true); + + /** Displays ED lines */ + void drawEdLines (QPainter *painter, bool alone, bool disp = true); + + /** Displays dilated ED lines */ + void drawDilatedEdLines (QPainter *painter, bool disp = true); /** Displays Canny lines */ - void drawCannyLines (QPainter *painter, bool disp = true); + void drawCannyLines (QPainter *painter, bool alone, bool disp = true); /** Displays dilated Canny lines */ void drawDilatedCannyLines (QPainter *painter, bool disp = true); diff --git a/Code/FBSD/BSTools/bsyorkview.cpp b/Code/FBSD/BSTools/bsyorkview.cpp index 76db756c7e944758d1d3d4d68ee3a133659b83de..0869ba91aa75052e21fff90cccbb4aa97acf046e 100755 --- a/Code/FBSD/BSTools/bsyorkview.cpp +++ b/Code/FBSD/BSTools/bsyorkview.cpp @@ -47,16 +47,26 @@ bool BSYorkView::processKeyEvent (QKeyEvent *event) update (); setWindowTitle (york->itemTitle ()); break; + case Qt::Key_D : // Canny dilation - if (york->toggleCannyDilation ()) + if (york->toggleDilationType ()) { scene()->update (); update (); } break; - case Qt::Key_J : // Info + + case Qt::Key_J : // Still used ? york->computeBScovering (); break; + + case Qt::Key_P : // Capture +// viewport()->grab ( +// QRect (QPoint (0, 0), +// QSize (york->getWidth(), york->getHeight())) +// ).toImage().save ("external.png"); +// cout << "External detectors view shot in external.png" << endl; + break; } return processed; } diff --git a/Code/FBSD/BSTools/extlines.cpp b/Code/FBSD/BSTools/extlines.cpp index 14a599f150ee0ecf645691a8e6cbac0d1637c3d1..5bd54dff37ad37cd09e6f65ebfe87e52b3cc3a56 100755 --- a/Code/FBSD/BSTools/extlines.cpp +++ b/Code/FBSD/BSTools/extlines.cpp @@ -2,14 +2,57 @@ #include <fstream> #include <cmath> #include "extlines.h" +#include "bsdetector.h" using namespace std; const int ExtLines::COV_DILATION = 4; +const double ExtLines::MIN_LENGTH = 10.; -ExtLines::ExtLines (const char * name, int width, int height, int nbinfo) +ExtLines::ExtLines (bool groundTruth) +{ + QImage im; + im.load ("Data/york.jpg"); + width = im.width (); + height = im.height (); + gt = groundTruth; + + if (groundTruth) + { + double val[4]; + int i = 0, nb = 0; + ifstream input ("Data/yorklines.txt", ios::in); + bool reading = true; + if (input) + { + while (reading) + { + input >> val[i]; + if (input.eof ()) reading = false; + if (++i == 4) + { + ExtLine cl; + cl.sx = val[0]; + cl.sy = height - 1 - val[1]; + cl.ex = val[2]; + cl.ey = height - 1 - val[3]; + exts.push_back (cl); + i = 0; + nb++; + } + } + } + } + stats (im); + stats ("Data/cannylines.txt", 5, "Data/cannycov.txt", "Data/cannyln.txt"); + stats ("Data/edlines.txt", 4, "Data/edcov.txt", "Data/edln.txt"); + stats ("Data/lsdlines.txt", 7, "Data/lsdcov.txt", "Data/lsdln.txt"); +} + + +ExtLines::ExtLines (const char *name, int width, int height, int nbinfo) { this->width = width; this->height = height; @@ -37,6 +80,7 @@ ExtLines::ExtLines (const char * name, int width, int height, int nbinfo) } } } + gt = true; } @@ -93,12 +137,12 @@ double ExtLines::covering (const vector<BlurredSegment *> &segs) const } -double ExtLines::cannyLineCovering (const char *name, - int &nb, double &lg, double minl) const +double ExtLines::covering (const char *name, int nbinfo, + int &nb, double &lg, double minl) const { - // 1. Reading canny lines file + // 1. Reading external lines file vector<ExtLine> cannys; - double val[5]; + double val[nbinfo]; double clLength = 0.; int i = 0; nb = 0; @@ -111,7 +155,7 @@ double ExtLines::cannyLineCovering (const char *name, { input >> val[i]; if (input.eof ()) reading = false; - if (++i == 5) + if (++i == nbinfo) { ExtLine cl; cl.sx = val[0]; @@ -131,7 +175,7 @@ double ExtLines::cannyLineCovering (const char *name, } } - // 2. Spreading canny lines + // 2. Spreading external lines bool cmap[width * height]; for (int i = 0; i < width * height; i++) cmap[i] = false; vector<ExtLine>::iterator it = cannys.begin (); @@ -184,3 +228,118 @@ double ExtLines::cannyLineCovering (const char *name, } return (nbextin / (double) nbext); } + + +int ExtLines::count (const char *name, int nbinfo, + double &lg, double minl) const +{ + vector<ExtLine> cannys; + double val[nbinfo]; + double clLength = 0.; + int i = 0; + int nb = 0; + lg = 0.; + ifstream input (name, ios::in); + bool reading = true; + if (input) + { + while (reading) + { + input >> val[i]; + if (input.eof ()) reading = false; + if (++i == nbinfo) + { + ExtLine cl; + cl.sx = val[0]; + cl.sy = height - 1 - val[1]; + cl.ex = val[2]; + cl.ey = height - 1 - val[3]; + cannys.push_back (cl); + clLength = sqrt ((cl.sx - cl.ex) * (cl.sx - cl.ex) + + (cl.sy - cl.ey) * (cl.sy - cl.ey)); + if (clLength > minl) + { + lg += clLength; + nb++; + } + i = 0; + } + } + } + return (nb); +} + + +void ExtLines::stats (const QImage &im) +{ + BSDetector detector; + int **tabImage = new int*[height]; + for (int i = 0; i < height; i++) + { + tabImage[i] = new int[width]; + for(int j = 0; j < width; j++) + { + QColor c = QColor (im.pixel (j, height - i - 1)); + tabImage[i][j] = c.value (); + } + } + detector.setGradientMap (new VMap (width, height, tabImage, + VMap::TYPE_SOBEL_5X5)); + if (MIN_LENGTH != 0.) + { + if (! detector.isFinalSpreadTestOn ()) detector.switchFinalSpreadTest (); + detector.setFinalSpreadMinLength ((int) (MIN_LENGTH + 0.5)); + } + else + if (detector.isFinalSpreadTestOn ()) detector.switchFinalSpreadTest (); + detector.detectAll (); + vector<BlurredSegment *> bss = detector.getBlurredSegments (); + if (gt) + { + double covFBSD = covering (bss); + ofstream outf ("Data/fbsdcov.txt", ios::out); + outf << covFBSD << endl; + outf.close (); + } + + double lbs = 0.; + int nbs = (int) bss.size (); + vector<BlurredSegment *>::iterator it = bss.begin (); + while (it != bss.end ()) + { + Pt2i lastleft = (*it)->getLastLeft (); + Pt2i lastright = (*it)->getLastRight (); + lbs += sqrt ((lastleft.x () - lastright.x ()) + * (lastleft.x () - lastright.x ()) + + (lastleft.y () - lastright.y ()) + * (lastleft.y () - lastright.y ())); + it ++; + } + ofstream outl ("Data/fbsdln.txt", ios::out); + outl << nbs << " " << lbs << " " << (lbs / nbs) << endl; + outl.close (); + + for (int i = 0; i < height; i++) delete [] tabImage[i]; + delete [] tabImage; +} + + +void ExtLines::stats (const char *lname, int nbinfo, + const char *covname, const char *lgname) +{ + int nel = 0; + double lel = 0.; + if (gt) + { + double covel = covering (lname, nbinfo, nel, lel, MIN_LENGTH); + + ofstream outf (covname, ios::out); + outf << covel << endl; + outf.close (); + } + else nel = count (lname, nbinfo, lel, MIN_LENGTH); + + ofstream outl (lgname, ios::out); + outl << nel << " " << lel << " " << (lel / nel) << endl; + outl.close (); +} diff --git a/Code/FBSD/BSTools/extlines.h b/Code/FBSD/BSTools/extlines.h index 2f9b3552f33e6e36f4d9f8dfc5f30bca8e700449..26660b01b3ceb1a44b5ec9a01dde5da5bc1ab9f0 100755 --- a/Code/FBSD/BSTools/extlines.h +++ b/Code/FBSD/BSTools/extlines.h @@ -2,7 +2,7 @@ #define EXT_LINES_H -#include <QString> +#include <QtGui> #include <vector> #include "blurredsegment.h" @@ -17,6 +17,11 @@ class ExtLines { public: + /** + * \brief Creates an external lines set and runs statistics. + */ + ExtLines (bool groundTruth); + /** * \brief Creates an external lines set. */ @@ -62,19 +67,30 @@ public: double covering (const vector<BlurredSegment *> &segs) const; /** - * \brief Returns the covering ratio of CannyLine segments. - * @param name Output file name. + * \brief Returns the covering ratio of external lines. + * @param name External lines file name. + * @param nbinfo count of data per line. * @param nb Extracted number of lines. * @param lb Extracted total length of lines. * @param minl Minimal length of extarcted lines. */ - double cannyLineCovering (const char *name, - int &nb, double &lg, double minl) const; + double covering (const char *name, int nbinfo, + int &nb, double &lg, double minl) const; + /** + * \brief Returns the count and cumulated length of external lines. + * @param name External lines file name. + * @param nbinfo count of data per line. + * @param lb Extracted total length of lines. + * @param minl Minimal length of extarcted lines. + */ + int count (const char *name, int nbinfo, double &lg, double minl) const; private: + /** Minimal length of considered lines. */ + static const double MIN_LENGTH; /** Dilation distance for lines covering estimation. */ static const int COV_DILATION; @@ -91,6 +107,8 @@ private: double ey; }; + /** Indicatres if a ground truth is available. */ + bool gt; /** Set of recorded external lines. */ vector<ExtLine> exts; @@ -99,6 +117,11 @@ private: /** Image height */ int height; + + void stats (const QImage &im); + void stats (const char *lname, int nbinfo, + const char *covname, const char *lgname); + }; #endif diff --git a/Code/FBSD/BlurredSegment/bsdetector.cpp b/Code/FBSD/BlurredSegment/bsdetector.cpp index c7d518f4cdb89cb68e196f072d96e860abfb872f..81448514f06b0657fb67eb8632ab8594fdef4a22 100755 --- a/Code/FBSD/BlurredSegment/bsdetector.cpp +++ b/Code/FBSD/BlurredSegment/bsdetector.cpp @@ -30,7 +30,7 @@ const int BSDetector::DEFAULT_FAST_TRACK_MAX_MARGIN = 2; const int BSDetector::DEFAULT_BS_MIN_SIZE = 5; const int BSDetector::ABSOLUTE_BS_MIN_SIZE = 3; const int BSDetector::DEFAULT_CONNECT_MIN_SIZE = 5; -const int BSDetector::DEFAULT_AUTO_RESOLUTION = 10; +const int BSDetector::DEFAULT_AUTO_RESOLUTION = 15; const int BSDetector::PRELIM_MIN_HALF_WIDTH = 10; @@ -68,7 +68,7 @@ BSDetector::BSDetector () densityTestOn = true; finalDensityTestOn = false; finalLengthTestOn = false; - finalSpreadTestOn = false; + finalSpreadTestOn = true; finalSpreadMin = 10; // nbSmallBS = 0; multiSelection = false; diff --git a/Code/FBSD/BlurredSegment/bsdetector.h b/Code/FBSD/BlurredSegment/bsdetector.h index 3c32febf16d59d2a7f1c4ff096d48b5e27d5fa46..1c513fb0dfbbba9b92cef115fa4bfaf3b741453a 100755 --- a/Code/FBSD/BlurredSegment/bsdetector.h +++ b/Code/FBSD/BlurredSegment/bsdetector.h @@ -517,12 +517,28 @@ public: inline void switchFinalDensityTest () { finalDensityTestOn = ! finalDensityTestOn; } + /** + * \brief Returns whether the spread test at final step is set. + */ + inline bool isFinalSpreadTestOn () const { return (finalSpreadTestOn); } + + /** + * \brief Switches on or off the final spread test modality. + */ + inline void switchFinalSpreadTest () { + finalSpreadTestOn = ! finalSpreadTestOn; } + /** * \brief Returns the minimal spread of final blurred segments. */ inline int finalSpreadMinLength () const { return (finalSpreadTestOn ? finalSpreadMin : 0); } + /** + * \brief Returns the minimal spread of final blurred segments. + */ + inline void setFinalSpreadMinLength (int val) { finalSpreadMin = val; } + /** * \brief Returns whether the length test at final step is set. */ diff --git a/Code/FBSD/main.cpp b/Code/FBSD/main.cpp index 1afb8753de3551f0145e17052c4a67be5754a9e7..85053dc3f694e757dd24abc17a0f74ac5e90f4c1 100755 --- a/Code/FBSD/main.cpp +++ b/Code/FBSD/main.cpp @@ -11,7 +11,6 @@ int main (int argc, char *argv[]) int val = 0; int imageName = 0; bool random = false, testing = false; - bool york = false; // DEV bool yt = false; // DEV QApplication app (argc, argv); @@ -35,7 +34,16 @@ int main (int argc, char *argv[]) if (string(argv[i]) == string ("-random")) random = true; else if (string(argv[i]) == string ("-test")) testing = true; // DEV IN - else if (string(argv[i]) == string ("-york")) york = true; + else if (string(argv[i]) == string ("-own")) + { + new ExtLines (false); + return (EXIT_SUCCESS); + } + else if (string(argv[i]) == string ("-york")) + { + new ExtLines (true); + return (EXIT_SUCCESS); + } else if (string(argv[i]) == string ("-yt")) yt = true; else if (string(argv[i]) == string ("-profile")) window.toggleProfWindow (); @@ -88,50 +96,10 @@ int main (int argc, char *argv[]) return (EXIT_SUCCESS); } // DEV IN - else if (york) - { - QImage im; - im.load ("york.jpg"); - int width = im.width (); - int height = im.height (); - BSDetectionWidget bsdw; - BSDetector detector; - detector.setGradientMap (new VMap (width, height, bsdw.getBitmap (im), - VMap::TYPE_SOBEL_5X5)); - int ncl, nbs; - double lcl, lbs; - detector.detectAll (); - ExtLines yl ("yorklines.txt", width, height); - vector<BlurredSegment *> bss = detector.getBlurredSegments (); - double covFBSD = yl.covering (bss); - double covCL = yl.cannyLineCovering ("cannylines.txt", ncl, lcl, 0.); - ofstream outf ("cmpcov.txt", ios::out); - outf << covCL << " " << covFBSD << endl; - outf.close (); - - nbs = (int) bss.size (); - lbs = 0.; - vector<BlurredSegment *>::iterator it = bss.begin (); - while (it != bss.end ()) - { - Pt2i lastleft = (*it)->getLastLeft (); - Pt2i lastright = (*it)->getLastRight (); - lbs += sqrt ((lastleft.x () - lastright.x ()) - * (lastleft.x () - lastright.x ()) - + (lastleft.y () - lastright.y ()) - * (lastleft.y () - lastright.y ())); - it ++; - } - ofstream outl ("cmplines.txt", ios::out); - outl << ncl << " " << lcl << " " << (lcl / ncl) << " " - << nbs << " " << lbs << " " << (lbs / nbs) << endl; - outl.close (); - return (EXIT_SUCCESS); - } else if (yt) { QImage im; - im.load ("york.jpg"); + im.load ("Data/york.jpg"); int width = im.width (); int height = im.height (); int **tabImage = new int*[height]; @@ -157,7 +125,7 @@ int main (int argc, char *argv[]) detector.detectAll (); } double diff = (clock () - start) / (double) CLOCKS_PER_SEC; - ofstream outf ("fbsdperf.txt", ios::out); + ofstream outf ("Data/fbsdperf.txt", ios::out); outf << diff << endl; outf.close (); return (EXIT_SUCCESS);