diff --git a/Article/Fig_synth/bias.txt b/Article/Fig_synth/bias.txt new file mode 100644 index 0000000000000000000000000000000000000000..d6fb4bfe1ca6fe919ecba93539ee0edd74e6cd43 --- /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 0000000000000000000000000000000000000000..ff45cfc0fbab9e67b780ae609686f73cf4aec16b --- /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 2bfe3c790d89d74a2bdf0a97a6183b67cb526a18..c7b013c6b1cb17fadb38784123e4d3be82b0f451 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 5a1009a3e8366bb7e4c11cd31501dafb5b19426a..99e66b17b089d4d41718566474b4ba4a209ddf4f 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 be0ecbadfcac150e3a037339764e2119859103c8..2cbedd84ba08e4d5928b3625c9390d66fc34b002 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 231311e64a7c113c96a0502596a04c94d1638228..2567c72a87777df30008778a4bcdc992e369a733 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 114b70901567280134081d15aaebc1e6d6c05714..f9ba1152bed20d84236a9a4c3a2cff30f4f539d4 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 2b4d16e4e911cfffec9ab142022f06639ce5a4e9..d53850a2825255f842a221eec7346eaac1ef0a2a 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 cbb53bd5d5aa2d6609a036c3fcbf71845eacda45..5880343375cfe6909945d3667f37cd905d5be76b 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 8ab1ccc66d6e8e1d867747efcd9dcf6f2922e143..664f67e7da4ef159f51f03690f765e764e52f282 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.