7 #include "ColorFilter.h" 8 #include "Correlation.h" 9 #include "DocumentModelCoords.h" 10 #include "EngaugeAssert.h" 12 #include "GridClassifier.h" 19 #include "QtToString.h" 20 #include "Transformation.h" 22 int GridClassifier::NUM_PIXELS_PER_HISTOGRAM_BINS = 1;
23 double GridClassifier::PEAK_HALF_WIDTH = 4;
24 int GridClassifier::MIN_STEP_PIXELS = qFloor (4 * GridClassifier::PEAK_HALF_WIDTH);
25 const QString GNUPLOT_DELIMITER (
"\t");
29 int GridClassifier::BIN_START_UNSHIFTED = qFloor (GridClassifier::PEAK_HALF_WIDTH);
37 int GridClassifier::binFromCoordinate (
double coord,
39 double coordMax)
const 41 ENGAUGE_ASSERT (coordMin < coordMax);
42 ENGAUGE_ASSERT (coordMin <= coord);
43 ENGAUGE_ASSERT (coord <= coordMax);
45 int bin = qFloor (0.5 + (m_numHistogramBins - 1.0) * (coord - coordMin) / (coordMax - coordMin));
51 const QPixmap &originalPixmap,
60 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::classify";
62 QImage image = originalPixmap.toImage ();
64 m_numHistogramBins = image.width() / NUM_PIXELS_PER_HISTOGRAM_BINS;
65 ENGAUGE_ASSERT (m_numHistogramBins > 1);
67 double xMin, xMax, yMin, yMax;
68 double binStartX, binStepX, binStartY, binStepY;
70 m_binsX =
new double [unsigned (m_numHistogramBins)];
71 m_binsY =
new double [unsigned (m_numHistogramBins)];
73 computeGraphCoordinateLimits (image,
79 initializeHistogramBins ();
80 populateHistogramBins (image,
86 searchStartStepSpace (isGnuplot,
95 searchStartStepSpace (isGnuplot,
104 searchCountSpace (m_binsX,
108 searchCountSpace (m_binsY,
117 void GridClassifier::computeGraphCoordinateLimits (
const QImage &image,
124 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::computeGraphCoordinateLimits";
129 QPointF posGraphTL, posGraphTR, posGraphBL, posGraphBR;
139 xMin = qMin (qMin (qMin (posGraphTL.x(), posGraphTR.x()), posGraphBL.x()), posGraphBR.x());
140 xMax = qMax (qMax (qMax (posGraphTL.x(), posGraphTR.x()), posGraphBL.x()), posGraphBR.x());
141 yMin = qMin (qMin (qMin (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
142 yMax = qMax (qMax (qMax (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
150 yMax = qMax (qMax (qMax (posGraphTL.y(), posGraphTR.y()), posGraphBL.y()), posGraphBR.y());
154 ENGAUGE_ASSERT (xMin < xMax);
155 ENGAUGE_ASSERT (yMin < yMax);
158 double GridClassifier::coordinateFromBin (
int bin,
160 double coordMax)
const 162 ENGAUGE_ASSERT (1 < m_numHistogramBins);
163 ENGAUGE_ASSERT (coordMin < coordMax);
165 return coordMin + (coordMax - coordMin) *
double (bin) / (double (m_numHistogramBins) - 1.0);
168 void GridClassifier::copyVectorToVector (
const double from [],
171 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
172 to [bin] = from [bin];
176 void GridClassifier::dumpGnuplotCoordinate (
const QString &coordinateLabel,
179 double coordinateMin,
180 double coordinateMax,
184 QString filename = QString (
"gridclassifier_%1_corr%2_startMax%3_stepMax%4.gnuplot")
185 .arg (coordinateLabel)
186 .arg (corr, 8,
'f', 3,
'0')
190 cout << GNUPLOT_FILE_MESSAGE.toLatin1().data() << filename.toLatin1().data() <<
"\n";
192 QFile fileDump (filename);
193 fileDump.open (QIODevice::WriteOnly | QIODevice::Text);
194 QTextStream strDump (&fileDump);
200 for (bin = 0; bin < m_numHistogramBins; bin++) {
201 if (bins [bin] > binCountMax) {
202 binCountMax = qMax (
signed (binCountMax),
203 signed (bins [bin]));
208 double *picketFence =
new double [unsigned (m_numHistogramBins)];
209 loadPicketFence (picketFence,
217 << GNUPLOT_DELIMITER <<
"coordinate" 218 << GNUPLOT_DELIMITER <<
"binCount" 219 << GNUPLOT_DELIMITER <<
"startStep" 220 << GNUPLOT_DELIMITER <<
"picketFence" <<
"\n";
223 for (bin = 0; bin < m_numHistogramBins; bin++) {
225 double coordinate = coordinateFromBin (bin,
228 double startStepValue (((bin - binStart) % binStep == 0) ? 1 : 0);
230 << GNUPLOT_DELIMITER << coordinate
231 << GNUPLOT_DELIMITER << bins [bin]
232 << GNUPLOT_DELIMITER << binCountMax * startStepValue
233 << GNUPLOT_DELIMITER << binCountMax * picketFence [bin] <<
"\n";
236 delete [] picketFence;
239 void GridClassifier::dumpGnuplotCorrelations (
const QString &coordinateLabel,
242 const double signalA [],
243 const double signalB [],
244 const double correlations [])
246 QString filename = QString (
"gridclassifier_%1_correlations.gnuplot")
247 .arg (coordinateLabel);
249 cout << GNUPLOT_FILE_MESSAGE.toLatin1().data() << filename.toLatin1().data() <<
"\n";
251 QFile fileDump (filename);
252 fileDump.open (QIODevice::WriteOnly | QIODevice::Text);
253 QTextStream strDump (&fileDump);
258 double signalAMax = 1, signalBMax = 1, correlationsMax = 1;
259 for (bin = 0; bin < m_numHistogramBins; bin++) {
260 if (bin == 0 || signalA [bin] > signalAMax) {
261 signalAMax = signalA [bin];
263 if (bin == 0 || signalB [bin] > signalBMax) {
264 signalBMax = signalB [bin];
266 if (bin == 0 || correlations [bin] > correlationsMax) {
267 correlationsMax = correlations [bin];
272 if (qAbs (signalAMax) <= 0) {
275 if (qAbs (signalBMax) <= 0) {
280 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
282 strDump << coordinateFromBin (bin,
285 << GNUPLOT_DELIMITER << signalA [bin] / signalAMax
286 << GNUPLOT_DELIMITER << signalB [bin] / signalBMax
287 << GNUPLOT_DELIMITER << correlations [bin] / correlationsMax <<
"\n";
291 void GridClassifier::initializeHistogramBins ()
293 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::initializeHistogramBins";
295 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
301 void GridClassifier::loadPicketFence (
double picketFence [],
307 const double PEAK_HEIGHT = 1.0;
311 ENGAUGE_ASSERT (binStart >= PEAK_HALF_WIDTH);
312 ENGAUGE_ASSERT (binStep != 0);
314 count = qFloor (1 + (m_numHistogramBins - binStart - PEAK_HALF_WIDTH) / binStep);
318 int binStartMinusHalfWidth = qFloor (binStart - PEAK_HALF_WIDTH);
319 int binStopPlusHalfWidth = qFloor ((binStart + (count - 1) * binStep) + PEAK_HALF_WIDTH);
323 double areaUnnormalized = count * PEAK_HEIGHT * PEAK_HALF_WIDTH;
324 double normalizationOffset = -1.0 * areaUnnormalized / m_numHistogramBins;
326 for (
int bin = 0; bin < m_numHistogramBins; bin++) {
330 picketFence [bin] = normalizationOffset;
332 if ((binStartMinusHalfWidth <= bin) &&
333 (bin <= binStopPlusHalfWidth)) {
336 int ordinalClosestPeak = qFloor ((bin - binStart + binStep / 2) / binStep);
337 int binClosestPeak = binStart + ordinalClosestPeak * binStep;
340 int distanceToClosestPeak = qAbs (bin - binClosestPeak);
342 if (distanceToClosestPeak < PEAK_HALF_WIDTH) {
345 picketFence [bin] = 1.0 - double (distanceToClosestPeak) / PEAK_HALF_WIDTH + normalizationOffset;
352 void GridClassifier::populateHistogramBins (
const QImage &image,
359 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::populateHistogramBins";
364 for (
int x = 0; x < image.width(); x++) {
365 for (
int y = 0; y < image.height(); y++) {
367 QColor pixel = image.pixel (x, y);
380 while (posGraph.x() < xMin) {
383 while (posGraph.x() > xMax) {
388 int binX = binFromCoordinate (posGraph.x(), xMin, xMax);
389 int binY = binFromCoordinate (posGraph.y(), yMin, yMax);
391 ENGAUGE_ASSERT (0 <= binX);
392 ENGAUGE_ASSERT (0 <= binY);
393 ENGAUGE_ASSERT (binX < m_numHistogramBins);
394 ENGAUGE_ASSERT (binY < m_numHistogramBins);
397 binX = qMin (binX, m_numHistogramBins - 1);
398 binY = qMin (binY, m_numHistogramBins - 1);
407 void GridClassifier::searchCountSpace (
double bins [],
412 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::searchCountSpace" 413 <<
" start=" << binStart
414 <<
" step=" << binStep;
418 double *picketFence =
new double [unsigned (m_numHistogramBins)];
419 double corr, corrMax = 0;
421 int countStop = qFloor (1 + (m_numHistogramBins - binStart) / binStep);
422 for (
int count = 2; count <= countStop; count++) {
424 loadPicketFence (picketFence,
430 correlation.correlateWithoutShift (m_numHistogramBins,
434 if (isFirst || (corr > corrMax)) {
442 delete [] picketFence;
445 void GridClassifier::searchStartStepSpace (
bool isGnuplot,
447 const QString &coordinateLabel,
455 LOG4CPP_INFO_S ((*mainCat)) <<
"GridClassifier::searchStartStepSpace";
458 double *signalA =
new double [unsigned (m_numHistogramBins)];
459 double *signalB =
new double [unsigned (m_numHistogramBins)];
460 double *correlations =
new double [unsigned (m_numHistogramBins)];
461 double *correlationsMax =
new double [unsigned (m_numHistogramBins)];
465 double *picketFence =
new double [unsigned (m_numHistogramBins)];
467 double corr = 0, corrMax = 0;
475 binStartMax = BIN_START_UNSHIFTED + 1;
476 binStepMax = qMin (MIN_STEP_PIXELS, m_numHistogramBins / 8);
477 for (
int binStep = qMin (MIN_STEP_PIXELS, m_numHistogramBins / 8); binStep < m_numHistogramBins / 4; binStep++) {
479 loadPicketFence (picketFence,
482 qFloor (PEAK_HALF_WIDTH),
485 correlation.correlateWithShift (m_numHistogramBins,
491 if (isFirst || (corr > corrMax)) {
493 int binStartMaxNext = binStart + BIN_START_UNSHIFTED + 1;
496 if (binStartMaxNext < m_numHistogramBins) {
498 binStartMax = binStartMaxNext;
499 binStepMax = binStep;
501 copyVectorToVector (bins, signalA);
502 copyVectorToVector (picketFence, signalB);
503 copyVectorToVector (correlations, correlationsMax);
508 dumpGnuplotCoordinate(coordinateLabel,
523 start = coordinateFromBin (qFloor (binStartMax),
526 if (binStartMax + binStepMax < m_numHistogramBins) {
529 double next = coordinateFromBin (qFloor (binStartMax + binStepMax),
536 double next = coordinateFromBin (m_numHistogramBins - 1,
543 dumpGnuplotCorrelations (coordinateLabel,
553 delete [] correlations;
554 delete [] correlationsMax;
555 delete [] picketFence;
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...
bool colorCompare(QRgb rgb1, QRgb rgb2) const
See if the two color values are close enough to be considered to be the same.
double thetaPeriod() const
Return the period of the theta value for polar coordinates, consistent with CoordThetaUnits.
Fast cross correlation between two functions.
Class for filtering image to remove unimportant information.
GridClassifier()
Single constructor.
CoordsType coordsType() const
Get method for coordinates type.
double originRadius() const
Get method for origin radius in polar mode.
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.