svgui  1.9
ImageRegionFinder.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2007 QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "ImageRegionFinder.h"
00017 
00018 #include <QImage>
00019 #include <cmath>
00020 #include <stack>
00021 #include <iostream>
00022 
00023 ImageRegionFinder::ImageRegionFinder()
00024 {
00025 }
00026 
00027 ImageRegionFinder::~ImageRegionFinder()
00028 {
00029 }
00030 
00031 QRect
00032 ImageRegionFinder::findRegionExtents(QImage *image, QPoint origin) const
00033 {
00034     int w = image->width(), h = image->height();
00035 
00036     QImage visited(w, h, QImage::Format_Mono);
00037     visited.fill(0);
00038 
00039     std::stack<QPoint> s;
00040     s.push(origin);
00041 
00042     int xmin = origin.x();
00043     int xmax = xmin;
00044     int ymin = origin.y();
00045     int ymax = ymin;
00046 
00047     QRgb opix = image->pixel(origin);
00048 
00049     while (!s.empty()) {
00050 
00051         QPoint p = s.top();
00052         s.pop();
00053 
00054         visited.setPixel(p, 1);
00055 
00056         int x = p.x(), y = p.y();
00057 
00058         if (x < xmin) xmin = x;
00059         if (x > xmax) xmax = x;
00060 
00061         if (y < ymin) ymin = y;
00062         if (y > ymax) ymax = y;
00063 
00064         std::stack<QPoint> neighbours;
00065 
00066         int similarNeighbourCount = 0;
00067 
00068         for (int dx = -1; dx <= 1; ++dx) {
00069             for (int dy = -1; dy <= 1; ++dy) {
00070 
00071                 if ((dx != 0 && dy != 0) ||
00072                     (dx == 0 && dy == 0)) 
00073                     continue;
00074 
00075                 if (x + dx < 0 || x + dx >= w ||
00076                     y + dy < 0 || y + dy >= h)
00077                     continue;
00078 
00079                 if (visited.pixelIndex(x + dx, y + dy) != 0)
00080                     continue;
00081 
00082                 if (!similar(opix, image->pixel(x + dx, y + dy))) 
00083                     continue;
00084 
00085                 neighbours.push(QPoint(x + dx, y + dy));
00086                 ++similarNeighbourCount;
00087             }
00088         }
00089 
00090         if (similarNeighbourCount >= 2) {
00091             while (!neighbours.empty()) {
00092                 s.push(neighbours.top());
00093                 neighbours.pop();
00094             }
00095         }
00096     }
00097 
00098     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
00099 }
00100 
00101 bool
00102 ImageRegionFinder::similar(QRgb a, QRgb b) const
00103 {
00104     if (b == qRgb(0, 0, 0) || b == qRgb(255, 255, 255)) {
00105         // black and white are boundary cases, don't compare similar
00106         // to anything -- not even themselves
00107         return false;
00108     }
00109 
00110     float ar = float(qRed(a) / 255.f);
00111     float ag = float(qGreen(a) / 255.f);
00112     float ab = float(qBlue(a) / 255.f);
00113     float amag = sqrtf(ar * ar + ag * ag + ab * ab);
00114     float thresh = amag / 2;
00115 
00116     float dr = float(qRed(a) - qRed(b)) / 255.f;
00117     float dg = float(qGreen(a) - qGreen(b)) / 255.f;
00118     float db = float(qBlue(a) - qBlue(b)) / 255.f;
00119     float dist = sqrtf(dr * dr + dg * dg + db * db);
00120 
00121 //    cerr << "thresh=" << thresh << ", dist=" << dist << endl;
00122 
00123     return (dist < thresh);
00124 }
00125