Chris@283: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@283: 
Chris@283: /*
Chris@283:     Sonic Visualiser
Chris@283:     An audio file viewer and annotation editor.
Chris@283:     Centre for Digital Music, Queen Mary, University of London.
Chris@283:     This file copyright 2007 QMUL.
Chris@283:     
Chris@283:     This program is free software; you can redistribute it and/or
Chris@283:     modify it under the terms of the GNU General Public License as
Chris@283:     published by the Free Software Foundation; either version 2 of the
Chris@283:     License, or (at your option) any later version.  See the file
Chris@283:     COPYING included with this distribution for more information.
Chris@283: */
Chris@283: 
Chris@283: #include "ImageRegionFinder.h"
Chris@283: 
Chris@283: #include <QImage>
Chris@283: #include <cmath>
Chris@283: #include <stack>
Chris@283: #include <iostream>
Chris@283: 
Chris@283: ImageRegionFinder::ImageRegionFinder()
Chris@283: {
Chris@283: }
Chris@283: 
Chris@283: ImageRegionFinder::~ImageRegionFinder()
Chris@283: {
Chris@283: }
Chris@283: 
Chris@283: QRect
Chris@283: ImageRegionFinder::findRegionExtents(QImage *image, QPoint origin) const
Chris@283: {
Chris@283:     int w = image->width(), h = image->height();
Chris@283: 
Chris@283:     QImage visited(w, h, QImage::Format_Mono);
Chris@283:     visited.fill(0);
Chris@283: 
Chris@283:     std::stack<QPoint> s;
Chris@283:     s.push(origin);
Chris@283: 
Chris@283:     int xmin = origin.x();
Chris@283:     int xmax = xmin;
Chris@283:     int ymin = origin.y();
Chris@283:     int ymax = ymin;
Chris@283: 
Chris@283:     QRgb opix = image->pixel(origin);
Chris@283: 
Chris@283:     while (!s.empty()) {
Chris@283: 
Chris@283:         QPoint p = s.top();
Chris@283:         s.pop();
Chris@283: 
Chris@283:         visited.setPixel(p, 1);
Chris@283: 
Chris@283:         int x = p.x(), y = p.y();
Chris@283: 
Chris@283:         if (x < xmin) xmin = x;
Chris@283:         if (x > xmax) xmax = x;
Chris@283: 
Chris@283:         if (y < ymin) ymin = y;
Chris@283:         if (y > ymax) ymax = y;
Chris@283: 
Chris@283:         std::stack<QPoint> neighbours;
Chris@283: 
Chris@283:         int similarNeighbourCount = 0;
Chris@283: 
Chris@283:         for (int dx = -1; dx <= 1; ++dx) {
Chris@283:             for (int dy = -1; dy <= 1; ++dy) {
Chris@283: 
Chris@283:                 if ((dx != 0 && dy != 0) ||
Chris@283:                     (dx == 0 && dy == 0)) 
Chris@283:                     continue;
Chris@283: 
Chris@283:                 if (x + dx < 0 || x + dx >= w ||
Chris@283:                     y + dy < 0 || y + dy >= h)
Chris@283:                     continue;
Chris@283: 
Chris@283:                 if (visited.pixelIndex(x + dx, y + dy) != 0)
Chris@283:                     continue;
Chris@283: 
Chris@283:                 if (!similar(opix, image->pixel(x + dx, y + dy))) 
Chris@283:                     continue;
Chris@283: 
Chris@283:                 neighbours.push(QPoint(x + dx, y + dy));
Chris@283:                 ++similarNeighbourCount;
Chris@283:             }
Chris@283:         }
Chris@283: 
Chris@283:         if (similarNeighbourCount >= 2) {
Chris@283:             while (!neighbours.empty()) {
Chris@283:                 s.push(neighbours.top());
Chris@283:                 neighbours.pop();
Chris@283:             }
Chris@283:         }
Chris@283:     }
Chris@283: 
Chris@283:     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
Chris@283: }
Chris@283: 
Chris@283: bool
Chris@283: ImageRegionFinder::similar(QRgb a, QRgb b) const
Chris@283: {
Chris@283:     if (b == qRgb(0, 0, 0) || b == qRgb(255, 255, 255)) {
Chris@283:         // black and white are boundary cases, don't compare similar
Chris@283:         // to anything -- not even themselves
Chris@283:         return false;
Chris@283:     }
Chris@283: 
Chris@905:     float ar = float(qRed(a)) / 255.f;
Chris@905:     float ag = float(qGreen(a)) / 255.f;
Chris@905:     float ab = float(qBlue(a)) / 255.f;
Chris@283:     float amag = sqrtf(ar * ar + ag * ag + ab * ab);
Chris@283:     float thresh = amag / 2;
Chris@283: 
Chris@283:     float dr = float(qRed(a) - qRed(b)) / 255.f;
Chris@283:     float dg = float(qGreen(a) - qGreen(b)) / 255.f;
Chris@283:     float db = float(qBlue(a) - qBlue(b)) / 255.f;
Chris@283:     float dist = sqrtf(dr * dr + dg * dg + db * db);
Chris@283: 
Chris@682: //    cerr << "thresh=" << thresh << ", dist=" << dist << endl;
Chris@283: 
Chris@283:     return (dist < thresh);
Chris@283: }
Chris@283: