comparison layer/ImageRegionFinder.cpp @ 283:86a112b5b319

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