TuttleOFX
1
|
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