/home/neoflo/smb4k/SERVEUR/Millie/trunk/src/operator/CannyOperators.cpp

Aller à la documentation de ce fichier.
00001 /******************************************************************************
00002  *       __    _    _   _       _       _   _____                             *
00003  *       | \  / |  | | | |     | |     | |  | ___|                            *
00004  *       |  \/  |  | | | |     | |     | |  | |_                              *
00005  *       |      |  | | | |     | |     | |  |  _|                             *
00006  *       | |\/| |  | | | |__   | |__   | |  | |__                             *
00007  *       |_|  |_|  |_| |____|  |____|  |_|  |____|                            *
00008  * __________________________________________________________________________ *
00009  *                 Multifunctional Library For Image Processing               *
00010  *                                                                            *
00011  *                                                                            *
00012  *                                                                            *
00013  *      (c) Copyright 2007 by Humbert Florent                                 *
00014  *                                                                            *
00015  *      This program is free software; you can redistribute it and/or modify  *
00016  *      it under the terms of the GNU General Public License as published by  *
00017  *      the Free Software Foundation; only version 2 of the License.          *
00018  *                                                                            *
00019  *      This program is distributed in the hope that it will be useful,       *
00020  *      but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00021  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00022  *      GNU General Public License for more details.                          *
00023  *                                                                            *
00024  *      You should have received a copy of the GNU General Public License     *
00025  *      along with this program; if not, write to the Free Software           *
00026  *      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA             *
00027  *      02111-1307, USA.                                                      *
00028  ******************************************************************************/
00029 
00032 #include <vector>
00033 #include <iostream>
00034 #include <list>
00035 
00036 #include "operator/CannyOperators.hpp"
00037 #include "operator/ConvolveOperator/ConvolveOperator.hpp"
00038 
00039 #include "BorderExtenderCopy.hpp"
00040 
00041 #include "PredefinedKernel.hpp"
00042 
00050 using namespace Millie;
00051 
00062 inline static float convolvePosition(Image& c, int x, int y, int canal, const Kernel& kernel)
00063 {
00064   if(kernel.getWidth() != kernel.getHeight())
00065     throw IllegalArgument("convolePosition : malmed kernel");
00066 
00067 
00068   int width = c.getWidth();
00069   int height = c.getHeight();
00070 
00071   int aperture = kernel.getWidth()/2;
00072 
00073   float v = 0;
00074   for(int dy=-aperture; dy<=aperture; dy++)
00075   {
00076     for(int dx=-aperture; dx<=aperture; dx++)
00077     {
00078       int xk = x + dx;
00079       int yk = y + dy;
00080       if (xk<0)
00081         xk=0;
00082       if (xk>=width)
00083         xk=width-1;
00084       if (yk<0)
00085         yk=0;
00086       if (yk>=height)
00087         yk=height-1;
00088       float vk = c.getPixel(xk,yk, canal);
00089       v += kernel(dx+aperture,dy+aperture) * vk;
00090     }
00091   }
00092 
00093   return v;
00094 }
00095 
00096 
00097 inline static void cannyGradient(Image & c, int x, int y, int canal, float & norme, float & angle)
00098 {
00099   static const KernelSobelHorizontal sobelY;
00100   static const KernelSobelVertical sobelX;
00101   float gx = convolvePosition(c, x, y, canal, sobelX);
00102   float gy = convolvePosition(c, x, y, canal, sobelY);
00103 
00104   norme = sqrt(gx*gx+gy*gy);
00105   angle = 0.0f;
00106   if (norme>0.00f)
00107   {
00108     angle = acos(gx/ norme);
00109     if (gy>0.00f)
00110       angle = 2.0f*M_PI - angle;
00111   }
00112 }
00113 
00123 inline static bool isLocalMaxima(Image& c, int x, int y, int canal)
00124 {
00125   float norme;
00126   float angle;
00127   cannyGradient(c, x, y, canal, norme, angle);
00128 
00129   // gradient ~= 0 => consider this is not a local maxima
00130   if (norme<1)
00131     return true;
00132 
00133   // gradient direction
00134   float gx = cos(angle);
00135   float gy = -sin(angle);
00136 
00137   // scaling
00138   float gmax = std::max( std::abs(gx), std::abs(gy) );
00139   /*gmax ne peut être nul*/
00140   float scale = 1.0/gmax;
00141 
00142   // gradient value at next position in the gradient direction
00143   int nx = (int) (x + gx * scale);
00144   int ny = (int) (y + gy * scale);
00145   float normen;
00146   float anglen;
00147   cannyGradient(c,nx,ny, canal, normen, anglen);
00148 
00149   // gradient value at previous position in the gradient direction
00150   int px = static_cast<int>(x - gx * scale);
00151   int py = static_cast<int>(y - gy * scale);
00152   float normep;
00153   float anglep;
00154   cannyGradient(c, px, py, canal, normep, anglep);
00155 
00156   // is the current gradient value a local maxima ?
00157   if (norme>normen && norme>normep)
00158     return true;
00159 
00160   // otherwise
00161   return false;
00162 }
00163 
00164 
00165 void Millie::cannyOperator(Image& out, const Image& c,
00166                           int lowThreshold,
00167                           int highThreshold,
00168                           int rayon,
00169                           float sigma)
00170 {
00171   if(c.getNumComponents() != out.getNumComponents())
00172     throw IllegalArgument("cannyOperator : c.getNumComponents() != out.getNumComponents()");
00173 
00174   /*définition du noyau de gauss*/
00175   KernelGaussian gauss(rayon, sigma);
00176 
00177   /*définition d'un étendeur de bords pour la convolution*/
00178   BorderExtenderCopy beCopy;
00179 
00180   /*proximity kernel*/
00181   float f[] = {1,1,1,
00182                1,0,1,
00183                1,1,1};
00184   Kernel proximityKernel(3,3,1,1,f);
00185 
00186   int width = c.getWidth();
00187   int height = c.getHeight();
00188 
00189   /*définition d'une image de même nombre de canaux que c*/
00190   Image cg(c.getNumComponents());
00191 
00192   /*calcul de la convolution avec le noyau gaussien*/
00193   ConvolveOperator cOp(gauss);
00194   cOp.compute(cg, c, beCopy);
00195 
00196   if(cg.getWidth() != width || cg.getHeight() != height)
00197   {
00198     std::cerr<<"Probleme dans cannyOperator";
00199     throw RuntimeException("cannyOperator");
00200   }
00201 
00202 
00203   out.resize(width, height);
00204    for(int canal=0; canal< c.getNumComponents(); canal++)
00205     for (int y=0; y<height; y++)
00206       for (int x=0; x<width; x++)
00207          out.setPixel(x,y,canal,0.0f);
00208 
00209   std::list<std::pair<int, int> > pixels;
00210 
00211 
00212   // gradient thresholding
00213   for(int canal=0; canal< c.getNumComponents(); canal++)
00214   {
00215     pixels.resize(0);
00216     for (int y=0; y<height; y++)
00217     {
00218       for (int x=0; x<width; x++)
00219       {
00220 
00221         // not a local maxima -> not an edge
00222         if (!isLocalMaxima(cg,x,y, canal))
00223           continue;
00224 
00225         // gradient intesity
00226         float norme;
00227         float angle;
00228         cannyGradient(cg,x,y, canal, norme, angle);
00229 
00230         // low-threshold -> not an edge
00231         if (norme<lowThreshold)
00232           continue;
00233 
00234         // high-threshold -> is an edge
00235         if (norme>highThreshold)
00236         {
00237           out.setPixel(x,y, canal, 255.0f);
00238           continue;
00239         }
00240 
00241         // between thresholds -> "unknown state" (depends of neighbors)
00242         pixels.push_back(std::pair<int,int>(x,y));
00243 
00244       }
00245     }
00246 
00247     // edge continuation
00248     bool change=true;
00249     while(change)
00250     {
00251 
00252       // for each pixel in "unknown state"
00253       change=false;
00254       std::list<std::pair<int, int> >::iterator it;
00255       for(it = pixels.begin(); it != pixels.end(); )
00256       {
00257         std::pair<int,int> & xy_pair = *it;
00258         int x = xy_pair.first;
00259         int y = xy_pair.second;
00260 
00261         // look at the neighbors
00262         int v = static_cast<int>(convolvePosition(out,x,y, canal, proximityKernel));
00263 
00264         // if neighbors is an edge -> this pixel is also an edge
00265         if (v!=0)
00266         {
00267           out.setPixel(x,y,canal, 255);
00268           it = pixels.erase(it);
00269           change=true;
00270 
00271         }
00272         else
00273         {
00274           ++it;
00275         }
00276       }
00277 
00278     }
00279 
00280     // exit when no more change
00281   }
00282 }
00283 

Généré le Fri May 18 23:24:37 2007 pour Millie par  doxygen 1.5.1