vl_imsmooth.c
Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
00009 All rights reserved.
00010 
00011 This file is part of the VLFeat library and is made available under
00012 the terms of the BSD license (see the COPYING file).
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   /* Note that MATLAB uses a column major ordering, while VLFeat a row
00047      major (standard) ordering for the image data. Effectively, VLFeat
00048      is operating on a transposed image, but this is fine since filters
00049      are symmetric.
00050 
00051      Therefore:
00052 
00053      input image width  = numRows
00054      input image height = numColumns
00055      output image width = numOutputRows (downsamped rows)
00056      outout image height = numOutputColumns (downsampled columns)
00057 
00058      In addition a temporary buffer is used. This is an image that
00059      is obtained from the input image by convolving and downsampling
00060      along the height and saving the result transposed:
00061 
00062      temp image width  = numOutputColumns
00063      temp image height = numRows
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 /* VL_IMSMOOTH_INSTANTIATING */
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 /* option codes */
00143 enum {
00144   opt_padding = 0,
00145   opt_subsample,
00146   opt_kernel,
00147   opt_verbose
00148 } ;
00149 
00150 /* options */
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    *                                               Check the arguments
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    *                                                        Do the job
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 /* VL_IMSMOOTH_INSTANTIATING */
00362 #endif


libvlfeat
Author(s): Andrea Vedaldi
autogenerated on Thu Jun 6 2019 20:25:51