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
00030
00031
00032
00033
00034 #include <ntg/utils/cast.hh>
00035 #include <oln/convol/fast_gaussian_coefficient.hh>
00036 #include <vector>
00037
00038 namespace oln {
00039 namespace convol {
00040 namespace fast {
00043 namespace internal {
00044
00065 template <class WorkType, class FloatType, class I>
00066 void
00067 recursivefilter_(I& image,
00068 const recursivefilter_coef_<FloatType>& c,
00069 const oln_point_type(I)& start,
00070 const oln_point_type(I)& finish,
00071 coord len,
00072 const oln_dpoint_type(I)& d)
00073 {
00074 std::vector<WorkType> tmp1(len);
00075 std::vector<WorkType> tmp2(len);
00076
00077
00078
00079
00080
00081
00082
00083
00084 tmp1[0] =
00085 c.n[0]*image[start];
00086
00087 tmp1[1] =
00088 c.n[0]*image[start + d]
00089 + c.n[1]*image[start]
00090 - c.d[1]*tmp1[0];
00091
00092 tmp1[2] =
00093 c.n[0]*image[start + d + d]
00094 + c.n[1]*image[start + d]
00095 + c.n[2]*image[start]
00096 - c.d[1]*tmp1[1]
00097 - c.d[2]*tmp1[0];
00098
00099 tmp1[3] =
00100 c.n[0]*image[start + d + d + d]
00101 + c.n[1]*image[start + d + d]
00102 + c.n[2]*image[start + d]
00103 + c.n[3]*image[start]
00104 - c.d[1]*tmp1[2] - c.d[2]*tmp1[1]
00105 - c.d[3]*tmp1[0];
00106
00107 oln_point_type(I) current(start + d + d + d + d);
00108 for (coord i = 4; i < len; ++i)
00109 {
00110 tmp1[i] =
00111 c.n[0]*image[current]
00112 + c.n[1]*image[current - d]
00113 + c.n[2]*image[current - d - d]
00114 + c.n[3]*image[current - d - d - d]
00115 - c.d[1]*tmp1[i - 1] - c.d[2]*tmp1[i - 2]
00116 - c.d[3]*tmp1[i - 3] - c.d[4]*tmp1[i - 4];
00117 current += d;
00118 }
00119
00120
00121
00122 tmp2[len - 1] = 0;
00123
00124 tmp2[len - 2] =
00125 c.nm[1]*image[finish];
00126
00127 tmp2[len - 3] =
00128 c.nm[1]*image[finish - d]
00129 + c.nm[2]*image[finish]
00130 - c.dm[1]*tmp2[len-2];
00131
00132 tmp2[len - 4] =
00133 c.nm[1]*image[finish - d - d]
00134 + c.nm[2]*image[finish - d]
00135 + c.nm[3]*image[finish]
00136 - c.dm[1]*tmp2[len-3]
00137 - c.dm[2]*tmp2[len-2];
00138
00139 current = finish - d - d - d ;
00140
00141 for (coord i = len - 5; i >= 0; --i)
00142 {
00143 tmp2[i] =
00144 c.nm[1]*image[current]
00145 + c.nm[2]*image[current + d]
00146 + c.nm[3]*image[current + d + d]
00147 + c.nm[4]*image[current + d + d + d]
00148 - c.dm[1]*tmp2[i+1] - c.dm[2]*tmp2[i+2]
00149 - c.dm[3]*tmp2[i+3] - c.dm[4]*tmp2[i+4];
00150 current -= d;
00151 }
00152
00153
00154
00155 current = start;
00156 for (coord i = 0; i < len; ++i)
00157 {
00158 image[current] = ntg::cast::force<oln_value_type(I)>(tmp1[i] + tmp2[i]);
00159 current += d;
00160 }
00161 }
00162
00168 template<unsigned dim>
00169 struct gaussian_ {};
00170
00171
00182 template<>
00183 struct gaussian_<1>
00184 {
00185 template <class I, class F> static
00186 void
00187 doit(abstract::image_with_dim<1, I>& img, const F& coef)
00188 {
00189
00190
00191 recursivefilter_<float>(img, coef,
00192 oln_point_type(I)(-img.border()),
00193 oln_point_type(I)(img.ncols() - 1 + img.border()),
00194 img.ncols() + 2 * img.border(),
00195 oln_dpoint_type(I)(1));
00196 }
00197 };
00198
00199
00210 template<>
00211 struct gaussian_<2>
00212 {
00213 template <class I, class F> static
00214 void
00215 doit(abstract::image_with_dim<2, I>& img, const F& coef)
00216 {
00217
00218 for (coord j = 0; j < img.ncols(); ++j)
00219 recursivefilter_<float>(img, coef,
00220 oln_point_type(I)(-img.border(), j),
00221 oln_point_type(I)(img.nrows() - 1 + img.border(), j),
00222 img.nrows() + 2 * img.border(),
00223 oln_dpoint_type(I)(1, 0));
00224
00225
00226 for (coord i = 0; i < img.nrows(); ++i)
00227 recursivefilter_<float>(img, coef,
00228 oln_point_type(I)(i, -img.border()),
00229 oln_point_type(I)(i, img.ncols() - 1 + img.border()),
00230 img.ncols() + 2 * img.border(),
00231 oln_dpoint_type(I)(0, 1));
00232 }
00233 };
00234
00245 template<>
00246 struct gaussian_<3>
00247 {
00248 template <class I, class F> static
00249 void
00250 doit(abstract::image_with_dim<3, I>& img, const F& coef)
00251 {
00252
00253 for (coord j = 0; j < img.nrows(); ++j)
00254 for (coord k = 0; k < img.ncols(); ++k)
00255 recursivefilter_<float>(img, coef,
00256 oln_point_type(I)(-img.border(), j, k),
00257 oln_point_type(I)(img.nslices() - 1 + img.border(), j, k),
00258 img.ncols() + 2 * img.border(),
00259 oln_dpoint_type(I)(1, 0, 0));
00260
00261
00262 for (coord i = 0; i < img.nslices(); ++i)
00263 for (coord k = 0; k < img.ncols(); ++k)
00264 recursivefilter_<float>(img, coef,
00265 oln_point_type(I)(i, -img.border(), k),
00266 oln_point_type(I)(i, img.nrows() - 1 + img.border(), k),
00267 img.nrows() + 2 * img.border(),
00268 oln_dpoint_type(I)(0, 1, 0));
00269
00270
00271 for (coord i = 0; i < img.nslices(); ++i)
00272 for (coord j = 0; j < img.nrows(); ++j)
00273 recursivefilter_<float>(img, coef,
00274 oln_point_type(I)(i, j, -img.border()),
00275 oln_point_type(I)(i, j, img.ncols() - 1 + img.border()),
00276 img.ncols() + 2 * img.border(),
00277 oln_dpoint_type(I)(0, 0, 1));
00278 }
00279 };
00280
00295 template <class C, class B, class I, class F, class BE>
00296 typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00297 gaussian_common_(const convert::abstract::conversion<C,B>& c,
00298 const abstract::image<I>& in,
00299 const F& coef,
00300 ntg::float_s sigma,
00301 const abstract::behavior<BE> &behavior)
00302 {
00303 typename mute<I, ntg::float_s>::ret work_img(in.size());
00304
00305 oln_iter_type(I) it(in);
00306 for_all(it)
00307 work_img[it] = ntg::cast::force<ntg::float_s>(in[it]);
00308
00309
00310
00311 if (sigma > 0.006)
00312 {
00313
00314
00315
00316
00317 behavior.adapt_border(work_img, ntg::cast::round<coord>(5 * sigma));
00318
00319 gaussian_<I::dim>::doit(work_img, coef);
00320 }
00321
00322
00323
00324 typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00325 out_img(in.size());
00326
00327 for_all(it)
00328 out_img[it] = c(work_img[it]);
00329
00330 return out_img;
00331 }
00332
00333 }
00334
00335 template <class C, class B, class I, class BE>
00336 typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00337 gaussian(const convert::abstract::conversion<C,B>& c,
00338 const abstract::image<I>& in, ntg::float_s sigma,
00339 const abstract::behavior<BE> &behavior)
00340 {
00341 internal::recursivefilter_coef_<float>
00342 coef(1.68f, 3.735f,
00343 1.783f, 1.723f,
00344 -0.6803f, -0.2598f,
00345 0.6318f, 1.997f,
00346 sigma,
00347 internal::recursivefilter_coef_<float>::DericheGaussian);
00348
00349 return internal::gaussian_common_(c, in, coef, sigma, behavior);
00350 }
00351
00352 template <class C, class B, class I, class BE>
00353 typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00354 gaussian_derivative(const convert::abstract::conversion<C,B>& c,
00355 const abstract::image<I>& in, ntg::float_s sigma,
00356 const abstract::behavior<BE> &behavior)
00357 {
00358 internal::recursivefilter_coef_<float>
00359 coef(-0.6472f, -4.531f,
00360 1.527f, 1.516f,
00361 0.6494f, 0.9557f,
00362 0.6719f, 2.072f,
00363 sigma,
00364 internal::recursivefilter_coef_<float>
00365 ::DericheGaussianFirstDerivative);
00366
00367 return internal::gaussian_common_(c, in, coef, sigma, behavior);
00368 }
00369
00370 template <class C, class B, class I, class BE>
00371 typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00372 gaussian_second_derivative(const convert::abstract::conversion<C,B>& c,
00373 const abstract::image<I>& in, ntg::float_s sigma,
00374 const abstract::behavior<BE> &behavior)
00375 {
00376 internal::recursivefilter_coef_<float>
00377 coef(-1.331f, 3.661f,
00378 1.24f, 1.314f,
00379 0.3225f, -1.738f,
00380 0.748f, 2.166f,
00381 sigma,
00382 internal::recursivefilter_coef_<float>
00383 ::DericheGaussianSecondDerivative);
00384
00385 return internal::gaussian_common_(c, in, coef, sigma, behavior);
00386 }
00387
00388 }
00389 }
00390 }