From e4f56b1a2d2878dd7662f65768a58d531db1a306 Mon Sep 17 00:00:00 2001 From: even <philippe.even@loria.fr> Date: Mon, 31 Dec 2018 17:54:35 +0100 Subject: [PATCH] Article: synthetic tests corrected --- Article/Fig_synth/bias.txt | 31 ++ Article/Fig_synth/res.txt | 36 +++ Article/Fig_synth/statsTable.tex | 18 +- Article/expe.tex | 15 +- Article/method.tex | 19 +- Code/Seg/BSTools/bsdetectionwidget.cpp | 264 ++++++++++++++++-- Code/Seg/BSTools/bsdetectionwidget.h | 2 + Code/Seg/BlurredSegment/bsdetector.h | 19 +- .../Seg/ImageTools/digitalstraightsegment.cpp | 22 ++ Code/Seg/ImageTools/digitalstraightsegment.h | 18 ++ 10 files changed, 383 insertions(+), 61 deletions(-) create mode 100644 Article/Fig_synth/bias.txt create mode 100644 Article/Fig_synth/res.txt diff --git a/Article/Fig_synth/bias.txt b/Article/Fig_synth/bias.txt new file mode 100644 index 0000000..d6fb4bf --- /dev/null +++ b/Article/Fig_synth/bias.txt @@ -0,0 +1,31 @@ +1000 cartes avec 1 seul segment noir sur fond blanc +valeur du biais : 1.4 + + RESULTS FOR THE OLD DETECTOR +4.541 (pm 4.95509) segments searches (local min) / image +1.451 (pm 1.04819) provided segments / image +0.959 (pm 0.285308) provided long segments / image +0.034 (pm 0.2022) undetected segments per image +97.9024 (pm 2.46633) % of points found +1.17362 (pm 4.36513) % of points found more than once (redetections) +51.2433 (pm 36.4633) % false points produced +Precision : 0.656421 (pm 0.131706) +Width difference : 1.51583 (0.570322) per matched segment +Absolute width difference : 1.55401 (0.573155) per matched segment +Angle difference : 0.00662025 (0.610569) degrees per matched segment +Absolute angle difference : 0.282725 (0.675162) per matched segment +Absolute long edge angle difference : 0.066072 (0.112616) per matched segment + RESULTS FOR THE NEW DETECTOR +4.527 (pm 5.0781) segments searches (local min) / image +1.652 (pm 1.33891) provided segments / image +0.957 (pm 0.295361) provided long segments / image +0.055 (pm 0.27212) undetected segments per image +97.5876 (pm 4.39869) % of points found +1.12609 (pm 3.86839) % of points found more than once (redetections) +51.7437 (pm 35.7317) % false points produced +Precision : 0.653497 (pm 0.132444) +Width difference : 1.47118 (0.572052) per matched segment +Absolute width difference : 1.57777 (0.568894) per matched segment +Angle difference : -0.00543952 (0.719087) degrees per matched segment +Absolute angle difference : 0.366833 (0.791719) per matched segment +Long edge absolute angle difference : 0.0974464 (0.226732) per matched segment diff --git a/Article/Fig_synth/res.txt b/Article/Fig_synth/res.txt new file mode 100644 index 0000000..ff45cfc --- /dev/null +++ b/Article/Fig_synth/res.txt @@ -0,0 +1,36 @@ +1000 cartes avec 1000 segments noirs sur fond blanc +re-estimation de la largeur en retirant un biais de 1.4 + + RESULTS FOR THE OLD DETECTOR +69.719 (pm 20.3805) segments searches (local min) / image +25.23 (pm 6.65638) provided segments / image +10.766 (pm 1.96395) provided long segments / image +2.298 (pm 2.82935) undetected segments per image +88.3997 (pm 4.31352) % of points found +2.27666 (pm 1.50916) % of points found more than once (redetections) +32.2193 (pm 13.8132) % false points produced +Precision : 0.732884 (pm 0.0844506) +Biased width : 4.57922 (0.38789) per matched segment +Width : 3.37696 (0.350989) per matched segment +Width difference : 0.64275 (0.319964) per matched segment +Absolute width difference : 0.874094 (0.288227) per matched segment +Angle difference : 0.0497484 (0.756378) degrees per matched segment +Absolute angle difference : 1.2933 (0.92141) per matched segment +Absolute long edge angle difference : 0.44657 (0.55775) per matched segment + RESULTS FOR THE NEW DETECTOR +63.6 (pm 17.4179) segments searches (local min) / image +23.722 (pm 4.90028) provided segments / image +11.619 (pm 2.08619) provided long segments / image +0.475 (pm 0.756272) undetected segments per image +89.813 (pm 3.17276) % of points found +1.83739 (pm 1.3875) % of points found more than once (redetections) +22.5376 (pm 10.2339) % false points produced +Precision : 0.799399 (pm 0.0701648) +Biased width : 4.49693 (0.320961) per matched segment +Width : 3.26288 (0.297711) per matched segment +Width difference : 0.408348 (0.27149) per matched segment +Absolute width difference : 0.741648 (0.24851) per matched segment +Angle difference : 0.0354951 (0.641921) degrees per matched segment +Absolute angle difference : 0.982936 (0.696344) per matched segment +Long edge absolute angle difference : 0.480284 (0.568648) per matched segment + diff --git a/Article/Fig_synth/statsTable.tex b/Article/Fig_synth/statsTable.tex index 2bfe3c7..c7b013c 100644 --- a/Article/Fig_synth/statsTable.tex +++ b/Article/Fig_synth/statsTable.tex @@ -3,20 +3,18 @@ Detector : & \multicolumn{3}{c|}{old} & \multicolumn{3}{c|}{new} \\ \hline Amount of detected segments per image -& 21.22 & $\pm$ & 5.32 & 27.33 & $\pm$ & 6.38 \\ +& 25.23 & $\pm$ & 6.66 & 23.72 & $\pm$ & 4.90 \\ Amount of detected long segments per image -& 10.90 & $\pm$ & 1.88 & 9.03 & $\pm$ & 2.15 \\ +& 10.77 & $\pm$ & 1.96 & 11.62 & $\pm$ & 2.09 \\ Amount of undetected input segments per image -& 1.15 & $\pm$ & 1.80 & 0.28 & $\pm$ & 0.56 \\ +& 2.30 & $\pm$ & 2.83 & 0.47 & $\pm$ & 0.76 \\ Ratio of true detection (\%) : $\#(D\cap S)/\#S$ -& 96.83 & $\pm$ & 0.61 & 96.81 & $\pm$ & 0.62 \\ -Ratio of false detection (\%) : $\#(D\cap\overline{S})/\#S$ -& 6.9 & $\pm$ & 1.0 & 6.52 & $\pm$ & 0.94 \\ +& 88.40 & $\pm$ & 4.31 & 89.81 & $\pm$ & 3.17 \\ +Precision (\%) : $\#(D\cap S)/\#D$ +& 73.29 & $\pm$ & 8.45 & 79.94 & $\pm$ & 7.02 \\ Width difference (in pixels) to matched input segment -& 2.08 & $\pm$ & 0.27 & 1.91 & $\pm$ & 0.24 \\ +& 0.87 & $\pm$ & 0.29 & 0.74 & $\pm$ & 0.24 \\ Angle difference (in degrees) to matched input segment -& 0.87 & $\pm$ & 0.78 & 0.92 & $\pm$ & 0.75 \\ -Long segment angle difference (in degrees) -& 0.40 & $\pm$ & 0.63 & 0.34 & $\pm$ & 0.60 \\ +& 1.29 & $\pm$ & 0.92 & 0.98 & $\pm$ & 0.70 \\ \hline \end{tabular} diff --git a/Article/expe.tex b/Article/expe.tex index 5a1009a..99e66b1 100755 --- a/Article/expe.tex +++ b/Article/expe.tex @@ -14,13 +14,18 @@ optimized basic routines. The first test (\RefFig{fig:synth}) compares the performance of both detectors on a set of 1000 synthesized images containing 10 randomly -placed input segments with random width between 1 and 4 pixels. +placed input segments with random width between 2 and 5 pixels. +The absolute value of the difference of each found segment to its +matched input segment is measured. +On such perfect image, the numerical error on the gradient extraction +biases the line width measures. This bias was estimated in quasi ideal +context (only one input segment, thus no risk of perturbation) +and the found value (1.4 pixels) was taken into account in the test. Altough this perfect world context with low gradient noise tends to soften the old detector weaknesses, the results of \RefTab{tab:synth} show slightly -better width and angle measurements on long segments for the new detector. -The new detector generates more small segments that degrade the angle -estimations, but it produces a smaller amount of false detections and -succeeds in finding most of the input segments. +better width and angle measurements for the new detector. +The new detector shows more precise, with a smaller amount of false +detections and succeeds in finding most of the input segments. The second test (\RefFig{fig:hard}) visually compares the results of both detectors on quite difficult images, even for other detectors from diff --git a/Article/method.tex b/Article/method.tex index be0ecba..2cbedd8 100755 --- a/Article/method.tex +++ b/Article/method.tex @@ -175,16 +175,16 @@ the two opposite edges of a thin straight object. \begin{figure}[h] \center \begin{tabular}{c@{\hspace{0.2cm}}c} - \includegraphics[width=0.48\textwidth]{Fig_method/briques1_zoom.png} & - \includegraphics[width=0.48\textwidth]{Fig_method/briques2_zoom.png} + \includegraphics[width=0.38\textwidth]{Fig_method/briques1_zoom.png} & + \includegraphics[width=0.38\textwidth]{Fig_method/briques2_zoom.png} \end{tabular} \begin{picture}(1,1)(0,0) {\color{dwhite}{ - \put(-260,-17.5){\circle*{8}} - \put(-86,-17.5){\circle*{8}} + \put(-240,-12.5){\circle*{8}} + \put(-102,-12.5){\circle*{8}} }} - \put(-262.5,-20){a} - \put(-89,-20){b} + \put(-242.5,-15){a} + \put(-104.5,-15){b} \end{picture} \caption{Blurred segments obtained in \textit{line} or \textit{edge selection mode} as a result of the gradient direction filtering @@ -209,7 +209,6 @@ detection of all the segments crossed by the input stroke $AB$. In order to avoid multiple detections of the same edge, an occupancy mask, initially empty, collects the dilated points of all the blurred segments, so that these points can not be added to another segment. - \input{Fig_method/algoMulti} First the positions $M_j$ of the prominent local maxima of the gradient @@ -222,7 +221,7 @@ $2~\varepsilon_{ini}$, and $M_j$ is used as start point of the blurred segment; \item the occupancy mask is filled in with the points of the dilated blurred segments $\mathcal{B}_j''$ at the end of each successful detection -(a 21 pixels bowl is used to get the segment dilation); +(a 21 pixels bowl is used); \item points marked as occupied are rejected when selecting candidates for the blurred segment extension in the fine tracking step. \end{enumerate} @@ -241,14 +240,14 @@ 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. -\input{Fig_method/algoAuto} - The automatic detection of blurred segments in a whole image is left available for testing in an online demonstration at the following address: \\ \href{http://ipol-geometry.loria.fr/~kerautre/ipol_demo/AdaptDirBS_IPOLDemo}{ \small{\url{ http://ipol-geometry.loria.fr/~kerautre/ipol_demo/AdaptDirBS_IPOLDemo}}} +\input{Fig_method/algoAuto} + %The behavior of the unsupervised detection is depicted through the two %examples of \RefFig{fig:auto}. %The example on the left shows the detection of thin straight objects on a diff --git a/Code/Seg/BSTools/bsdetectionwidget.cpp b/Code/Seg/BSTools/bsdetectionwidget.cpp index 231311e..2567c72 100755 --- a/Code/Seg/BSTools/bsdetectionwidget.cpp +++ b/Code/Seg/BSTools/bsdetectionwidget.cpp @@ -1424,15 +1424,39 @@ void BSDetectionWidget::localTest () } +void BSDetectionWidget::createMap (QString name, + bool *tofind, bool *found, int iw, int ih) +{ + QImage mymap = QImage (width, height, QImage::Format_RGB32); + for (int j = 0; j < ih; j ++) + for (int i = 0; i < iw; i ++) + { + int col = 0; + if (tofind[j * iw + i]) + if (found[j * iw + i]) col = 255 * 256; + else col = 255; + else if (found[j * iw + i]) col = 255 * 256 * 256; + mymap.setPixel (i, j, col); + } + mymap.save (name); +} + + QSize BSDetectionWidget::setRandomImage (int type) { - width = 256; - height = 256; + int swidth = 256; + int sheight = 256; + int sminwidth = 2; + int smaxwidth = 5; + int sminlength = 20; + int margin = 10; int longEdgeThreshold = 1600; + width = swidth + 2 * margin; + height = sheight + 2 * margin; loadedImage = QImage (width, height, QImage::Format_RGB32); srand (time (NULL)); udef = false; - detector.setFineTracksMaxWidth (6); + detector.setFineTracksMaxWidth (7); if (! detector.isFinalLengthTestOn ()) detector.switchFinalLengthTest (); int nbsegs = 10; @@ -1443,6 +1467,7 @@ QSize BSDetectionWidget::setRandomImage (int type) vector<BlurredSegment *> rbs[nbsegs]; bool dispEach = false; + bool dispLast = false; int nbruns = 1000; int nbIniPts[nbruns]; int oldTrials[nbruns]; @@ -1455,12 +1480,22 @@ QSize BSDetectionWidget::setRandomImage (int type) int newNbNomatch[nbruns]; int oldUndet[nbruns]; int newUndet[nbruns]; + int oldTrueArea[nbruns]; + int newTrueArea[nbruns]; + int oldFalseArea[nbruns]; + int newFalseArea[nbruns]; int oldRedet[nbruns]; int newRedet[nbruns]; int oldFalse[nbruns]; int newFalse[nbruns]; + double oldPrec[nbruns]; + double newPrec[nbruns]; double oldNbMatched[nbruns]; double newNbMatched[nbruns]; + double oldWidthBias[nbruns]; + double newWidthBias[nbruns]; + double oldWidth[nbruns]; + double newWidth[nbruns]; double oldWidthDiff[nbruns]; double newWidthDiff[nbruns]; double oldAbsWDiff[nbruns]; @@ -1479,16 +1514,43 @@ QSize BSDetectionWidget::setRandomImage (int type) for (int i = 0; i < width; i ++) for (int j = 0; j < height; j ++) { +// val = rand () % 30; // ZZZ val = 255 - (rand () % 30); loadedImage.setPixel (i, j, val + val * 256 + val * 256 * 256); } for (int i = 0; i < nbsegs; i++) { - rp1[i].set (rand () % width, rand () % height); - do rp2[i].set (rand () % width, rand () % height); - while (rp1[i].chessboard (rp2[i]) < 20); - rdir[i] = rp1[i].vectorTo (rp2[i]); - rw[i] = 1 + rand () % 3; + rp1[i].set (margin + rand () % swidth, margin + rand () % sheight); + bool nok = false; + do + { + nok = false; + rp2[i].set (margin + rand () % swidth, margin + rand () % sheight); + if (rp1[i].chessboard (rp2[i]) < sminlength) nok = true; + else + { + double score1, score2, score3; + rdir[i] = rp1[i].vectorTo (rp2[i]); + Pt2i bsc ((rp1[i].x () + rp2[i].x ()) / 2, + (rp1[i].y () + rp2[i].y ()) / 2); + for (int si = 0; (! nok) && si < i - 1; si ++) + { + score1 = rdir[si].squaredScalarProduct (rdir[i]) + / (rdir[si].norm2 () * rdir[i].norm2 ()); + Vr2i ali = rp1[si].vectorTo (bsc); + score2 = rdir[si].squaredScalarProduct (ali) + / (rdir[si].norm2 () * ali.norm2 ()); + bsc.set ((rp1[si].x () + rp2[si].x ()) / 2, + (rp1[si].y () + rp2[si].y ()) / 2); + ali = rp1[i].vectorTo (bsc); + score3 = rdir[i].squaredScalarProduct (ali) + / (rdir[i].norm2 () * ali.norm2 ()); + if (score1 > 0.7 && (score2 > 0.7 || score3 > 0.7)) nok = true; + } + } + } + while (nok); + rw[i] = sminwidth + rand () % (smaxwidth - sminwidth); DigitalStraightSegment dss (rp1[i], rp2[i], rw[i]); vector<Pt2i> pix; @@ -1499,6 +1561,8 @@ QSize BSDetectionWidget::setRandomImage (int type) Pt2i p = *it++; if (p.x () >= 0 && p.x () < width && p.y () >= 0 && p.y () < height) loadedImage.setPixel (p.x (), height - 1 - p.y (), 0); +// loadedImage.setPixel (p.x (), height - 1 - p.y (), // ZZZ +// 255 + 255 * 256 + 255 * 256 * 256); // ZZZ } } @@ -1511,13 +1575,24 @@ QSize BSDetectionWidget::setRandomImage (int type) if (dispEach) cout << "Preparing the result maps" << endl; nbIniPts[run] = 0; - bool virgin[width * height]; + bool tofind[width * height]; + bool stilltofind[width * height]; + bool found[width * height]; + bool foundin[width * height]; + bool foundout[width * height]; for (int j = 0; j < height; j++) for (int i = 0; i < width; i++) { - virgin[j * width + i] = QColor(loadedImage.pixel(i,j)).value () < 10; - nbIniPts[run] ++; + tofind[j * width + i] = QColor (loadedImage.pixel (i, height - 1 - j)) + .value () < 10; +// .value () > 200; // ZZZ + stilltofind[j * width + i] = tofind[j * width + i]; + found[j * width + i] = false; + foundin[j * width + i] = false; + foundout[j * width + i] = false; + if (tofind[j * width + i]) nbIniPts[run] ++; } +if (nbIniPts[run] == 0) cout << "CARTE VIDE" << endl; int detmap[width * height]; int *dm = detmap; for (int i = 0; i < width * height; i++) *dm++ = 0; @@ -1539,6 +1614,7 @@ QSize BSDetectionWidget::setRandomImage (int type) DigitalStraightSegment *dss = (*bsit)->getSegment (); if (dss != NULL) { + dss = dss->erosion (7, 5); vector<Pt2i> dsspts; dss->getPoints (dsspts); vector<Pt2i>::iterator dssit = dsspts.begin (); @@ -1548,10 +1624,18 @@ QSize BSDetectionWidget::setRandomImage (int type) if (dsspt.x () >= 0 && dsspt.x () < width && dsspt.y () >= 0 && dsspt.y () < height) { - virgin[dsspt.y () * width + dsspt.x ()] = false; - detmap[dsspt.y () * width + dsspt.x ()] += - (QColor(loadedImage.pixel(dsspt.x(),dsspt.y())) .value () < 10 ? - 1 : -1); + stilltofind[dsspt.y () * width + dsspt.x ()] = false; + found[dsspt.y () * width + dsspt.x ()] = true; + if (tofind[dsspt.y () * width + dsspt.x ()]) + { + detmap[dsspt.y () * width + dsspt.x ()] ++; + foundin[dsspt.y () * width + dsspt.x ()] = true; + } + else + { + detmap[dsspt.y () * width + dsspt.x ()] --; + foundout[dsspt.y () * width + dsspt.x ()] = true; + } } } @@ -1587,6 +1671,7 @@ QSize BSDetectionWidget::setRandomImage (int type) oldNbNomatch[run] ++; nomatchlength += sqrt (bsl2); } + delete dss; } else nbdssnul ++; bsit ++; @@ -1602,8 +1687,17 @@ QSize BSDetectionWidget::setRandomImage (int type) cout << oldLongDetections[run] << " long blurred segments detected on " << oldTrials[run] << " trials " << endl; } + if (dispLast && run == nbruns - 1) + createMap ("oldmap.png", tofind, found, width, height); oldUndet[run] = 0; - for (int i = 0; i < width * height; i++) if (virgin[i]) oldUndet[run] ++; + oldTrueArea[run] = 0; + oldFalseArea[run] = 0; + for (int i = 0; i < width * height; i++) + { + if (stilltofind[i]) oldUndet[run] ++; + if (foundin[i]) oldTrueArea[run] ++; + if (foundout[i]) oldFalseArea[run] ++; + } if (dispEach) cout << (nbIniPts[run] - oldUndet[run]) << " points detected on " << nbIniPts[run] << " (" @@ -1619,17 +1713,22 @@ QSize BSDetectionWidget::setRandomImage (int type) oldFalse[run] = 0; for (int i = 0; i < width * height; i++) if (detmap[i] < 0) oldFalse[run] ++; + oldPrec[run] = nbIniPts[run] - oldUndet[run]; + oldPrec[run] = oldPrec[run] / (oldPrec[run] + oldFalse[run]); if (dispEach) { cout << oldFalse[run] << " false points detected on " << nbIniPts[run] << " (" << oldFalse[run] * 100 / (double) nbIniPts[run] << " %)" << endl; + cout << "Precision : " << oldPrec[run] << endl; cout << oldNbNomatch[run] << " unmatched blurred segment (mean length : " << (oldNbNomatch[run] != 0 ? nomatchlength / oldNbNomatch[run] : 0) << ")" << endl; cout << nbdssnul << " DSS nuls" << endl; } + oldWidthBias[run] = 0.; + oldWidth[run] = 0.; oldWidthDiff[run] = 0.; oldAbsWDiff[run] = 0.; oldAngDiff[run] = 0.; @@ -1647,6 +1746,11 @@ QSize BSDetectionWidget::setRandomImage (int type) double bsl2 = (ptb.x () - ptf.x ()) * (ptb.x () - ptf.x ()) + (ptb.y () - ptf.y ()) * (ptb.y () - ptf.y ()); DigitalStraightSegment *mydss = (*sit)->getSegment (); + oldWidthBias[run] += (mydss->width () / (double) (mydss->period ())) + * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); + mydss = mydss->erosion (7, 5); + oldWidth[run] += (mydss->width () / (double) (mydss->period ())) + * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); double wd = (mydss->width () / (double) (mydss->period ()) - rw[si]) * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); oldWidthDiff[run] += wd; @@ -1669,11 +1773,18 @@ QSize BSDetectionWidget::setRandomImage (int type) oldAngDiff[run] += (onleft ? ang : -ang); if (bsl2 > longEdgeThreshold) oldLongADiff[run] += ang; } + delete mydss; sit ++; } } if (dispEach) { + cout << "Biased width = " + << (oldNbMatched[run] != 0 ? + oldWidthBias[run] / oldNbMatched[run] : 0) << endl; + cout << "Width = " + << (oldNbMatched[run] != 0 ? + oldWidth[run] / oldNbMatched[run] : 0) << endl; cout << "Width difference = " << (oldNbMatched[run] != 0 ? oldWidthDiff[run] / oldNbMatched[run] : 0) << endl; @@ -1694,7 +1805,12 @@ QSize BSDetectionWidget::setRandomImage (int type) if (dispEach) cout << "Resetting the result maps" << endl; for (int j = 0; j < height; j++) for (int i = 0; i < width; i++) - virgin[j * width + i] = QColor(loadedImage.pixel(i,j)).value () < 10; + { + stilltofind[j * width + i] = tofind[j * width + i]; + found[j * width + i] = false; + foundin[j * width + i] = false; + foundout[j * width + i] = false; + } dm = detmap; for (int i = 0; i < width * height; i++) *dm++ = 0; @@ -1715,6 +1831,7 @@ QSize BSDetectionWidget::setRandomImage (int type) DigitalStraightSegment *dss = (*bsit)->getSegment (); if (dss != NULL) { + dss = dss->erosion (7, 5); vector<Pt2i> dsspts; dss->getPoints (dsspts); vector<Pt2i>::iterator dssit = dsspts.begin (); @@ -1724,10 +1841,18 @@ QSize BSDetectionWidget::setRandomImage (int type) if (dsspt.x () >= 0 && dsspt.x () < width && dsspt.y () >= 0 && dsspt.y () < height) { - virgin[dsspt.y () * width + dsspt.x ()] = false; - detmap[dsspt.y () * width + dsspt.x ()] += - (QColor(loadedImage.pixel(dsspt.x(),dsspt.y())).value () < 10 ? - 1 : -1); + stilltofind[dsspt.y () * width + dsspt.x ()] = false; + found[dsspt.y () * width + dsspt.x ()] = true; + if (tofind[dsspt.y () * width + dsspt.x ()]) + { + detmap[dsspt.y () * width + dsspt.x ()] ++; + foundin[dsspt.y () * width + dsspt.x ()] = true; + } + else + { + detmap[dsspt.y () * width + dsspt.x ()] --; + foundout[dsspt.y () * width + dsspt.x ()] = true; + } } } @@ -1763,6 +1888,7 @@ QSize BSDetectionWidget::setRandomImage (int type) newNbNomatch[run] ++; nomatchlength += sqrt (bsl2); } + delete dss; } else nbdssnul ++; bsit ++; @@ -1778,8 +1904,17 @@ QSize BSDetectionWidget::setRandomImage (int type) cout << newLongDetections[run] << " long blurred segments detected on " << newTrials[run] << " trials " << endl; } + if (dispLast && run == nbruns - 1) + createMap ("newmap.png", tofind, found, width, height); newUndet[run] = 0; - for (int i = 0; i < width * height; i++) if (virgin[i]) newUndet[run] ++; + newTrueArea[run] = 0; + newFalseArea[run] = 0; + for (int i = 0; i < width * height; i++) + { + if (stilltofind[i]) newUndet[run] ++; + if (foundin[i]) newTrueArea[run] ++; + if (foundout[i]) newFalseArea[run] ++; + } if (dispEach) cout << (nbIniPts[run] - newUndet[run]) << " points detected on " << nbIniPts[run] << " (" @@ -1795,17 +1930,22 @@ QSize BSDetectionWidget::setRandomImage (int type) newFalse[run] = 0; for (int i = 0; i < width * height; i++) if (detmap[i] < 0) newFalse[run] ++; + newPrec[run] = nbIniPts[run] - newUndet[run]; + newPrec[run] = newPrec[run] / (newPrec[run] + newFalse[run]); if (dispEach) { cout << newFalse[run] << " false points detected on " << nbIniPts[run] << " (" << newFalse[run] * 100 / (double) nbIniPts[run] << " %)" << endl; + cout << "Precision : " << newPrec[run] << endl; cout << newNbNomatch[run] << " unmatched blurred segment (mean length : " << (newNbNomatch[run] != 0 ? nomatchlength / newNbNomatch[run] : 0) << ")" << endl; cout << nbdssnul << " DSS nuls" << endl; } + newWidthBias[run] = 0.; + newWidth[run] = 0.; newWidthDiff[run] = 0.; newAbsWDiff[run] = 0.; newAngDiff[run] = 0.; @@ -1823,6 +1963,11 @@ QSize BSDetectionWidget::setRandomImage (int type) double bsl2 = (ptb.x () - ptf.x ()) * (ptb.x () - ptf.x ()) + (ptb.y () - ptf.y ()) * (ptb.y () - ptf.y ()); DigitalStraightSegment *mydss = (*sit)->getSegment (); + newWidthBias[run] += (mydss->width () / (double) (mydss->period ())) + * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); + mydss = mydss->erosion (7, 5); + newWidth[run] += (mydss->width () / (double) (mydss->period ())) + * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); double wd = (mydss->width () / (double) (mydss->period ()) - rw[si]) * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); newWidthDiff[run] += wd; @@ -1845,11 +1990,18 @@ QSize BSDetectionWidget::setRandomImage (int type) newAngDiff[run] += (onleft ? ang : -ang); if (bsl2 > longEdgeThreshold) newLongADiff[run] += ang; } + delete mydss; sit ++; } } if (dispEach) { + cout << "Biased width = " + << (newNbMatched[run] != 0 ? + newWidthBias[run] / newNbMatched[run] : 0) << endl; + cout << "Width = " + << (newNbMatched[run] != 0 ? + newWidth[run] / newNbMatched[run] : 0) << endl; cout << "Width difference = " << (newNbMatched[run] != 0 ? newWidthDiff[run] / newNbMatched[run] : 0) << endl; @@ -1939,10 +2091,44 @@ QSize BSDetectionWidget::setRandomImage (int type) sdev = sqrt (sdev / (nbruns - 1)); cout << 100 * mean << " (pm " << 100 * sdev << ") % false points produced" << endl; + mean = 0.; + sdev = 0.; + int numer = 0; + int denom = 0; + for (int i = 0; i < nbruns; i++) + { + numer += nbIniPts[i] - oldUndet[i]; + denom += oldFalse[i] + nbIniPts[i] - oldUndet[i]; + } + mean = numer / (double) denom; + for (int i = 0; i < nbruns; i++) + sdev += (oldPrec[i] - mean) * (oldPrec[i] - mean); + sdev = sqrt (sdev / (nbruns - 1)); + cout << "Precision : " << mean << " (pm " << sdev << ")" << endl; total = 0; for (int i = 0; i < nbruns; i++) total += oldNbMatched[i]; mean = 0.; sdev = 0.; + for (int i = 0; i < nbruns; i++) mean += oldWidthBias[i]; + mean /= total; + for (int i = 0; i < nbruns; i++) + sdev += (oldWidthBias[i] / (double) oldNbMatched[i] - mean) + * (oldWidthBias[i] / (double) oldNbMatched[i] - mean); + sdev = sqrt (sdev / (nbruns - 1)); + cout << "Biased width : " << mean << " (" << sdev + << ") per matched segment" << endl; + mean = 0.; + sdev = 0.; + for (int i = 0; i < nbruns; i++) mean += oldWidth[i]; + mean /= total; + for (int i = 0; i < nbruns; i++) + sdev += (oldWidth[i] / (double) oldNbMatched[i] - mean) + * (oldWidth[i] / (double) oldNbMatched[i] - mean); + sdev = sqrt (sdev / (nbruns - 1)); + cout << "Width : " << mean << " (" << sdev + << ") per matched segment" << endl; + mean = 0.; + sdev = 0.; for (int i = 0; i < nbruns; i++) mean += oldWidthDiff[i]; mean /= total; for (int i = 0; i < nbruns; i++) @@ -2059,10 +2245,44 @@ QSize BSDetectionWidget::setRandomImage (int type) sdev = sqrt (sdev / (nbruns - 1)); cout << 100 * mean << " (pm " << 100 * sdev << ") % false points produced" << endl; + mean = 0.; + sdev = 0.; + numer = 0; + denom = 0; + for (int i = 0; i < nbruns; i++) + { + numer += nbIniPts[i] - newUndet[i]; + denom += newFalse[i] + nbIniPts[i] - newUndet[i]; + } + mean = numer / (double) denom; + for (int i = 0; i < nbruns; i++) + sdev += (newPrec[i] - mean) * (newPrec[i] - mean); + sdev = sqrt (sdev / (nbruns - 1)); + cout << "Precision : " << mean << " (pm " << sdev << ")" << endl; total = 0; for (int i = 0; i < nbruns; i++) total += newNbMatched[i]; mean = 0.; sdev = 0.; + for (int i = 0; i < nbruns; i++) mean += newWidthBias[i]; + mean /= total; + for (int i = 0; i < nbruns; i++) + sdev += (newWidthBias[i] / (double) newNbMatched[i] - mean) + * (newWidthBias[i] / (double) newNbMatched[i] - mean); + sdev = sqrt (sdev / (nbruns - 1)); + cout << "Biased width : " << mean << " (" << sdev + << ") per matched segment" << endl; + mean = 0.; + sdev = 0.; + for (int i = 0; i < nbruns; i++) mean += newWidth[i]; + mean /= total; + for (int i = 0; i < nbruns; i++) + sdev += (newWidth[i] / (double) newNbMatched[i] - mean) + * (newWidth[i] / (double) newNbMatched[i] - mean); + sdev = sqrt (sdev / (nbruns - 1)); + cout << "Width : " << mean << " (" << sdev + << ") per matched segment" << endl; + mean = 0.; + sdev = 0.; for (int i = 0; i < nbruns; i++) mean += newWidthDiff[i]; mean /= total; for (int i = 0; i < nbruns; i++) diff --git a/Code/Seg/BSTools/bsdetectionwidget.h b/Code/Seg/BSTools/bsdetectionwidget.h index 114b709..f9ba115 100755 --- a/Code/Seg/BSTools/bsdetectionwidget.h +++ b/Code/Seg/BSTools/bsdetectionwidget.h @@ -38,6 +38,8 @@ public: */ ~BSDetectionWidget (); +void createMap (QString name, bool *tofind, bool *found, int iw, int ih); + /** * \brief Creates and opens a random image to be processed. * @param type Gradient extraction method. diff --git a/Code/Seg/BlurredSegment/bsdetector.h b/Code/Seg/BlurredSegment/bsdetector.h index 2b4d16e..d53850a 100755 --- a/Code/Seg/BlurredSegment/bsdetector.h +++ b/Code/Seg/BlurredSegment/bsdetector.h @@ -17,8 +17,8 @@ class BSDetector public: - /** Version number **/ - static const string VERSION; + /** Version number */ + static const std::string VERSION; /** Identifier for the final detection step. */ static const int STEP_FINAL; @@ -141,16 +141,7 @@ public: * @param step Detection step. */ BlurredSegment *getBlurredSegment (int step = STEP_FINAL) const; - - - /** - * \brief Returns the current version of the detector. - * @return the current version. - */ - std::string version(); - - - + /** * \brief Returns the list of detected blurred segments at final step. */ @@ -600,7 +591,8 @@ public: * \brief Toggles the detector used (between IWCIA '09 and present). */ inline void switchDetector () { oldp = ! oldp; } - + +std::string version (); private : @@ -729,6 +721,5 @@ private : */ void freeMultiSelection (); - }; #endif diff --git a/Code/Seg/ImageTools/digitalstraightsegment.cpp b/Code/Seg/ImageTools/digitalstraightsegment.cpp index cbb53bd..5880343 100755 --- a/Code/Seg/ImageTools/digitalstraightsegment.cpp +++ b/Code/Seg/ImageTools/digitalstraightsegment.cpp @@ -55,6 +55,15 @@ DigitalStraightSegment::DigitalStraightSegment (Pt2i p1, Pt2i p2, int width) } +DigitalStraightSegment::DigitalStraightSegment (int va, int vb, int vc, + int vnu, int vmin, int vmax) + : DigitalStraightLine (va, vb, vc, vnu) +{ + min = vmin; + max = vmax; +} + + Pt2i DigitalStraightSegment::getABoundingPoint (bool upper) const { int sa = a, sb = b, u1 = 1, v1 = 0, u2 = 0, v2 = 1; @@ -155,3 +164,16 @@ void DigitalStraightSegment::getPoints (vector<Pt2i> &pts) const it ++; } } + + +DigitalStraightSegment *DigitalStraightSegment::erosion (int num, int den) const +{ + int newwidth = nu; + if (nu > period ()) + { + newwidth = nu - (num * period ()) / den; + if (newwidth < period ()) newwidth = period (); + } + return (new DigitalStraightSegment (a, b, c + (nu - newwidth) / 2, + newwidth, min, max)); +} diff --git a/Code/Seg/ImageTools/digitalstraightsegment.h b/Code/Seg/ImageTools/digitalstraightsegment.h index 8ab1ccc..664f67e 100755 --- a/Code/Seg/ImageTools/digitalstraightsegment.h +++ b/Code/Seg/ImageTools/digitalstraightsegment.h @@ -67,6 +67,13 @@ public: */ void getPoints (vector<Pt2i> &pts) const; + /** + * \brief Returns an erosion of the segment. + * @param num Erosion value numerator. + * @param den Erosion value denominator. + */ + DigitalStraightSegment *erosion (int num, int den) const; + protected: @@ -86,6 +93,17 @@ protected: int max; + /** + * Creates a segment from its characteristics. + * @param va Slope X coordinate. + * @param vb Slope Y coordinate. + * @param vc Shift to origin. + * @param vnu Arithmetical width. + * @param vmin Bounding line lower coordinate. + * @param vmax Bounding line upper coordinate. + */ + DigitalStraightSegment (int va, int vb, int vc, int vnu, int vmin, int vmax); + /** * \brief Adjusts the provided area on the segment limits. * @param xmin Left coordinate of the area. -- GitLab