Engauge Digitizer  2
GridHealerVertical.cpp
Go to the documentation of this file.
1 /******************************************************************************************************
2  * (C) 2018 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 "GridHealerVertical.h"
9 #include "GridLog.h"
10 #include "Pixels.h"
11 #include <qmath.h>
12 
14  const DocumentModelGridRemoval &modelGridRemoval) :
15  GridHealerAbstractBase (gridLog,
16  modelGridRemoval)
17 {
18 }
19 
20 void GridHealerVertical::applyMutualPairs (const QImage &image)
21 {
22  MutualPairHalves::const_iterator itrBelow = mutualPairHalvesBelow().begin();
23  MutualPairHalves::const_iterator itrAbove = mutualPairHalvesAbove().begin();
24 
25  while (itrBelow != mutualPairHalvesBelow().end() &&
26  itrAbove != mutualPairHalvesAbove().end()) {
27 
28  QPoint p0 = *(itrBelow++);
29  QPoint p1 = *(itrAbove++);
30 
31  // Save (independent,dependent) pairs
32  if (Pixels::pixelIsBlack (image, p0.x(), p0.y())) {
33  m_blackPixelsBelow [p0.y()] = p0.x();
34  }
35 
36  if (Pixels::pixelIsBlack (image, p1.x(), p1.y())) {
37  m_blackPixelsAbove [p1.y()] = p1.x();
38  }
39 
40  saveGapSeparation (qAbs (p1.x() - p0.x()));
41  }
42 }
43 
45 {
46  // LOG4CPP_INFO_S is replaced by GridLog
47  GridIndependentToDependent::const_iterator itrBelow, itrAbove;
48  for (itrBelow = m_blackPixelsBelow.begin(); itrBelow != m_blackPixelsBelow.end(); itrBelow++) {
49  QPoint p (itrBelow.value(),
50  itrBelow.key());
53  }
54  for (itrAbove = m_blackPixelsAbove.begin(); itrAbove != m_blackPixelsAbove.end(); itrAbove++) {
55  QPoint p (itrAbove.value(),
56  itrAbove.key());
59  }
60 
61  // Algorithm requires at least one point in each of the lists
62  if (m_blackPixelsBelow.count() > 0 &&
63  m_blackPixelsAbove.count() > 0) {
64 
65  int yFirst = qMin (m_blackPixelsBelow.firstKey (),
66  m_blackPixelsAbove.firstKey ());
67  int yLast = qMax (m_blackPixelsBelow.lastKey (),
68  m_blackPixelsAbove.lastKey ());
69 
70  int yBelowEnd = 0; // Used by inner loop to skip to this iterator value
71 
72  for (int yBelowStart = yFirst; yBelowStart <= yLast; yBelowStart++) {
73 
74  if ((yBelowEnd < yBelowStart) &&
75  m_blackPixelsBelow.contains (yBelowStart)) {
76 
77  // This could be the start of a new trapezoid. Find where the range on the same side ends
78  int yBelowOutOfBounds = yLast + 1; // Value forcing transition to out of range
79 
80  for (yBelowEnd = yBelowStart + 1; yBelowEnd <= yBelowOutOfBounds; yBelowEnd++) {
81 
82  if (!m_blackPixelsBelow.contains (yBelowEnd) || (yBelowEnd == yBelowOutOfBounds)) {
83 
84  doHealingOnBelowRange (image,
85  yBelowStart,
86  yBelowEnd,
87  qFloor (maxPointSeparation()));
88 
89  // Go back to outer loop, which will skip to xBelowEnd
90  break;
91  }
92  }
93  }
94  }
95  }
96 }
97 
98 void GridHealerVertical::doHealingOnBelowAndAboveRangePair (QImage &image,
99  int yBelowStart,
100  int yBelowEnd,
101  int yAboveStart,
102  int yAboveEnd)
103 {
104  // LOG4CPP_INFO_S is replaced by GridLog
105 
106  int x0 = m_blackPixelsBelow [yBelowStart];
107  int x1 = m_blackPixelsBelow [yBelowEnd ];
108  int x2 = m_blackPixelsAbove [yAboveEnd ];
109  int x3 = m_blackPixelsAbove [yAboveStart];
110  int y0 = yBelowStart;
111  int y1 = yBelowEnd;
112  int y2 = yAboveEnd;
113  int y3 = yAboveStart;
114 
115  gridLog().showOutputTrapezoid (QPoint (x0, y0),
116  QPoint (x1, y1),
117  QPoint (x2, y2),
118  QPoint (x3, y3));
119 
120  if (pointsAreGood (image, x0, y0, x2, y2)) {
121 
122  // Big enough so keep it. Four points that define the trapezoid to be filled in
123  fillTrapezoid (image,
124  x0, y0,
125  x1, y1,
126  x2, y2,
127  x3, y3);
128  }
129 }
130 
131 void GridHealerVertical::doHealingOnBelowRange (QImage &image,
132  int xBelowStart,
133  int xBelowEnd,
134  int maxHorSep)
135 {
136  // LOG4CPP_INFO_S is replaced by GridLog
137 
138  // Below range goes from xBelowStart (inclusive) to xBelowEnd (exclusive). There could
139  // be zero, one or more above ranges that overlap within maxHorSep, corresponding
140  // to an equal number of trapezoids to be filled in
141  //
142  // It is important to note that every above point between xBelowStart-maxHorSep to
143  // xBelowEnd+maxHorSep is close enough (<close distance) to a point in the below range
144 
145  int xAboveOutOfBounds = xBelowEnd + maxHorSep + 1; // Value forcing transition to out of range
146 
147  int xAboveEnd = 0; // Used by inner loop to skip to this iterator value
148 
149  for (int xAboveStart = xBelowStart - maxHorSep; xAboveStart <= xAboveOutOfBounds; xAboveStart++) {
150 
151  if ((xAboveEnd < xAboveStart) &&
152  m_blackPixelsAbove.contains (xAboveStart) &&
153  (xAboveStart < xAboveOutOfBounds)) {
154 
155  for (xAboveEnd = xAboveStart + 1; xAboveEnd <= xAboveOutOfBounds; xAboveEnd++) {
156 
157  if (!m_blackPixelsAbove.contains (xAboveEnd) || (xAboveEnd == xAboveOutOfBounds)) {
158 
159  int xBelowStartNearEnough = qMax (xBelowStart, xAboveStart - maxHorSep);
160  int xBelowEndNearEnough = qMin (xBelowEnd - 1, xAboveEnd + maxHorSep);
161  int xAboveEndInclusive = xAboveEnd - 1;
162 
163  if (xBelowStartNearEnough <= xBelowEndNearEnough) {
164 
165  doHealingOnBelowAndAboveRangePair (image,
166  xBelowStartNearEnough,
167  xBelowEndNearEnough,
168  xAboveStart,
169  xAboveEndInclusive);
170 
171  // Go back to outer loop, which will skip to xAboveEnd
172  break;
173  }
174  }
175  }
176  }
177  }
178 }
Class that does special logging for GridLog and GridRemoval classes.
Definition: GridLog.h:16
double maxPointSeparation() const
Max point separation get method.
void saveGapSeparation(double gapSeparation)
Gap separation set method.
virtual void doHealingAcrossGaps(QImage &image)
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.
virtual void applyMutualPairs(const QImage &image)
Apply mutual pair points after all grid removal is done.
const MutualPairHalves & mutualPairHalvesBelow() const
Mutual pair halves for above grid line.
Class that &#39;heals&#39; the curves after one grid line has been removed.
const double HALFWIDTH_VERTICAL
GridLog & gridLog()
Logging get method.
GridHealerVertical(GridLog &gridLog, const DocumentModelGridRemoval &modelGridRemoval)
Single constructor.
void showInputPixel(const QPoint &p, double halfWidth)
Show pixels that are inputs to GridHealer.
Definition: GridLog.cpp:68
void showOutputTrapezoid(const QPoint &p0, const QPoint &p1, const QPoint &p2, const QPoint &p3)
Show trapezoids that are intermediate results in GridHealer.
Definition: GridLog.cpp:104
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.
Model for DlgSettingsGridRemoval and CmdSettingsGridRemoval. The settings are unstable until the user...
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.