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 Chris@283: #include Chris@283: #include Chris@283: #include 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 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 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@283: float ar = float(qRed(a) / 255.f); Chris@283: float ag = float(qGreen(a) / 255.f); Chris@283: 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@283: // std::cerr << "thresh=" << thresh << ", dist=" << dist << std::endl; Chris@283: Chris@283: return (dist < thresh); Chris@283: } Chris@283: