TuttleOFX  1
edgeDetect.hpp
Go to the documentation of this file.
00001 /**
00002  * \brief This file provides a set of reimplementations of CImg functions by means of the generic image library (gil).
00003  *        Functions for edge detection
00004  */
00005 #ifndef _EDGE_DETECT_HPP_
00006 #define _EDGE_DETECT_HPP_
00007 
00008 #include <cmath>
00009 #include <vector>
00010 
00011 #include <boost/gil/gil_all.hpp>
00012 #include <terry/globals.hpp>
00013 #include <tuttle/plugin/exceptions.hpp>
00014 
00015 
00016 namespace tuttle {
00017 namespace imageUtils {
00018 
00019 using namespace tuttle::plugin;
00020 namespace bgil = boost::gil;
00021 
00022 /**
00023  * @brief Apply precise forward/backward finite differences to get a gradient image
00024  *
00025  * @param[in]       src         Source view
00026  * @param[out]      final_dst   Destination view
00027  * @return outline image (destination)
00028  * @warning Destination MUST BE different from source.
00029  */
00030 template <typename S_VIEW, typename D_VIEW>
00031 D_VIEW&
00032 simple_structure_tensor(const S_VIEW& src, D_VIEW& final_dst, float threshold) {
00033     if (final_dst.width() < 3) {
00034         std::cerr << "Error: destination width must be >= 3" << std::endl;
00035         return final_dst;
00036     }
00037 
00038     // Concept checking
00039     bgil::gil_function_requires<bgil::ColorSpacesCompatibleConcept<
00040         typename bgil::color_space_type<S_VIEW>::type,
00041         typename bgil::color_space_type<D_VIEW>::type > > ();
00042 
00043 
00044     typedef typename S_VIEW::x_iterator sIterator;
00045     typedef typename D_VIEW::x_iterator dIterator;
00046     typedef typename S_VIEW::locator locator;
00047     typedef typename bgil::channel_type<S_VIEW>::type  pix_t;
00048     typedef typename bgil::channel_type<D_VIEW>::type dpix_t;
00049 
00050     int w = src.width() < final_dst.width() ?
00051             src.width() : final_dst.width();
00052     int h = src.height() < final_dst.height() ?
00053             src.height() : final_dst.height();
00054     int nc = final_dst.num_channels() < src.num_channels() ?
00055              final_dst.num_channels() : src.num_channels();
00056     float r, g, b;
00057     float Icc, Inc, Icn, Ipc, Icp;
00058     float ixf, ixb, iyf, iyb;
00059     int ny, nym1, nx, nxm1;
00060     int x, y, c, xf;
00061     const int mc = 5;
00062     const int mc2 = mc/2;
00063     float q, chaos, mean;
00064 
00065     for (y = 0; y < h; y++) {
00066         dIterator dst_it = final_dst.row_begin(y);
00067 
00068         nym1 = y - 1 >= 0 ? -1 : 0;
00069         ny   = y + 1  < h ?  1 : 0;
00070         for (x = 0; x < w; x++) {
00071             nxm1 = x - 1 >= 0 ? -1 : 0;
00072             nx   = x + 1 < w  ?  1 : 0;
00073             locator loc = src.xy_at(x, y);
00074             mean = chaos = r = g = b = 0.0f;
00075             for (c = 0; c < nc; c++) {
00076                 // Get neighbors pixels
00077                 Icc = loc(0,    0)[c];
00078                 Inc = loc(nx,   0)[c];
00079                 Ipc = loc(nxm1, 0)[c];
00080                 Icn = loc(0,   ny)[c];
00081                 Icp = loc(0, nym1)[c];
00082                 ixf = Inc - Icc;
00083                 ixb = Icc - Ipc;
00084                 iyf = Icn - Icc;
00085                 iyb = Icc - Icp;
00086 
00087                 // Compute rgb tensors value
00088                 r += 0.5f  * (ixf*ixf + ixb*ixb);
00089                 g += 0.25f * (ixf*iyf + ixf*iyb +
00090                               ixb*iyf + ixb*iyb);
00091                 b += 0.5f  * (iyf*iyf + iyb*iyb);
00092             }
00093             for (c = 0; c < 3; c++) {
00094                 if (x > mc2 && x < w - mc2)
00095                     for(xf = 0; xf < mc; xf++) {
00096                         mean  += loc(xf - mc2, 0)[c];
00097                         chaos += powf(loc(xf - mc2, 0)[c], 2.0f);
00098                     }
00099                 if (y > mc2 && y < h - mc2)
00100                     for(xf = 0; xf < mc; xf++) {
00101                         mean  += loc(0, xf - mc2)[c];
00102                         chaos += powf(loc(0, xf - mc2)[c], 2.0f);
00103                     }
00104             }
00105             mean  = powf(mean / (mc * 2.0f * 3), 2.0f);
00106             chaos = fabs((chaos / (mc * 2.0f * 3)) - mean);
00107             q = threshold * chaos;
00108             if (q > 0.0f) {
00109                 // Threshold by q
00110                 (*dst_it)[0] = (dpix_t)(floorf(r / q) * q);
00111                 (*dst_it)[1] = (dpix_t)(g);
00112                 (*dst_it)[2] = (dpix_t)(floorf(b / q) * q);
00113             } else {
00114                 (*dst_it)[0] = (dpix_t)(r);
00115                 (*dst_it)[1] = (dpix_t)(g);
00116                 (*dst_it)[2] = (dpix_t)(b);
00117             }
00118             dst_it++;
00119         }
00120     }
00121     return final_dst;
00122 }
00123 
00124 template<typename S_VIEW, typename D_VIEW>
00125 void harris(const S_VIEW& src, D_VIEW& dst, float threshold){
00126     const int mc = 5;
00127     const int mc2 = mc / 2;
00128     float xMatrix[mc] = {-0.5f, -0.5f,  0, 0.5f,  0.5f};
00129 
00130     int x,y,c,xf;
00131     const int w = dst.width(), h = dst.height();
00132     const int nc = dst.num_channels() <
00133                    src.num_channels() ? dst.num_channels() :
00134                                         src.num_channels();
00135     // Concept checking
00136     bgil::gil_function_requires<bgil::ColorSpacesCompatibleConcept<
00137     typename bgil::color_space_type<S_VIEW>::type,
00138     typename bgil::color_space_type<D_VIEW>::type > > ();
00139 
00140     typedef typename D_VIEW::x_iterator dIterator;
00141     typedef typename S_VIEW::locator locator;
00142 
00143     typedef typename bgil::channel_type<D_VIEW>::type  pix_t;
00144     float chaos, mean, q, px, py, Ix[3], Iy[3];
00145 
00146     for(y = mc2; y < h - mc2; y++) {
00147         dIterator dst_it = dst.row_begin(y);
00148         dst_it+=mc2;
00149         for(x = mc2; x < w - mc2; x++) {
00150             chaos = mean = 0.0f;
00151             memset(Ix, 0, 3*sizeof(float));
00152             memset(Iy, 0, 3*sizeof(float));
00153             locator sLoc = src.xy_at(x, y);
00154             for(c = 0; c < 3; c++) {
00155                 for(xf = 0; xf < mc; xf++) {
00156                     px = sLoc(xf - mc2, 0)[c];
00157                     Ix[c] += px * xMatrix[xf];
00158                     mean += px;
00159                     chaos += powf(sLoc(xf - mc2, 0)[c], 2.0f);
00160                 }
00161                 for(xf = 0; xf < mc; xf++) {
00162                     py = sLoc(0, xf - mc2)[c];
00163                     Iy[c] += py * xMatrix[xf];
00164                     mean += py;
00165                     chaos += powf(sLoc(0, xf - mc2)[c], 2.0f);
00166                 }
00167             }
00168             // Compute variance
00169             mean /= 2.0f * mc * 3.0f;
00170             mean = powf(mean, 2.0f);
00171             // Chaos is the variance
00172             chaos /= (mc * 2.0f) * 3.0f;
00173             chaos -= mean;
00174             q = threshold * fabs(chaos);
00175             for(c = 0; c < 3; c++) {
00176                 Ix[c] /= 3.0f;
00177                 Iy[c] /= 3.0f;
00178             }
00179             if (q != 0.0f) {
00180                 // Threshold by q
00181                 (*dst_it)[0] = pix_t(floorf((Ix[0]*Ix[0]) / q) * q +
00182                                      floorf((Ix[1]*Ix[1]) / q) * q +
00183                                      floorf((Ix[2]*Ix[2]) / q) * q);
00184                 (*dst_it)[1] = pix_t(Ix[0]*Iy[0] +
00185                                      Ix[1]*Iy[1] +
00186                                      Ix[2]*Iy[2]);
00187                 (*dst_it)[2] = pix_t(floorf((Iy[0]*Iy[0]) / q) * q +
00188                                      floorf((Iy[1]*Iy[1]) / q) * q +
00189                                      floorf((Iy[2]*Iy[2]) / q) * q);
00190             } else {
00191                 (*dst_it)[0] = pix_t(Ix[0]*Ix[0] +
00192                                      Ix[1]*Ix[1] +
00193                                      Ix[2]*Ix[2]);
00194                 (*dst_it)[1] = pix_t(Ix[0]*Iy[0] +
00195                                      Ix[1]*Iy[1] +
00196                                      Ix[2]*Iy[2]);
00197                 (*dst_it)[2] = pix_t(Iy[0]*Iy[0] +
00198                                      Iy[1]*Iy[1] +
00199                                      Iy[2]*Iy[2]);
00200             }
00201             dst_it++;
00202         }
00203     }
00204     for(y = 0; y < mc2; y++) {
00205         dIterator dst_it = dst.row_begin(y);
00206         for(x = 0; x < mc2; x++) {
00207             for(c = 0; c < nc; c++) {
00208                 (*dst_it)[c] = pix_t(0);
00209             }
00210             dst_it++;
00211         }
00212         dst_it = dst.row_begin(y);
00213         for(x = w - mc2; x < w; x++) {
00214             for(c = 0; c < nc; c++) {
00215                 (*dst_it)[c] = pix_t(0);
00216             }
00217             dst_it++;
00218         }
00219     }
00220     for(y = h - mc2; y < h; y++) {
00221         dIterator dst_it = dst.row_begin(y);
00222         for(x = 0; x < mc2; x++) {
00223             for(c = 0; c < nc; c++) {
00224                 (*dst_it)[c] = pix_t(0);
00225             }
00226             dst_it++;
00227         }
00228         dst_it = dst.row_begin(y);
00229         for(x = w - mc2; x < w; x++) {
00230             for(c = 0; c < nc; c++) {
00231                 (*dst_it)[c] = pix_t(0);
00232             }
00233             dst_it++;
00234         }
00235     }
00236 }
00237 
00238 /**
00239  * @brief Compute the eigenvalues and eigenvectors of a symmetric matrix.
00240  *
00241  * @param[in]       tensorXY    tensor (view iterator) at a certain position
00242  * @param[out]      val         eigenvalue
00243  * @param[out]      val         eigenvector
00244  * @warning vec MUST BE a linear float vector of dimension 4.
00245  */
00246 template <typename ViewIt>
00247  void symmetric_eigen(ViewIt & tensorXY, std::vector<double> & val, 
00248                       std::vector<double> & vec) {
00249     const double a = (*tensorXY)[0],
00250                  b = (*tensorXY)[1],
00251                  c = (*tensorXY)[1],
00252                  d = (*tensorXY)[2],
00253                  e = a + d;
00254     double f = (e * e - 4.0 *
00255                (a * d - b * c));
00256     if (f > 0)
00257         f = std::sqrt(f);
00258     else
00259         f = 0.0;
00260 
00261     const double  l1 = 0.5 * (e - f),
00262                   l2 = 0.5 * (e + f);
00263     const double theta1 = std::atan2(l2 - a, b),
00264                  theta2 = std::atan2(l1 - a, b);
00265     val[0] = l2;
00266     val[1] = l1;
00267     vec[0] = std::cos(theta1);
00268     vec[1] = std::sin(theta1);
00269     vec[2] = std::cos(theta2);
00270     vec[3] = std::sin(theta2);
00271 }
00272 
00273 }
00274 }
00275 
00276 #endif