7 #include "ColorFilter.h"
8 #include "Correlation.h"
9 #include "DocumentModelCoords.h"
10 #include "EngaugeAssert.h"
11 #include "GridClassifier.h"
17 #include "QtToString.h"
18 #include "Transformation.h"
20 int GridClassifier::NUM_PIXELS_PER_HISTOGRAM_BINS = 1;
21 double GridClassifier::PEAK_HALF_WIDTH = 4;
22 int GridClassifier::MIN_STEP_PIXELS = 4 * GridClassifier::PEAK_HALF_WIDTH;
23 const QString GNUPLOT_DELIMITER (
"\t");
27 int GridClassifier::BIN_START_UNSHIFTED = GridClassifier::PEAK_HALF_WIDTH;
35 int GridClassifier::binFromCoordinate (
double coord,
37 double coordMax)
const
39 ENGAUGE_ASSERT (coordMin < coordMax);
40 ENGAUGE_ASSERT (coordMin <= coord);
41 ENGAUGE_ASSERT (coord <= coordMax);
43 int bin = 0.5 + (m_numHistogramBins - 1.0) * (coord - coordMin) / (coordMax - coordMin);
49 const QPixmap &originalPixmap,
58 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::classify";
60 QImage image = originalPixmap.toImage ();
62 m_numHistogramBins = image.width() / NUM_PIXELS_PER_HISTOGRAM_BINS;
63 ENGAUGE_ASSERT (m_numHistogramBins > 1);
65 double xMin, xMax, yMin, yMax;
66 double binStartX, binStepX, binStartY, binStepY;
68 m_binsX =
new double [m_numHistogramBins];
69 m_binsY =
new double [m_numHistogramBins];
71 computeGraphCoordinateLimits (image,
77 initializeHistogramBins ();
78 populateHistogramBins (image,
84 searchStartStepSpace (isGnuplot,
93 searchStartStepSpace (isGnuplot,
102 searchCountSpace (m_binsX,
106 searchCountSpace (m_binsY,
115 void GridClassifier::computeGraphCoordinateLimits (
const QImage &image,
122 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::computeGraphCoordinateLimits";
127 QPointF posGraphTL, posGraphTR, posGraphBL, posGraphBR;
137 xMin = qMin (qMin (qMin (posGraphTL.x(), posGraphTR.x()), posGraphBL.x()), posGraphBR.x());
138 xMax = qMax (qMax (qMax (posGraphTL.x(), posGraphTR.x()), posGraphBL.x()), posGraphBR.x());
139 yMin = qMin (qMin (qMin (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
140 yMax = qMax (qMax (qMax (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
148 yMax = qMax (qMax (qMax (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
152 ENGAUGE_ASSERT (xMin < xMax);
153 ENGAUGE_ASSERT (yMin < yMax);
156 double GridClassifier::coordinateFromBin (
int bin,
158 double coordMax)
const
160 ENGAUGE_ASSERT (1 < m_numHistogramBins);
161 ENGAUGE_ASSERT (coordMin < coordMax);
163 return coordMin + (coordMax - coordMin) * (
double) bin / ((
double) m_numHistogramBins - 1.0);
169 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
170 to [bin] = from [bin];
174 void GridClassifier::dumpGnuplotCoordinate (
const QString &coordinateLabel,
177 double coordinateMin,
178 double coordinateMax,
182 QString filename = QString (
"gridclassifier_%1_corr%2_startMax%3_stepMax%4.gnuplot")
183 .arg (coordinateLabel)
184 .arg (corr, 8,
'f', 3,
'0')
188 cout <<
"Writing gnuplot file: " << filename.toLatin1().data() <<
"\n";
190 QFile fileDump (filename);
191 fileDump.open (QIODevice::WriteOnly | QIODevice::Text);
192 QTextStream strDump (&fileDump);
198 for (bin = 0; bin < m_numHistogramBins; bin++) {
199 if (bins [bin] > binCountMax) {
200 binCountMax = qMax ((
double) binCountMax,
206 double *picketFence =
new double [m_numHistogramBins];
207 loadPicketFence (picketFence,
215 << GNUPLOT_DELIMITER <<
"coordinate"
216 << GNUPLOT_DELIMITER <<
"binCount"
217 << GNUPLOT_DELIMITER <<
"startStep"
218 << GNUPLOT_DELIMITER <<
"picketFence" <<
"\n";
221 for (bin = 0; bin < m_numHistogramBins; bin++) {
223 double coordinate = coordinateFromBin (bin,
226 double startStepValue (((bin - binStart) % binStep == 0) ? 1 : 0);
228 << GNUPLOT_DELIMITER << coordinate
229 << GNUPLOT_DELIMITER << bins [bin]
230 << GNUPLOT_DELIMITER << binCountMax * startStepValue
231 << GNUPLOT_DELIMITER << binCountMax * picketFence [bin] <<
"\n";
234 delete [] picketFence;
237 void GridClassifier::dumpGnuplotCorrelations (
const QString &coordinateLabel,
240 const double signalA [],
241 const double signalB [],
242 const double correlations [])
244 QString filename = QString (
"gridclassifier_%1_correlations.gnuplot")
245 .arg (coordinateLabel);
247 cout <<
"Writing gnuplot file: " << filename.toLatin1().data() <<
"\n";
249 QFile fileDump (filename);
250 fileDump.open (QIODevice::WriteOnly | QIODevice::Text);
251 QTextStream strDump (&fileDump);
256 double signalAMax = 1, signalBMax = 1, correlationsMax = 1;
257 for (bin = 0; bin < m_numHistogramBins; bin++) {
258 if (bin == 0 || signalA [bin] > signalAMax) {
259 signalAMax = signalA [bin];
261 if (bin == 0 || signalB [bin] > signalBMax) {
262 signalBMax = signalB [bin];
264 if (bin == 0 || correlations [bin] > correlationsMax) {
265 correlationsMax = correlations [bin];
270 if (signalAMax == 0) {
273 if (signalBMax == 0) {
278 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
280 strDump << coordinateFromBin (bin,
283 << GNUPLOT_DELIMITER << signalA [bin] / signalAMax
284 << GNUPLOT_DELIMITER << signalB [bin] / signalBMax
285 << GNUPLOT_DELIMITER << correlations [bin] / correlationsMax <<
"\n";
289 void GridClassifier::initializeHistogramBins ()
291 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::initializeHistogramBins";
293 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
299 void GridClassifier::loadPicketFence (
double picketFence [],
305 const double PEAK_HEIGHT = 1.0;
309 ENGAUGE_ASSERT (binStart >= PEAK_HALF_WIDTH);
310 ENGAUGE_ASSERT (binStep != 0);
312 count = 1 + (m_numHistogramBins - binStart - PEAK_HALF_WIDTH) / binStep;
316 int binStartMinusHalfWidth = binStart - PEAK_HALF_WIDTH;
317 int binStopPlusHalfWidth = (binStart + (count - 1) * binStep) + PEAK_HALF_WIDTH;
321 double areaUnnormalized = count * PEAK_HEIGHT * PEAK_HALF_WIDTH;
322 double normalizationOffset = -1.0 * areaUnnormalized / m_numHistogramBins;
324 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
328 picketFence [bin] = normalizationOffset;
330 if ((binStartMinusHalfWidth <= bin) &&
331 (bin <= binStopPlusHalfWidth)) {
334 int ordinalClosestPeak = (int) ((bin - binStart + binStep / 2) / binStep);
335 int binClosestPeak = binStart + ordinalClosestPeak * binStep;
338 int distanceToClosestPeak = qAbs (bin - binClosestPeak);
340 if (distanceToClosestPeak < PEAK_HALF_WIDTH) {
343 picketFence [bin] = 1.0 - (double) distanceToClosestPeak / PEAK_HALF_WIDTH + normalizationOffset;
350 void GridClassifier::populateHistogramBins (
const QImage &image,
357 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::populateHistogramBins";
362 for (
int x = 0; x < image.width(); x++) {
363 for (
int y = 0; y < image.height(); y++) {
365 QColor pixel = image.pixel (x, y);
378 while (posGraph.x() < xMin) {
381 while (posGraph.x() > xMax) {
386 int binX = binFromCoordinate (posGraph.x(), xMin, xMax);
387 int binY = binFromCoordinate (posGraph.y(), yMin, yMax);
389 ENGAUGE_ASSERT (0 <= binX);
390 ENGAUGE_ASSERT (0 <= binY);
391 ENGAUGE_ASSERT (binX < m_numHistogramBins);
392 ENGAUGE_ASSERT (binY < m_numHistogramBins);
395 binX = qMin (binX, m_numHistogramBins - 1);
396 binY = qMin (binY, m_numHistogramBins - 1);
405 void GridClassifier::searchCountSpace (
double bins [],
410 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::searchCountSpace"
411 <<
" start=" << binStart
412 <<
" step=" << binStep;
416 double *picketFence =
new double [m_numHistogramBins];
417 double corr, corrMax;
419 int countStop = 1 + (m_numHistogramBins - binStart) / binStep;
420 for (
int count = 2; count <= countStop; count++) {
422 loadPicketFence (picketFence,
428 correlation.correlateWithoutShift (m_numHistogramBins,
432 if (isFirst || (corr > corrMax)) {
440 delete [] picketFence;
443 void GridClassifier::searchStartStepSpace (
bool isGnuplot,
445 const QString &coordinateLabel,
453 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::searchStartStepSpace";
456 double *signalA =
new double [m_numHistogramBins];
457 double *signalB =
new double [m_numHistogramBins];
458 double *correlations =
new double [m_numHistogramBins];
459 double *correlationsMax =
new double [m_numHistogramBins];
463 double *picketFence =
new double [m_numHistogramBins];
465 double corr = 0, corrMax = 0;
473 binStartMax = BIN_START_UNSHIFTED + 1;
474 binStepMax = qMin (MIN_STEP_PIXELS, m_numHistogramBins / 8);
475 for (
int binStep = qMin (MIN_STEP_PIXELS, m_numHistogramBins / 8); binStep < m_numHistogramBins / 4; binStep++) {
477 loadPicketFence (picketFence,
483 correlation.correlateWithShift (m_numHistogramBins,
489 if (isFirst || (corr > corrMax)) {
491 int binStartMaxNext = binStart + BIN_START_UNSHIFTED + 1;
494 if (binStartMaxNext < m_numHistogramBins) {
496 binStartMax = binStartMaxNext;
497 binStepMax = binStep;
499 copyVectorToVector (bins, signalA);
500 copyVectorToVector (picketFence, signalB);
501 copyVectorToVector (correlations, correlationsMax);
506 dumpGnuplotCoordinate(coordinateLabel,
521 start = coordinateFromBin (binStartMax,
524 if (binStartMax + binStepMax < m_numHistogramBins) {
527 double next = coordinateFromBin (binStartMax + binStepMax,
534 double next = coordinateFromBin (m_numHistogramBins - 1,
541 dumpGnuplotCorrelations (coordinateLabel,
551 delete [] correlations;
552 delete [] correlationsMax;
553 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. ...