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