Engauge Digitizer  2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Public Member Functions | Static Public Member Functions | List of all members
Pixels Class Reference

Utility class for pixel manipulation. More...

#include <Pixels.h>

Collaboration diagram for Pixels:
Collaboration graph

Public Member Functions

 Pixels ()
 Single constructor. More...
 
int countBlackPixelsAroundPoint (const QImage &image, int x, int y, int stopCountAt)
 Fill triangle between these three points. More...
 
void fillHole (QImage &image, int row, int col, int thresholdCount) const
 Fill white hole encompassing (row,col) if number of pixels in that hole is below the threshold. More...
 
void fillHoles (QImage &image, int thresholdCount)
 Fill in white holes, surrounded by black pixels, smaller than some threshold number of pixels. More...
 
void fillIsolatedWhitePixels (QImage &image)
 Fill in white pixels surrounded by more black pixels than white pixels. More...
 

Static Public Member Functions

static bool pixelIsBlack (const QImage &image, int x, int y)
 Return true if pixel is black in black and white image. More...
 

Detailed Description

Utility class for pixel manipulation.

Definition at line 31 of file Pixels.h.

Constructor & Destructor Documentation

Pixels::Pixels ( )

Single constructor.

Definition at line 12 of file Pixels.cpp.

13 {
14 }

Member Function Documentation

int Pixels::countBlackPixelsAroundPoint ( const QImage &  image,
int  x,
int  y,
int  stopCountAt 
)

Fill triangle between these three points.

Definition at line 16 of file Pixels.cpp.

20 {
21  int count = 0;
22  QueuedPoints queuedPoints;
23  HashLookup hashLookup; // Prevents reprocessing of already-processed pixels
24 
25  // First point
26  if (pixelIsBlack (image, x, y)) {
27  queuedPoints.push_back (QPoint (x, y));
28  }
29 
30  while (queuedPoints.count () > 0) {
31 
32  // Pop off queue
33  QPoint p = queuedPoints.front ();
34  queuedPoints.pop_front ();
35 
36  QString hash = hashForCoordinates (p.x(),
37  p.y());
38 
39  // Skip if out of bounds, processed already or not black
40  bool inBounds = (0 <= p.x() &&
41  0 <= p.y() &&
42  p.x() < image.width () &&
43  p.y() < image.height ());
44  if (inBounds &&
45  !hashLookup.contains (hash) &&
46  pixelIsBlack (image, p.x(), p.y())) {
47 
48  // Black pixel. Add to count, and remember to not reprocess later
49  ++count;
50  if (count == stopCountAt) {
51  return count; // Reached limit. Stop immediately (probably for speed)
52  }
53  hashLookup [hash] = true;
54 
55  // Queue neighbors for processing
56  for (int dx = -1; dx <= 1; dx++) {
57  for (int dy = -1; dy <= 1; dy++) {
58  if (dx != 0 || dy != 0) {
59  queuedPoints.push_back (QPoint (p.x() + dx,
60  p.y() + dy));
61  }
62  }
63  }
64  }
65  }
66 
67  return count; // Did not reach limit
68 }
QQueue< QPoint > QueuedPoints
Definition: Pixels.h:21
QMap< QString, bool > HashLookup
Quick lookup table for pixel coordinate hashes processed so far.
Definition: Pixels.h:16
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
void Pixels::fillHole ( QImage &  image,
int  row,
int  col,
int  thresholdCount 
) const

Fill white hole encompassing (row,col) if number of pixels in that hole is below the threshold.

Definition at line 70 of file Pixels.cpp.

74 {
75  // Square of 1 pixel is surrounded by 3x3 box with indexes -1 to +2
76  // 2-4 pixels 4x4 -2 to +2
77  // 5-9 5x5 -2 to +3
78  // 10-16 6x6 -3 to +3
79  int rowStart = qFloor (row - (1 + qSqrt (thresholdCount - 1))); // Inclusive
80  int colStart = qFloor (col - (1 + qSqrt (thresholdCount - 1))); // Inclusive
81  int rowStop = qFloor (row + (1 + qSqrt (thresholdCount))); // Exclusive
82  int colStop = qFloor (col + (1 + qSqrt (thresholdCount))); // Exclusive
83 
84  // First pass is for counting
85  int countWhite = 0;
86  for (int rowIter = rowStart; rowIter < rowStop; rowIter++) {
87  for (int colIter = colStart; colIter < colStop; colIter++) {
88  if (!pixelIsBlack (image,
89  colIter,
90  rowIter)) {
91  ++countWhite;
92  }
93  }
94  }
95 
96  // Second pass fills in the hole
97  if (countWhite < thresholdCount) {
98  for (int rowIter = rowStart; rowIter < rowStop; rowIter++) {
99  for (int colIter = colStart; colIter < colStop; colIter++) {
100  image.setPixel (colIter,
101  rowIter,
102  Qt::black);
103  }
104  }
105  }
106 }
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
void Pixels::fillHoles ( QImage &  image,
int  thresholdCount 
)

Fill in white holes, surrounded by black pixels, smaller than some threshold number of pixels.

Originally this was recursive but the high recursion levels (for big regions) overflowed the stack

Definition at line 108 of file Pixels.cpp.

110 {
111  int height = image.height();
112  int width = image.width();
113 
114  // 2d matrix, indexed as 1d vector, of pixel states
115  QVector<PixelFillState> states (image.width() * image.height());
116  states.fill (PIXEL_FILL_STATE_UNPROCESSED);
117 
118  // Search for unprocessed pixels
119  for (int col = 0; col < width; col++) {
120  for (int row = 0; row < height; row++) {
121  if (states [indexCollapse (row, col, width)] == PIXEL_FILL_STATE_UNPROCESSED) {
122 
123  // Found an unprocessed pixel so process it
124  if (pixelIsBlack (image, col, row)) {
125 
126  // Black pixel needs no processing
127  states [indexCollapse (row, col, width)] = PIXEL_FILL_STATE_PROCESSED;
128 
129  } else {
130 
131  // Get this pixel and all of its white neighbors
132  int pixelsInRegion = fillPass (image,
133  states,
134  row,
135  col,
138  NO_FILL);
139 
140  FillIt fillIt = (pixelsInRegion < thresholdCount) ? YES_FILL : NO_FILL;
141 
142  fillPass (image,
143  states,
144  row,
145  col,
148  fillIt);
149  }
150  }
151  }
152  }
153 }
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
void Pixels::fillIsolatedWhitePixels ( QImage &  image)

Fill in white pixels surrounded by more black pixels than white pixels.

This is much faster than fillHoles and effectively as good

Definition at line 155 of file Pixels.cpp.

156 {
157  const int BORDER = 1;
158  const int HALF_NUMBER_NEIGHBORS = 4; // 8 neighbors in each direction from (col,row)
159 
160  int height = image.height();
161  int width = image.width();
162 
163  // 2d matrix, indexed as 1d vector, of neighbor counts
164  QVector<bool> pixelsAreBlack (image.width() * image.height());
165 
166  // Replace slow QImage addressing by faster QVector addressing
167  for (int col = 0; col < width; col++) {
168  for (int row = 0; row < height; row++) {
169  pixelsAreBlack [indexCollapse (row, col, width)] = pixelIsBlack (image, col, row);
170  }
171  }
172 
173  // Search for white pixels. Black pixels will be ignored, and also pixels along the four
174  // borders are ignored so we do not need to worry about going out of bounds
175  for (int col = BORDER; col < width - BORDER; col++) {
176  for (int row = BORDER; row < height - BORDER; row++) {
177  int count = 0;
178  count += pixelsAreBlack [indexCollapse (row - 1, col - 1, width)] ? 1 : 0;
179  count += pixelsAreBlack [indexCollapse (row - 1, col , width)] ? 1 : 0;
180  count += pixelsAreBlack [indexCollapse (row - 1, col + 1, width)] ? 1 : 0;
181  count += pixelsAreBlack [indexCollapse (row , col - 1, width)] ? 1 : 0;
182  count += pixelsAreBlack [indexCollapse (row , col + 1, width)] ? 1 : 0;
183  count += pixelsAreBlack [indexCollapse (row + 1, col - 1, width)] ? 1 : 0;
184  count += pixelsAreBlack [indexCollapse (row + 1, col , width)] ? 1 : 0;
185  count += pixelsAreBlack [indexCollapse (row + 1, col + 1, width)] ? 1 : 0;
186  if (count > HALF_NUMBER_NEIGHBORS) {
187  image.setPixel (col,
188  row,
189  Qt::black);
190  }
191  }
192  }
193 }
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
bool Pixels::pixelIsBlack ( const QImage &  image,
int  x,
int  y 
)
static

Return true if pixel is black in black and white image.

Definition at line 286 of file Pixels.cpp.

289 {
290  QRgb rgb = image.pixel (x, y);
291  return qGray (rgb) < 128;
292 }

The documentation for this class was generated from the following files: