1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Sonic Visualiser
An audio file viewer and annotation editor.
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2007 QMUL.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#include "ImageRegionFinder.h"
#include <QImage>
#include <cmath>
#include <stack>
#include <iostream>
namespace sv {
ImageRegionFinder::ImageRegionFinder()
{
}
ImageRegionFinder::~ImageRegionFinder()
{
}
QRect
ImageRegionFinder::findRegionExtents(QImage *image, QPoint origin) const
{
int w = image->width(), h = image->height();
QImage visited(w, h, QImage::Format_Mono);
visited.fill(0);
std::stack<QPoint> s;
s.push(origin);
int xmin = origin.x();
int xmax = xmin;
int ymin = origin.y();
int ymax = ymin;
QRgb opix = image->pixel(origin);
while (!s.empty()) {
QPoint p = s.top();
s.pop();
visited.setPixel(p, 1);
int x = p.x(), y = p.y();
if (x < xmin) xmin = x;
if (x > xmax) xmax = x;
if (y < ymin) ymin = y;
if (y > ymax) ymax = y;
std::stack<QPoint> neighbours;
int similarNeighbourCount = 0;
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
if ((dx != 0 && dy != 0) ||
(dx == 0 && dy == 0))
continue;
if (x + dx < 0 || x + dx >= w ||
y + dy < 0 || y + dy >= h)
continue;
if (visited.pixelIndex(x + dx, y + dy) != 0)
continue;
if (!similar(opix, image->pixel(x + dx, y + dy)))
continue;
neighbours.push(QPoint(x + dx, y + dy));
++similarNeighbourCount;
}
}
if (similarNeighbourCount >= 2) {
while (!neighbours.empty()) {
s.push(neighbours.top());
neighbours.pop();
}
}
}
return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
}
bool
ImageRegionFinder::similar(QRgb a, QRgb b) const
{
if (b == qRgb(0, 0, 0) || b == qRgb(255, 255, 255)) {
// black and white are boundary cases, don't compare similar
// to anything -- not even themselves
return false;
}
float ar = float(qRed(a)) / 255.f;
float ag = float(qGreen(a)) / 255.f;
float ab = float(qBlue(a)) / 255.f;
float amag = sqrtf(ar * ar + ag * ag + ab * ab);
float thresh = amag / 2;
float dr = float(qRed(a) - qRed(b)) / 255.f;
float dg = float(qGreen(a) - qGreen(b)) / 255.f;
float db = float(qBlue(a) - qBlue(b)) / 255.f;
float dist = sqrtf(dr * dr + dg * dg + db * db);
// cerr << "thresh=" << thresh << ", dist=" << dist << endl;
return (dist < thresh);
}
} // end namespace sv
|