00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
00130 if (norme<1)
00131 return true;
00132
00133
00134 float gx = cos(angle);
00135 float gy = -sin(angle);
00136
00137
00138 float gmax = std::max( std::abs(gx), std::abs(gy) );
00139
00140 float scale = 1.0/gmax;
00141
00142
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
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
00157 if (norme>normen && norme>normep)
00158 return true;
00159
00160
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
00175 KernelGaussian gauss(rayon, sigma);
00176
00177
00178 BorderExtenderCopy beCopy;
00179
00180
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
00190 Image cg(c.getNumComponents());
00191
00192
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
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
00222 if (!isLocalMaxima(cg,x,y, canal))
00223 continue;
00224
00225
00226 float norme;
00227 float angle;
00228 cannyGradient(cg,x,y, canal, norme, angle);
00229
00230
00231 if (norme<lowThreshold)
00232 continue;
00233
00234
00235 if (norme>highThreshold)
00236 {
00237 out.setPixel(x,y, canal, 255.0f);
00238 continue;
00239 }
00240
00241
00242 pixels.push_back(std::pair<int,int>(x,y));
00243
00244 }
00245 }
00246
00247
00248 bool change=true;
00249 while(change)
00250 {
00251
00252
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
00262 int v = static_cast<int>(convolvePosition(out,x,y, canal, proximityKernel));
00263
00264
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
00281 }
00282 }
00283