Engauge Digitizer  2
GridHealerAbstractBase.cpp
1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5  ******************************************************************************************************/
6 
7 #include "DocumentModelGridRemoval.h"
8 #include "EngaugeAssert.h"
9 #include "GridHealerAbstractBase.h"
10 #include "GridLog.h"
11 #include "GridTriangleFill.h"
12 #include "Logger.h"
13 #include "Pixels.h"
14 #include <QFile>
15 #include <QImage>
16 #include <qmath.h>
17 #include <QRgb>
18 #include <QTextStream>
19 
21  const DocumentModelGridRemoval &modelGridRemoval) :
22  m_modelGridRemoval (modelGridRemoval),
23  m_maxPointSeparation (0),
24  m_gridLog (gridLog)
25 {
26 }
27 
28 GridHealerAbstractBase::~GridHealerAbstractBase()
29 {
30 }
31 
33  int y0,
34  int x1,
35  int y1)
36 {
37  m_mutualPairHalvesBelow.push_back (QPoint (x0, y0));
38  m_mutualPairHalvesAbove.push_back (QPoint (x1, y1));
39 }
40 
42  int xBL, int yBL,
43  int xBR, int yBR,
44  int xTR, int yTR,
45  int xTL, int yTL)
46 {
47  // Sanity checks
48  if (xBL == 0 || yBL == 0 || xBR == 0 || yBR == 0 || xTR == 0 || yTR == 0 || xTL == 0 || yTL == 0) {
49  LOG4CPP_ERROR_S ((*mainCat)) << "GridHealerAbstractBase::fillTrapezoid received undefined corner coordinate "
50  << "xBL=" << xBL << " yBL=" << yBL << " xBR=" << xBR << " yBR=" << yBR
51  << "xTR=" << xTR << " yTR=" << yTR << " xTL=" << xTL << " yTL=" << yTL;
52  }
53 
54  if (!Pixels::pixelIsBlack(image, xBL, yBL)) {
55  LOG4CPP_ERROR_S ((*mainCat)) << "GridHealerAbstractBase::fillTrapezoid has bad bottom left point";
56  }
57  if (!Pixels::pixelIsBlack(image, xBR, yBR)) {
58  LOG4CPP_ERROR_S ((*mainCat)) << "GridHealerAbstractBase::fillTrapezoid has bad bottom right point";
59  }
60  if (!Pixels::pixelIsBlack(image, xTR, yTR)) {
61  LOG4CPP_ERROR_S ((*mainCat)) << "GridHealerAbstractBase::fillTrapezoid has bad top right point";
62  }
63  if (!Pixels::pixelIsBlack(image, xTL, yTL)) {
64  LOG4CPP_ERROR_S ((*mainCat)) << "GridHealerAbstractBase::fillTrapezoid has bad top left point";
65  }
66 
67  // Any quadrilateral (including this trapezoid) can be considered the union of two triangles
68  GridTriangleFill triangleFill;
69  triangleFill.fill (m_gridLog,
70  image,
71  QPoint (xBL, yBL),
72  QPoint (xBR, yBR),
73  QPoint (xTR, yTR));
74  triangleFill.fill (m_gridLog,
75  image,
76  QPoint (xBL, yBL),
77  QPoint (xTL, yTL),
78  QPoint (xTR, yTR));
79 }
80 
82 {
83  return m_gridLog;
84 }
85 
86 void GridHealerAbstractBase::healed (QImage &image)
87 {
88  applyMutualPairs (image);
89  doHealingAcrossGaps (image);
90 }
91 
93 {
94  return m_maxPointSeparation;
95 }
96 
98 {
99  return m_modelGridRemoval;
100 }
101 
102 const MutualPairHalves &GridHealerAbstractBase::mutualPairHalvesAbove () const
103 {
104  return m_mutualPairHalvesAbove;
105 }
106 
107 const MutualPairHalves &GridHealerAbstractBase::mutualPairHalvesBelow () const
108 {
109  return m_mutualPairHalvesBelow;
110 }
111 
113 {
114  // For now we will use the close distance as the minimum pixel count
115  return qFloor (modelGridRemoval.closeDistance());
116 }
117 
118 bool GridHealerAbstractBase::pointsAreGood (const QImage &image,
119  int x0,
120  int y0,
121  int x1,
122  int y1) const
123 {
124  Pixels pixels;
125 
126  int stopCountAt = pixelCountInRegionThreshold (m_modelGridRemoval);
127 
128  // Skip if either endpoint is an unwanted artifact. Look at start point below (since it is connected
129  // to the end point below), and the start point above (which is connected to the end point above)
130  return ((pixels.countBlackPixelsAroundPoint (image, x0, y0, stopCountAt) >= stopCountAt) &&
131  (pixels.countBlackPixelsAroundPoint (image, x1, y1, stopCountAt) >= stopCountAt));
132 }
133 
134 void GridHealerAbstractBase::saveGapSeparation (double gapSeparation)
135 {
136  // Right triangle with one edge crossing the gap (separation value) and hypotenuse giving
137  // maximum point separation (closest distance) gives the maximum horizontal separation
138  m_maxPointSeparation = qFloor (qSqrt (qPow (modelGridRemoval().closeDistance(), 2) -
139  qPow (gapSeparation, 2)));
140 }
Class that does special logging for GridLog and GridRemoval classes.
Definition: GridLog.h:16
void fill(GridLog &gridLog, QImage &image, const QPoint &p0, const QPoint &p1, const QPoint &p2)
Fill triangle between these three points.
double closeDistance() const
Get method for close distance.
double maxPointSeparation() const
Max point separation get method.
void saveGapSeparation(double gapSeparation)
Gap separation set method.
Utility class for pixel manipulation.
Definition: Pixels.h:31
virtual void doHealingAcrossGaps(QImage &image)=0
Guts of the algorithm in which sequences of black pixels across the gap from each other are filled in...
bool pointsAreGood(const QImage &image, int x0, int y0, int x1, int y1) const
Apply blackPixelRegionIsBigEnough to regions around each of two points.
const MutualPairHalves & mutualPairHalvesBelow() const
Mutual pair halves for above grid line.
void healed(QImage &image)
Return healed image after grid removal.
GridHealerAbstractBase(GridLog &gridLog, const DocumentModelGridRemoval &modelGridRemoval)
Single constructor.
GridLog & gridLog()
Logging get method.
virtual void applyMutualPairs(const QImage &image)=0
Apply mutual pair points after all grid removal is done.
static int pixelCountInRegionThreshold(const DocumentModelGridRemoval &modelGridRemoval)
Threshold number of pixels in a region to be considered too-small or big-enough.
int countBlackPixelsAroundPoint(const QImage &image, int x, int y, int stopCountAt)
Fill triangle between these three points.
Definition: Pixels.cpp:16
Class that does raster-line fill of a triangle, with logging customizations for GridHealer (and there...
static bool pixelIsBlack(const QImage &image, int x, int y)
Return true if pixel is black in black and white image.
Definition: Pixels.cpp:286
const MutualPairHalves & mutualPairHalvesAbove() const
Mutual pair halves for below grid line.
void addMutualPair(int x0, int y0, int x1, int y1)
Add two points on either side of a gap. Later, after removal, the black points will be processed.
Model for DlgSettingsGridRemoval and CmdSettingsGridRemoval. The settings are unstable until the user...
DocumentModelGridRemoval & modelGridRemoval()
DocumentModelGridRemoval get method.
void fillTrapezoid(QImage &image, int xBL, int yBL, int xBR, int yBR, int xTR, int yTR, int xTL, int yTL)
Fill trapezoid with bottom left, bottom right, top right, and top left points.