contrib/oxl/osl/osl_canny_smooth.txx
Go to the documentation of this file.
00001 #ifndef osl_canny_smooth_txx_
00002 #define osl_canny_smooth_txx_
00003 //:
00004 // \file
00005 //
00006 // Notes
00007 // -  if this file is not in Templates, gcc 2.7 does not instantiate.
00008 // -  even if this file is in Templates, SunPro 5.0 will fail to
00009 //    instantiate symbols whose signatures contain a parameter of
00010 //    the form "type * const *". hence the 'unpro_const' macro. fsm.
00011 //
00012 // \author fsm
00013 
00014 #include "osl_canny_smooth.h"
00015 #include <vcl_cmath.h>
00016 #include <vil1/vil1_rgb.h>
00017 #include <vil1/vil1_memory_image_of.h>
00018 
00019 
00020 template <class T>
00021 inline float as_float(T const &v) { return float(v); }
00022 
00023 VCL_DEFINE_SPECIALIZATION
00024 inline float as_float(vil1_rgb<unsigned char> const &v) { return v.grey(); }
00025 
00026 //--------------------------------------------------------------------------------
00027 
00028 // the input image has xsize_ rows and ysize_ columns.
00029 // the size of the convolution mask is k_size_ and we ignore a border of size
00030 // width_ around the edge of the image.
00031 //
00032 // first we do
00033 // tmp[x][y] = kernel_[0]*image_in[x-width_  ][y]
00034 //           + kernel_[1]*image_in[x-width_+1][y]
00035 //           + kernel_[2]*image_in[x-width_+2][y]
00036 //           + ...
00037 // and then we do
00038 // smooth_[x][y] = kernel_[0]*tmp[x][y-width_  ]
00039 //               + kernel_[1]*tmp[x][y-width_+1]
00040 //               + kernel_[2]*tmp[x][y-width_+2]
00041 //               + ...
00042 template <class T>
00043 void osl_canny_smooth_rothwell(T const * const *image_in, int xsize_, int ysize_,
00044                                float const *kernel_, int width_, int k_size_,
00045                                float * unpro_const *smooth_)
00046 {
00047   // temporary buffer.
00048   vil1_memory_image_of<float> tmp(ysize_, xsize_);
00049   tmp.fill(0);
00050 
00051   // x direction
00052   for (int y=0; y<ysize_; ++y)
00053     for (int x=width_; x<xsize_-width_; ++x)
00054       for (int i=0,xx=x-width_; i<k_size_; i++,xx++)
00055         tmp[x][y] += as_float(image_in[xx][y]) * kernel_[i];
00056 
00057   // y direction
00058   for (int y=width_; y<ysize_-width_; ++y)
00059     for (int x=0; x<xsize_; ++x)
00060       for (int i=0,yy=y-width_; i<k_size_; i++,yy++)
00061         smooth_[x][y] += tmp[x][yy]*kernel_[i];
00062 }
00063 
00064 //
00065 //: Computes the gradient images with the origin at (x0,y0) and of square size image_size.
00066 //
00067 template <class T>
00068 void osl_canny_smooth_rothwell_adaptive(T const * const *image_, int /*xsize_*/, int /*ysize_*/,
00069                                         int x0, int y0, int image_size,
00070                                         float const *kernel_, int width_, int k_size_,
00071                                         float * unpro_const *dx,
00072                                         float * unpro_const *dy,
00073                                         float * unpro_const *grad)
00074 {
00075   // Zero the derivative images
00076   for (int j=0; j<image_size; ++j)
00077     for (int i=0; i<image_size; ++i)  {
00078       dx[i][j] = 0.0;
00079       dy[i][j] = 0.0;
00080       grad[i][j] = 0.0;
00081     }
00082 
00083   // Do the different convolutions - we checked that we would not
00084   // go beyond the image bounds before calling Compute_adaptive_images
00085 
00086   // Compute the image gradients in the x direction
00087   for (int y=width_; y<image_size-width_; ++y)
00088     for (int x=width_; x<image_size-width_; ++x)
00089       for (int i=0,j=x-width_; i<k_size_; i++,j++)
00090         dx[x][y] += as_float(image_[j+x0][y+y0])*kernel_[i];
00091 
00092   // and in the y direction
00093   for (int x=width_; x<image_size-width_; ++x)
00094     for (int y=width_; y<image_size-width_; ++y)
00095       for (int i=0,j=y-width_; i<k_size_; i++,j++)
00096         dx[x][y] += as_float(image_[x+x0][j+y0])*kernel_[i];
00097 
00098   // and grad
00099   for (int x=width_; x<image_size-width_; ++x)
00100     for (int y=width_; y<image_size-width_; ++y)
00101       grad[x][y] = vcl_sqrt(dx[x][y]*dx[x][y] + dy[x][y]*dy[x][y]);
00102 }
00103 
00104 
00105 //--------------------------------------------------------------------------------
00106 
00107 //
00108 //: Convolves the image with the smoothing kernel.
00109 //  sub_area_ is used to smooth pixels lying in a border of size width_.
00110 //
00111 //  Meaning of sub_area_[x] :
00112 //    It is the probability that the variable will assume a value <= x
00113 //    in the distribution function. It is the hashed area under the
00114 //    distribution profile.
00115 // \verbatim
00116 //                     . .
00117 //                   . ### .
00118 //                 .  #####| .
00119 //               . ########|   .
00120 //             . ##########|     .
00121 //         __ .############|      .__
00122 //       __________________|___________
00123 //                         x
00124 // \endverbatim
00125 //
00126 
00127 #define thePixel(b,x,y) as_float(b[x][y])
00128 
00129 template <class T>
00130 void osl_canny_smooth(T const * const * image_in, int xsize_, int ysize_,
00131                       float const *kernel_, int width_, float const *sub_area_,
00132                       float * unpro_const * image_out)
00133 {
00134   vil1_memory_image_of<float> tmp(ysize_, xsize_);
00135   tmp.fill(0);
00136 
00137   // x direction
00138   for (int y=0; y<ysize_; ++y) {
00139     // left border of size width_
00140     for (int x=0; x<width_-1; ++x) {
00141       tmp[x][y] = thePixel(image_in,x,y)*kernel_[0];
00142       for (int k=1; k < width_; ++k) {
00143         if (x-k < 0)
00144           tmp[x][y] += thePixel(image_in,x+k,y)*kernel_[k];
00145         else
00146           tmp[x][y] += thePixel(image_in,x-k,y)*kernel_[k] + thePixel(image_in,x+k,y)*kernel_[k];
00147       }
00148       tmp[x][y] /= sub_area_[x+1];
00149     }
00150 
00151     // Middle pixels along x direction
00152     for (int x=width_-1; x<xsize_-width_+1; ++x) {
00153       tmp[x][y] = thePixel(image_in,x,y)*kernel_[0];
00154       for (int k=1; k < width_; ++k)
00155         tmp[x][y] += thePixel(image_in,x-k,y)*kernel_[k] + thePixel(image_in,x+k,y)*kernel_[k];
00156     }
00157 
00158     // Right border of size width_
00159     for (int x=xsize_-width_+1; x < xsize_; ++x) {
00160       tmp[x][y] = thePixel(image_in,x,y)*kernel_[0];
00161       for (int k=1; k < width_; ++k) {
00162         if (x+k >= xsize_)
00163           tmp[x][y] += thePixel(image_in,x-k,y)*kernel_[k];
00164         else
00165           tmp[x][y] += thePixel(image_in,x-k,y)*kernel_[k] + thePixel(image_in,x+k,y)*kernel_[k];
00166       }
00167       tmp[x][y] /= sub_area_[xsize_-x];
00168     }
00169   }
00170 
00171 
00172   // y direction
00173   for (int x=0; x < xsize_; ++x) {
00174     // Top border of size width_
00175     for (int y=0; y < width_-1; ++y) {
00176       image_out[x][y] = tmp[x][y]*kernel_[0];
00177       for (int k=1; k < width_; ++k) {
00178         if (y-k < 0)
00179           image_out[x][y] += tmp[x][y+k]*kernel_[k];
00180         else
00181           image_out[x][y] += tmp[x][y-k]*kernel_[k] + tmp[x][y+k]*kernel_[k];
00182       }
00183       image_out[x][y] /= sub_area_[y+1];
00184     }
00185 
00186     // Middle pixels along y direction
00187     for (int y=width_-1; y < ysize_-width_+1; ++y) {
00188       image_out[x][y] = tmp[x][y]*kernel_[0];
00189       for (int k=1; k < width_; ++k) {
00190         image_out[x][y] += tmp[x][y-k]*kernel_[k] + tmp[x][y+k]*kernel_[k];
00191       }
00192     }
00193 
00194     // Bottom border of size width_
00195     for (int y=ysize_-width_+1; y < ysize_; ++y) {
00196       image_out[x][y] = tmp[x][y]*kernel_[0];
00197       for (int k=1; k < width_; ++k) {
00198         if (y+k >= ysize_)
00199           image_out[x][y] += tmp[x][y-k]*kernel_[k];
00200         else
00201           image_out[x][y] += tmp[x][y-k]*kernel_[k] + tmp[x][y+k]*kernel_[k];
00202       }
00203       image_out[x][y] /= sub_area_[ysize_-y];
00204     }
00205   }
00206 }
00207 
00208 //--------------------------------------------------------------------------------
00209 
00210 #define OSL_CANNY_SMOOTH_INSTANTIATE(T) \
00211 template void osl_canny_smooth_rothwell(T const * const *image_in, int xsize_, int ysize_, \
00212                                         float const *kernel_, int width_, int k_size_, \
00213                                         float * unpro_const *smooth_); \
00214 template void osl_canny_smooth_rothwell_adaptive(T const * const *in, int xsize_, int ysize_, \
00215                                                  int x0, int y0, int image_size,  \
00216                                                  float const *kernel_, int width_, int k_size_, \
00217                                                  float * unpro_const *dx, float * unpro_const *dy, float * unpro_const *grad); \
00218 template void osl_canny_smooth(T const * const *image_in, int xsize_, int ysize_, \
00219                                float const *kernel_, int width_, float const *sub_area_, \
00220                                float * unpro_const * image_out)
00221 //VCL_INSTANTIATE_INLINE(float as_float(T const &));
00222 
00223 #endif // osl_canny_smooth_txx_