Skip to content
Snippets Groups Projects
Commit 728a7172 authored by even's avatar even
Browse files

Install code

parent 691754a4
No related branches found
No related tags found
No related merge requests found
Showing
with 4517 additions and 0 deletions
#include <QtGui>
#include <iostream>
#include <cmath>
#include "bsaccumulatoritem.h"
using namespace std;
const int BSAccumulatorItem::DEFAULT_PEN_WIDTH = 1;
const int BSAccumulatorItem::LEFT_MARGIN = 16;
const int BSAccumulatorItem::TEXT_HEIGHT = 16;
BSAccumulatorItem::BSAccumulatorItem (BSDetector *sd, int w, int h)
{
detector = sd;
width = w;
height = h;
selaccu = 1;
map[0] = NULL;
map[1] = NULL;
solution[0] = -1;
solution[1] = -1;
resol[0] = 1.;
resol[1] = 1.;
mask = NULL;
verbose = true;
infoPen = QPen (Qt::red, DEFAULT_PEN_WIDTH, Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin);
scalePen = QPen (Qt::red, 2);
markPen = QPen (Qt::blue, 4);
}
BSAccumulatorItem::~BSAccumulatorItem ()
{
delete [] map[0];
delete [] map[1];
}
QRectF BSAccumulatorItem::boundingRect () const
{
return QRectF (0, 0, width, height);
}
void BSAccumulatorItem::paint (QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED (option);
Q_UNUSED (widget);
if (! detector->isFiltering (selaccu))
{
painter->fillRect (0, 0, width, height, QBrush (Qt::black));
return;
}
// Updates the grid
LineSpaceFilter *hugues = detector->getFilter (selaccu);
int nbc = hugues->width ();
int nbl = hugues->height ();
int cw = width / nbc;
int ch = height / nbl;
// Updates the accumulator
if (map[selaccu] == NULL) map[selaccu] = new uchar[nbc * nbl];
hugues->getAccumulator (map[selaccu], solution);
resol[0] = hugues->angularResolution () * 180. / M_PI;
resol[1] = hugues->distanceResolution ();
mask = hugues->getMask ();
// Draws the accumulator
if (solution[0] >= 0)
{
uchar *pix = map[selaccu];
for (int i = 0; i < nbc * nbl; i++, pix++)
painter->fillRect ((i % nbc) * cw, (nbl - 1 - i / nbc) * ch, cw, ch,
QBrush (QColor ((int) *pix, (int) *pix, (int) *pix)));
// Marks the filtering cells
if (mask != NULL)
{
painter->setPen (markPen);
bool *maski = mask;
for (int j = 0; j < nbl; j++)
for (int i = 0; i < nbc; i++)
if (*maski++)
painter->drawPoint ((i + 0.5) * cw, (nbl - j - 0.5) * ch);
}
if (verbose)
{
// Displays the scale (one radian / one pixel)
painter->setPen (scalePen);
int sh = (int) (ch / resol[1] + 0.5);
painter->drawRect (0, height - 1 - sh, (int) (cw / resol[0] + 0.5), sh);
// Displays information
initText (painter);
addText (painter, QString ("S size : ") + QString::number (nbc)
+ QString ("x") + QString::number (nbl));
addText (painter, QString ("R resolution : ")
+ QString::number (resol[0]) + QString (" pixels x ")
+ QString::number (resol[1]) + QString (" degrees"));
addText (painter, QString ("P sub-pixellisation level : ")
+ QString::number (hugues->getSubpix ()));
addText (painter, QString ("F selectivity : ")
+ QString::number (hugues->getSelectionThreshold ())
+ QString ("% of max vote"));
}
}
}
bool BSAccumulatorItem::resizeAccumulator (bool larger)
{
if (! detector->isFiltering (selaccu)) return false;
LineSpaceFilter *hugues = detector->getFilter (selaccu);
bool res = hugues->resize (larger);
if (res)
{
delete [] map[selaccu];
map[selaccu] = new uchar[hugues->width () * hugues->height ()];
}
return (res);
}
bool BSAccumulatorItem::zoomAccumulator (bool in)
{
if (! detector->isFiltering (selaccu)) return false;
LineSpaceFilter *hugues = detector->getFilter (selaccu);
return (hugues->zoom (in));
}
bool BSAccumulatorItem::subpixellise (bool larger)
{
if (! detector->isFiltering (selaccu)) return false;
LineSpaceFilter *hugues = detector->getFilter (selaccu);
return (hugues->subpixellise (larger));
}
bool BSAccumulatorItem::setFilterSelectivity (bool larger)
{
if (! detector->isFiltering (selaccu)) return false;
LineSpaceFilter *hugues = detector->getFilter (selaccu);
return (hugues->setSelectivity (larger));
}
void BSAccumulatorItem::initText (QPainter *painter)
{
painter->setPen (infoPen);
textOffset = 0;
}
void BSAccumulatorItem::addText (QPainter *painter, const QString &text)
{
textOffset += TEXT_HEIGHT;
painter->drawText (LEFT_MARGIN, textOffset, text);
}
#ifndef BS_ACCUMULATOR_ITEM_H
#define BS_ACCUMULATOR_ITEM_H
#include <QGraphicsItem>
#include "bsdetector.h"
/**
* @class BSAccumulatorItem bsaccumulatoritem.h
* \brief Hough accumulator grid display and control.
* \author {P. Even}
*/
class BSAccumulatorItem : public QGraphicsItem
{
public:
/**
* \brief Creates a Hough accumulator grid.
* @param sd Associated blurred segment detector.
* @param w Accumulator width.
* @param h Accumulator height.
*/
BSAccumulatorItem (BSDetector *sd, int w, int h);
/** Deletes the Hough accumulator grid.
*/
~BSAccumulatorItem ();
/** \brief Inquires if the pre-filter accumulator is displayed.
*/
inline bool isPrefilterDisplayed () const {return (selaccu == 0); }
/** \brief Switches the displayed accumulator filter.
*/
inline void switchAccumulator () { selaccu = (selaccu != 0 ? 0 : 1); }
/** \brief Returns the size of the filter accumulator graphics item.
*/
QRectF boundingRect () const;
/** \brief Draws the accumulator of the selected filter.
*/
void paint (QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
/**
* \brief Switches on or off the information text display modality.
*/
inline void switchInfoDisplay () { verbose = ! verbose; }
/** \brief Resizes the accumulator array.
* @param larger Sets larger if true, smaller otherwise.
*/
bool resizeAccumulator (bool larger);
/** \brief Zooms in or out the accumulator array.
* @param in Zooms in if true, out otherwise.
*/
bool zoomAccumulator (bool in);
/** \brief Modifies the subpixellisation of the accumulator array.
* @param in Sets larger if true, smaller otherwise.
*/
bool subpixellise (bool larger);
/** \brief Modifies the filter selectivity.
* @param larger Makes the filter more selective if true, less otherwise.
*/
bool setFilterSelectivity (bool larger);
private:
/** Default value for pen width. */
static const int DEFAULT_PEN_WIDTH;
/** Left margin for information text. */
static const int LEFT_MARGIN;
/** Information text height. */
static const int TEXT_HEIGHT;
/** Blurred segment detector. */
BSDetector *detector;
/** Accumulator displayed (0 = prefilter, 1 = final filter). */
int selaccu;
/** Accumulator width. */
int width;
/** Accumulator height. */
int height;
/** Contents of the accumulator.
* The array of vote counts for each cell. */
uchar *map[2];
/** Coordinates of the cell with the highest vote. */
int solution[2];
/** Accumulator scale in pixels.
* One radian for the angles, and one pixel for the distances. */
double resol[2];
/** Contents of the applied accumulator mask.
* An array of booleans values for each cell,
* that are set to true if the cell belongs to the mask. */
bool *mask;
/** Information text modality. */
bool verbose;
/** Information text style. */
QPen infoPen;
/** Information text vertical offset. */
int textOffset;
/** Scale display style. */
QPen scalePen;
/** Mark display style. */
QPen markPen;
/**
* \brief Initializes the text display (color and position).
* @param painter : Painter to be decorated.
*/
void initText (QPainter *painter);
/**
* \brief Paints a new text in the graphics item (updates text position).
* @param painter : Painter to be decorated.
* @param text : Text to be displayed.
*/
void addText (QPainter *painter, const QString &text);
};
#endif
#include <QtGui>
#include <iostream>
#include "bsaccumulatorview.h"
using namespace std;
const int BSAccumulatorView::CELL_SIZE = 12;
BSAccumulatorView::BSAccumulatorView (BSDetector *sd)
{
int w = LineSpaceFilter::DEFAULT_NB_ANG_CELLS * CELL_SIZE;
int h = LineSpaceFilter::DEFAULT_NB_DIST_CELLS * CELL_SIZE;
setBackgroundBrush (QBrush (Qt::yellow));
setScene (new QGraphicsScene (0, 0, w, h));
grid = new BSAccumulatorItem (sd, w, h);
scene()->addItem (grid);
setWindowTitle (grid->isPrefilterDisplayed () ?
"Pre-filter accumulator" : "Final filter accumulator");
}
BSAccumulatorView::~BSAccumulatorView ()
{
scene()->removeItem (grid);
delete grid;
}
void BSAccumulatorView::paint (QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED (painter);
Q_UNUSED (option);
Q_UNUSED (widget);
}
bool BSAccumulatorView::processKeyEvent (QKeyEvent *event)
{
bool processed = false;
switch (event->key ())
{
case Qt::Key_I :
grid->switchAccumulator ();
setWindowTitle (grid->isPrefilterDisplayed () ?
"Pre-filter accumulator" : "Final filter accumulator");
processed = true;
break;
case Qt::Key_V :
grid->switchInfoDisplay ();
processed = true;
break;
case Qt::Key_S :
processed = grid->resizeAccumulator (
(event->modifiers () & Qt::ShiftModifier) == 0);
break;
case Qt::Key_R :
processed = grid->zoomAccumulator (
(event->modifiers () & Qt::ShiftModifier) == 0);
break;
case Qt::Key_P :
processed = grid->subpixellise (
(event->modifiers () & Qt::ShiftModifier) != 0);
break;
case Qt::Key_F :
processed = grid->setFilterSelectivity (
(event->modifiers () & Qt::ShiftModifier) == 0);
break;
}
return processed;
}
#ifndef BS_ACCUMULATOR_H
#define BS_ACCUMULATOR_H
#include <QGraphicsView>
#include "bsaccumulatoritem.h"
class BSAccumulatorView : public QGraphicsView
{
public:
/**
* \brief Creates an accumulator analyzer.
*/
BSAccumulatorView (BSDetector *sd);
/**
* \brief Deletes the accumulator analyzer.
*/
~BSAccumulatorView ();
/**
* \brief Redraws the accumulator analyzer.
*/
void paint (QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
/**
* \brief Processes key pressed events.
*/
bool processKeyEvent (QKeyEvent *event);
protected:
private:
static const int CELL_SIZE;
BSAccumulatorItem *grid;
};
#endif
#include <QtGui>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "bsdetectionwidget.h"
using namespace std;
const int BSDetectionWidget::MAX_WIDTH_TUNING = 400;
const int BSDetectionWidget::DETECTION_LACKS_TUNING = 20;
const int BSDetectionWidget::DEFAULT_PEN_WIDTH = 1;
BSDetectionWidget::BSDetectionWidget (QWidget *parent)
{
Q_UNUSED (parent);
// Sets default user interface parameters
setFocus ();
grabKeyboard ();
fixed = false;
// Sets initial values for the gradient map
gMap = NULL;
// Initializes the auxiliary views
accuview = NULL;
strucview = NULL;
profileview = NULL;
alternate = 0;
verbose = false;
instanceOfAll = 0;
}
BSDetectionWidget::~BSDetectionWidget ()
{
if (accuview != NULL) delete accuview;
if (strucview != NULL) delete strucview;
}
QSize BSDetectionWidget::openImage (const QString &fileName, int type)
{
QSize newSize (0, 0);
loadedImage.load (fileName);
width = loadedImage.width ();
height = loadedImage.height ();
newSize = loadedImage.size ();
augmentedImage = loadedImage;
if (gMap != NULL) delete gMap;
gMap = new VMap (width, height, getBitmap (augmentedImage), type);
detector.setGradientMap (gMap);
update ();
if (profileview != NULL) profileview->setImage (&loadedImage, gMap);
if (strucview != NULL) strucview->setGradientImage (gMap);
return newSize;
}
int **BSDetectionWidget::getBitmap (const QImage &image)
{
int w = image.width ();
int h = image.height ();
int **tabImage = new int*[h];
for (int i = 0; i < h; i++)
{
tabImage[i] = new int[w];
for(int j = 0; j < w; j++)
{
QColor c = QColor (image.pixel (j, h - i - 1));
tabImage[i][j] = c.value ();
}
}
return tabImage;
}
bool BSDetectionWidget::saveAugmentedImage (const QString &fileName,
const char *fileFormat)
{
QImage aImage = augmentedImage;
return (aImage.save (fileName, fileFormat));
}
void BSDetectionWidget::clearImage ()
{
augmentedImage.fill (qRgb (255, 255, 255));
update ();
}
void BSDetectionWidget::paintEvent (QPaintEvent *)
{
QPainter painter (this);
painter.drawImage (QPoint (0, 0), augmentedImage);
}
void BSDetectionWidget::storeExtractedSegment ()
{
BlurredSegment *bs = detector.getBlurredSegment (1);
if (bs != NULL)
{
ExtractedSegment es;
es.bs = bs;
es.p1 = p1;
es.p2 = p2;
extractedSegments.push_back (es);
detector.preserveFormerBlurredSegment ();
}
}
void BSDetectionWidget::displayExtractedSegments ()
{
augmentedImage = loadedImage;
QPainter painter (&augmentedImage);
if (! extractedSegments.empty ())
{
vector<ExtractedSegment>::iterator it = extractedSegments.begin ();
while (it != extractedSegments.end ())
{
vector<Pt2i> bnd;
DigitalStraightSegment *dss = it->bs->getSegment ();
dss->getBoundPoints (bnd, false, 0, 0, width, height);
drawListOfPixels (bnd, Qt::green, painter);
dss->getBoundPoints (bnd, true, 0, 0, width, height);
drawListOfPixels (bnd, Qt::green, painter);
bnd = it->bs->getAllPoints ();
drawListOfPixels (bnd, Qt::blue, painter);
drawLine (it->p1, it->p2, Qt::white, painter);
it ++;
}
}
update (QRect (QPoint (0, 0), QPoint (width, height)));
}
void BSDetectionWidget::clearExtractedSegments ()
{
vector<ExtractedSegment>::iterator it = extractedSegments.begin ();
while (it != extractedSegments.end ())
delete ((it++)->bs->getSegment ());
extractedSegments.clear ();
}
void BSDetectionWidget::closeAccuAnalyzer ()
{
if (accuview != NULL)
{
accuview->close ();
delete accuview;
accuview = NULL;
}
}
void BSDetectionWidget::closePixelAnalyzer ()
{
if (strucview != NULL)
{
strucview->close ();
delete strucview;
strucview = NULL;
}
}
void BSDetectionWidget::closeProfileAnalyzer ()
{
if (profileview != NULL)
{
profileview->close ();
delete profileview;
profileview = NULL;
}
}
void BSDetectionWidget::switchAccuAnalyzer ()
{
if (accuview != NULL)
{
accuview->close ();
delete accuview;
accuview = NULL;
}
else
{
accuview = new BSAccumulatorView (&detector);
accuview->show ();
}
}
void BSDetectionWidget::switchPixelAnalyzer ()
{
if (strucview != NULL)
{
strucview->close ();
delete strucview;
strucview = NULL;
}
else
{
strucview = new BSStructureView (&loadedImage, &detector);
strucview->setGradientImage (gMap);
strucview->show ();
}
}
void BSDetectionWidget::switchProfileAnalyzer ()
{
if (profileview != NULL)
{
profileview->close ();
delete profileview;
profileview = NULL;
}
else
{
profileview = new BSProfileView ();
profileview->setImage (&loadedImage, gMap);
if (! p1.equals (p2)) profileview->buildScans (p1, p2);
profileview->show ();
}
}
void BSDetectionWidget::mousePressEvent (QMouseEvent *event)
{
this->p1 = Pt2i (event->pos().x (), height - 1 - event->pos().y());
}
void BSDetectionWidget::mouseReleaseEvent (QMouseEvent *event)
{
fixed = true;
this->p2 = Pt2i (event->pos().x (), height - 1 - event->pos().y());
alternate = 0;
cerr << "p1 defined: " << p1.x () << " " << p1.y () << endl;
cerr << "p2 defined: " << p2.x () << " " << p2.y () << endl;
extract ();
}
void BSDetectionWidget::mouseMoveEvent (QMouseEvent *event)
{
fixed = false;
this->p2 = Pt2i (event->pos().x (), height - 1 - event->pos().y ());
if (verbose) cerr << "(" << p1.x () << ", " << p1.y () << ") ("
<< p2.x () << ", " << p2.y () << ")" << endl;
if (p1.manhattan (p2) > 5
&& (width > p2.x() && height > p2.y()
&& p2.x() > 0 && p2.y() > 0))
{
extract ();
}
}
void BSDetectionWidget::keyPressEvent (QKeyEvent *event)
{
if (isActiveWindow ()) switch (event->key ())
{
case Qt::Key_U :
cerr << "p1 update: " << p1.x () << " " << p1.y () << endl;
cerr << "p2 update: " << p2.x () << " " << p2.y () << endl;
extract (true);
break;
case Qt::Key_M : // Multi-selection switch
detector.switchMultiSelection ();
cout << "Multi-selection "
<< (detector.isMultiSelection () ? "on" : "off") << endl;
break;
case Qt::Key_Y : // Initial detection extension limitation
detector.switchInitialBounding ();
extract (true);
cout << "Initial step max extension = "
<< detector.initialDetectionMaxExtent () << endl;
break;
case Qt::Key_D : // Density test at initial step
detector.switchDensityTest ();
extract (true);
cout << "Density test : "
<< (detector.isSetDensityTest () ? "on" : "off") << endl;
break;
case Qt::Key_W : // Input max width
detector.setInputMaxWidth (detector.getInputMaxWidth () +
(event->modifiers () & Qt::ShiftModifier ? -1 : 1));
extract (true);
cout << "Input max width = " << detector.getInputMaxWidth () << endl;
break;
case Qt::Key_L : // Output blurred segment min size
detector.setBSminSize (detector.getBSminSize () +
(event->modifiers () & Qt::ShiftModifier ? -1 : 1));
extract (true);
cout << "Output BS min size = " << detector.getBSminSize () << endl;
break;
case Qt::Key_H : // Pixel lack tolerence
detector.setPixelLackTolerence (detector.getPixelLackTolerence () +
(event->modifiers () & Qt::ShiftModifier ? -1 : 1));
extract (true);
cout << "Lack tolerence = " << detector.getPixelLackTolerence ()
<< " pixels" << endl;
break;
case Qt::Key_N : // Automatic detection grid resolution
detector.setAutoGridResolution (detector.getAutoGridResolution () +
(event->modifiers () & Qt::ShiftModifier ? -1 : 1));
cout << "Auto grid resolution = "
<< detector.getAutoGridResolution () << " pixels" << endl;
break;
case Qt::Key_Q :
detector.switchAutoRestart ();
extract (true);
cout << "Segment continuation after = "
<< detector.getRestartOnLack () << " pixels" << endl;
break;
case Qt::Key_T :
detector.toggleThinning ();
extract (true);
cout << "Thinning "
<< (detector.isThinningActivated () ? "on" : "off") << endl;
break;
case Qt::Key_X :
detector.switchAutoWidth ();
cout << "Final step max width " << (detector.autoWidthOn () ?
"fitted to initial segment" : "left unchanged") << endl;
extract (true);
break;
case Qt::Key_S :
detector.switchDynamicScans ();
cout << (detector.dynamicScansOn () ?
"Dynamic scans" : "Static scans") << endl;
extract (true);
break;
case Qt::Key_O :
detector.switchOrthoScans ();
cout << (detector.orthoScansOn () ?
"Orthographic scans" : "Directional scans") << endl;
extract (true);
break;
case Qt::Key_F :
detector.switchFiltering (1);
cout << "Final filtering "
<< (detector.isFiltering (1) ? "on" : "off") << endl;
extract (true);
break;
case Qt::Key_P :
detector.switchFiltering (0);
cout << "Pre-filtering "
<< (detector.isFiltering (0) ? "on" : "off") << endl;
extract (true);
break;
case Qt::Key_G :
detector.switchConnectivityConstraint ();
cout << "Connectivity constraint "
<< (detector.isSetConnectivityConstraint () ? "on" : "off") << endl;
extract (true);
break;
case Qt::Key_C :
if (event->modifiers () & Qt::ControlModifier)
storeExtractedSegment ();
break;
case Qt::Key_V :
if (event->modifiers () & Qt::ControlModifier)
displayExtractedSegments ();
else switchVerbose ();
break;
case Qt::Key_Z :
if (event->modifiers () & Qt::ControlModifier)
clearExtractedSegments ();
break;
case Qt::Key_E :
if (event->modifiers () & Qt::ShiftModifier)
detector.invertEdgeDirection ();
else detector.switchEdgeDirectionConstraint ();
switch (detector.edgeDirectionConstraint ())
{
case 0 :
cout << "Stroke detection" << endl;
break;
case 1 :
cout << "Edge detection" << endl;
break;
case -1 :
cout << "Opposite edge detection" << endl;
break;
}
extract (true);
break;
case Qt::Key_1 :
switchPixelAnalyzer ();
break;
case Qt::Key_2 :
switchAccuAnalyzer ();
break;
case Qt::Key_3 :
switchProfileAnalyzer ();
break;
case Qt::Key_6 :
displayNextOfAll ();
break;
case Qt::Key_7 :
extractAll ();
break;
case Qt::Key_8 :
alternateTest ();
break;
case Qt::Key_9 :
performanceTest ();
break;
case Qt::Key_0 :
localTest ();
break;
}
else if (strucview != NULL && strucview->isActiveWindow ())
{
if (strucview->processKeyEvent (event)) extract (true);
}
else if (accuview != NULL && accuview->isActiveWindow ())
{
if (accuview->processKeyEvent (event)) extract (true);
}
else if (profileview != NULL && profileview->isActiveWindow ())
{
if (profileview->processKeyEvent (event)) extract (true);
}
}
void BSDetectionWidget::drawListOfPixels (vector<Pt2i> vectPixels,
QColor color, QPainter &painter)
{
vector<Pt2i>::iterator iter = vectPixels.begin ();
while (iter != vectPixels.end ())
{
Pt2i p = *iter;
painter.setPen (QPen (color, DEFAULT_PEN_WIDTH, Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin));
if (p.x() < width && p.y() < height && p.x() >= 0 && p.y() >= 0)
painter.drawPoint (QPoint (p.x(), height - 1 - p.y())); // dec 1
iter ++;
}
}
void BSDetectionWidget::drawListOfPixels (vector<Pt2i> vectPixels,
QPainter &painter)
{
vector<Pt2i>::iterator iter = vectPixels.begin ();
while (iter != vectPixels.end ())
{
Pt2i p = *iter;
painter.setPen (QPen (QBrush (loadedImage.pixel (p.x (),
loadedImage.height () - 1 - p.y ())),
DEFAULT_PEN_WIDTH, Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin));
if (p.x() < width && p.y() < height && p.x() >= 0 && p.y() >= 0)
painter.drawPoint (QPoint (p.x(), height - 1 - p.y())); // dec 1
iter ++;
}
}
void BSDetectionWidget::drawLine (const Pt2i from, const Pt2i to,
QColor color, QPainter &painter)
{
int n;
Pt2i *pts = from.drawing (to, &n);
painter.setPen (QPen (color, DEFAULT_PEN_WIDTH, Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin));
for (int i = 0; i < n; i++)
painter.drawPoint (QPoint (pts[i].x (),
height - 1 - pts[i].y ())); // dec 1
delete [] pts;
}
void BSDetectionWidget::extract (bool withAllDisplay)
{
if (! p1.equals (p2))
{
fixed = withAllDisplay;
extract ();
}
}
void BSDetectionWidget::extract ()
{
augmentedImage = loadedImage;
QPainter painter (&augmentedImage);
if (p1.equals (p2))
{
update (QRect (QPoint (0, 0), QPoint (width, height)));
fixed = false;
return;
}
drawLine (p1, p2, Qt::red, painter);
if (detector.isMultiSelection ()) detector.multidetect (p1, p2);
else detector.detect (p1, p2);
// Update auxiliary view if not dragging
if (fixed)
{
if (profileview != NULL)
{
profileview->buildScans (p1, p2);
profileview->scene()->update ();
}
if (accuview != NULL) accuview->scene()->update ();
if (strucview != NULL) strucview->scene()->update ();
}
if (detector.isMultiSelection ())
{
vector<BlurredSegment *> mbs = detector.getBlurredSegments ();
vector<BlurredSegment *>::iterator it = mbs.begin ();
while (it != mbs.end ())
{
DigitalStraightSegment *dss = (*it)->getSegment ();
if (dss != NULL)
{
vector<Pt2i> bnd;
dss->getBounds (bnd, 0, 0, width, height);
drawListOfPixels (bnd, Qt::green, painter);
}
it++;
}
}
else
{
BlurredSegment *bs = detector.getBlurredSegment (1);
if (bs != NULL)
{
DigitalStraightSegment *dss = bs->getSegment ();
if (dss != NULL)
{
vector<Pt2i> bnd;
dss->getBounds (bnd, 0, 0, width, height);
drawListOfPixels (bnd, Qt::green, painter);
}
}
}
update (QRect (QPoint (0, 0), QPoint (width, height)));
if (verbose && fixed) displayExtractionResult ();
fixed = false;
}
void BSDetectionWidget::extractAll ()
{
bool formerMultiMode = detector.isMultiSelection ();
if (! formerMultiMode) detector.switchMultiSelection ();
augmentedImage = loadedImage;
QPainter painter (&augmentedImage);
detector.detectAll ();
// Update auxiliary view if not dragging
if (fixed)
{
if (profileview != NULL)
{
profileview->buildScans (p1, p2);
profileview->scene()->update ();
}
if (accuview != NULL) accuview->scene()->update ();
if (strucview != NULL) strucview->scene()->update ();
}
vector<BlurredSegment *> mbs = detector.getBlurredSegments ();
instanceOfAll = mbs.size ();
cout << instanceOfAll << " blurred segments detected" << endl;
vector<BlurredSegment *>::iterator it = mbs.begin ();
while (it != mbs.end ())
{
/*
DigitalStraightSegment *dss = (*it)->getSegment ();
if (dss != NULL)
{
vector<Pt2i> bnd;
dss->getBounds (bnd, 0, 0, width, height);
drawListOfPixels (bnd, Qt::green, painter);
}
*/
drawListOfPixels ((*it)->getAllPoints (), Qt::green, painter);
it++;
}
update (QRect (QPoint (0, 0), QPoint (width, height)));
if (verbose && fixed) displayExtractionResult ();
fixed = false;
if (! formerMultiMode) detector.switchMultiSelection ();
}
void BSDetectionWidget::displayNextOfAll ()
{
augmentedImage = loadedImage;
QPainter painter (&augmentedImage);
vector<BlurredSegment *> mbs = detector.getBlurredSegments ();
if (++instanceOfAll > (int) (mbs.size ())) instanceOfAll = 0;
vector<BlurredSegment *>::iterator it = mbs.begin ();
QColor bsCol = Qt::blue;
int index = 0;
while (index <= instanceOfAll && it != mbs.end ())
{
if (index++ == instanceOfAll) bsCol = Qt::green;
/*
DigitalStraightSegment *dss = (*it)->getSegment ();
if (dss != NULL)
{
vector<Pt2i> bnd;
dss->getBounds (bnd, 0, 0, width, height);
drawListOfPixels (bnd, Qt::green, painter);
}
*/
drawListOfPixels ((*it)->getAllPoints (), bsCol, painter);
it++;
}
update (QRect (QPoint (0, 0), QPoint (width, height)));
}
void BSDetectionWidget::displayExtractionResult ()
{
int res = detector.result ();
if (res == BSDetector::RESULT_UNDETERMINED)
cout << "Extraction : undetermined." << endl;
else if (res == BSDetector::RESULT_OK)
cout << "Extraction : OK." << endl;
else if (res == BSDetector::RESULT_INITIAL_NO_DETECTION)
cout << "Extraction : no initial detection (bsini == NULL)." << endl;
else if (res == BSDetector::RESULT_INITIAL_TOO_FEW)
cout << "Extraction : two few points at initial detection." << endl;
else if (res == BSDetector::RESULT_INITIAL_TOO_SPARSE)
cout << "Extraction : unsuccessful density test at initial detection."
<< endl;
else if (res == BSDetector::RESULT_INITIAL_TOO_MANY_OUTLIERS)
cout << "Extraction : unsuccessful filter test at initial detection."
<< endl;
else if (res == BSDetector::RESULT_FINAL_NO_DETECTION)
cout << "Extraction : no final detection (bsini == NULL)." << endl;
else if (res == BSDetector::RESULT_FINAL_TOO_FEW)
cout << "Extraction : two few points at final detection." << endl;
else if (res == BSDetector::RESULT_FINAL_TOO_SPARSE)
cout << "Extraction : unsuccessful density test at final detection."
<< endl;
else if (res == BSDetector::RESULT_FINAL_TOO_MANY_OUTLIERS)
cout << "Extraction : unsuccessful filter test at final detection."
<< endl;
}
void BSDetectionWidget::alternateTest ()
{
if (p1.equals (p2))
{
cout << "Stroke undefined" << endl;
return;
}
if (++alternate == 3) alternate = 0;
if (alternate == 0)
{
}
else if (alternate == 1)
{
}
else if (alternate == 2)
{
}
// extract (true);
}
void BSDetectionWidget::performanceTest ()
{
/*
if (p1.equals (p2))
{
cout << "Stroke undefined" << endl;
return;
}
cout << "Run test" << endl;
clock_t start = clock ();
for (int i = 0; i < 1000; i++) detector.detect (p1, p2);
double diff = (clock () - start) / (double) CLOCKS_PER_SEC;
cout << "Test run : " << diff << endl;
extract (true);
*/
cout << "Complete extractions test" << endl;
clock_t start = clock ();
for (int i = 0; i < 100; i++) detector.detectAll ();
double diff = (clock () - start) / (double) CLOCKS_PER_SEC;
cout << "Test run : " << diff << endl;
extract (true);
}
void BSDetectionWidget::localTest ()
{
cout << "Run test" << endl;
/*
p1 = Pt2i (212, 169);
p2 = Pt2i (232, 152);
*/
p1 = Pt2i (298, 199);
p2 = Pt2i (279, 173);
extract (true);
cout << "Test run" << endl;
}
#ifndef BS_DETECTION_WIDGET_H
#define BS_DETECTION_WIDGET_H
#include <QGraphicsView>
#include <QColor>
#include <QImage>
#include <QWidget>
#include <QVector>
#include <fstream>
#include "bsdetector.h"
#include "bsaccumulatorview.h"
#include "bsstructureview.h"
#include "bsprofileview.h"
using namespace std;
/**
* @class BSDetectionWidget bsdetectionwidget.h
* \brief Segment extraction view and controller.
* \author {P. Even and B. Kerautret}
*/
class BSDetectionWidget : public QWidget
{
Q_OBJECT
public:
/**
* \brief Creates a segment extraction widget.
*/
BSDetectionWidget (QWidget *parent = 0);
/**
* \brief Deletes the segment extraction widget.
*/
~BSDetectionWidget ();
/**
* \brief Opens the image to be processed.
* @param type Name of the image file to open.
* @param type Gradient extraction method.
*/
QSize openImage (const QString &fileName, int type = 0);
/**
* \brief Builds and returns the image bitmap.
*/
int **getBitmap (const QImage &image);
/**
* \brief Updates the Qt widget display.
void paint (QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
*/
/**
* \brief Saves the augmented image with extraction results.
*/
bool saveAugmentedImage (const QString &fileName, const char *fileFormat);
/**
* \brief Requires the accumulation window closure.
*/
void closeAccuAnalyzer ();
/**
* \brief Requires the pixel analysis window closure.
*/
void closePixelAnalyzer ();
/**
* \brief Requires the profile analysis window closure.
*/
void closeProfileAnalyzer ();
/**
* \brief Switches the pixel display window on or off.
*/
void switchPixelAnalyzer ();
/**
* \brief Switches the accumulator display window on or off.
*/
void switchAccuAnalyzer ();
/**
* \brief Switches the profile display window on or off.
*/
void switchProfileAnalyzer ();
/**
* \brief Switches the extraction result display on or off.
*/
inline void switchVerbose () { verbose = ! verbose; }
/**
* \brief Runs a comparative test.
*/
void alternateTest ();
/**
* \brief Runs a performance test.
* Displays the time spent for 1000 detections under the present stroke.
*/
void performanceTest ();
/**
* \brief Runs a local test (to be adapted).
*/
void localTest ();
public slots:
/**
* \brief Clears the widget drawing.
*/
void clearImage ();
protected:
/**
* \brief Updates the widget drawing.
*/
void paintEvent (QPaintEvent *event);
/**
* \brief Processes mouse press events.
*/
void mousePressEvent (QMouseEvent *event);
/**
* \brief Processes mouse release events.
*/
void mouseReleaseEvent (QMouseEvent *event);
/**
* \brief Processes move release events.
*/
void mouseMoveEvent (QMouseEvent *event);
/**
* \brief Processes key press events.
*/
void keyPressEvent (QKeyEvent *event);
private:
/** Sensitiveness of segment max width parameter. */
static const int MAX_WIDTH_TUNING;
/** Sensitiveness of detection lacks parameter. */
static const int DETECTION_LACKS_TUNING;
/** Default value for pen width. */
static const int DEFAULT_PEN_WIDTH;
/** Initial scan end points */
Pt2i p1, p2;
/** Flag indicating if the stroke is completely defined. */
bool fixed;
/** Flag indicating whether extraction result should be displayed. */
bool verbose;
/** Activation of alternate comparative tests (F8). */
int alternate;
/** Index of the last blurred segment displayed in a multi-selection. */
int instanceOfAll;
/** Presently loaded image. */
QImage loadedImage;
/** Present image augmented with processed data. */
QImage augmentedImage;
/** Gradient map of the loaded picture. */
VMap *gMap;
/** Width of the present image. */
int width;
/** Height of the present image. */
int height;
/** Blurred segment detector. */
BSDetector detector;
/** Aggregation of segment extraction results with initial conditions. */
struct ExtractedSegment
{
/** Extracted blurred segment. */
BlurredSegment *bs;
/** Selected strock start point. */
Pt2i p1;
/** Selected stroke end point. */
Pt2i p2;
};
/** List of registred blurred segments. */
vector<ExtractedSegment> extractedSegments;
/** Scanned profile graphics view. */
BSProfileView *profileview;
/** Filter accumulator view. */
BSAccumulatorView *accuview;
/** Blurred segment contents view. */
BSStructureView *strucview;
/**
* \brief Draws a list of points with the given color.
*/
void drawListOfPixels (vector<Pt2i> vectPixels,
QColor color, QPainter &painter);
/**
* \brief Draws a list of image pixels.
*/
void drawListOfPixels (vector<Pt2i> vectPixels,
QPainter &painter);
/**
* \brief Draws the line joining two points.
*/
void drawLine (const Pt2i from, const Pt2i to,
QColor color, QPainter &painter);
/**
* \brief Registers the last extracted blurred segment.
*/
void storeExtractedSegment ();
/**
* \brief Displays the registred blurred segments.
*/
void displayExtractedSegments ();
/**
* \brief Clears off the already extracted segments.
*/
void clearExtractedSegments ();
/**
* \brief Displays the last extraction result.
*/
void displayExtractionResult ();
/**
* \brief Detects a blurred segment under the selected stroke.
* @param withAllDisplay Indicates if all information about the extraction
* should be displayed.
*/
void extract (bool withAllDisplay);
/**
* \brief Detects and displays a blurred segment under the selected stroke.
*/
void extract ();
/**
* \brief Detects and displays all the blurred segment in the picture.
*/
void extractAll ();
/**
* \brief Highlights the next blurred segment in multi-selection mode.
*/
void displayNextOfAll ();
};
#endif
This diff is collapsed.
#ifndef BS_PROFILE_ITEM_H
#define BS_PROFILE_ITEM_H
#include <QGraphicsItem>
#include <QImage>
#include <QKeyEvent>
#include "vmap.h"
#include "scannerprovider.h"
/**
* @class BSProfileItem bsprofileitem.h
* \brief Scan intensity profile view and controller.
* \author {P. Even}
*/
class BSProfileItem : public QGraphicsItem
{
public:
/**
* \brief Creates a profile analysis widget.
*/
BSProfileItem ();
/**
* \brief Declares the image to be analysed.
*/
void setImage (QImage *image, VMap *idata);
/**
* \brief Sets the image scan area from an initial scan.
* The initial scan is a straight segment from p1 to p2.
*/
void buildScans (Pt2i p1, Pt2i p2);
/**
* \brief Returns the widget size.
* Nominally the image size.
*/
QRectF boundingRect () const;
/**
* \brief Updates the widget display.
*/
void paint (QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
/**
* \brief Returns the displayed information title.
*/
inline QString itemTitle () const
{
if (displayItem == DISPLAY_INTENSITY)
return ("Intensity profiles");
else if (displayItem == DISPLAY_GRADIENT)
return ("Gradient profiles");
else if (displayItem == DISPLAY_CORRELATION_MEAN_1D)
return ("Correlation profiles (mean 1D)");
else if (displayItem == DISPLAY_CORRELATION_FULL_2D)
return ("Correlation profiles (full 2D)");
else if (displayItem == DISPLAY_CORRELATION_MEAN_2D)
return ("Correlation profiles (mean 2D)");
else return ("No profile");
}
/**
* \brief Increments the current stripe index.
* @param inc Direction (1 for leftwards, -1 for rightwards)
*/
void incStripe (int inc);
/**
* \brief Increments or decrements the scan correlation width.
* @param down Direction (1 to increment, -1 to decrement)
*/
void incCorrelWidth (int down);
/**
* \brief Increments or decrements the scan correlation thickness.
* @param down Direction (1 to increment, -1 to decrement)
*/
void incCorrelThick (int down);
/**
* \brief Increments or decrements the scan correlation ratio.
* @param down Direction (1 to increment, -1 to decrement)
*/
void incCorrelRatio (int down);
/**
* \brief Toggles the displayed information.
* @param next Get next information if true, previous on otherwise.
*/
void toggleDisplay (bool next);
protected:
private:
/** Available information : intensity profiles. */
static const int DISPLAY_INTENSITY;
/** Available information : gradient profiles. */
static const int DISPLAY_GRADIENT;
/** Available information : 1D mean correlation profiles. */
static const int DISPLAY_CORRELATION_MEAN_1D;
/** Available information : 2D full correlation profiles. */
static const int DISPLAY_CORRELATION_FULL_2D;
/** Available information : 1D full correlation profiles. */
static const int DISPLAY_CORRELATION_MEAN_2D;
/** Number of the first information. */
static const int DISPLAY_MIN;
/** Number of the last information. */
static const int DISPLAY_MAX;
/** Analysis widget height. */
int widHeight;
/** Analysis widget width. */
int widWidth;
/** Profile area width. */
int profileWidth;
/** Intensity profile vertical zoom factor. */
int profileRatio;
/** Intensity profile lowest visible value. */
int profileLow;
/** Gradient profile vertical unzoom factor. */
int gradientUnRatio;
/** Gradient profile lowest visible value. */
int gradientLow;
/** Correlation profile vertical zoom factor (power of 2). */
int correlRatio;
/** Correlation profile width. */
int correlWidth;
/** Correlation profile scan thickness. */
int correlThick;
/** Stripe area width. */
int stripeWidth;
/** Stripe area margin width. */
int stripeMargin;
/** Stripe points zoom factor. */
int stripeResol;
/** Analysed image. */
QImage *image;
/* Analysed image width. */
int imageWidth;
/** Analyzed image height. */
int imageHeight;
/** Gradient map. */
VMap *gMap;
/** Central scan start point. */
Pt2i pt1;
/** Central scan start point. */
Pt2i pt2;
/** Central and left scans. */
vector <vector <Pt2i> > leftscan;
/** Right scans. */
vector <vector <Pt2i> > rightscan;
/** Minimum scan length allowed. */
static const int MIN_SCAN;
// Just for local minima extraction.
vector <vector <int> > leftCorrel;
vector <vector <int> > rightCorrel;
vector <vector <int> > leftReCorrel;
vector <vector <int> > rightReCorrel;
/** Displayed information (intensity, gradient, correlation). */
int displayItem;
/** Current stripe index. */
int stripe;
/** Min stripe index (right scan size). */
int minStripe;
/** Max stripe index (left scan size). */
int maxStripe;
/** Scanner provider (that selects the appropriate octant) */
ScannerProvider scanp;
/**
* \brief Correlation calculation (first release).
* \author {B. Kerautret}
* Compares portions of scan bars with a profile extracted at
* the first scan centered on the blurred segment.
*/
void setCorrelationStripes (Pt2i p1, Pt2i p2, int segwidth);
/**
* \brief Correlation calculation (second release).
* \author {B. Kerautret}
* Compares portions of scan bars with a mean profile extracted at
* the center of the first Nth scans (N = correlThick).
*/
bool setMeanCorrelationStripes ();
/**
* \brief Correlation calculation (third release).
* \author {B. Kerautret}
* Compares 2D portions of scan bars (N = correlThick) with a 2D profile
* extracted at the center of the first Nth scans (N = correlThick).
*/
bool setFull2dCorrelationStripes ();
/**
* \brief Correlation calculation (fourth release).
* \author {B. Kerautret}
* Compares mean portions of scan bars (N = correlThick) with a mean
* profile extracted at the center of the first Nth scans (N = correlThick).
*/
bool setMean2dCorrelationStripes ();
/**
* \brief Extract local minima from given signal.
* @param indices List of indices of the signal local minima.
* @param signal Input signal.
*/
void getLocalMinimaIndices (vector<int> &indices,
const vector<int> &signal) const;
/**
* \brief Draws the scan strip.
*/
void paintStripes (QPainter *painter);
/**
* \brief Draws the intensity profile.
*/
void paintIntensityProfile (QPainter *painter);
/**
* \brief Draws the gradient profile.
*/
void paintGradientProfile (QPainter *painter);
/**
* \brief Draws the correlation profile.
*/
void paintCorrelationProfile (QPainter *painter);
};
#endif
#include <QtGui>
#include <iostream>
#include <cstdlib>
#include "bsprofileview.h"
using namespace std;
BSProfileView::BSProfileView ()
{
// CAUTION : don't activate antialiasing here !!!
setBackgroundBrush (QBrush (Qt::white));
setScene (new QGraphicsScene (0, 0, 610, 610));
prof = new BSProfileItem ();
scene()->addItem (prof);
setWindowTitle (prof->itemTitle ());
resize (QSize (616, 616));
}
BSProfileView::~BSProfileView ()
{
scene()->removeItem (prof);
delete prof;
}
void BSProfileView::paint (QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED (option);
Q_UNUSED (widget);
Q_UNUSED (painter);
}
void BSProfileView::setImage (QImage *image, VMap *idata)
{
prof->setImage (image, idata);
}
void BSProfileView::buildScans (Pt2i p1, Pt2i p2)
{
prof->buildScans (p1, p2);
}
bool BSProfileView::processKeyEvent (QKeyEvent *event)
{
switch (event->key ())
{
case Qt::Key_W : // Width of correlation measure
prof->incCorrelWidth (event->modifiers () & Qt::ShiftModifier);
prof->update ();
break;
case Qt::Key_T : // Thickness of correlation measure
prof->incCorrelThick (event->modifiers () & Qt::ShiftModifier);
prof->update ();
break;
case Qt::Key_R : // Ratio of correlation measure
prof->incCorrelRatio (event->modifiers () & Qt::ShiftModifier);
prof->update ();
break;
case Qt::Key_I :
prof->toggleDisplay ((event->modifiers () & Qt::ShiftModifier) == 0);
setWindowTitle (prof->itemTitle ());
prof->update ();
break;
case Qt::Key_Up :
prof->incStripe (1);
prof->update ();
break;
case Qt::Key_Down :
prof->incStripe (-1);
prof->update ();
break;
}
return false;
}
#ifndef BS_PROFILE_VIEW_H
#define BS_PROFILE_VIEW_H
#include <QGraphicsView>
#include "bsprofileitem.h"
/**
* @class BSProfileView bsprofileview.h
* \brief A Qt window containing informations about scanned profiles.
* \author {P. Even}
*/
class BSProfileView : public QGraphicsView
{
public:
/**
* \brief Creates a profile analysis window.
*/
BSProfileView ();
/**
* \brief Deletes the profile analysis window.
*/
~BSProfileView ();
/**
* \brief Updates the profile analysis window display.
*/
void paint (QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
/**
* \brief Declares the image to be analysed.
*/
void setImage (QImage *image, VMap *idata);
/**
* \brief Sets the image scan area from an initial scan.
* The initial scan is a straight segment from p1 to p2.
*/
void buildScans (Pt2i p1, Pt2i p2);
/**
* \brief Processes key pressed events.
*/
bool processKeyEvent (QKeyEvent *event);
private:
/** Profile analysis widget. */
BSProfileItem *prof;
};
#endif
#include <QtGui>
#include <iostream>
#include "bsstructureitem.h"
using namespace std;
const int BSStructureItem::DISPLAY_FINAL_BLURRED_SEGMENT = 1;
const int BSStructureItem::DISPLAY_FINAL_CONNECTED_COMPONENTS = 2;
const int BSStructureItem::DISPLAY_FINAL_SCANS_AND_FILTER = 3;
const int BSStructureItem::DISPLAY_INITIAL_BLURRED_SEGMENT = 4;
const int BSStructureItem::DISPLAY_INITIAL_CONNECTED_COMPONENTS = 5;
const int BSStructureItem::DISPLAY_INITIAL_SCANS_AND_FILTER = 6;
const int BSStructureItem::DISPLAY_MIN = DISPLAY_FINAL_BLURRED_SEGMENT;
const int BSStructureItem::DISPLAY_MAX = DISPLAY_INITIAL_SCANS_AND_FILTER;
const int BSStructureItem::DEFAULT_PEN_WIDTH = 1;
const int BSStructureItem::LEFT_MARGIN = 16;
const int BSStructureItem::TEXT_HEIGHT = 16;
const int BSStructureItem::MAX_ZOOM = 16;
BSStructureItem::BSStructureItem (int width, int height, const QImage *im,
BSDetector *detector)
{
w = width;
h = height;
zoom = 1;
focx = 0;
focy = 0;
det = detector;
displayItem = DISPLAY_MIN;
displayScanLines = false;
this->im = im;
verbose = true;
infoPen = QPen (Qt::red, DEFAULT_PEN_WIDTH, Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin);
}
BSStructureItem::~BSStructureItem ()
{
}
void BSStructureItem::zoomIn ()
{
if (zoom < MAX_ZOOM) zoom *= 2;
}
void BSStructureItem::zoomOut ()
{
if (zoom > 1)
{
int w2 = w / 2;
int h2 = h / 2;
zoom /= 2;
if (focx < w2 / zoom - w2) focx = w2 / zoom - w2;
if (focx > w2 - w2 / zoom) focx = w2 - w2 / zoom;
if (focy < h2 / zoom - h2) focy = h2 / zoom - h2;
if (focy > h2 - h2 / zoom) focy = h2 - h2 / zoom;
}
}
void BSStructureItem::shift (int dx, int dy)
{
int w2 = w / 2;
int h2 = h / 2;
focx += zoom * dx;
focy += zoom * dy;
if (focx < w2 / zoom - w2) focx = w2 / zoom - w2;
if (focx > w2 - w2 / zoom) focx = w2 - w2 / zoom;
if (focy < h2 / zoom - h2) focy = h2 / zoom - h2;
if (focy > h2 - h2 / zoom) focy = h2 - h2 / zoom;
}
QRectF BSStructureItem::boundingRect () const
{
return QRectF (0, 0, w - 1, h - 1); // ZZZ
}
void BSStructureItem::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED (option);
Q_UNUSED (widget);
if (displayItem == DISPLAY_FINAL_BLURRED_SEGMENT)
paintBlurredSegment (painter, 1);
else if (displayItem == DISPLAY_FINAL_CONNECTED_COMPONENTS)
paintConnectedComponents (painter, 1);
else if (displayItem == DISPLAY_FINAL_SCANS_AND_FILTER)
paintScansAndFilter (painter, 1);
if (displayItem == DISPLAY_INITIAL_BLURRED_SEGMENT)
paintBlurredSegment (painter, 0);
else if (displayItem == DISPLAY_INITIAL_CONNECTED_COMPONENTS)
paintConnectedComponents (painter, 0);
else if (displayItem == DISPLAY_INITIAL_SCANS_AND_FILTER)
paintScansAndFilter (painter, 0);
}
void BSStructureItem::paintBlurredSegment (QPainter *painter, int step)
{
BlurredSegment *bs = det->getBlurredSegment (step);
if (bs != NULL)
{
DigitalStraightSegment *dss = bs->getSegment ();
if (dss != NULL)
{
vector<Pt2i> bnd;
dss->getBounds (bnd, 0, 0, w, h);
paintPixels (painter, bnd, Qt::green);
}
paintPixels (painter, bs->getAllPoints (), Qt::blue);
if (verbose)
{
initText (painter);
if (dss != NULL)
addText (painter, QString ("Segment width = ")
+ QString::number (dss->width ()) + QString ("/")
+ QString::number (dss->period ()) + QString (" = ")
+ QString::number (dss->width () / (double) dss->period ()));
else addText (painter, QString ("Segment width = 0"));
addText (painter, QString ("W : input max width = ")
+ QString::number (det->getInputMaxWidth ()));
addText (painter, QString ("L : output BS min size = ")
+ QString::number (det->getBSminSize ()));
addText (painter, QString ("H : pixel lack tolerence = ")
+ QString::number (det->getPixelLackTolerence ()));
if (step == 0)
{
addText (painter, QString ("D : extension limit = ")
+ QString::number (det->initialDetectionMaxExtent ()));
addText (painter, QString ("P : Prefiltering ")
+ (det->isFiltering (step) ?
(QString ("on : ")
+ QString::number (det->prefilteringInputSize ())
+ QString (" -> ")
+ QString::number (det->prefilteringOutputSize ())
+ QString (" pixels")) :
QString ("off")));
}
}
}
}
void BSStructureItem::paintConnectedComponents (QPainter *painter, int step)
{
BlurredSegment *bs = det->getBlurredSegment (step);
if (bs != NULL)
{
QColor cols[] = {Qt::blue, Qt::red, Qt::green};
int col = 0;
vector < vector <Pt2i> > cc = bs->getConnectedComponents ();
vector < vector <Pt2i> >::const_iterator it = cc.begin ();
while (it != cc.end ())
{
paintPixels (painter, *it, cols[col]);
if (++col == 3) col = 0;
it++;
}
}
if (verbose)
{
initText (painter);
int ccs = det->connectedComponentMinSize ();
if (bs != NULL)
{
int bsccp = bs->countOfConnectedPoints (ccs);
int bssize = bs->getAllPoints().size ();
addText (painter, QString ("G connectivity constraint ")
+ (det->isSetConnectivityConstraint () ?
QString ("on") : QString ("off")));
addText (painter, QString ("C connected components min size = ")
+ QString::number (ccs) + QString (" points"));
addText (painter, QString::number (bssize) + QString (" points"));
addText (painter, QString::number (bs->countOfConnectedComponents ())
+ QString (" connected components"));
addText (painter, QString::number (bs->countOfConnectedPoints ())
+ QString (" connected points"));
addText (painter, QString::number (bs->countOfConnectedComponents (ccs))
+ QString (" connected components with min size ")
+ QString::number (ccs));
addText (painter, QString::number (bsccp)
+ QString (" connected points with min size ")
+ QString::number (ccs));
if (bsccp < bssize / 2)
addText (painter, QString ("BS too sparse !"));
}
}
}
void BSStructureItem::paintScansAndFilter (QPainter *painter, int step)
{
if (det->scanRecordOn (step))
{
if (displayScanLines)
{
QColor col[] = {Qt::blue, Qt::red, Qt::green};
int i = 0;
vector < vector <Pt2i> > scns = det->getScans (step);
if (scns.size () > 0)
{
vector <vector <Pt2i> >::const_iterator it = scns.begin ();
paintPixel (painter, it->front (), col[2]);
paintPixel (painter, it->back (), col[2]);
it++; // Displays only the bounds of the central scan
while (it != scns.end ())
{
paintPixels (painter, *it, col[i]);
it++;
if (++i == 3) i = 0;
}
}
}
else
{
// Displays scan bounds
paintPixels (painter, det->getScanBound1 (step), Qt::blue);
paintPixels (painter, det->getScanBound2 (step), Qt::blue);
// Displays filter
if (det->isFiltering (step))
{
paintPixels (painter, det->getAccepted (step), Qt::green);
paintPixels (painter, det->getRejected (step), Qt::red);
BlurredSegment *bs = det->getBlurredSegment (step);
if (bs != NULL) paintPixels (painter, bs->getStartPt (), Qt::yellow);
}
}
}
if (verbose)
{
initText (painter);
addText (painter,
QString ("S : ") + (det->dynamicScansOn () ?
QString ("dynamic scans") : QString ("static scans")));
addText (painter,
QString ("O : ") + (det->orthoScansOn () ?
QString ("vert/horiz scans") : QString ("directional scans")));
}
}
void BSStructureItem::toggleDisplay (bool next)
{
displayItem += (next ? 1 : -1);
if (displayItem > DISPLAY_MAX) displayItem = DISPLAY_MIN;
else if (displayItem < DISPLAY_MIN) displayItem = DISPLAY_MAX;
det->setScanRecord (1, displayItem == DISPLAY_FINAL_SCANS_AND_FILTER);
det->setScanRecord (0, displayItem == DISPLAY_INITIAL_SCANS_AND_FILTER);
}
void BSStructureItem::paintPixels (QPainter *painter,
const vector<Pt2i> &pix, const QColor col)
{
QBrush brush (col);
vector<Pt2i>::const_iterator iter = pix.begin ();
while (iter != pix.end ())
{
Pt2i p = *iter;
int dx = w / 2 + focx - p.x ();
int dy = h / 2 - focy - p.y ();
painter->fillRect (w / 2 - zoom * dx,
(h / 2 + zoom * dy),
zoom, zoom, brush);
iter++;
}
}
void BSStructureItem::paintPixels (QPainter *painter,
const vector<Pt2i> &pix)
{
vector<Pt2i>::const_iterator iter = pix.begin ();
while (iter != pix.end ())
{
Pt2i p = *iter;
int dx = w / 2 + focx - p.x ();
int dy = h / 2 - focy - p.y ();
QBrush brush (im->pixel (p.x (), im->height () - 1 - p.y ()));
painter->fillRect (w / 2 - zoom * dx,
(h / 2 + zoom * dy),
zoom, zoom, brush);
iter++;
}
}
void BSStructureItem::paintPixel (QPainter *painter,
const Pt2i &pix, const QColor col)
{
QBrush brush (col);
int dx = w / 2 + focx - pix.x ();
int dy = h / 2 - focy - pix.y ();
painter->fillRect (w / 2 - zoom * dx, (h / 2 + zoom * dy), // dec 1
zoom, zoom, brush);
}
void BSStructureItem::initText (QPainter *painter)
{
painter->setPen (infoPen);
textOffset = 0;
}
void BSStructureItem::addText (QPainter *painter, const QString &text)
{
textOffset += TEXT_HEIGHT;
painter->drawText (LEFT_MARGIN, textOffset, text);
}
#ifndef BS_STRUCTURE_ITEM_H
#define BS_STRUCTURE_ITEM_H
#include <QGraphicsItem>
#include <vector>
#include "bsdetector.h"
class BSStructureItem : public QGraphicsItem
{
public:
/**
* \brief Creates a pixel analysis grid.
*/
BSStructureItem (int width, int height,
const QImage *im, BSDetector *detector);
/**
* \brief Deletes the pixel analysis grid.
*/
~BSStructureItem ();
/**
* \brief Return the zoom factor.
*/
inline int zoomFactor () const { return zoom; }
/**
* \brief Zooms the grid in.
*/
void zoomIn ();
/**
* \brief Zooms the grid out.
*/
void zoomOut ();
/**
* \brief Return the focus point abscissae.
*/
inline int focusX () const { return focx; }
/**
* \brief Return the focus point ordinate.
*/
inline int focusY () const { return focy; }
/**
* \brief Shifts the grid.
* @param dx shift X value.
* @param dy shift Y value.
*/
void shift (int dx, int dy);
/**
* \brief Toggles the displayed information.
* @param next Get next information if true, previous on otherwise.
*/
void toggleDisplay (bool next);
/**
* \brief Switches on or off the information text display modality.
*/
inline void switchInfoDisplay () { verbose = ! verbose; }
/**
* \brief Switches on or off the scan line display modality.
* @param next Get next information if true, previous on otherwise.
*/
inline void switchScanDisplay () { displayScanLines = ! displayScanLines; }
/**
* \brief Returns the displayed information title.
*/
inline QString itemTitle () const
{
if (displayItem == DISPLAY_FINAL_BLURRED_SEGMENT)
return ("Final blurred segment");
else if (displayItem == DISPLAY_FINAL_CONNECTED_COMPONENTS)
return ("Final connected components");
else if (displayItem == DISPLAY_FINAL_SCANS_AND_FILTER)
return ("Final scans and filter");
else if (displayItem == DISPLAY_INITIAL_BLURRED_SEGMENT)
return ("Initial blurred segment");
else if (displayItem == DISPLAY_INITIAL_CONNECTED_COMPONENTS)
return ("Initial connected components");
else if (displayItem == DISPLAY_INITIAL_SCANS_AND_FILTER)
return ("Initial scans and filter");
else return ("No info");
}
/**
* \brief Returns the grid area.
*/
QRectF boundingRect () const;
/**
* \brief Redraws the pixel analysis grid.
*/
void paint (QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
private:
/** Available information : final blurred segment pixels and bounds. */
static const int DISPLAY_FINAL_BLURRED_SEGMENT;
/** Available information : final connected components. */
static const int DISPLAY_FINAL_CONNECTED_COMPONENTS;
/** Available information : final scans and filter output. */
static const int DISPLAY_FINAL_SCANS_AND_FILTER;
/** Available information : initial blurred segment points and bounds. */
static const int DISPLAY_INITIAL_BLURRED_SEGMENT;
/** Available information : initial connected components. */
static const int DISPLAY_INITIAL_CONNECTED_COMPONENTS;
/** Available information : initial scans and filter output. */
static const int DISPLAY_INITIAL_SCANS_AND_FILTER;
/** Number of the first information. */
static const int DISPLAY_MIN;
/** Number of the last information. */
static const int DISPLAY_MAX;
/** Default value for pen width. */
static const int DEFAULT_PEN_WIDTH;
/** Left margin for information text. */
static const int LEFT_MARGIN;
/** Information text height. */
static const int TEXT_HEIGHT;
const QImage *im;
/** Grid width. */
int w;
/** Grid height. */
int h;
/** Zoom factor. */
static const int MAX_ZOOM;
/** Zoom factor. */
int zoom;
/** Focus point abscissae. */
int focx;
/** Focus point ordinate. */
int focy;
/** Segment detector. */
BSDetector *det;
/** Displayed information. */
int displayItem;
/** Scan display modality. */
bool displayScanLines;
/** Information text modality. */
bool verbose;
/** Information text style. */
QPen infoPen;
/** Information text vertical offset. */
int textOffset;
/**
* \brief Draws blurred segment structure information for the given step.
* @param painter : Painter to be decorated.
* @param step Initial step addressed if set to 0, final step otherwise.
*/
void paintBlurredSegment (QPainter *painter, int step);
/**
* \brief Draws connected components information for the given step.
* @param painter : Painter to be decorated.
* @param step Initial step addressed if set to 0, final step otherwise.
*/
void paintConnectedComponents (QPainter *painter, int step);
/**
* \brief Draws scans and filter information for the given step.
* @param painter : Painter to be decorated.
* @param step Initial step addressed if set to 0, final step otherwise.
*/
void paintScansAndFilter (QPainter *painter, int step);
/**
* \brief Draws a vector of pixels with given color.
* @param painter : Painter to be decorated.
* @param pix : Pixels to display.
* @param col : Pixels color.
*/
void paintPixels (QPainter *painter,
const vector<Pt2i> &pix, const QColor col);
/**
* \brief Draws a list of image pixels.
* @param painter : Painter to be decorated.
* @param pix : List of pixels to display.
* @param col : Pixels color.
*/
void paintPixels (QPainter *painter, const vector<Pt2i> &pix);
/**
* \brief Draws a pixel with given color.
* @param painter : Painter to be decorated.
* @param pix : Pixel to display.
* @param col : Color to apply.
*/
void paintPixel (QPainter *painter, const Pt2i &pix, const QColor col);
/**
* \brief Initializes the text display (color and position).
* @param painter : Painter to be decorated.
*/
void initText (QPainter *painter);
/**
* \brief Paints a new text in the graphics item (updates text position).
* @param painter : Painter to be decorated.
* @param text : Text to be displayed.
*/
void addText (QPainter *painter, const QString &text);
};
#endif
#include <QtGui>
#include <iostream>
#include "bsstructureview.h"
#include "math.h"
using namespace std;
BSStructureView::BSStructureView (QImage *im, BSDetector *sd)
{
graylevelImage = im;
currentImage = im;
det = sd;
int w = im->width ();
int h = im->height ();
imageInBack = true;
gradImage = NULL;
gradInBack = false;
setBackgroundBrush (QBrush (*currentImage));
setScene (new QGraphicsScene (0, 0, w, h));
grid = new BSStructureItem (w, h, im, sd);
scene()->addItem (grid);
setWindowTitle (grid->itemTitle ());
}
BSStructureView::~BSStructureView ()
{
scene()->removeItem (grid);
delete grid;
delete gradImage;
}
void BSStructureView::setGradientImage (VMap *gMap)
{
if (gradImage != NULL) delete gradImage;
int w = gMap->getWidth ();
int h = gMap->getHeight ();
double gn[w * h];
for (int j = 0; j < h; j++)
for (int i = 0; i < w; i++)
gn[j * w + i] = gMap->cmpNorm (i, j);
// gn[j * w + i] = sqrt (gMap->sqNorm (i, j));
double max = 0;
for (int i = 0; i < w * h; i++) if (max < gn[i]) max = gn[i];
gradImage = new QImage (w, h, QImage::Format_RGB32);
for (int j = 0; j < h; j++)
for (int i = 0; i < w; i++)
{
uint val = (uint) (gn[(h - 1 - j) * w + i] * 255 / max);
gradImage->setPixel (i, j, val + val * 256 + val * 256 * 256);
}
// gradImage->save ("gradient.png");
}
void BSStructureView::updateBackground (bool zoomChanged)
{
if (imageInBack)
{
int w = currentImage->width ();
int h = currentImage->height ();
int zf = grid->zoomFactor ();
if (zoomChanged) image = currentImage->scaled (w * zf, h * zf);
QBrush qb (image);
qb.setTransform (QTransform::fromTranslate (
w / 2 - zf * (w / 2 + grid->focusX ()),
h / 2 - zf * (h / 2 + grid->focusY ())));
setBackgroundBrush (qb);
}
}
void BSStructureView::toggleBackground ()
{
imageInBack = ! imageInBack;
if (imageInBack) setBackgroundBrush (QBrush (image));
else setBackgroundBrush (QBrush (Qt::white));
}
void BSStructureView::toggleGradient ()
{
if (currentImage == gradImage) currentImage = graylevelImage;
else if (gradImage != NULL) currentImage = gradImage;
}
void BSStructureView::paint (QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED (painter);
Q_UNUSED (option);
Q_UNUSED (widget);
}
bool BSStructureView::processKeyEvent (QKeyEvent *event)
{
bool processed = false;
switch (event->key ())
{
case Qt::Key_I : // Info
if (event->modifiers () & Qt::ControlModifier) grid->switchScanDisplay ();
else grid->toggleDisplay ((event->modifiers () & Qt::ShiftModifier) == 0);
setWindowTitle (grid->itemTitle ());
update ();
processed = true;
break;
case Qt::Key_V : // Info display
grid->switchInfoDisplay ();
update ();
processed = true;
break;
case Qt::Key_B : // Background
if (event->modifiers () & Qt::ShiftModifier) toggleGradient ();
else toggleBackground ();
updateBackground (true);
update ();
processed = true;
break;
case Qt::Key_Plus : // Zoom in
grid->zoomIn ();
updateBackground (true);
update ();
processed = true;
break;
case Qt::Key_Minus : // Zoom out
grid->zoomOut ();
updateBackground (true);
update ();
processed = true;
break;
case Qt::Key_Left : // Go leftwards
grid->shift (-1, 0);
updateBackground (false);
update ();
processed = true;
break;
case Qt::Key_Right : // Go rightwards
grid->shift (1, 0);
updateBackground (false);
update ();
processed = true;
break;
case Qt::Key_Up : // Go upwards
grid->shift (0, -1);
updateBackground (false);
update ();
processed = true;
break;
case Qt::Key_Down : // Go downwards
grid->shift (0, 1);
updateBackground (false);
update ();
processed = true;
break;
case Qt::Key_C : // Increments the connected components min size
det->incConnectedComponentMinSize (
(event->modifiers () & Qt::ShiftModifier) == 0);
update ();
processed = true;
break;
case Qt::Key_G : // Increments the connected components min size
det->switchConnectivityConstraint ();
update ();
processed = true;
break;
case Qt::Key_S : // Switch dynamic scans
det->switchDynamicScans ();
update ();
processed = true;
break;
case Qt::Key_O : // Switch orthographic scans
det->switchOrthoScans ();
update ();
processed = true;
break;
case Qt::Key_P : // Switch pre-filtering
det->switchFiltering (0);
update ();
processed = true;
break;
case Qt::Key_F : // Switch final filtering
det->switchFiltering (1);
update ();
processed = true;
break;
case Qt::Key_D : // Initial detection extension limitation
det->switchInitialBounding ();
update ();
processed = true;
break;
case Qt::Key_W : // Input max width
det->setInputMaxWidth (det->getInputMaxWidth () +
(event->modifiers () & Qt::ShiftModifier ? -1 : 1));
update ();
processed = true;
break;
case Qt::Key_L : // Output blurred segment min size
det->setBSminSize (det->getBSminSize () +
(event->modifiers () & Qt::ShiftModifier ? -1 : 1));
update ();
processed = true;
break;
case Qt::Key_H : // Pixel lack tolerence
det->setPixelLackTolerence (det->getPixelLackTolerence () +
(event->modifiers () & Qt::ShiftModifier ? -1 : 1));
update ();
processed = true;
break;
}
return processed;
}
#ifndef BS_STRUCTURE_VIEW_H
#define BS_STRUCTURE_VIEW_H
#include <QGraphicsView>
#include <QImage>
#include "bsstructureitem.h"
class BSStructureView : public QGraphicsView
{
public:
/**
* \brief Creates a pixel analyzer.
*/
BSStructureView (QImage *im, BSDetector *sd);
/**
* \brief Deletes the pixel analyzer.
*/
~BSStructureView ();
/**
* Sets the gradient image.
*/
void setGradientImage (VMap *gMap);
/**
* Toggles the window background between the current image or plain white.
*/
void toggleBackground ();
/**
* Toggles the current image between gray level or gradient image.
*/
void toggleGradient ();
/**
* \brief Redraws the pixel analyzer.
*/
void paint (QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
/**
* \brief Processes key pressed events.
*/
bool processKeyEvent (QKeyEvent *event);
protected:
private:
/** Pointer to the blurred segment detector. */
BSDetector *det;
/** Pointer to the raw image. */
QImage *graylevelImage;
/** Pointer to the blurred segment structure graphics item. */
BSStructureItem *grid;
/** Background image. */
QImage image;
/** Background image display modality. */
bool imageInBack;
/** Pointer to the gradient image. */
QImage *currentImage;
/** Pointer to the currently displayed image. */
QImage *gradImage;
/** Gradient image display modality. */
bool gradInBack;
/**
* Updates the background image.
* @param zoomChanged If 'true', the zoom factorshould be taken into account
*/
void updateBackground (bool zoomChanged);
};
#endif
#include "bswindow.h"
#include <QtGui>
//#include <QtWidgets>
#include <QFileDialog>
#include <QMenuBar>
#include <iostream>
BSWindow::BSWindow (int *val)
{
Q_UNUSED (val);
showProf = false;
showAccu = false;
showSeg = false;
gradType = VMap::TYPE_SOBEL_5X5;
detectionWidget = new BSDetectionWidget;
setCentralWidget (detectionWidget);
// setFocus();
// createActions ();
// createMenus ();
setWindowTitle (tr ("Blurred Segments"));
resize (400, 400);
}
BSWindow::BSWindow ()
{
showProf = false;
showAccu = false;
showSeg = false;
gradType = 0;
detectionWidget = new BSDetectionWidget;
setCentralWidget (detectionWidget);
// setFocus ();
// createActions ();
// createMenus ();
setWindowTitle (tr ("Blurred Segments"));
resize (400, 400);
}
void BSWindow::setFile (QString fileName)
{
resize (detectionWidget->openImage (fileName, gradType));
}
void BSWindow::runOptions ()
{
if (showProf) detectionWidget->switchProfileAnalyzer ();
if (showAccu) detectionWidget->switchAccuAnalyzer ();
if (showSeg) detectionWidget->switchPixelAnalyzer ();
}
void BSWindow::runTest ()
{
detectionWidget->localTest ();
}
void BSWindow::closeEvent (QCloseEvent *event)
{
detectionWidget->closeProfileAnalyzer ();
detectionWidget->closeAccuAnalyzer ();
detectionWidget->closePixelAnalyzer ();
event->accept ();
}
void BSWindow::open ()
{
QSize windowSize;
QString fileName = QFileDialog::getOpenFileName (this,
tr ("Open File"), QDir::currentPath ());
if (! fileName.isEmpty ())
{
windowSize = detectionWidget->openImage (fileName, gradType);
updateActions ();
}
resize (windowSize);
}
void BSWindow::save ()
{
QAction *action = qobject_cast < QAction *> (sender ());
QByteArray fileFormat = action->data().toByteArray ();
saveFile (fileFormat);
}
void BSWindow::updateActions ()
{
}
void BSWindow::createActions ()
{
openAct = new QAction (tr ("&Open..."), this);
openAct->setShortcut (tr ("Ctrl+O"));
connect (openAct, SIGNAL (triggered ()), this, SLOT (open()));
foreach (QByteArray format, QImageWriter::supportedImageFormats ())
{
QString text = tr("%1...").arg (QString(format).toUpper ());
QAction *action = new QAction (text, this);
action->setData (format);
connect (action, SIGNAL (triggered ()), this, SLOT (save ()));
saveAsActs.append (action);
}
exitAct = new QAction (tr ("E&xit"), this);
exitAct->setShortcut (tr ("Ctrl+Q"));
connect (exitAct, SIGNAL (triggered ()), this, SLOT (close ()));
}
void BSWindow::createMenus ()
{
saveAsMenu = new QMenu (tr ("&Save As"), this);
foreach (QAction *action, saveAsActs) saveAsMenu->addAction (action);
fileMenu = new QMenu (tr ("&File"), this);
fileMenu->addAction (openAct);
fileMenu->addMenu (saveAsMenu);
fileMenu->addSeparator ();
fileMenu->addAction (exitAct);
menuBar()->addMenu (fileMenu);
}
bool BSWindow::saveFile (const QByteArray &fileFormat)
{
QString initialPath = QDir::currentPath () + "/untitled." + fileFormat;
QString fileName = QFileDialog::getSaveFileName (this, tr ("Save As"),
initialPath, tr ("%1 Files (*.%2);;All Files (*)")
.arg(QString(fileFormat.toUpper()))
.arg(QString(fileFormat)));
if (fileName.isEmpty ()) return false;
else return detectionWidget->saveAugmentedImage (fileName, fileFormat);
}
#ifndef BS_WINDOW_H
#define BS_WINDOW_H
#include <QList>
#include <QMainWindow>
#include "bsdetectionwidget.h"
/**
* @class BSWindow bswindow.h
* \brief Blurred segment extraction Qt window.
* \author {P. Even and B. Kerautret}
*/
class BSWindow : public QMainWindow
{
Q_OBJECT
public:
/**
* \brief Creates a blurred segment extraction window.
*/
BSWindow ();
/**
* \brief Creates a segment extraction window.
*/
BSWindow (int *val);
/**
* Sets the processed image.
*/
void setFile (QString fileName);
/**
* Switches the profile analysis window on or off.
*/
inline void toggleProfWindow () { showProf = ! showProf; }
/**
* Switches the accumulator analysis window on or off.
*/
inline void toggleAccuWindow () { showAccu = ! showAccu; }
/**
* Switches the segment analysis window on or off.
*/
inline void toggleSegWindow () { showSeg= ! showSeg; }
/**
* Sets the gradient extraction method to be used.
*/
inline void useGradient (int type) { gradType = type; }
/**
* Takes into account the option (after image load).
*/
void runOptions ();
/**
* Performs a simple test.
*/
void runTest ();
protected:
void closeEvent (QCloseEvent *event);
private slots:
void open ();
void save ();
void updateActions ();
private:
/** Blurred segment detection widget. */
BSDetectionWidget *detectionWidget;
bool showProf;
bool showAccu;
bool showSeg;
int gradType;
void createActions ();
void createMenus ();
bool saveFile (const QByteArray &fileFormat);
QMenu *saveAsMenu;
QMenu *fileMenu;
QAction *openAct;
QList<QAction *> saveAsActs;
QAction *exitAct;
};
#endif
#include "biptlist.h"
#include <iostream>
BiPtList::BiPtList (Pt2i pt)
{
pts.push_back (pt);
start = 0;
cpt = 1;
}
BiPtList::~BiPtList ()
{
}
void BiPtList::addFront (Pt2i pt)
{
pts.push_front (pt);
start++;
cpt++;
}
void BiPtList::addBack (Pt2i pt)
{
pts.push_back (pt);
cpt++;
}
void BiPtList::removeFront (int n)
{
if (n >= frontSize ()) n = frontSize () - 1; // We keep at least one point
for (int i = 0; i < n; i++) pts.pop_front ();
cpt -= n;
start -= n;
if (start < 0) start = 0; // Theoretically impossible
}
void BiPtList::removeBack (int n)
{
if (n >= backSize ()) n = backSize () - 1; // We keep at least one point
for (int i = 0; i < n; i++) pts.pop_back ();
cpt -= n;
if (start >= cpt) start = cpt - 1; // Theoretically impossible
}
void BiPtList::findExtrema (int &xmin, int &ymin, int &xmax, int &ymax) const
{
deque<Pt2i>::const_iterator it = pts.begin ();
xmin = it->x ();
ymin = it->y ();
xmax = it->x ();
ymax = it->y ();
while (it != pts.end ())
{
if (xmin > it->x ()) xmin = it->x ();
if (xmax < it->x ()) xmax = it->x ();
if (ymin > it->y ()) ymin = it->y ();
if (ymax < it->y ()) ymax = it->y ();
it++;
}
}
vector<Pt2i> BiPtList::frontToBackPoints () const
{
vector<Pt2i> res;
for (deque<Pt2i>::const_iterator it = pts.begin ();
it != pts.end (); it++)
res.push_back (*it);
return (res);
}
vector<Pt2i> *BiPtList::vide () const
{
return (new vector<Pt2i> ());
}
vector<Pt2i> *BiPtList::frontPoints () const
{
// Fournis du bord au centre : pertinent ?
vector<Pt2i> *res = new vector<Pt2i> ();
deque<Pt2i>::const_iterator it = pts.begin ();
for (int i = 0; i < start; i++) res->push_back (*it++);
return res;
}
vector<Pt2i> *BiPtList::backPoints () const
{
vector<Pt2i> *res = new vector<Pt2i> ();
deque<Pt2i>::const_iterator it = pts.begin ();
it += start + 1;
for (int i = 0; i < cpt - start - 1; i++) res->push_back (*it++);
return res;
}
#ifndef BIPT_LIST_H
#define BIPT_LIST_H
#include "pt2i.h"
#include <deque>
using namespace std;
/**
* @class BiPtList biptlist.h
* \brief Bi-directional list of points.
* \author {P. Even}
*/
class BiPtList
{
public:
/**
* Creates a extendable bi-directional list with one point.
* @param pt Initial point of the list.
*/
BiPtList (Pt2i pt);
/**
* Deletes the bi-directional list.
*/
~BiPtList ();
/**
* Returns the count of point in the bi-directional list.
*/
inline int size () const { return (cpt); }
/**
* Returns the count of point on the back part of the bi-directional list.
*/
inline int backSize () const { return (cpt - start - 1); }
/**
* Returns the count of point on the back part of the bi-directional list.
*/
inline int frontSize () const { return (start); }
/**
* Returns the initial point of the bi-directional list.
*/
inline Pt2i initialPoint () const { return (pts[start]); }
/**
* Returns the back end point of the bi-directional list.
*/
inline Pt2i backPoint () const { return (pts.back ()); }
/**
* Returns the front end point of the bi-directional list.
*/
inline Pt2i frontPoint () const { return (pts.front ()); }
/**
* Returns the height of the point to the line between the list end points..
*/
inline AbsRat heightToEnds (const Pt2i &pt) const {
return (pt.triangleRationalHeight (pts.front (), pts.back ())); }
/**
* Adds the point on front side.
* @param pt The point to add.
*/
void addFront (Pt2i pt);
/**
* Adds the point on back side.
* @param pt The point to add.
*/
void addBack (Pt2i pt);
/**
* Removes n point on front side.
* @param n The count of points to remove.
*/
void removeFront (int n);
/**
* Removes n point on back side.
* @param n The count of points to remove.
*/
void removeBack (int n);
/**
* Fills in the given parameters with the point min and max coordinates.
* @param xmin Minimum X value.
* @param ymin Minimum Y value.
* @param xmax Maximum X value.
* @param ymax Maximum Y value.
*/
void findExtrema (int &xmin, int &ymin, int &xmax, int &ymax) const;
/**
* Returns front to back points in a vector.
*/
vector<Pt2i> frontToBackPoints () const;
/**
* Returns a pointer to a empty vector.
*/
vector<Pt2i> *vide () const;
/**
* Returns a pointer to a vector filled in with front points.
* Front points are entered from segment edge to the initial point excluded.
*/
vector<Pt2i> *frontPoints () const;
/**
* Returns a pointer to a vector filled in with back points.
* Back points are entered from initial point excluded to segment edge.
*/
vector<Pt2i> *backPoints () const;
private:
/** List of points. */
deque<Pt2i> pts;
/** Index of the initial point. */
int start;
/** Length of the point list. */
int cpt;
};
#endif
#include "blurredsegment.h"
BlurredSegment::BlurredSegment ()
{
plist = NULL;
dss = NULL;
}
BlurredSegment::BlurredSegment (BiPtList *ptlist, DigitalStraightSegment *seg)
{
plist = ptlist;
dss = seg;
}
BlurredSegment::~BlurredSegment ()
{
if (plist != NULL) delete plist;
if (dss != NULL) delete dss;
}
AbsRat BlurredSegment::segmentRationalWidth () const
{
return (AbsRat (dss->width (), dss->period ()));
}
vector<Pt2i> BlurredSegment::getAllPoints () const
{
return (plist->frontToBackPoints ());
}
vector<Pt2i> *BlurredSegment::getAllRight () const
{
return (plist->backPoints ());
}
vector<Pt2i> *BlurredSegment::getAllLeft () const
{
return (plist->frontPoints ());
}
int BlurredSegment::size () const
{
return (plist->size ());
}
vector<Pt2i> BlurredSegment::getStartPt () const
{
vector<Pt2i> res;
res.push_back (plist->initialPoint ());
return res;
}
const Pt2i BlurredSegment::getLastRight () const
{
return (plist->backPoint ());
}
const Pt2i BlurredSegment::getLastLeft () const
{
return (plist->frontPoint ());
}
Vr2i BlurredSegment::getSupportVector ()
{
return (dss->supportVector ());
}
Vr2i BlurredSegment::boundingBoxSize () const
{
int xmin, ymin, xmax, ymax;
plist->findExtrema (xmin, ymin, xmax, ymax);
return (Vr2i (xmax - xmin, ymax - ymin));
}
vector <vector <Pt2i> > BlurredSegment::connectedComponents () const
{
vector <vector <Pt2i> > ccs;
vector <Pt2i> pts = getAllPoints ();
if (pts.size () > 1)
{
vector <Pt2i> cc;
bool started = false;
vector <Pt2i>::const_iterator it = pts.begin ();
Pt2i pix = *it++;
while (it != pts.end ())
{
if (it->isConnectedTo (pix))
{
if (! started)
{
cc.push_back (pix);
started = true;
}
cc.push_back (*it);
}
else
{
if (started)
{
ccs.push_back (cc);
cc.clear ();
started = false;;
}
}
pix = *it++;
}
}
return ccs;
}
int BlurredSegment::countOfConnectedPoints () const
{
int count = 0;
vector <Pt2i> pts = getAllPoints ();
if (pts.size () > 1)
{
bool started = false;
vector <Pt2i>::const_iterator it = pts.begin ();
Pt2i pix = *it++;
while (it != pts.end ())
{
if (it->isConnectedTo (pix))
{
if (started) count ++;
else
{
count += 2;
started = true;
}
}
else
{
if (started) started = false;;
}
pix = *it++;
}
}
return count;
}
int BlurredSegment::countOfConnectedComponents () const
{
int count = 0;
vector <Pt2i> pts = getAllPoints ();
if (pts.size () > 1)
{
bool started = false;
vector <Pt2i>::const_iterator it = pts.begin ();
Pt2i pix = *it++;
while (it != pts.end ())
{
if (it->isConnectedTo (pix))
{
if (! started)
{
count ++;
started = true;
}
}
else
{
if (started) started = false;;
}
pix = *it++;
}
}
return count;
}
int BlurredSegment::countOfConnectedPoints (int min) const
{
int count = 0;
vector <Pt2i> pts = getAllPoints ();
if (pts.size () > 1)
{
int cpt = 1;
vector <Pt2i>::const_iterator it = pts.begin ();
Pt2i pix = *it++;
while (it != pts.end ())
{
if (it->isConnectedTo (pix))
{
if (++cpt == min) count += min;
else if (cpt > min) count ++;
}
else cpt = 1;
pix = *it++;
}
}
return count;
}
int BlurredSegment::countOfConnectedComponents (int min) const
{
int count = 0;
vector <Pt2i> pts = getAllPoints ();
if (pts.size () > 1)
{
int cpt = 1;
vector <Pt2i>::const_iterator it = pts.begin ();
Pt2i pix = *it++;
while (it != pts.end ())
{
if (it->isConnectedTo (pix))
{
if (++cpt == min) count ++;
}
else cpt = 1;;
pix = *it++;
}
}
return count;
}
vector <vector <Pt2i> >
BlurredSegment::getConnectedComponents () const
{
vector < vector <Pt2i> > res;
vector <Pt2i> pts = getAllPoints ();
if (pts.size () > 1)
{
vector <Pt2i>::const_iterator bit = pts.begin ();
vector <Pt2i>::const_iterator eit = pts.end ();
while (bit != eit)
{
vector <Pt2i> lres;
Pt2i pix = *bit++;
bool compose = true;
do
{
lres.push_back (pix);
compose = bit->isConnectedTo (pix);
if (compose) pix = *bit++;
}
while (compose && bit != eit);
if (compose) lres.push_back (pix);
res.push_back (lres);
}
}
return res;
}
#ifndef BLURRED_SEGMENT_H
#define BLURRED_SEGMENT_H
#include "convexhull.h"
#include "digitalstraightsegment.h"
#include "biptlist.h"
using namespace std;
/**
* @class BlurredSegment blurredsegment.h
* \brief A list of 2D points lying inside a digital straight line.
* \author {P. Even}
*/
class BlurredSegment
{
public:
/**
* Creates a blurred segment from nothing.
*/
BlurredSegment ();
/**
* Creates a blurred segment from a list of points.
* @param ptlist List of points of the blurred segment to build.
* @param seg Bounding digital straight segment.
*/
BlurredSegment (BiPtList *ptlist, DigitalStraightSegment *seg);
/**
* \brief Deletes the blurred segment.
*/
virtual ~BlurredSegment ();
/**
* \brief Returns the minimal vertical or horizontal width.
*/
virtual AbsRat segmentRationalWidth () const;
/**
* \brief Returns if the segment has non null thickness (not aligned points).
*/
inline bool isThick () const { return (dss->width () < 2); }
/**
* \brief Returns the underlying digital straight segment.
*/
inline DigitalStraightSegment *getSegment () { return dss; }
/**
* \brief Returns the count of points of the blurred segment.
*/
int size () const;
/**
* \brief Returns the start point of the blurred segment.
*/
inline const Pt2i getCenter () const { return plist->initialPoint (); }
/**
* \brief Returns the colinear points at the left of the start point.
*/
inline const vector<Pt2i> *getLeftLine () const { return plist->vide (); }
/**
* \brief Returns the colinear points at the right of the start point.
*/
inline const vector<Pt2i> *getRightLine () const { return plist->vide (); }
/**
* \brief Returns the left points added to the blurred segment start point.
*/
inline const vector<Pt2i> *getLeftPoints () const {
return plist->frontPoints (); }
/**
* \brief Returns the right points added to the blurred segment start point.
*/
inline const vector<Pt2i> *getRightPoints () const {
return plist->backPoints (); }
/**
* \brief Returns the set of all the points on the blurred segment.
* Points are ordered from the left end point up to the right end point.
*/
vector<Pt2i> getAllPoints () const;
/**
* \brief Returns the set of points on the left part of the blurred segment.
* Points are ordered from the furthest to the nearest to the start point.
*/
vector<Pt2i> *getAllLeft () const;
/**
* \brief Returns the set of points on the left part of the blurred segment.
* Points are ordered from the nearest to the furthest to the start point.
*/
vector<Pt2i> *getAllRight () const;
/**
* \brief Returns a vector containing the start point of the blurred segment.
*/
vector<Pt2i> getStartPt () const;
/**
* \brief Returns the last accepted point on the right side.
*/
const Pt2i getLastRight () const;
/**
* \brief Returns the last accepted point on the left side.
*/
const Pt2i getLastLeft () const;
/**
* \brief Returns the support vector of the blurred segment.
*/
virtual Vr2i getSupportVector ();
/**
* \brief Returns the size of the segment bounding box in a vector 2D.
*/
Vr2i boundingBoxSize () const;
/**
* \brief Returns the connected components of the blurred segment.
*/
vector <vector <Pt2i> > connectedComponents () const;
/**
* \brief Returns the count of connected points in the blurred segment.
*/
int countOfConnectedPoints () const;
/**
* \brief Returns the count of connected components in the blurred segment.
*/
int countOfConnectedComponents () const;
/**
* \brief Returns the count of connected points of given minimal size.
* @param min Minimal size of the connected components.
*/
int countOfConnectedPoints (int min) const;
/**
* \brief Returns the count of connected components of given minimal size.
* @param min Minimal size of the connected components.
*/
int countOfConnectedComponents (int min) const;
/**
* \brief Returns the connected components of the blurred segment.
*/
vector <vector <Pt2i> > getConnectedComponents () const;
protected:
/** Bounding straight segment. */
DigitalStraightSegment *dss;
/** Bi-directional list of points. */
BiPtList *plist;
};
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment