00001
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifdef VL_IMSMOOTH_INSTANTIATING
00016
00017 #include <vl/float.th>
00018 #include <vl/host.h>
00019
00020 #if (FLT == VL_TYPE_FLOAT)
00021 #define IMCONVCOL vl_imconvcol_vf
00022 #define IMCONVCOLTRI vl_imconvcoltri_f
00023 #else
00024 #define IMCONVCOL vl_imconvcol_vd
00025 #define IMCONVCOLTRI vl_imconvcoltri_d
00026 #endif
00027
00028 VL_INLINE void
00029 VL_XCAT(_vl_imsmooth_smooth_, SFX)
00030 (T * outputImage,
00031 vl_size numOutputRows,
00032 vl_size numOutputColumns,
00033 T const * inputImage,
00034 vl_size numRows,
00035 vl_size numColumns,
00036 vl_size numChannels,
00037 int kernel,
00038 double sigma,
00039 int step,
00040 int flags)
00041 {
00042 T * tempImage = (T*) mxMalloc (sizeof(T) * numRows * numOutputColumns) ;
00043 vl_uindex k ;
00044 vl_index j ;
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 switch (kernel) {
00067 case GAUSSIAN :
00068 {
00069 vl_size W = ceil (4.0 * sigma) ;
00070 T * filter = (T*) mxMalloc (sizeof(T) * (2 * W + 1)) ;
00071 T acc = 0 ;
00072 for (j = 0 ; j < (signed)(2 * W + 1) ; ++j) {
00073 T z = ( (T) j - W) / (sigma + VL_EPSILON_F) ;
00074 filter[j] = exp(- 0.5 * (z*z)) ;
00075 acc += filter[j] ;
00076 }
00077 for (j = 0 ; j < (signed)(2 * W + 1) ; ++j) {
00078 filter[j] /= acc ;
00079 }
00080
00081 for (k = 0 ; k < numChannels ; ++k) {
00082
00083 IMCONVCOL (tempImage, numOutputColumns,
00084 inputImage, numRows, numColumns, numRows,
00085 filter, -W, W, step, flags) ;
00086
00087 IMCONVCOL (outputImage, numOutputRows,
00088 tempImage, numOutputColumns, numRows, numOutputColumns,
00089 filter, -W, W, step, flags) ;
00090
00091 inputImage += numRows * numColumns ;
00092 outputImage += numOutputRows * numOutputColumns ;
00093 }
00094 mxFree (filter) ;
00095 break ;
00096 }
00097
00098 case TRIANGULAR:
00099 {
00100 unsigned int W = VL_MAX((unsigned int) sigma, 1) ;
00101 for (k = 0 ; k < numChannels ; ++k) {
00102
00103 IMCONVCOLTRI (tempImage, numOutputColumns,
00104 inputImage, numRows, numColumns, numRows,
00105 W, step, flags) ;
00106
00107 IMCONVCOLTRI (outputImage, numOutputRows,
00108 tempImage, numOutputColumns, numRows, numOutputColumns,
00109 W, step, flags) ;
00110
00111 inputImage += numRows * numColumns ;
00112 outputImage += numOutputRows * numOutputColumns ;
00113 }
00114 break ;
00115 }
00116
00117 default:
00118 abort() ;
00119 }
00120 mxFree (tempImage) ;
00121 }
00122
00123 #undef FLT
00124 #undef IMCONVCOLTRI
00125 #undef IMCONVCOL
00126 #undef VL_IMSMOOTH_INSTANTIATING
00127
00128
00129
00130 #else
00131
00132 #include <mexutils.h>
00133
00134 #include <vl/generic.h>
00135 #include <vl/mathop.h>
00136 #include <vl/imopv.h>
00137
00138 #include <stdlib.h>
00139 #include <string.h>
00140 #include <math.h>
00141
00142
00143 enum {
00144 opt_padding = 0,
00145 opt_subsample,
00146 opt_kernel,
00147 opt_verbose
00148 } ;
00149
00150
00151 vlmxOption options [] = {
00152 {"Padding", 1, opt_padding },
00153 {"Verbose", 0, opt_verbose },
00154 {"Subsample", 1, opt_subsample },
00155 {"Kernel", 1, opt_kernel },
00156 {0, 0, 0 }
00157 } ;
00158
00159 enum {GAUSSIAN, TRIANGULAR} ;
00160
00161
00162 #define VL_IMSMOOTH_INSTANTIATING
00163 #define FLT VL_TYPE_FLOAT
00164 #include "vl_imsmooth.c"
00165
00166 #define VL_IMSMOOTH_INSTANTIATING
00167 #define FLT VL_TYPE_DOUBLE
00168 #include "vl_imsmooth.c"
00169
00170 void
00171 mexFunction(int nout, mxArray *out[],
00172 int nin, const mxArray *in[])
00173 {
00174 enum {IN_I = 0, IN_S, IN_END} ;
00175 enum {OUT_J = 0} ;
00176 int opt ;
00177 int next = IN_END ;
00178 mxArray const *optarg ;
00179
00180 int padding = VL_PAD_BY_CONTINUITY ;
00181 int kernel = GAUSSIAN ;
00182 int flags ;
00183 vl_size step = 1 ;
00184 int verb = 0 ;
00185 double sigma ;
00186 mxClassID classid ;
00187
00188 mwSize M, N, K, M_, N_, ndims ;
00189 mwSize dims_ [3] ;
00190 mwSize const * dims ;
00191
00192
00193
00194
00195
00196 if (nin < 2) {
00197 mexErrMsgTxt("At least two input arguments required.");
00198 } else if (nout > 1) {
00199 mexErrMsgTxt("Too many output arguments.");
00200 }
00201
00202 while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) {
00203 switch (opt) {
00204 case opt_padding :
00205 {
00206 enum {buflen = 32} ;
00207 char buf [buflen] ;
00208 if (!vlmxIsString(optarg, -1)) {
00209 vlmxError(vlmxErrInvalidArgument,
00210 "PADDING argument must be a string.") ;
00211 }
00212 mxGetString(optarg, buf, buflen) ;
00213 buf [buflen - 1] = 0 ;
00214 if (vlmxCompareStringsI("zero", buf) == 0) {
00215 padding = VL_PAD_BY_ZERO ;
00216 } else if (vlmxCompareStringsI("continuity", buf) == 0) {
00217 padding = VL_PAD_BY_CONTINUITY ;
00218 } else {
00219 vlmxError(vlmxErrInvalidArgument,
00220 "PADDING must be either ZERO or CONTINUITY, was '%s'.",
00221 buf) ;
00222 }
00223 break ;
00224 }
00225
00226 case opt_subsample :
00227 if (!vlmxIsPlainScalar(optarg)) {
00228 vlmxError(vlmxErrInvalidArgument,
00229 "SUBSAMPLE must be a scalar.") ;
00230 }
00231 step = *mxGetPr(optarg) ;
00232 if (step < 1) {
00233 vlmxError(vlmxErrInvalidArgument,
00234 "SUBSAMPLE must be not less than one.") ;
00235 }
00236 break ;
00237
00238 case opt_kernel :
00239 {
00240 enum {buflen = 32} ;
00241 char buf [buflen] ;
00242 if (!vlmxIsString(optarg, -1)) {
00243 vlmxError(vlmxErrInvalidArgument,
00244 "KERNEL argument must be a string.") ;
00245 }
00246 mxGetString(optarg, buf, buflen) ;
00247 buf [buflen - 1] = 0 ;
00248 if (vlmxCompareStringsI("gaussian", buf) == 0) {
00249 kernel = GAUSSIAN ;
00250 } else if (vlmxCompareStringsI("triangular", buf) == 0) {
00251 kernel = TRIANGULAR ;
00252 } else {
00253 vlmxError(vlmxErrInvalidArgument,
00254 "Unknown kernel type '%s'.",
00255 buf) ;
00256 }
00257 break ;
00258 }
00259
00260 case opt_verbose :
00261 ++ verb ;
00262 break ;
00263
00264 default:
00265 abort() ;
00266 }
00267 }
00268
00269 if (! vlmxIsPlainScalar(IN(S))) {
00270 vlmxError(vlmxErrInvalidArgument,
00271 "S must be a real scalar.") ;
00272 }
00273
00274 classid = mxGetClassID(IN(I)) ;
00275
00276 if (classid != mxDOUBLE_CLASS &&
00277 classid != mxSINGLE_CLASS) {
00278 vlmxError(vlmxErrInvalidArgument,
00279 "I must be either DOUBLE or SINGLE.") ;
00280 }
00281 if (mxGetNumberOfDimensions(IN(I)) > 3) {
00282 vlmxError(vlmxErrInvalidArgument,
00283 "I must be either a two or three dimensional array.") ;
00284 }
00285
00286 ndims = mxGetNumberOfDimensions(IN(I)) ;
00287 dims = mxGetDimensions(IN(I)) ;
00288 M = dims[0] ;
00289 N = dims[1] ;
00290 K = (ndims > 2) ? dims[2] : 1 ;
00291
00292 sigma = * mxGetPr(IN(S)) ;
00293 if ((sigma < 0.01) && (step == 1)) {
00294 OUT(J) = mxDuplicateArray(IN(I)) ;
00295 return ;
00296 }
00297
00298 M_ = (M - 1) / step + 1 ;
00299 N_ = (N - 1) / step + 1 ;
00300 dims_ [0] = M_ ;
00301 dims_ [1] = N_ ;
00302 if (ndims > 2) dims_ [2] = K ;
00303
00304 OUT(J) = mxCreateNumericArray(ndims, dims_, classid, mxREAL) ;
00305
00306 if (verb) {
00307 char const *classid_str = 0, *kernel_str = 0, *padding_str = 0 ;
00308 switch (padding) {
00309 case VL_PAD_BY_ZERO : padding_str = "with zeroes" ; break ;
00310 case VL_PAD_BY_CONTINUITY : padding_str = "by continuity" ; break ;
00311 default: abort() ;
00312 }
00313 switch (classid) {
00314 case mxDOUBLE_CLASS: classid_str = "DOUBLE" ; break ;
00315 case mxSINGLE_CLASS: classid_str = "SINGLE" ; break ;
00316 default: abort() ;
00317 }
00318 switch (kernel) {
00319 case GAUSSIAN: kernel_str = "Gaussian" ; break ;
00320 case TRIANGULAR: kernel_str = "triangular" ; break ;
00321 default: abort() ;
00322 }
00323
00324 mexPrintf("vl_imsmooth: [%dx%dx%d] -> [%dx%dx%d] (%s, subsampling step %d)\n",
00325 N, M, K, N_, M_, K, classid_str, step) ;
00326 mexPrintf("vl_imsmooth: padding: %s\n", padding_str) ;
00327 mexPrintf("vl_imsmooth: kernel: %s\n", kernel_str) ;
00328 mexPrintf("vl_imsmooth: sigma: %g\n", sigma) ;
00329 mexPrintf("vl_imsmooth: SIMD enabled: %s\n",
00330 vl_get_simd_enabled() ? "yes" : "no") ;
00331 }
00332
00333
00334
00335
00336 flags = padding ;
00337 flags |= VL_TRANSPOSE ;
00338
00339 switch (classid) {
00340 case mxSINGLE_CLASS:
00341 _vl_imsmooth_smooth_f ((float*) mxGetPr(OUT(J)),
00342 M_, N_,
00343 (float const*) mxGetPr(IN(I)),
00344 M, N, K,
00345 kernel, sigma, step, flags) ;
00346 break ;
00347
00348 case mxDOUBLE_CLASS:
00349 _vl_imsmooth_smooth_d ((double*) mxGetPr(OUT(J)),
00350 M_, N_,
00351 (double const*) mxGetPr(IN(I)),
00352 M, N, K,
00353 kernel, sigma, step, flags) ;
00354 break ;
00355
00356 default:
00357 abort() ;
00358 }
00359 }
00360
00361
00362 #endif