7 #include "ColorFilter.h"
8 #include "Correlation.h"
9 #include "DocumentModelCoords.h"
10 #include "EngaugeAssert.h"
12 #include "GridClassifier.h"
18 #include "QtToString.h"
19 #include "Transformation.h"
21 int GridClassifier::NUM_PIXELS_PER_HISTOGRAM_BINS = 1;
22 double GridClassifier::PEAK_HALF_WIDTH = 4;
23 int GridClassifier::MIN_STEP_PIXELS = 4 * GridClassifier::PEAK_HALF_WIDTH;
24 const QString GNUPLOT_DELIMITER (
"\t");
28 int GridClassifier::BIN_START_UNSHIFTED = GridClassifier::PEAK_HALF_WIDTH;
36 int GridClassifier::binFromCoordinate (
double coord,
38 double coordMax)
const
40 ENGAUGE_ASSERT (coordMin < coordMax);
41 ENGAUGE_ASSERT (coordMin <= coord);
42 ENGAUGE_ASSERT (coord <= coordMax);
44 int bin = 0.5 + (m_numHistogramBins - 1.0) * (coord - coordMin) / (coordMax - coordMin);
50 const QPixmap &originalPixmap,
59 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::classify";
61 QImage image = originalPixmap.toImage ();
63 m_numHistogramBins = image.width() / NUM_PIXELS_PER_HISTOGRAM_BINS;
64 ENGAUGE_ASSERT (m_numHistogramBins > 1);
66 double xMin, xMax, yMin, yMax;
67 double binStartX, binStepX, binStartY, binStepY;
69 m_binsX =
new double [m_numHistogramBins];
70 m_binsY =
new double [m_numHistogramBins];
72 computeGraphCoordinateLimits (image,
78 initializeHistogramBins ();
79 populateHistogramBins (image,
85 searchStartStepSpace (isGnuplot,
94 searchStartStepSpace (isGnuplot,
103 searchCountSpace (m_binsX,
107 searchCountSpace (m_binsY,
116 void GridClassifier::computeGraphCoordinateLimits (
const QImage &image,
123 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::computeGraphCoordinateLimits";
128 QPointF posGraphTL, posGraphTR, posGraphBL, posGraphBR;
138 xMin = qMin (qMin (qMin (posGraphTL.x(), posGraphTR.x()), posGraphBL.x()), posGraphBR.x());
139 xMax = qMax (qMax (qMax (posGraphTL.x(), posGraphTR.x()), posGraphBL.x()), posGraphBR.x());
140 yMin = qMin (qMin (qMin (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
141 yMax = qMax (qMax (qMax (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
149 yMax = qMax (qMax (qMax (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
153 ENGAUGE_ASSERT (xMin < xMax);
154 ENGAUGE_ASSERT (yMin < yMax);
157 double GridClassifier::coordinateFromBin (
int bin,
159 double coordMax)
const
161 ENGAUGE_ASSERT (1 < m_numHistogramBins);
162 ENGAUGE_ASSERT (coordMin < coordMax);
164 return coordMin + (coordMax - coordMin) * (
double) bin / ((
double) m_numHistogramBins - 1.0);
170 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
171 to [bin] = from [bin];
175 void GridClassifier::dumpGnuplotCoordinate (
const QString &coordinateLabel,
178 double coordinateMin,
179 double coordinateMax,
183 QString filename = QString (
"gridclassifier_%1_corr%2_startMax%3_stepMax%4.gnuplot")
184 .arg (coordinateLabel)
185 .arg (corr, 8,
'f', 3,
'0')
189 cout << GNUPLOT_FILE_MESSAGE.toLatin1().data() << filename.toLatin1().data() <<
"\n";
191 QFile fileDump (filename);
192 fileDump.open (QIODevice::WriteOnly | QIODevice::Text);
193 QTextStream strDump (&fileDump);
199 for (bin = 0; bin < m_numHistogramBins; bin++) {
200 if (bins [bin] > binCountMax) {
201 binCountMax = qMax ((
double) binCountMax,
207 double *picketFence =
new double [m_numHistogramBins];
208 loadPicketFence (picketFence,
216 << GNUPLOT_DELIMITER <<
"coordinate"
217 << GNUPLOT_DELIMITER <<
"binCount"
218 << GNUPLOT_DELIMITER <<
"startStep"
219 << GNUPLOT_DELIMITER <<
"picketFence" <<
"\n";
222 for (bin = 0; bin < m_numHistogramBins; bin++) {
224 double coordinate = coordinateFromBin (bin,
227 double startStepValue (((bin - binStart) % binStep == 0) ? 1 : 0);
229 << GNUPLOT_DELIMITER << coordinate
230 << GNUPLOT_DELIMITER << bins [bin]
231 << GNUPLOT_DELIMITER << binCountMax * startStepValue
232 << GNUPLOT_DELIMITER << binCountMax * picketFence [bin] <<
"\n";
235 delete [] picketFence;
238 void GridClassifier::dumpGnuplotCorrelations (
const QString &coordinateLabel,
241 const double signalA [],
242 const double signalB [],
243 const double correlations [])
245 QString filename = QString (
"gridclassifier_%1_correlations.gnuplot")
246 .arg (coordinateLabel);
248 cout << GNUPLOT_FILE_MESSAGE.toLatin1().data() << filename.toLatin1().data() <<
"\n";
250 QFile fileDump (filename);
251 fileDump.open (QIODevice::WriteOnly | QIODevice::Text);
252 QTextStream strDump (&fileDump);
257 double signalAMax = 1, signalBMax = 1, correlationsMax = 1;
258 for (bin = 0; bin < m_numHistogramBins; bin++) {
259 if (bin == 0 || signalA [bin] > signalAMax) {
260 signalAMax = signalA [bin];
262 if (bin == 0 || signalB [bin] > signalBMax) {
263 signalBMax = signalB [bin];
265 if (bin == 0 || correlations [bin] > correlationsMax) {
266 correlationsMax = correlations [bin];
271 if (signalAMax == 0) {
274 if (signalBMax == 0) {
279 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
281 strDump << coordinateFromBin (bin,
284 << GNUPLOT_DELIMITER << signalA [bin] / signalAMax
285 << GNUPLOT_DELIMITER << signalB [bin] / signalBMax
286 << GNUPLOT_DELIMITER << correlations [bin] / correlationsMax <<
"\n";
290 void GridClassifier::initializeHistogramBins ()
292 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::initializeHistogramBins";
294 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
300 void GridClassifier::loadPicketFence (
double picketFence [],
306 const double PEAK_HEIGHT = 1.0;
310 ENGAUGE_ASSERT (binStart >= PEAK_HALF_WIDTH);
311 ENGAUGE_ASSERT (binStep != 0);
313 count = 1 + (m_numHistogramBins - binStart - PEAK_HALF_WIDTH) / binStep;
317 int binStartMinusHalfWidth = binStart - PEAK_HALF_WIDTH;
318 int binStopPlusHalfWidth = (binStart + (count - 1) * binStep) + PEAK_HALF_WIDTH;
322 double areaUnnormalized = count * PEAK_HEIGHT * PEAK_HALF_WIDTH;
323 double normalizationOffset = -1.0 * areaUnnormalized / m_numHistogramBins;
325 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
329 picketFence [bin] = normalizationOffset;
331 if ((binStartMinusHalfWidth <= bin) &&
332 (bin <= binStopPlusHalfWidth)) {
335 int ordinalClosestPeak = (int) ((bin - binStart + binStep / 2) / binStep);
336 int binClosestPeak = binStart + ordinalClosestPeak * binStep;
339 int distanceToClosestPeak = qAbs (bin - binClosestPeak);
341 if (distanceToClosestPeak < PEAK_HALF_WIDTH) {
344 picketFence [bin] = 1.0 - (double) distanceToClosestPeak / PEAK_HALF_WIDTH + normalizationOffset;
351 void GridClassifier::populateHistogramBins (
const QImage &image,
358 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::populateHistogramBins";
363 for (
int x = 0; x < image.width(); x++) {
364 for (
int y = 0; y < image.height(); y++) {
366 QColor pixel = image.pixel (x, y);
379 while (posGraph.x() < xMin) {
382 while (posGraph.x() > xMax) {
387 int binX = binFromCoordinate (posGraph.x(), xMin, xMax);
388 int binY = binFromCoordinate (posGraph.y(), yMin, yMax);
390 ENGAUGE_ASSERT (0 <= binX);
391 ENGAUGE_ASSERT (0 <= binY);
392 ENGAUGE_ASSERT (binX < m_numHistogramBins);
393 ENGAUGE_ASSERT (binY < m_numHistogramBins);
396 binX = qMin (binX, m_numHistogramBins - 1);
397 binY = qMin (binY, m_numHistogramBins - 1);
406 void GridClassifier::searchCountSpace (
double bins [],
411 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::searchCountSpace"
412 <<
" start=" << binStart
413 <<
" step=" << binStep;
417 double *picketFence =
new double [m_numHistogramBins];
418 double corr, corrMax;
420 int countStop = 1 + (m_numHistogramBins - binStart) / binStep;
421 for (
int count = 2; count <= countStop; count++) {
423 loadPicketFence (picketFence,
429 correlation.correlateWithoutShift (m_numHistogramBins,
433 if (isFirst || (corr > corrMax)) {
441 delete [] picketFence;
444 void GridClassifier::searchStartStepSpace (
bool isGnuplot,
446 const QString &coordinateLabel,
454 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::searchStartStepSpace";
457 double *signalA =
new double [m_numHistogramBins];
458 double *signalB =
new double [m_numHistogramBins];
459 double *correlations =
new double [m_numHistogramBins];
460 double *correlationsMax =
new double [m_numHistogramBins];
464 double *picketFence =
new double [m_numHistogramBins];
466 double corr = 0, corrMax = 0;
474 binStartMax = BIN_START_UNSHIFTED + 1;
475 binStepMax = qMin (MIN_STEP_PIXELS, m_numHistogramBins / 8);
476 for (
int binStep = qMin (MIN_STEP_PIXELS, m_numHistogramBins / 8); binStep < m_numHistogramBins / 4; binStep++) {
478 loadPicketFence (picketFence,
484 correlation.correlateWithShift (m_numHistogramBins,
490 if (isFirst || (corr > corrMax)) {
492 int binStartMaxNext = binStart + BIN_START_UNSHIFTED + 1;
495 if (binStartMaxNext < m_numHistogramBins) {
497 binStartMax = binStartMaxNext;
498 binStepMax = binStep;
500 copyVectorToVector (bins, signalA);
501 copyVectorToVector (picketFence, signalB);
502 copyVectorToVector (correlations, correlationsMax);
507 dumpGnuplotCoordinate(coordinateLabel,
522 start = coordinateFromBin (binStartMax,
525 if (binStartMax + binStepMax < m_numHistogramBins) {
528 double next = coordinateFromBin (binStartMax + binStepMax,
535 double next = coordinateFromBin (m_numHistogramBins - 1,
542 dumpGnuplotCorrelations (coordinateLabel,
552 delete [] correlations;
553 delete [] correlationsMax;
554 delete [] picketFence;
double originRadius() const
Get method for origin radius in polar mode.
Fast cross correlation between two functions.
Class for filtering image to remove unimportant information.
double thetaPeriod() const
Return the period of the theta value for polar coordinates, consistent with CoordThetaUnits.
QRgb marginColor(const QImage *image) const
Identify the margin color of the image, which is defined as the most common color in the four margins...
GridClassifier()
Single constructor.
CoordsType coordsType() const
Get method for coordinates type.
bool colorCompare(QRgb rgb1, QRgb rgb2) const
See if the two color values are close enough to be considered to be the same.
Classify the grid pattern in an original image.
void classify(bool isGnuplot, const QPixmap &originalPixmap, const Transformation &transformation, int &countX, double &startX, double &stepX, int &countY, double &startY, double &stepY)
Classify the specified image, and return the most probably x and y grid settings. ...