Mercurial > hg > svgui
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layer/ImageRegionFinder.cpp Thu Jul 05 15:36:37 2007 +0000 @@ -0,0 +1,125 @@ +/* -*- 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> + +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); + +// std::cerr << "thresh=" << thresh << ", dist=" << dist << std::endl; + + return (dist < thresh); +} +