diff --git a/Article/method.tex b/Article/method.tex index a61e645f1b2227d7e7f850bea6011862b3e2374a..b07121d78e5b0ceb7e287fb6bff654efd0e3473d 100755 --- a/Article/method.tex +++ b/Article/method.tex @@ -372,8 +372,9 @@ of interfering outliers insertion. 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}}} - +\href{http://ipol-geometry.loria.fr/~kerautre/ipol_demo/AdaptDirBS_IPOLDemo}{ +\small{\url{ +http://ipol-geometry.loria.fr/~kerautre/ipol_demo/AdaptDirBS_IPOLDemo}}} %The behavior of the unsupervised detection is depicted through the two %examples of \RefFig{fig:auto}. diff --git a/Code/Seg/BSTools/bsdetectionwidget.cpp b/Code/Seg/BSTools/bsdetectionwidget.cpp index bd1b18a87fcc6dbeabfe057cbc28adee2a99f9f3..04ae746f654dd57f01e9b2b0d91aabc9cada9222 100755 --- a/Code/Seg/BSTools/bsdetectionwidget.cpp +++ b/Code/Seg/BSTools/bsdetectionwidget.cpp @@ -28,8 +28,6 @@ BSDetectionWidget::BSDetectionWidget (QWidget *parent) grabKeyboard (); udef = false; nodrag = true; - nbdettrials = 0; - nbmaxdettrials = 0; // Initializes the gradient map and the auxiliary views gMap = NULL; @@ -46,13 +44,12 @@ BSDetectionWidget::BSDetectionWidget (QWidget *parent) blevel = 0; // Sets display parameters + darkHighlightOn = false; selectionColor = Qt::red; bsColor = Qt::blue; - //bsHighColor = Qt::black; bsHighColor = Qt::yellow; bsPointsVisible = true; boundColor = Qt::green; - //boundHighColor = Qt::black; boundHighColor = Qt::magenta; } @@ -294,6 +291,22 @@ void BSDetectionWidget::switchIdetAnalyzer () } +void BSDetectionWidget::switchHighlightColors () +{ + darkHighlightOn = ! darkHighlightOn; + if (darkHighlightOn) + { + bsHighColor = Qt::black; + boundHighColor = Qt::blue; + } + else + { + bsHighColor = Qt::yellow; + boundHighColor = Qt::magenta; + } +} + + void BSDetectionWidget::mousePressEvent (QMouseEvent *event) { oldp1.set (p1); @@ -320,14 +333,12 @@ void BSDetectionWidget::mouseReleaseEvent (QMouseEvent *event) alternate = 0; cerr << "p1 defined: " << p1.x () << " " << p1.y () << endl; cerr << "p2 defined: " << p2.x () << " " << p2.y () << endl; - detector.setMaxTrials (0); + detector.resetMaxDetections (); extract (); - nbdettrials = detector.countOfTrials (); - nbmaxdettrials = 0; if (detector.isMultiSelection ()) cout << detector.getBlurredSegments().size () << " blurred segments detected on " - << nbdettrials << " essais " << endl; + << detector.countOfTrials () << " essais " << endl; } } @@ -530,13 +541,11 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) { // Runs an automatic detection udef = false; - detector.setMaxTrials (-1); + detector.resetMaxDetections (); extract (); - nbdettrials = detector.countOfTrials (); - nbmaxdettrials = 0; -// cout << detector.getBlurredSegments().size () -// << " blurred segments detected on " -// << nbdettrials << " essais " << endl; + cout << detector.getBlurredSegments().size () + << " blurred segments detected on " + << detector.countOfTrials () << " essais " << endl; } break; @@ -552,14 +561,13 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) else { // Highlights the next segment in a multi-detection - if (! detector.getBlurredSegments().empty ()) + vector<BlurredSegment *> bsl = detector.getBlurredSegments (); + if (! bsl.empty ()) { - nbmaxdettrials += (event->modifiers () & Qt::ShiftModifier ? -1 : 1); - if (nbmaxdettrials < 0) nbmaxdettrials = nbdettrials; - else if (nbmaxdettrials > nbdettrials) nbmaxdettrials = 0; - detector.setMaxTrials (nbmaxdettrials); - cout << "Selection du segment " << nbmaxdettrials << endl; + detector.incMaxDetections (event->modifiers () & Qt::ShiftModifier); extract (); + cout << "Selection of segment " + << detector.getMaxDetections () << endl; } } break; @@ -770,6 +778,11 @@ void BSDetectionWidget::keyPressEvent (QKeyEvent *event) } break; + case Qt::Key_Exclam : + switchHighlightColors (); + displayDetectionResult (); + break; + case Qt::Key_1 : switchPixelAnalyzer (); break; @@ -989,8 +1002,8 @@ void BSDetectionWidget::displayDetectionResult () // if (dss == NULL) cout << "DSS null" << endl; // else bsw += dss->width () / (double) dss->period (); // } - drawBlurredSegment (painter, *it, nbmaxdettrials == 0 || - (*it == bss.back () && detector.isLastTrialOk ())); + drawBlurredSegment (painter, *it, detector.getMaxDetections () == 0 + || *it == bss.back ()); it++; } // cout << bsc << " effective blurred segments" << endl; @@ -1121,6 +1134,23 @@ void BSDetectionWidget::writeDetectionStatus () } +void BSDetectionWidget::saveMask () +{ + QImage mim (width, height, QImage::Format_RGB32); + bool *mask = gMap->getMask (); + int nb = 0; + for (int j = 0; j < height; j++) + for (int i = 0; i < width; i++) + { + if (*mask) nb++; + mim.setPixel (i, height - 1 - j, + *mask++ ? 0 : 255 + 255 * 256 + 255 * 256 * 256); + } + mim.save ("mask.png"); + cout << "mask.png created with " << nb << " points" << endl; +} + + void BSDetectionWidget::extract () { if (udef) @@ -1222,6 +1252,498 @@ void BSDetectionWidget::localTest () } else cout << "Run autotest" << endl; + detector.resetMaxDetections (); extract (); cout << "Test run" << endl; } + + +QSize BSDetectionWidget::setRandomImage (int type) +{ + width = 256; + height = 256; + loadedImage = QImage (width, height, QImage::Format_RGB32); + srand (time (NULL)); + udef = false; + detector.setFineTracksMaxWidth (6); + if (! detector.isFinalLengthTestOn ()) detector.switchFinalLengthTest (); + + int nbsegs = 10; + Pt2i rp1[nbsegs]; + Pt2i rp2[nbsegs]; + Vr2i rdir[nbsegs]; + int rw[nbsegs]; + vector<BlurredSegment *> rbs[nbsegs]; + + bool dispEach = false; + int nbruns = 100; + int nbIniPts[nbruns]; + int oldTrials[nbruns]; + int newTrials[nbruns]; + int oldDetections[nbruns]; + int newDetections[nbruns]; + int oldUndet[nbruns]; + int newUndet[nbruns]; + int oldRedet[nbruns]; + int newRedet[nbruns]; + int oldFalse[nbruns]; + int newFalse[nbruns]; + double oldNbMatched[nbruns]; + double newNbMatched[nbruns]; + double oldWidthDiff[nbruns]; + double newWidthDiff[nbruns]; + double oldAbsDiff[nbruns]; + double newAbsDiff[nbruns]; + double oldAngDiff[nbruns]; + double newAngDiff[nbruns]; + + for (int run = 0; run < nbruns; run ++) + { + if (dispEach) cout << "Generating new segments" << endl; + int val; + for (int i = 0; i < width; i ++) + for (int j = 0; j < height; j ++) + { + 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; + + DigitalStraightSegment dss (rp1[i], rp2[i], rw[i]); + vector<Pt2i> pix; + dss.getPoints (pix); + vector<Pt2i>::iterator it = pix.begin (); + while (it != pix.end ()) + { + 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); + } + } + + if (dispEach) cout << "Initializing the detector" << endl; + if (gMap != NULL) delete gMap; + gMap = new VMap (width, height, getBitmap (loadedImage), type); + detector.setGradientMap (gMap); + buildGradientImage (0); + gMap->incGradientThreshold (50 - gMap->getGradientThreshold ()); + + if (dispEach) cout << "Preparing the result maps" << endl; + nbIniPts[run] = 0; + bool virgin[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] ++; + } + int detmap[width * height]; + int *dm = detmap; + for (int i = 0; i < width * height; i++) *dm++ = 0; + + if (dispEach) cout << "Running the old detection" << endl; + if (! detector.oldDetectorOn ()) detector.switchDetector (); + extract (); + + if (dispEach) cout << "Analyzing the old blurred segments" << endl; + for (int i = 0; i < nbsegs; i++) rbs[i].clear (); + int nbnomatch = 0; + int nbokortho = 0; + int nbokcolin = 0; + int nbokmid = 0; + int nbdssnul = 0; + double nomatchlength = 0.; + vector<BlurredSegment *> bss = detector.getBlurredSegments (); + vector<BlurredSegment *>::iterator bsit = bss.begin (); + while (bsit != bss.end ()) + { + DigitalStraightSegment *dss = (*bsit)->getSegment (); + if (dss != NULL) + { + vector<Pt2i> dsspts; + dss->getPoints (dsspts); + vector<Pt2i>::iterator dssit = dsspts.begin (); + while (dssit != dsspts.end ()) + { + Pt2i dsspt = *dssit++; + 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); + } + } + + Vr2i dssdir = dss->supportVector (); + Pt2i ptb = (*bsit)->getLastRight (); + Pt2i ptf = (*bsit)->getLastLeft (); + Pt2i bsc ((ptb.x () + ptf.x ()) / 2, (ptb.y () + ptf.y ()) / 2); + double bsl2 = (ptb.x () - ptf.x ()) * (ptb.x () - ptf.x ()) + + (ptb.y () - ptf.y ()) * (ptb.y () - ptf.y ()); + bool searching = true; + for (int si = 0; searching && si < nbsegs; si++) + { + if (rdir[si].squaredVectorProduct (dssdir) + < 0.1 * rdir[si].norm2 () * dssdir.norm2 ()) + { + nbokortho ++; + Vr2i bsac = rp1[si].vectorTo (bsc); + if (rdir[si].squaredVectorProduct (bsac) + < 0.1 * rdir[si].norm2 () * bsac.norm2 ()) + { + nbokcolin ++; + if (rdir[si].scalarProduct (bsac) > 0) + { + Vr2i bscb = bsc.vectorTo (rp2[si]); + if (rdir[si].scalarProduct (bscb) > 0) + { + nbokmid ++; + rbs[si].push_back (*bsit); + searching = false; + } + } + } + } + } + if (searching) + { + nbnomatch ++; + nomatchlength += sqrt (bsl2); + } + } + else nbdssnul ++; + bsit ++; + } + + if (dispEach) cout << " OLD DETECTOR :" << endl; + oldTrials[run] = detector.countOfTrials (); + oldDetections[run] = (int) (detector.getBlurredSegments().size ()); + if (dispEach) + cout << oldDetections[run] << " blurred segments detected on " + << oldTrials[run] << " trials " << endl; + oldUndet[run] = 0; + for (int i = 0; i < width * height; i++) if (virgin[i]) oldUndet[run] ++; + if (dispEach) + cout << (nbIniPts[run] - oldUndet[run]) << " points detected on " + << nbIniPts[run] << " (" + << (nbIniPts[run] - oldUndet[run]) * 100 / (double) nbIniPts[run] + << " %)" << endl; + oldRedet[run] = 0; + for (int i = 0; i < width * height; i++) + if (detmap[i] > 1) oldRedet[run] += (detmap[i] - 1); + if (dispEach) + cout << oldRedet[run] << " points redetected on " << nbIniPts[run] + << " (" << oldRedet[run] * 100 / (double) nbIniPts[run] + << " %)" << endl; + oldFalse[run] = 0; + for (int i = 0; i < width * height; i++) + if (detmap[i] < 0) oldFalse[run] ++; + if (dispEach) + { + cout << oldFalse[run] << " false points detected on " << nbIniPts[run] + << " (" << oldFalse[run] * 100 / (double) nbIniPts[run] + << " %)" << endl; + cout << nbnomatch << " unmatched blurred segment (mean length : " + << (nbnomatch != 0 ? nomatchlength / nbnomatch : 0) << ")" << endl; + cout << nbokortho << " test ortho OK" << endl; + cout << nbokcolin << " test colin OK" << endl; + cout << nbokmid << " test mid OK" << endl; + cout << nbdssnul << " DSS nuls" << endl; + } + + oldWidthDiff[run] = 0.; + oldAbsDiff[run] = 0.; + oldAngDiff[run] = 0.; + oldNbMatched[run] = 0; + for (int si = 0; si < nbsegs; si ++) + { + if (! rbs[si].empty ()) oldNbMatched[run] ++; + vector<BlurredSegment *>::iterator sit = rbs[si].begin (); + while (sit != rbs[si].end ()) + { + Pt2i ptb = (*sit)->getLastRight (); + Pt2i ptf = (*sit)->getLastLeft (); + double bsl2 = (ptb.x () - ptf.x ()) * (ptb.x () - ptf.x ()) + + (ptb.y () - ptf.y ()) * (ptb.y () - ptf.y ()); + DigitalStraightSegment *mydss = (*sit)->getSegment (); + double wd = (mydss->width () / (double) (mydss->period ())) + * sqrt (bsl2) / sqrt (rdir[si].norm2 ()) - rw[si]; + oldWidthDiff[run] += wd; + if (wd < 0) wd = -wd; + oldAbsDiff[run] += wd; + Vr2i mydir = mydss->supportVector (); + double ang = rdir[si].scalarProduct (mydir); + if (ang < 0.) ang = - ang; + double den = sqrt (rdir[si].norm2 ()) * sqrt (mydir.norm2 ()); + if (den > ang) + { + ang = acos (ang / den) * 180 / M_PI; + oldAngDiff[run] += ang * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); + } + sit ++; + } + } + if (dispEach) + { + cout << "Width difference = " + << (oldNbMatched[run] != 0 ? + oldWidthDiff[run] / oldNbMatched[run] : 0) << endl; + cout << "Absolute width difference = " + << (oldNbMatched[run] != 0 ? + oldAbsDiff[run] / oldNbMatched[run] : 0) << endl; + cout << "Angle difference = " + << (oldNbMatched[run] != 0 ? + oldAngDiff[run] / oldNbMatched[run] : 0) << endl; + } + + 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; + dm = detmap; + for (int i = 0; i < width * height; i++) *dm++ = 0; + + if (dispEach) cout << "Running the new detection" << endl; + detector.switchDetector (); + extract (); + + if (dispEach) cout << "Analyzing the new blurred segments" << endl; + for (int i = 0; i < nbsegs; i++) rbs[i].clear (); + nbnomatch = 0; + nomatchlength = 0.; + nbokortho = 0; + nbokcolin = 0; + nbokmid = 0; + nbdssnul = 0; + nomatchlength = 0.; + bss = detector.getBlurredSegments (); + bsit = bss.begin (); + while (bsit != bss.end ()) + { + DigitalStraightSegment *dss = (*bsit)->getSegment (); + if (dss != NULL) + { + vector<Pt2i> dsspts; + dss->getPoints (dsspts); + vector<Pt2i>::iterator dssit = dsspts.begin (); + while (dssit != dsspts.end ()) + { + Pt2i dsspt = *dssit++; + 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); + } + } + + Vr2i dssdir = dss->supportVector (); + Pt2i ptb = (*bsit)->getLastRight (); + Pt2i ptf = (*bsit)->getLastLeft (); + Pt2i bsc ((ptb.x () + ptf.x ()) / 2, (ptb.y () + ptf.y ()) / 2); + double bsl2 = (ptb.x () - ptf.x ()) * (ptb.x () - ptf.x ()) + + (ptb.y () - ptf.y ()) * (ptb.y () - ptf.y ()); + bool searching = true; + for (int si = 0; searching && si < nbsegs; si++) + { + if (rdir[si].squaredVectorProduct (dssdir) + < 0.1 * rdir[si].norm2 () * dssdir.norm2 ()) + { + nbokortho ++; + Vr2i bsac = rp1[si].vectorTo (bsc); + if (rdir[si].squaredVectorProduct (bsac) + < 0.1 * rdir[si].norm2 () * bsac.norm2 ()) + { + nbokcolin ++; + if (rdir[si].scalarProduct (bsac) > 0) + { + Vr2i bscb = bsc.vectorTo (rp2[si]); + if (rdir[si].scalarProduct (bscb) > 0) + { + nbokmid ++; + rbs[si].push_back (*bsit); + searching = false; + } + } + } + } + } + if (searching) + { + nbnomatch ++; + nomatchlength += sqrt (bsl2); + } + } + else nbdssnul ++; + bsit ++; + } + + if (dispEach) cout << " NEW DETECTOR :" << endl; + newTrials[run] = detector.countOfTrials (); + newDetections[run] = (int) (detector.getBlurredSegments().size ()); + if (dispEach) + cout << newDetections[run] << " blurred segments detected on " + << newTrials[run] << " trials " << endl; + newUndet[run] = 0; + for (int i = 0; i < width * height; i++) if (virgin[i]) newUndet[run] ++; + if (dispEach) + cout << (nbIniPts[run] - newUndet[run]) << " points detected on " + << nbIniPts[run] << " (" + << (nbIniPts[run] - newUndet[run]) * 100 / (double) nbIniPts[run] + << " %)" << endl; + newRedet[run] = 0; + for (int i = 0; i < width * height; i++) + if (detmap[i] > 1) newRedet[run] += (detmap[i] - 1); + if (dispEach) + cout << (newRedet[run]) << " points redetected on " << nbIniPts[run] + << " (" << newRedet[run] * 100 / (double) nbIniPts[run] + << " %)" << endl; + newFalse[run] = 0; + for (int i = 0; i < width * height; i++) + if (detmap[i] < 0) newFalse[run] ++; + if (dispEach) + { + cout << newFalse[run] << " false points detected on " << nbIniPts[run] + << " (" << newFalse[run] * 100 / (double) nbIniPts[run] + << " %)" << endl; + cout << nbnomatch << " unmatched blurred segment (mean length : " + << (nbnomatch != 0 ? nomatchlength / nbnomatch : 0) << ")" << endl; + cout << nbokortho << " test ortho OK" << endl; + cout << nbokcolin << " test colin OK" << endl; + cout << nbokmid << " test mid OK" << endl; + cout << nbdssnul << " DSS nuls" << endl; + } + + newWidthDiff[run] = 0.; + newAbsDiff[run] = 0.; + newAngDiff[run] = 0.; + newNbMatched[run] = 0; + for (int si = 0; si < nbsegs; si ++) + { + if (! rbs[si].empty ()) newNbMatched[run] ++; + vector<BlurredSegment *>::iterator sit = rbs[si].begin (); + while (sit != rbs[si].end ()) + { + Pt2i ptb = (*sit)->getLastRight (); + Pt2i ptf = (*sit)->getLastLeft (); + double bsl2 = (ptb.x () - ptf.x ()) * (ptb.x () - ptf.x ()) + + (ptb.y () - ptf.y ()) * (ptb.y () - ptf.y ()); + DigitalStraightSegment *mydss = (*sit)->getSegment (); + double wd = (mydss->width () / (double) (mydss->period ())) + * sqrt (bsl2) / sqrt (rdir[si].norm2 ()) - rw[si]; + newWidthDiff[run] += wd; + if (wd < 0) wd = -wd; + newAbsDiff[run] += wd; + Vr2i mydir = mydss->supportVector (); + double ang = rdir[si].scalarProduct (mydir); + if (ang < 0.) ang = - ang; + double den = sqrt (rdir[si].norm2 ()) * sqrt (mydir.norm2 ()); + if (den > ang) + { + ang = acos (ang / den) * 180 / M_PI; + newAngDiff[run] += ang * sqrt (bsl2) / sqrt (rdir[si].norm2 ()); + } + sit ++; + } + } + if (dispEach) + { + cout << "Width difference = " + << (newNbMatched[run] != 0 ? + newWidthDiff[run] / newNbMatched[run] : 0) << endl; + cout << "Absolute width difference = " + << (newNbMatched[run] != 0 ? + newAbsDiff[run] / newNbMatched[run] : 0) << endl; + cout << "Angle difference = " + << (newNbMatched[run] != 0 ? + newAngDiff[run] / newNbMatched[run] : 0) << endl; + } + } + + double total_nbIniPts = 0; + for (int i = 0; i < nbruns; i++) total_nbIniPts += nbIniPts[i]; + + cout << " BILAN OLD" << endl; + double total_oldTrials = 0.; + for (int i = 0; i < nbruns; i++) total_oldTrials += oldTrials[i]; + cout << total_oldTrials / nbruns << " trials" << endl; + double total_oldDetections = 0.; + for (int i = 0; i < nbruns; i++) total_oldDetections += oldDetections[i]; + cout << total_oldDetections / nbruns << " detections" << endl; + double total_oldOkdet = 0; + for (int i = 0; i < nbruns; i++) + total_oldOkdet += nbIniPts[i] - oldUndet[i]; + cout << 100 * total_oldOkdet / total_nbIniPts << " % success" << endl; + double total_oldRedet = 0; + for (int i = 0; i < nbruns; i++) total_oldRedet += oldRedet[i]; + cout << 100 * total_oldRedet / total_nbIniPts << " % coverture" << endl; + double total_oldFalse = 0; + for (int i = 0; i < nbruns; i++) total_oldFalse += oldFalse[i]; + cout << 100 * total_oldFalse / total_nbIniPts + << " % false detections" << endl; + int total_nbmatched = 0; + for (int i = 0; i < nbruns; i++) total_nbmatched += oldNbMatched[i]; + double total_widthdiff = 0; + for (int i = 0; i < nbruns; i++) total_widthdiff += oldWidthDiff[i]; + cout << "Width difference : " << total_widthdiff / total_nbmatched + << " per matched segment" << endl; + double total_absdiff = 0; + for (int i = 0; i < nbruns; i++) total_absdiff += oldAbsDiff[i]; + cout << "Absolute width difference : " << total_absdiff / total_nbmatched + << " per matched segment" << endl; + double total_angdiff = 0; + for (int i = 0; i < nbruns; i++) total_angdiff += oldAngDiff[i]; + cout << "Angle difference : " << total_angdiff / total_nbmatched + << " degrees per matched segment" << endl; + + cout << " BILAN NEW" << endl; + double total_newTrials = 0.; + for (int i = 0; i < nbruns; i++) total_newTrials += newTrials[i]; + cout << total_newTrials / nbruns << " trials" << endl; + double total_newDetections = 0; + for (int i = 0; i < nbruns; i++) total_newDetections += newDetections[i]; + cout << total_newDetections / nbruns << " detections" << endl; + double total_newOkdet = 0; + for (int i = 0; i < nbruns; i++) + total_newOkdet += nbIniPts[i] - newUndet[i]; + cout << 100 * total_newOkdet / total_nbIniPts << " % success" << endl; + double total_newRedet = 0; + for (int i = 0; i < nbruns; i++) total_newRedet += newRedet[i]; + cout << 100 * total_newRedet / total_nbIniPts << " % coverture" << endl; + double total_newFalse = 0; + for (int i = 0; i < nbruns; i++) total_newFalse += newFalse[i]; + cout << 100 * total_newFalse / total_nbIniPts + << " % false detections" << endl; + total_nbmatched = 0; + for (int i = 0; i < nbruns; i++) total_nbmatched += newNbMatched[i]; + total_widthdiff = 0; + for (int i = 0; i < nbruns; i++) total_widthdiff += newWidthDiff[i]; + cout << "Width difference : " << total_widthdiff / total_nbmatched + << " per matched segment" << endl; + total_absdiff = 0; + for (int i = 0; i < nbruns; i++) total_absdiff += newAbsDiff[i]; + cout << "Absolute width difference : " << total_absdiff / total_nbmatched + << " per matched segment" << endl; + total_angdiff = 0; + for (int i = 0; i < nbruns; i++) total_angdiff += newAngDiff[i]; + cout << "Angle difference : " << total_angdiff / total_nbmatched + << " degrees per matched segment" << endl; + + cout << "Updating the displays" << endl; + augmentedImage = loadedImage; + update (); + if (idetview != NULL) idetview->setImage (&loadedImage, gMap); + if (profileview != NULL) profileview->setImage (&loadedImage, gMap); + if (strucview != NULL) strucview->setGradientImage (&gradImage); + return loadedImage.size (); +} diff --git a/Code/Seg/BSTools/bsdetectionwidget.h b/Code/Seg/BSTools/bsdetectionwidget.h index fe937fdb3e53903486d33dea30b58fab04339a1c..5deb3759cb1475a4c03f6fea6013feafabae43e4 100755 --- a/Code/Seg/BSTools/bsdetectionwidget.h +++ b/Code/Seg/BSTools/bsdetectionwidget.h @@ -38,6 +38,12 @@ public: */ ~BSDetectionWidget (); + /** + * \brief Creates and opens a random image to be processed. + * @param type Gradient extraction method. + */ + QSize setRandomImage (int type = 0); + /** * \brief Opens the image to be processed. * @param type Name of the image file to open. @@ -117,6 +123,11 @@ public: */ void switchIdetAnalyzer (); + /** + * \brief Switches the blurred segment highlight colors. + */ + void switchHighlightColors (); + /** * \brief Switches the extraction result display on or off. */ @@ -208,11 +219,9 @@ private: bool oldudef; /** Activation of alternate comparative tests (F8). */ int alternate; - /** Count of trials in a multi_detection. */ - int nbdettrials; - /** Maximum number of trials in a multi_detection. */ - int nbmaxdettrials; + /** Kind of highlight colors. */ + bool darkHighlightOn; /** Color of user selections. */ QColor selectionColor; /** Color of blurred segments. */ @@ -369,6 +378,11 @@ private: */ void writeDetectionStatus (); + /** + * \brief Stores the occupancy mask in a mask.png. + */ + void saveMask (); + /** * \brief Detects and displays a blurred segment under the selected stroke. */ diff --git a/Code/Seg/BSTools/bsidetitem.cpp b/Code/Seg/BSTools/bsidetitem.cpp index 6304da85ba1959f0b4fb36e30288dd55d24ca53a..2fcb8b850adb99f61103a2b150d282f0d59c2e3f 100755 --- a/Code/Seg/BSTools/bsidetitem.cpp +++ b/Code/Seg/BSTools/bsidetitem.cpp @@ -50,7 +50,7 @@ void BSIdetItem::paint (QPainter *painter, Q_UNUSED (option); Q_UNUSED (widget); - if (det->getBlurredSegments().empty () || det->getMaxTrials () > 0) + if (det->getBlurredSegments().empty () || det->getMaxDetections () > 0) { // buildScans (); paintStripes (painter); @@ -70,7 +70,7 @@ void BSIdetItem::setImage (QImage *image, VMap *idata) void BSIdetItem::buildScans () { - if ((! det->getBlurredSegments().empty ()) && det->getMaxTrials () <= 0) + if ((! det->getBlurredSegments().empty ()) && det->getMaxDetections () == 0) return; if (ds != NULL) diff --git a/Code/Seg/BSTools/bswindow.cpp b/Code/Seg/BSTools/bswindow.cpp index 8d86ae573742cceb643493ad446c1b7e6d9bce00..4eae19db40fd4d9317e4cb4ea29dbf7522a49fc6 100755 --- a/Code/Seg/BSTools/bswindow.cpp +++ b/Code/Seg/BSTools/bswindow.cpp @@ -40,6 +40,13 @@ BSWindow::BSWindow () } +void BSWindow::setRandom () +{ + resize (detectionWidget->setRandomImage (gradType)); + detectionWidget->setDefaults (); +} + + void BSWindow::setFile (QString fileName) { resize (detectionWidget->openImage (fileName, gradType)); diff --git a/Code/Seg/BSTools/bswindow.h b/Code/Seg/BSTools/bswindow.h index b5700167b9ff281404da4239a762973926a29103..6fd9e461bdd05faeb9ac8087bafa7c45a047000e 100755 --- a/Code/Seg/BSTools/bswindow.h +++ b/Code/Seg/BSTools/bswindow.h @@ -27,6 +27,11 @@ public: */ BSWindow (int *val); + /** + * Sets a random processed image. + */ + void setRandom (); + /** * Sets the processed image. */ diff --git a/Code/Seg/BlurredSegment/bsdetector.cpp b/Code/Seg/BlurredSegment/bsdetector.cpp index d39d0b0969c139a106ecb379e1a626207532dbdb..7b237096317460849fa43b2817c7a9ec588c42ca 100755 --- a/Code/Seg/BlurredSegment/bsdetector.cpp +++ b/Code/Seg/BlurredSegment/bsdetector.cpp @@ -20,7 +20,7 @@ const int BSDetector::RESULT_FINAL_TOO_FEW = 22; const int BSDetector::RESULT_FINAL_TOO_SPARSE = 23; const int BSDetector::RESULT_FINAL_TOO_MANY_OUTLIERS = 24; -const int BSDetector::DEFAULT_FAST_TRACK_SCAN_WIDTH = 32; +const int BSDetector::DEFAULT_FAST_TRACK_SCAN_WIDTH = 16; const int BSDetector::DEFAULT_FINE_TRACK_MAX_WIDTH = 3; const int BSDetector::DEFAULT_FAST_TRACK_MAX_MARGIN = 2; @@ -66,7 +66,7 @@ BSDetector::BSDetector () multiSelection = false; autodet = false; autoResol = DEFAULT_AUTO_RESOLUTION; - nbmaxtrials = 0; + maxtrials = 0; nbtrials = 0; bspre = NULL; @@ -105,6 +105,7 @@ void BSDetector::detectAll () autodet = true; freeMultiSelection (); gMap->setMasking (true); + gMap->clearMask (); bool isnext = true; nbtrials = 0; @@ -118,8 +119,8 @@ void BSDetector::detectAll () isnext = runMultiDetection (Pt2i (0, y), Pt2i (width - 1, y)); for (int y = height / 2 + autoResol; isnext && y < height - 1; y += autoResol) isnext = runMultiDetection (Pt2i (0, y), Pt2i (width - 1, y)); + if (maxtrials > (int) (mbsf.size ())) maxtrials = 0; - gMap->clearMask (); gMap->setMasking (false); } @@ -129,6 +130,7 @@ void BSDetector::detectAllWithBalancedXY () autodet = true; freeMultiSelection (); gMap->setMasking (true); + gMap->clearMask (); bool isnext = true; nbtrials = 0; @@ -164,7 +166,7 @@ void BSDetector::detectAllWithBalancedXY () if (yh >= height - 1) enhaut = false; } } - gMap->clearMask (); + if (maxtrials > (int) (mbsf.size ())) maxtrials = 0; gMap->setMasking (false); } @@ -176,9 +178,10 @@ void BSDetector::detectSelection (const Pt2i &p1, const Pt2i &p2) if (multiSelection) { gMap->setMasking (true); + gMap->clearMask (); nbtrials = 0; runMultiDetection (p1, p2); - gMap->clearMask (); + if (maxtrials > (int) (mbsf.size ())) maxtrials = 0; gMap->setMasking (false); } else @@ -216,7 +219,7 @@ bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2) { int oldEdgeDir = edgeDirection; if (edgeDirection != 0) edgeDirection = 1; - while (edgeDirection >= -1) + while (isnext && edgeDirection >= -1) { if (oldp) olddetect (p1, p2, true, ptstart); else detect (p1, p2, true, ptstart); @@ -225,11 +228,12 @@ bool BSDetector::runMultiDetection (const Pt2i &p1, const Pt2i &p2) gMap->setMask (bsf->getAllPoints ()); mbsf.push_back (bsf); bsf = NULL; // to avoid BS deletion + if ((int) (mbsf.size ()) == maxtrials) isnext = false; } + nbtrials ++; edgeDirection -= 2; } edgeDirection = oldEdgeDir; - if (++nbtrials == nbmaxtrials) isnext = false; } } return (isnext); @@ -253,7 +257,6 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, bsini = NULL; if (bsf != NULL) delete bsf; bsf = NULL; - lastTrialOk = false; inip1.set (p1); inip2.set (p2); @@ -349,8 +352,8 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, if (finalLengthTestOn) { DigitalStraightSegment *dss = bsf->getSegment (); - if ((int) (bsf->getAllPoints().size ()) - < (10 * dss->period ()) / dss->width ()) + if (dss == NULL || (int) (bsf->getAllPoints().size ()) + < (10 * dss->period ()) / dss->width ()) { resultValue = RESULT_FINAL_TOO_SPARSE; delete bsf; @@ -402,7 +405,6 @@ void BSDetector::olddetect (const Pt2i &p1, const Pt2i &p2, */ } - lastTrialOk = true; resultValue = RESULT_OK; } @@ -430,7 +432,6 @@ void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, bsini = NULL; if (bsf != NULL) delete bsf; bsf = NULL; - lastTrialOk = false; prep1.set (p1); prep2.set (p2); @@ -626,7 +627,6 @@ void BSDetector::detect (const Pt2i &p1, const Pt2i &p2, } } - lastTrialOk = true; resultValue = RESULT_OK; } @@ -636,11 +636,18 @@ BlurredSegment *BSDetector::getBlurredSegment (int step) const if (step == STEP_PRELIM) return (bspre); else if (step == STEP_INITIAL) return (bsini); else if (mbsf.empty ()) return (bsf); - else if (lastTrialOk) return (mbsf.back ()); + else return (mbsf.back ()); return NULL; } +void BSDetector::incMaxDetections (bool dir) +{ + maxtrials = maxtrials + (dir ? -1 : 1); + if (maxtrials < 0) maxtrials = (int) (mbsf.size ()); +} + + void BSDetector::getScanInput (int step, Pt2i &p1, Pt2i &p2, int &swidth, Pt2i &pc) const { diff --git a/Code/Seg/BlurredSegment/bsdetector.h b/Code/Seg/BlurredSegment/bsdetector.h index 48e2a39a2c9b1c2d6d1857633b7704d2f7189a8f..bbfecdb1860b64bf9ce07fb5dc66d030b963d4d4 100755 --- a/Code/Seg/BlurredSegment/bsdetector.h +++ b/Code/Seg/BlurredSegment/bsdetector.h @@ -545,21 +545,28 @@ public: */ inline int countOfTrials () const { return (nbtrials); } + /** + * \brief Returns the maximum number of detections set for a multi-detection. + */ + inline int getMaxDetections () const { return maxtrials; } + /** * \brief Sets the maximum number of trials in a multi-detection. + * Just kept for IPOL demo compatibility. * @param nb Number of trials (0 if illimited). */ - inline void setMaxTrials (int nb) { nbmaxtrials = nb; } + inline void setMaxTrials (int nb) { maxtrials = nb; resetMaxDetections (); } /** - * \brief Returns the maximum number of trials for a multi-detection. + * \brief Increments the maximum number of detections in a multi-detection. + * @param dir Increments if true, otherwise decrements. */ - inline int getMaxTrials () const { return nbmaxtrials; } + void incMaxDetections (bool dir); /** - * \brief Retuns whether the last trial was successful. + * \brief Resets the maximum number of detections set for a multi-detection. */ - inline bool isLastTrialOk () { return lastTrialOk; } + inline void resetMaxDetections () { maxtrials = 0; } /** * \brief Gets the last detection inputs. @@ -630,12 +637,10 @@ private : bool finalLengthTestOn; /** Segment multi-selection modality status. */ bool multiSelection; - /** Flag indicating if the last trial was successful. */ - bool lastTrialOk; /** Count of trials in a multi-detection. */ int nbtrials; /** Maximum number of trials in a multi-detection. */ - int nbmaxtrials; + int maxtrials; /** Automatic detection modality. */ bool autodet; /** Grid resolution for the automatic extraction. */ diff --git a/Code/Seg/ImageTools/digitalstraightsegment.cpp b/Code/Seg/ImageTools/digitalstraightsegment.cpp index 212aadc363bfba23462aa0f745a8abe1bd40f766..cbb53bd5d5aa2d6609a036c3fcbf71845eacda45 100755 --- a/Code/Seg/ImageTools/digitalstraightsegment.cpp +++ b/Code/Seg/ImageTools/digitalstraightsegment.cpp @@ -37,6 +37,24 @@ DigitalStraightSegment::DigitalStraightSegment (Pt2i p1, Pt2i p2, Pt2i p3, } +DigitalStraightSegment::DigitalStraightSegment (Pt2i p1, Pt2i p2, int width) + : DigitalStraightLine (p1, p2, DSL_THIN) +{ + nu = width * period (); + c = a * p1.x () + b * p1.y () - nu / 2; + if (a < (b < 0 ? -b : b)) + { + min = (p1.x () < p2.x () ? p1.x () : p2.x ()); + max = (p1.x () < p2.x () ? p2.x () : p1.x ()); + } + else + { + min = (p1.y () < p2.y () ? p1.y () : p2.y ()); + max = (p1.y () < p2.y () ? p2.y () : p1.y ()); + } +} + + Pt2i DigitalStraightSegment::getABoundingPoint (bool upper) const { int sa = a, sb = b, u1 = 1, v1 = 0, u2 = 0, v2 = 1; @@ -101,3 +119,39 @@ void DigitalStraightSegment::adjustWorkArea (int &xmin, int &ymin, height = (ymin >= y2 ? 0 : y2 - ymin); } } + + +void DigitalStraightSegment::getPoints (vector<Pt2i> &pts) const +{ + int xmin, ymin, w, h; + if (b > a || -b > a) + { + xmin = min; + w = max - min; + ymin = (b < 0 ? (c + nu - a * min) / b - 1 : (c - a * max) / b - 1); + h = (b < 0 ? (c - a * max) / b + 1 : (c + nu - a * min) / b + 1) - ymin; + } + else + { + ymin = min; + h = max - min; + xmin = (b < 0 ? (c - b * min) / a - 1 : (c - b * max) / a - 1); + w = (b < 0 ? (c + nu - b * max) / a : (c + nu - b * min) / a) + 1 - xmin; + } + vector<Pt2i> lowbound; + getBoundPoints (lowbound, false, xmin, ymin, w, h); + vector<Pt2i>::iterator it = lowbound.begin (); + + while (it != lowbound.end ()) + { + Pt2i p = *it; + while (owns (p)) + { + pts.push_back (p); + if (b > a) p.set (p.x (), p.y () + 1); + else if (-b > a) p.set (p.x (), p.y () - 1); + else p.set (p.x () + 1, p.y ()); + } + it ++; + } +} diff --git a/Code/Seg/ImageTools/digitalstraightsegment.h b/Code/Seg/ImageTools/digitalstraightsegment.h index 21c2074532e9208b244abfd58680de8cf3af3894..8ab1ccc66d6e8e1d867747efcd9dcf6f2922e143 100755 --- a/Code/Seg/ImageTools/digitalstraightsegment.h +++ b/Code/Seg/ImageTools/digitalstraightsegment.h @@ -47,12 +47,26 @@ public: DigitalStraightSegment (Pt2i p1, Pt2i p2, Pt2i p3, int xmin, int ymin, int xmax, int ymax); + /** + * Creates a digital straight segment from its end points and a width value. + * @param p1 First end point of the segment. + * @param p2 Second end point of the segment. + * @param width Width value. + */ + DigitalStraightSegment (Pt2i p1, Pt2i p2, int width); + /** * \brief Returns a bounding point of the digital line * @param upper true for a upper bounding point, false for a lower one. */ Pt2i getABoundingPoint (bool upper) const; + /** + * \brief Returns the points of the segment. + * @param pts Vector of points to fill in. + */ + void getPoints (vector<Pt2i> &pts) const; + protected: diff --git a/Code/Seg/ImageTools/vmap.cpp b/Code/Seg/ImageTools/vmap.cpp index 42e97fb4d23d3dfdc67a987058763192ac6a939e..be16b2212514a6670f0b69252726d82d0cb0f203 100755 --- a/Code/Seg/ImageTools/vmap.cpp +++ b/Code/Seg/ImageTools/vmap.cpp @@ -218,7 +218,7 @@ VMap::VMap (int width, int height, int **data, int type) VMap::~VMap () { delete [] map; - delete [] map; + delete [] imap; delete [] mask; delete [] dilations; delete [] bowl; @@ -642,6 +642,10 @@ int VMap::localMax (int *lmax, const vector<Pt2i> &pix, const Vr2i &gref) const // Gets the local maxima int count = searchLocalMax (lmax, n, gn); + // Prunes the already selected candidates + if (masking) + count = keepFreeElementsIn (pix, count, lmax); + // Prunes the candidates with opposite gradient if (orientedGradient) count = keepDirectedElementsAs (pix, count, lmax, gref); @@ -688,7 +692,8 @@ int VMap::searchLocalMax (int *lmax, int n, int *in) const up = false; int k = i; while (in[k - 1] == in[i]) k--; - lmax[count++] = k + (i - k) / 2; + if (in[k + (i - k) / 2] > gmagThreshold) + lmax[count++] = k + (i - k) / 2; } } else diff --git a/Code/Seg/ImageTools/vmap.h b/Code/Seg/ImageTools/vmap.h index 06671ce2f0774a980ae9e2ba143ebc6aab381693..54236e2079f2bff180cb02a9cc190eaac3c615b8 100755 --- a/Code/Seg/ImageTools/vmap.h +++ b/Code/Seg/ImageTools/vmap.h @@ -241,6 +241,11 @@ public: inline void switchOrientationConstraint () { orientedGradient = ! orientedGradient; } + /** + * \brief Returns the occupancy mask contents. + */ + inline bool *getMask () const { return (mask); } + /** * \brief Clears the occupancy mask. */ diff --git a/Code/Seg/ImageTools/vr2i.h b/Code/Seg/ImageTools/vr2i.h index cac1af7dd1b85a151609f2aeb215935d66e96409..5fc99ef15dda3db918812269775ab66e0b2bc33c 100755 --- a/Code/Seg/ImageTools/vr2i.h +++ b/Code/Seg/ImageTools/vr2i.h @@ -73,18 +73,29 @@ public: * \brief Returns the scalar product with the given vector. * If intensity value holds on a byte, scalar product (SP) holds on a short * and squared SP holds on a int. + * @param vec The given vector. */ inline int scalarProduct (Vr2i vec) const { return (xv * vec.xv + yv * vec.yv); } /** * @fn int squaredScalarProduct (Vr2i vec) - * \brief Returns the sqaured scalar product with the given vector. + * \brief Returns the squared scalar product with the given vector. + * @param vec The given vector. */ inline int squaredScalarProduct (Vr2i vec) const { return ((xv * vec.xv + yv * vec.yv) * (xv * vec.xv + yv * vec.yv)); } + /** + * @fn int squaredVectorProduct (Vr2i vec) + * \brief Returns the squared norm of the vector product with given vector. + * @param vec The given vector. + */ + inline int squaredVectorProduct (Vr2i vec) const { + return ((xv * vec.yv - yv * vec.xv) + * (xv * vec.yv - yv * vec.xv)); } + /** * @fn bool equals (Vr2i p) * \brief Checks equivalence to the given vector. diff --git a/Code/Seg/main.cpp b/Code/Seg/main.cpp index 30aa3b5762a312a42e2619f011719ae08b44af89..d48471616aceb542fe3b84aedaa76aef6e564a26 100755 --- a/Code/Seg/main.cpp +++ b/Code/Seg/main.cpp @@ -8,7 +8,7 @@ int main (int argc, char *argv[]) { int val = 0; int imageName = 0; - bool testing = false; + bool random = false, testing = false; QApplication app (argc, argv); /* @@ -32,6 +32,7 @@ int main (int argc, char *argv[]) else if (string(argv[i]) == string ("-idet")) window.toggleIdetWindow (); // Test command : time ./Seg -test ../Images/couloir.jpg else if (string(argv[i]) == string ("-test")) testing = true; + else if (string(argv[i]) == string ("-random")) random = true; else if (string(argv[i]) == string ("-sobel3x3")) window.useGradient (VMap::TYPE_SOBEL_3X3); else if (string(argv[i]) == string ("-sobel5x5")) @@ -63,7 +64,8 @@ int main (int argc, char *argv[]) } else imageName = i; } - if (imageName != 0) window.setFile (QString (argv[imageName])); + if (random) window.setRandom (); + else if (imageName != 0) window.setFile (QString (argv[imageName])); else window.setFile (QString ("../couloir.gif")); if (testing) { diff --git a/Methode/ctrl.tex b/Methode/ctrl.tex index 76475029b60bd070f78d691c22b67d8c753e2923..f11906425aed9f485a2bcdaa7f6aea33a8d93aaf 100755 --- a/Methode/ctrl.tex +++ b/Methode/ctrl.tex @@ -62,6 +62,7 @@ Ctrl-w && Commute le recentrage du scan sur le segment d\'etect\'e \\ Ctrl-x && Commute l'ajustement de la consigne d'\'epaisseur sur le segment d\'etect\'e \\ Ctrl-y && Commute l'affichage des pixels des segments flous \\ Ctrl-z && Commute le contr\^ole de la consigne d'\'epaisseur \\ +Ctrl-! && Commute la couleur de s\'election des segments flous \\ 1 && Commute la visu des segments (pixels) \\ 2 && Commute la visu de l'accumulateur \\ 3 && Commute la visu des profils \\