VL_EXPORT int vl_pgm_write_f (char const *name, float const* data, int width, int height) { int err = 0 ; int k ; float min = + VL_INFINITY_F ; float max = - VL_INFINITY_F ; float scale ; vl_uint8 * buffer = (vl_uint8*)vl_malloc (sizeof(float) * width * height) ; for (k = 0 ; k < width * height ; ++k) { min = VL_MIN(min, data [k]) ; max = VL_MAX(max, data [k]) ; } scale = 255 / (max - min + VL_EPSILON_F) ; for (k = 0 ; k < width * height ; ++k) { buffer [k] = (vl_uint8) ((data [k] - min) * scale) ; } err = vl_pgm_write (name, buffer, width, height) ; vl_free (buffer) ; return err ; }
VL_INLINE double vl_homogeneouskernelmap_get_smooth_spectrum (VlHomogeneousKernelMap const * self, double omega) { double kappa_hat = 0 ; double omegap ; double epsilon = 1e-2 ; double const omegaRange = 2.0 / (self->period * epsilon) ; double const domega = 2 * omegaRange / (2 * 1024.0 + 1) ; assert (self) ; switch (self->windowType) { case VlHomogeneousKernelMapWindowUniform: kappa_hat = vl_homogeneouskernelmap_get_spectrum(self, omega) ; break ; case VlHomogeneousKernelMapWindowRectangular: for (omegap = - omegaRange ; omegap <= omegaRange ; omegap += domega) { double win = sinc((self->period/2.0) * omegap) ; win *= (self->period/(2.0*VL_PI)) ; kappa_hat += win * vl_homogeneouskernelmap_get_spectrum(self, omegap + omega) ; } kappa_hat *= domega ; /* project on the postivie orthant (see PAMI) */ kappa_hat = VL_MAX(kappa_hat, 0.0) ; break ; default: abort() ; } return kappa_hat ; }
static void _vl_scalespace_start_octave_from_image (VlScaleSpace *self, float const *image, vl_index o) { float *level ; double sigma, imageSigma ; vl_index op ; assert(self) ; assert(image) ; assert(o >= self->geom.firstOctave) ; assert(o <= self->geom.lastOctave) ; /* * Copy the image to self->geom.octaveFirstSubdivision of octave o, upscaling or * downscaling as needed. */ level = vl_scalespace_get_level(self, VL_MAX(0, o), self->geom.octaveFirstSubdivision) ; copy_and_downsample(level, image, self->geom.width, self->geom.height, VL_MAX(0, o)) ; for (op = -1 ; op >= o ; --op) { VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, op + 1) ; float *succLevel = vl_scalespace_get_level(self, op + 1, self->geom.octaveFirstSubdivision) ; level = vl_scalespace_get_level(self, op, self->geom.octaveFirstSubdivision) ; copy_and_upsample(level, succLevel, ogeom.width, ogeom.height) ; } /* * Adjust the smoothing of the first level just initialised, accounting * for the fact that the input image is assumed to be a nominal scale * level. */ sigma = vl_scalespace_get_level_sigma(self, o, self->geom.octaveFirstSubdivision) ; imageSigma = self->geom.nominalScale ; if (sigma > imageSigma) { VlScaleSpaceOctaveGeometry ogeom = vl_scalespace_get_octave_geometry(self, o) ; double deltaSigma = sqrt (sigma*sigma - imageSigma*imageSigma) ; level = vl_scalespace_get_level (self, o, self->geom.octaveFirstSubdivision) ; vl_imsmooth_f (level, ogeom.width, level, ogeom.width, ogeom.height, ogeom.width, deltaSigma / ogeom.step, deltaSigma / ogeom.step) ; } }
VL_EXPORT T VL_XCAT(_vl_distance_l1_, SFX) (vl_size dimension, T const * X, T const * Y) { T const * X_end = X + dimension ; T acc = 0.0 ; while (X < X_end) { T d = *X++ - *Y++ ; acc += VL_MAX(d, -d) ; } return acc ; }
VL_EXPORT VlQS * vl_quickshift_new(vl_qs_type const * image, int height, int width, int channels) { VlQS * q = vl_malloc(sizeof(VlQS)); q->image = (vl_qs_type *)image; q->height = height; q->width = width; q->channels = channels; q->medoid = VL_FALSE; q->tau = VL_MAX(height,width)/50; q->sigma = VL_MAX(2, q->tau/3); q->dists = vl_calloc(height*width, sizeof(vl_qs_type)); q->parents = vl_calloc(height*width, sizeof(int)); q->density = vl_calloc(height*width, sizeof(vl_qs_type)) ; return q; }
VlScaleSpaceGeometry vl_scalespace_get_default_geometry (vl_size width, vl_size height) { VlScaleSpaceGeometry geom ; assert(width >= 1) ; assert(height >= 1) ; geom.width = width ; geom.height = height ; geom.firstOctave = 0 ; geom.lastOctave = VL_MAX(floor(vl_log2_d(VL_MIN(width, height))) - 3, 0) ; geom.octaveResolution= 3 ; geom.octaveFirstSubdivision = 0 ; geom.octaveLastSubdivision = geom.octaveResolution - 1 ; geom.baseScale = 1.6 * pow(2.0, 1.0 / geom.octaveResolution) ; geom.nominalScale = 0.5 ; return geom ; }
void vl_hog_render (VlHog const * self, float * image, float const * descriptor, vl_size width, vl_size height) { vl_index x, y, k, cx, cy ; vl_size hogStride = width * height ; assert(self) ; assert(image) ; assert(descriptor) ; assert(width > 0) ; assert(height > 0) ; for (y = 0 ; y < (signed)height ; ++y) { for (x = 0 ; x < (signed)width ; ++x) { float minWeight = 0 ; float maxWeight = 0 ; for (k = 0 ; k < (signed)self->numOrientations ; ++k) { float weight ; float const * glyph = self->glyphs + k * (self->glyphSize*self->glyphSize) ; float * glyphImage = image + self->glyphSize * x + y * width * (self->glyphSize*self->glyphSize) ; switch (self->variant) { case VlHogVariantUoctti: weight = descriptor[k * hogStride] + descriptor[(k + self->numOrientations) * hogStride] + descriptor[(k + 2 * self->numOrientations) * hogStride] ; break ; case VlHogVariantDalalTriggs: weight = descriptor[k * hogStride] + descriptor[(k + self->numOrientations) * hogStride] + descriptor[(k + 2 * self->numOrientations) * hogStride] + descriptor[(k + 3 * self->numOrientations) * hogStride] ; break ; default: abort() ; } maxWeight = VL_MAX(weight, maxWeight) ; minWeight = VL_MIN(weight, minWeight); for (cy = 0 ; cy < (signed)self->glyphSize ; ++cy) { for (cx = 0 ; cx < (signed)self->glyphSize ; ++cx) { *glyphImage++ += weight * (*glyph++) ; } glyphImage += (width - 1) * self->glyphSize ; } } /* next orientation */ { float * glyphImage = image + self->glyphSize * x + y * width * (self->glyphSize*self->glyphSize) ; for (cy = 0 ; cy < (signed)self->glyphSize ; ++cy) { for (cx = 0 ; cx < (signed)self->glyphSize ; ++cx) { float value = *glyphImage ; *glyphImage++ = VL_MAX(minWeight, VL_MIN(maxWeight, value)) ; } glyphImage += (width - 1) * self->glyphSize ; } } ++ descriptor ; } /* next column of cells (x) */ } /* next row of cells (y) */ }
/** @brief Driver. ** ** @param nount number of output arguments. ** @param out output arguments. ** @param nin number of input arguments. ** @param in input arguments. **/ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum { IN_H, IN_ID, IN_NEXT, IN_K, IN_X } ; enum { OUT_H, OUT_ID, OUT_NEXT} ; mxArray *h_, *id_, *next_ ; vl_uint32 * h ; vl_uint32 * next ; vl_uint8 * id ; vl_uint8 const * x ; unsigned int K, i, N, res, last, ndims ; /* ----------------------------------------------------------------- * Check arguments * -------------------------------------------------------------- */ if( nin != 5 ) { mexErrMsgTxt("Five arguments required") ; } else if (nout > 3) { mexErrMsgTxt("At most three output argument.") ; } if(! mxIsNumeric(in[IN_H]) || mxGetClassID(in[IN_H] )!= mxUINT32_CLASS || ! mxIsNumeric(in[IN_NEXT])|| mxGetClassID(in[IN_NEXT])!= mxUINT32_CLASS) { mexErrMsgTxt("H, NEXT must be UINT32.") ; } if(! mxIsNumeric(in[IN_X]) || mxGetClassID(in[IN_X]) != mxUINT8_CLASS) { mexErrMsgTxt("X must be UINT8") ; } if (mxGetM(in[IN_H]) != 1 || mxGetM(in[IN_NEXT]) != 1) { mexErrMsgTxt("H, NEXT must be row vectors") ; } if(! mxIsNumeric(in[IN_ID]) || mxGetClassID(in[IN_ID])!= mxUINT8_CLASS) { mexErrMsgTxt("ID must be UINT8.") ; } ndims = mxGetM(in[IN_ID]) ; res = mxGetN(in[IN_H]) ; if(res != mxGetN(in[IN_ID]) || res != mxGetN(in[IN_NEXT])) { mexErrMsgTxt("H, ID, NEXT must have the same number of columns") ; } if(ndims != mxGetM(in[IN_X])) { mexErrMsgTxt("ID and X must havethe same number of rows") ; } if(! uIsRealScalar(in[IN_K])) { mexErrMsgTxt("K must be a scalar") ; } K = (unsigned int) *mxGetPr(in[IN_K]) ; h_ = mxDuplicateArray(in[IN_H]) ; id_ = mxDuplicateArray(in[IN_ID]) ; next_ = mxDuplicateArray(in[IN_NEXT]) ; N = mxGetN(in[IN_X]) ; h = mxGetData(h_ ) ; id = mxGetData(id_ ) ; next = mxGetData(next_) ; x = mxGetData(in[IN_X]) ; /* Temporary remove mxArray pointers to these buffer as we will mxRealloc them and if the user presses Ctrl-C matlab will attempt to free unvalid memory */ mxSetData(h_, 0) ; mxSetData(id_, 0) ; mxSetData(next_, 0) ; /* search for last occupied slot */ last = res ; for (i = 0 ; i < res ; ++i) last = VL_MAX(last, next [i]) ; /* REMARK: last and next are 1 based */ if (K > res) { mexErrMsgTxt("K cannot be larger then the size of H") ; } if (last > res) { mexErrMsgTxt("An element of NEXT is greater than the size of the table") ; } /* mexPrintf("last:%d\n",last) ;*/ /* ----------------------------------------------------------------- * Do job * -------------------------------------------------------------- */ for (i = 0 ; i < N ; ++i) { /* hash */ unsigned int h1, h2 ; unsigned int j, p = 0 ; h1 = fnv_hash(x + i * ndims, ndims) % K ; h2 = h1 | 0x1 ; /* this needs to be odd */ /* search first free or matching position */ p = h1 % K ; for (j = 0 ; j < K ; ++j) { if (is_null (id + p * ndims, ndims) || is_equal(id + p * ndims, x + i * ndims, ndims)) break ; h1 += h2 ; p = h1 % K ; } /* search or make a free slot in the bucket */ while (! is_null (id + p * ndims, ndims) && ! is_equal(id + p * ndims, x + i * ndims, ndims)) { if (next [p] > res) { mexErrMsgTxt("An element of NEXT is greater than the size of the table") ; } /* append */ if (next [p] == 0) { if (last >= res) { size_t res_ = res + VL_MAX(res / 2, 2) ; h = mxRealloc(h, res_ * sizeof(vl_uint32) ) ; next = mxRealloc(next, res_ * sizeof(vl_uint32) ) ; id = mxRealloc(id, res_ * sizeof(vl_uint8) * ndims) ; memset (h + res, 0, (res_ - res) * sizeof(vl_uint32) ) ; memset (next + res, 0, (res_ - res) * sizeof(vl_uint32) ) ; memset (id + res * ndims, 0, (res_ - res) * sizeof(vl_uint8) * ndims) ; res = res_ ; } next [p] = ++ last ; } p = next [p] - 1 ; } /* accumulate */ h [p] += 1 ; /* mexPrintf("p %d dims %d i %d N %d\n ", p, ndims, i, N) ;*/ cpy(id + p * ndims, x + i * ndims, ndims) ; } mxSetData(h_, mxRealloc(h, last * sizeof(vl_uint32) )) ; mxSetData(next_, mxRealloc(next, last * sizeof(vl_uint32) )) ; mxSetData(id_, mxRealloc(id, last * sizeof(vl_uint8 ) * ndims)) ; mxSetN(h_, last) ; mxSetN(id_, last) ; mxSetN(next_, last) ; mxSetM(h_, 1) ; mxSetM(next_, 1) ; mxSetM(id_, ndims) ; out[OUT_H] = h_ ; out[OUT_ID] = id_ ; out[OUT_NEXT] = next_ ; }
/* ---------------------------------------------------------------- */ void VL_XCAT3(_vl_imconvcol_v, SFX, _sse2) (T* dst, int dst_stride, T const* src, int src_width, int src_height, int src_stride, T const* filt, int filt_begin, int filt_end, int step, unsigned int flags) { int x = 0 ; int y ; int dheight = (src_height - 1) / step + 1 ; vl_bool use_simd = VALIGNED(src_stride) ; vl_bool transp = flags & VL_TRANSPOSE ; vl_bool zeropad = (flags & VL_PAD_MASK) == VL_PAD_BY_ZERO ; double totcol = 0 ; double simdcol = 0 ; /* let filt point to the last sample of the filter */ filt += filt_end - filt_begin ; while (x < src_width) { /* Calculate dest[x,y] = sum_p image[x,p] filt[y - p] * where supp(filt) = [filt_begin, filt_end] = [fb,fe]. * * CHUNK_A: y - fe <= p < 0 * completes VL_MAX(fe - y, 0) samples * CHUNK_B: VL_MAX(y - fe, 0) <= p < VL_MIN(y - fb, height - 1) * completes fe - VL_MAX(fb, height - y) + 1 samples * CHUNK_C: completes all samples */ T const *filti ; int stop ; if ((x + VSIZE < src_width) & VALIGNED(src + x) & use_simd) { /* ---------------------------------------------- Vectorized */ for (y = 0 ; y < src_height ; y += step) { union { VTYPE v ; T x [VSIZE] ; } acc ; VTYPE v, c ; T const *srci ; acc.v = VSTZ () ; v = VSTZ() ; filti = filt ; stop = filt_end - y ; srci = src + x - stop * src_stride ; if (stop > 0) { if (zeropad) { v = VSTZ () ; } else { v = * (VTYPE*) (src + x) ; } while (filti > filt - stop) { c = VLD1 (filti--) ; acc.v = VADD (acc.v, VMUL (v, c)) ; srci += src_stride ; } } stop = filt_end - VL_MAX(filt_begin, y - src_height + 1) + 1 ; while (filti > filt - stop) { v = * (VTYPE*) srci ; c = VLD1 (filti--) ; acc.v = VADD (acc.v, VMUL (v, c)) ; srci += src_stride ; } if (zeropad) v = VSTZ () ; stop = filt_end - filt_begin + 1; while (filti > filt - stop) { c = VLD1 (filti--) ; acc.v = VADD (acc.v, VMUL (v, c)) ; } if (transp) { *dst = acc.x[0] ; dst += dst_stride ; *dst = acc.x[1] ; dst += dst_stride ; #if(VSIZE == 4) *dst = acc.x[2] ; dst += dst_stride ; *dst = acc.x[3] ; dst += dst_stride ; #endif dst += 1 * 1 - VSIZE * dst_stride ; } else { *dst = acc.x[0] ; dst += 1 ; *dst = acc.x[1] ; dst += 1 ; #if(VSIZE == 4) *dst = acc.x[2] ; dst += 1 ; *dst = acc.x[3] ; dst += 1 ; #endif dst += 1 * dst_stride - VSIZE * 1 ; } } /* next y */ if (transp) { dst += VSIZE * dst_stride - dheight * 1 ; } else { dst += VSIZE * 1 - dheight * dst_stride ; } x += VSIZE ; simdcol += VSIZE ; totcol += VSIZE ; } else { /* ------------------------------------------------- Vanilla */ for (y = 0 ; y < src_height ; y += step) { T acc = 0 ; T v = 0, c ; T const* srci ; filti = filt ; stop = filt_end - y ; srci = src + x - stop * src_stride ; if (stop > 0) { if (zeropad) { v = 0 ; } else { v = *(src + x) ; } while (filti > filt - stop) { c = *filti-- ; acc += v * c ; srci += src_stride ; } } stop = filt_end - VL_MAX(filt_begin, y - src_height + 1) + 1 ; while (filti > filt - stop) { v = *srci ; c = *filti-- ; acc += v * c ; srci += src_stride ; } if (zeropad) v = 0 ; stop = filt_end - filt_begin + 1 ; while (filti > filt - stop) { c = *filti-- ; acc += v * c ; } if (transp) { *dst = acc ; dst += 1 ; } else { *dst = acc ; dst += dst_stride ; } } /* next y */ if (transp) { dst += 1 * dst_stride - dheight * 1 ; } else { dst += 1 * 1 - dheight * dst_stride ; } x += 1 ; totcol += 1 ; } /* next x */ } }
/** @brief MEX driver. ** @param nout number of MATLAB output arguments. ** @param out MATLAB output arguments. ** @param nin number of MATLAB input arguments. ** @param in MATLAB input arguments. **/ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { int M, N, NE ; double* Xpt ; double* Wpt ; double* EDGESpt ; double* RESpt ; enum {X=0, W, EDGES} ; /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (nin != 3) { mexErrMsgTxt("Three arguments required."); } else if (nout > 1) { mexErrMsgTxt("Too many output arguments."); } if (!mxIsDouble(in[X]) || !mxIsDouble(in[W]) || !mxIsDouble(in[W])) { mexErrMsgTxt("The arguments must be real matrices.") ; } M = mxGetM(in[X]) ; N = mxGetN(in[X]) ; if( M != mxGetM(in[W]) || N != mxGetN(in[W]) ) { mexErrMsgTxt("X and W must have the same dimension.") ; } if(VL_MIN( mxGetM(in[EDGES]), mxGetN(in[EDGES]) ) != 1) { mexErrMsgTxt("EDGES must be a vector.") ; } NE = VL_MAX(mxGetM(in[EDGES]), mxGetN(in[EDGES])) ; if(NE < 2) { mexErrMsgTxt("At least two edges are required.\n") ; } Xpt = mxGetPr(in[X]) ; Wpt = mxGetPr(in[W]) ; EDGESpt = mxGetPr(in[EDGES]) ; { double x = EDGESpt[0] ; int j ; int ok = 1 ; for(j = 1 ; j < NE ; ++j) { ok &= (x < EDGESpt[j]) ; x = EDGESpt[j] ; } if(!ok) mexErrMsgTxt("EDGES must be increasing.") ; } /*if(nout == 0) return ;*/ /* If the input is a vector, make it a column. */ if(M == 1) { M = N ; N = 1 ; } /* Alloc the result. */ out[0] = mxCreateDoubleMatrix(NE, N, mxREAL) ; RESpt = mxGetPr(out[0]) ; /** ----------------------------------------------------------------- ** Do the job ** -------------------------------------------------------------- */ { pairs_t* pairs = mxMalloc(sizeof(pairs_t)*M) ; int e, i, j ; double c = 0 ; double* RESiterator = RESpt ; double* Xiterator = Xpt ; double* Witerator = Wpt ; for(j = 0 ; j < N ; ++j) { e = 0; for(i = 0 ; i < M ; ++i) { pairs[i].x = *Xiterator++ ; pairs[i].w = *Witerator++ ; } qsort(pairs, M, sizeof(pairs_t), cmp_pairs) ; /* Head */ for(i = 0 ; pairs[i].x < EDGESpt[e] ; ++i) ; /* Body */ while(i < M) { c = 0 ; e += 1 ; if(e == NE) break ; for( ; pairs[i].x < EDGESpt[e] && i < M ; ++i) c += pairs[i].w ; RESiterator[e-1] = c ; } /* Tail */ c = 0 ; for( ; pairs[i].x == EDGESpt[NE-1] && i < M ; ++i) c += pairs[i].w ; RESiterator[NE-1] = c ; /* Next column */ RESiterator += NE ; } mxFree(pairs) ; } return ; }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum {IN_I = 0, IN_END} ; enum {OUT_FRAMES=0, OUT_DESCRIPTORS, OUT_INFO, OUT_END} ; int verbose = 0 ; int opt ; int next = IN_END ; mxArray const *optarg ; VlEnumerator *pair ; float const *image ; vl_size numCols, numRows ; VlCovDetMethod method = VL_COVDET_METHOD_DOG; vl_bool estimateAffineShape = VL_FALSE ; vl_bool estimateOrientation = VL_FALSE ; vl_bool doubleImage = VL_TRUE ; vl_index octaveResolution = -1 ; double edgeThreshold = -1 ; double peakThreshold = -1 ; double lapPeakThreshold = -1 ; int descriptorType = -1 ; vl_index patchResolution = -1 ; double patchRelativeExtent = -1 ; double patchRelativeSmoothing = -1 ; float *patch = NULL ; float *patchXY = NULL ; vl_int liopNumSpatialBins = 6; vl_int liopNumNeighbours = 4; float liopRadius = 6.0; float liopIntensityThreshold = VL_NAN_F ; double boundaryMargin = 2.0 ; double * userFrames = NULL ; vl_size userFrameDimension = 0 ; vl_size numUserFrames = 0 ; VL_USE_MATLAB_ENV ; /* ----------------------------------------------------------------- * Check the arguments * -------------------------------------------------------------- */ if (nin < IN_END) { vlmxError(vlmxErrNotEnoughInputArguments, 0) ; } else if (nout > OUT_END) { vlmxError(vlmxErrTooManyOutputArguments, 0) ; } if (mxGetNumberOfDimensions(IN(I)) != 2 || mxGetClassID(IN(I)) != mxSINGLE_CLASS){ vlmxError(vlmxErrInvalidArgument, "I must be a matrix of class SINGLE.") ; } image = (float*) mxGetData(IN(I)) ; numRows = mxGetM(IN(I)) ; numCols = mxGetN(IN(I)) ; while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) { switch (opt) { case opt_verbose : ++ verbose ; break ; case opt_method: pair = vlmxDecodeEnumeration(optarg, vlCovdetMethods, VL_TRUE) ; if (pair == NULL) { vlmxError(vlmxErrInvalidArgument, "METHOD is not a supported detection method.") ; } method = (VlCovDetMethod)pair->value ; break; case opt_descriptor: pair = vlmxDecodeEnumeration(optarg, vlCovDetDescriptorTypes, VL_TRUE) ; if (pair == NULL) { vlmxError(vlmxErrInvalidArgument, "DESCRIPTOR is not a supported descriptor.") ; } descriptorType = (VlCovDetDescriptorType)pair->value ; break; case opt_estimate_affine_shape: if (!mxIsLogicalScalar(optarg)) { vlmxError(vlmxErrInvalidArgument, "ESTIMATEAFFINESHAPE must be a logical scalar value.") ; } else { estimateAffineShape = *mxGetLogicals(optarg) ; } break ; case opt_estimate_orientation: if (!mxIsLogicalScalar(optarg)) { vlmxError(vlmxErrInvalidArgument, "ESTIMATEORIENTATION must be a logical scalar value.") ; } else { estimateOrientation = *mxGetLogicals(optarg); } break ; case opt_double_image: if (!mxIsLogicalScalar(optarg)) { vlmxError(vlmxErrInvalidArgument, "DOUBLEIMAGE must be a logical scalar value.") ; } else { doubleImage = *mxGetLogicals(optarg); } break ; case opt_octave_resolution : if (!vlmxIsPlainScalar(optarg) || (octaveResolution = (vl_index)*mxGetPr(optarg)) < 1) { vlmxError(vlmxErrInvalidArgument, "OCTAVERESOLUTION must be an integer not smaller than 1.") ; } break ; case opt_edge_threshold : if (!vlmxIsPlainScalar(optarg) || (edgeThreshold = *mxGetPr(optarg)) < 1) { vlmxError(vlmxErrInvalidArgument, "EDGETHRESHOLD must be a real not smaller than 1.") ; } break ; case opt_peak_threshold : if (!vlmxIsPlainScalar(optarg) || (peakThreshold = *mxGetPr(optarg)) < 0) { vlmxError(vlmxErrInvalidArgument, "PEAKTHRESHOLD must be a non-negative real.") ; } break ; case opt_laplacian_peak_threshold : if (!vlmxIsPlainScalar(optarg) || (lapPeakThreshold = *mxGetPr(optarg)) < 0) { vlmxError(vlmxErrInvalidArgument, "LAPLACIANPEAKTHRESHOLD must be a non-negative real.") ; } break ; case opt_patch_relative_smoothing : if (!vlmxIsPlainScalar(optarg) || (patchRelativeSmoothing = *mxGetPr(optarg)) < 0) { vlmxError(vlmxErrInvalidArgument, "PATCHRELATIVESMOOTHING must be a non-negative real.") ; } break ; case opt_patch_relative_extent : if (!vlmxIsPlainScalar(optarg) || (patchRelativeExtent = *mxGetPr(optarg)) <= 0) { vlmxError(vlmxErrInvalidArgument, "PATCHRELATIVEEXTENT must be a posiive real.") ; } break ; case opt_patch_resolution : if (!vlmxIsPlainScalar(optarg) || (patchResolution = (vl_index)*mxGetPr(optarg)) <= 0) { vlmxError(vlmxErrInvalidArgument, "PATCHRESOLUTION must be a positive integer.") ; } break ; case opt_liop_bins : if (!vlmxIsPlainScalar(optarg) || (liopNumSpatialBins = (vl_int)*mxGetPr(optarg)) <= 0) { vlmxError(vlmxErrInvalidArgument, "number of LIOPNUMSPATIALBINS is not a positive scalar.") ; } break ; case opt_liop_neighbours : if (!vlmxIsPlainScalar(optarg) || (liopNumNeighbours = (vl_int)*mxGetPr(optarg)) <= 0) { vlmxError(vlmxErrInvalidArgument, "number of LIOPNUMNEIGHBOURS is not a positive scalar.") ; } break ; case opt_liop_radius : if (!vlmxIsPlainScalar(optarg) || (liopRadius = (float)*mxGetPr(optarg)) <= 0) { vlmxError(vlmxErrInvalidArgument, "LIOPRADIUS must is not a positive scalar.") ; } break ; case opt_liop_threshold : if (!vlmxIsPlainScalar(optarg)) { vlmxError(vlmxErrInvalidArgument, "LIOPINTENSITYTHRESHOLD is not a scalar.") ; } liopIntensityThreshold = *mxGetPr(optarg) ; break ; case opt_frames: if (!vlmxIsPlainMatrix(optarg,-1,-1)) { vlmxError(vlmxErrInvalidArgument, "FRAMES must be a palin matrix.") ; } numUserFrames = mxGetN (optarg) ; userFrameDimension = mxGetM (optarg) ; userFrames = mxGetPr (optarg) ; switch (userFrameDimension) { case 2: case 3: case 4: case 5: case 6: /* ok */ break ; default: vlmxError(vlmxErrInvalidArgument, "FRAMES of dimensions %d are not recognised", userFrameDimension); ; } break ; default : abort() ; } } if (descriptorType < 0) descriptorType = VL_COVDET_DESC_SIFT ; switch (descriptorType) { case VL_COVDET_DESC_NONE : break ; case VL_COVDET_DESC_PATCH : if (patchResolution < 0) patchResolution = 20 ; if (patchRelativeExtent < 0) patchRelativeExtent = 6 ; if (patchRelativeSmoothing < 0) patchRelativeSmoothing = 1 ; break ; case VL_COVDET_DESC_SIFT : /* the patch parameters are selected to match the SIFT descriptor geometry */ if (patchResolution < 0) patchResolution = 15 ; if (patchRelativeExtent < 0) patchRelativeExtent = 7.5 ; if (patchRelativeSmoothing < 0) patchRelativeSmoothing = 1 ; break ; case VL_COVDET_DESC_LIOP : if (patchResolution < 0) patchResolution = 20 ; if (patchRelativeExtent < 0) patchRelativeExtent = 4 ; if (patchRelativeSmoothing < 0) patchRelativeSmoothing = 0.5 ; break ; } if (patchResolution > 0) { vl_size w = 2*patchResolution + 1 ; patch = mxMalloc(sizeof(float) * w * w); patchXY = mxMalloc(2 * sizeof(float) * w * w); } if (descriptorType == VL_COVDET_DESC_LIOP && liopRadius > patchResolution) { vlmxError(vlmxErrInconsistentData, "LIOPRADIUS is larger than PATCHRESOLUTION.") ; } /* ----------------------------------------------------------------- * Detector * -------------------------------------------------------------- */ { VlCovDet * covdet = vl_covdet_new(method) ; /* set covdet parameters */ vl_covdet_set_transposed(covdet, VL_TRUE) ; vl_covdet_set_first_octave(covdet, doubleImage ? -1 : 0) ; if (octaveResolution >= 0) vl_covdet_set_octave_resolution(covdet, octaveResolution) ; if (peakThreshold >= 0) vl_covdet_set_peak_threshold(covdet, peakThreshold) ; if (edgeThreshold >= 0) vl_covdet_set_edge_threshold(covdet, edgeThreshold) ; if (lapPeakThreshold >= 0) vl_covdet_set_laplacian_peak_threshold(covdet, lapPeakThreshold) ; if (verbose) { VL_PRINTF("vl_covdet: doubling image: %s\n", VL_YESNO(vl_covdet_get_first_octave(covdet) < 0)) ; } /* process the image */ vl_covdet_put_image(covdet, image, numRows, numCols) ; /* fill with frames: eitehr run the detector of poure them in */ if (numUserFrames > 0) { vl_index k ; if (verbose) { mexPrintf("vl_covdet: sourcing %d frames\n", numUserFrames) ; } for (k = 0 ; k < (signed)numUserFrames ; ++k) { double const * uframe = userFrames + userFrameDimension * k ; double a11, a21, a12, a22 ; VlCovDetFeature feature ; feature.peakScore = VL_INFINITY_F ; feature.edgeScore = 1.0 ; feature.frame.x = (float)uframe[1] - 1 ; feature.frame.y = (float)uframe[0] - 1 ; switch (userFrameDimension) { case 2: a11 = 1.0 ; a21 = 0.0 ; a12 = 0.0 ; a22 = 1.0 ; break ; case 3: a11 = uframe[2] ; a21 = 0.0 ; a12 = 0.0 ; a22 = uframe[2] ; break ; case 4: { double sigma = uframe[2] ; double c = cos(uframe[3]) ; double s = sin(uframe[3]) ; a11 = sigma * c ; a21 = sigma * s ; a12 = sigma * (-s) ; a22 = sigma * c ; break ; } case 5: { double d2 ; if (uframe[2] < 0) { vlmxError(vlmxErrInvalidArgument, "FRAMES(:,%d) does not have a PSD covariance.", k+1) ; } a11 = sqrt(uframe[2]) ; a21 = uframe[3] / VL_MAX(a11, 1e-10) ; a12 = 0.0 ; d2 = uframe[4] - a21*a21 ; if (d2 < 0) { vlmxError(vlmxErrInvalidArgument, "FRAMES(:,%d) does not have a PSD covariance.", k+1) ; } a22 = sqrt(d2) ; break ; } case 6: { a11 = uframe[2] ; a21 = uframe[3] ; a12 = uframe[4] ; a22 = uframe[5] ; break ; } default: a11 = 0 ; a21 = 0 ; a12 = 0 ; a22 = 0 ; assert(0) ; } feature.frame.a11 = (float)a22 ; feature.frame.a21 = (float)a12 ; feature.frame.a12 = (float)a21 ; feature.frame.a22 = (float)a11 ; vl_covdet_append_feature(covdet, &feature) ; } } else { if (verbose) { mexPrintf("vl_covdet: detector: %s\n", vl_enumeration_get_by_value(vlCovdetMethods, method)->name) ; mexPrintf("vl_covdet: peak threshold: %g, edge threshold: %g\n", vl_covdet_get_peak_threshold(covdet), vl_covdet_get_edge_threshold(covdet)) ; } vl_covdet_detect(covdet) ; if (verbose) { vl_index i ; vl_size numFeatures = vl_covdet_get_num_features(covdet) ; mexPrintf("vl_covdet: %d features suppressed as duplicate (threshold: %g)\n", vl_covdet_get_num_non_extrema_suppressed(covdet), vl_covdet_get_non_extrema_suppression_threshold(covdet)) ; switch (method) { case VL_COVDET_METHOD_HARRIS_LAPLACE: case VL_COVDET_METHOD_HESSIAN_LAPLACE: { vl_size numScales ; vl_size const * numFeaturesPerScale ; numFeaturesPerScale = vl_covdet_get_laplacian_scales_statistics (covdet, &numScales) ; mexPrintf("vl_covdet: Laplacian scales:") ; for (i = 0 ; i <= (signed)numScales ; ++i) { mexPrintf("%d with %d scales;", numFeaturesPerScale[i], i) ; } mexPrintf("\n") ; } break ; default: break ; } mexPrintf("vl_covdet: detected %d features\n", numFeatures) ; } if (boundaryMargin > 0) { vl_covdet_drop_features_outside (covdet, boundaryMargin) ; if (verbose) { vl_size numFeatures = vl_covdet_get_num_features(covdet) ; mexPrintf("vl_covdet: kept %d inside the boundary margin (%g)\n", numFeatures, boundaryMargin) ; } } } /* affine adaptation if needed */ if (estimateAffineShape) { if (verbose) { vl_size numFeaturesBefore = vl_covdet_get_num_features(covdet) ; mexPrintf("vl_covdet: estimating affine shape for %d features\n", numFeaturesBefore) ; } vl_covdet_extract_affine_shape(covdet) ; if (verbose) { vl_size numFeaturesAfter = vl_covdet_get_num_features(covdet) ; mexPrintf("vl_covdet: %d features passed affine adaptation\n", numFeaturesAfter) ; } } /* orientation estimation if needed */ if (estimateOrientation) { vl_size numFeaturesBefore = vl_covdet_get_num_features(covdet) ; vl_size numFeaturesAfter ; vl_covdet_extract_orientations(covdet) ; numFeaturesAfter = vl_covdet_get_num_features(covdet) ; if (verbose && numFeaturesAfter > numFeaturesBefore) { mexPrintf("vl_covdet: %d duplicate features were crated due to ambiguous " "orientation detection (%d total)\n", numFeaturesAfter - numFeaturesBefore, numFeaturesAfter) ; } } /* store results back */ { vl_index i ; vl_size numFeatures = vl_covdet_get_num_features(covdet) ; VlCovDetFeature const * feature = vl_covdet_get_features(covdet); double * pt ; OUT(FRAMES) = mxCreateDoubleMatrix (6, numFeatures, mxREAL) ; pt = mxGetPr(OUT(FRAMES)) ; for (i = 0 ; i < (signed)numFeatures ; ++i) { /* save the transposed frame, adjust origin to MATLAB's*/ *pt++ = feature[i].frame.y + 1 ; *pt++ = feature[i].frame.x + 1 ; *pt++ = feature[i].frame.a22 ; *pt++ = feature[i].frame.a12 ; *pt++ = feature[i].frame.a21 ; *pt++ = feature[i].frame.a11 ; } } if (nout >= 2) { switch (descriptorType) { case VL_COVDET_DESC_NONE: OUT(DESCRIPTORS) = mxCreateDoubleMatrix(0,0,mxREAL); break ; case VL_COVDET_DESC_PATCH: { vl_size numFeatures ; VlCovDetFeature const * feature ; vl_index i ; vl_size w = 2*patchResolution + 1 ; float * desc ; if (verbose) { mexPrintf("vl_covdet: descriptors: type=patch, " "resolution=%d, extent=%g, smoothing=%g\n", patchResolution, patchRelativeExtent, patchRelativeSmoothing); } numFeatures = vl_covdet_get_num_features(covdet) ; feature = vl_covdet_get_features(covdet); OUT(DESCRIPTORS) = mxCreateNumericMatrix(w*w, numFeatures, mxSINGLE_CLASS, mxREAL) ; desc = mxGetData(OUT(DESCRIPTORS)) ; for (i = 0 ; i < (signed)numFeatures ; ++i) { vl_covdet_extract_patch_for_frame(covdet, desc, patchResolution, patchRelativeExtent, patchRelativeSmoothing, feature[i].frame) ; desc += w*w ; } break ; } case VL_COVDET_DESC_SIFT: { vl_size numFeatures = vl_covdet_get_num_features(covdet) ; VlCovDetFeature const * feature = vl_covdet_get_features(covdet); VlSiftFilt * sift = vl_sift_new(16, 16, 1, 3, 0) ; vl_index i ; vl_size dimension = 128 ; vl_size patchSide = 2 * patchResolution + 1 ; double patchStep = (double)patchRelativeExtent / patchResolution ; float tempDesc [128] ; float * desc ; if (verbose) { mexPrintf("vl_covdet: descriptors: type=sift, " "resolution=%d, extent=%g, smoothing=%g\n", patchResolution, patchRelativeExtent, patchRelativeSmoothing); } OUT(DESCRIPTORS) = mxCreateNumericMatrix(dimension, numFeatures, mxSINGLE_CLASS, mxREAL) ; desc = mxGetData(OUT(DESCRIPTORS)) ; vl_sift_set_magnif(sift, 3.0) ; for (i = 0 ; i < (signed)numFeatures ; ++i) { vl_covdet_extract_patch_for_frame(covdet, patch, patchResolution, patchRelativeExtent, patchRelativeSmoothing, feature[i].frame) ; vl_imgradient_polar_f (patchXY, patchXY +1, 2, 2 * patchSide, patch, patchSide, patchSide, patchSide) ; /* Note: the patch is transposed, so that x and y are swapped. However, if NBO is not divisible by 4, then the configuration of the SIFT orientations is not symmetric by rotations of pi/2. Hence the only option is to rotate the descriptor further by an angle we need to compute the descriptor rotaed by an additional pi/2 angle. In this manner, x concides and y is flipped. */ vl_sift_calc_raw_descriptor (sift, patchXY, tempDesc, (int)patchSide, (int)patchSide, (double)(patchSide-1) / 2, (double)(patchSide-1) / 2, (double)patchRelativeExtent / (3.0 * (4 + 1) / 2) / patchStep, VL_PI / 2) ; flip_descriptor (desc, tempDesc) ; desc += dimension ; } vl_sift_delete(sift) ; break ; } case VL_COVDET_DESC_LIOP : { /* TODO: get parameters form input */ vl_size numFeatures = vl_covdet_get_num_features(covdet) ; vl_size dimension ; VlCovDetFeature const * feature = vl_covdet_get_features(covdet); vl_index i ; vl_size patchSide = 2 * patchResolution + 1 ; float * desc ; VlLiopDesc * liop = vl_liopdesc_new(liopNumNeighbours, liopNumSpatialBins, liopRadius, (vl_size)patchSide) ; if (!vl_is_nan_f(liopIntensityThreshold)) { vl_liopdesc_set_intensity_threshold(liop, liopIntensityThreshold) ; } dimension = vl_liopdesc_get_dimension(liop) ; if (verbose) { mexPrintf("vl_covdet: descriptors: type=liop, " "resolution=%d, extent=%g, smoothing=%g\n", patchResolution, patchRelativeExtent, patchRelativeSmoothing); } OUT(DESCRIPTORS) = mxCreateNumericMatrix(dimension, numFeatures, mxSINGLE_CLASS, mxREAL); desc = mxGetData(OUT(DESCRIPTORS)) ; vl_tic(); for(i = 0; i < (signed)numFeatures; i++){ vl_covdet_extract_patch_for_frame(covdet, patch, patchResolution, patchRelativeExtent, patchRelativeSmoothing, feature[i].frame); vl_liopdesc_process(liop, desc, patch); desc += dimension; } mexPrintf("time: %f\n",vl_toc()); mexPrintf("threshold: %f\n",liop->intensityThreshold); break; } default: assert(0) ; /* descriptor type */ } } if (nout >= 3) { vl_index i ; vl_size numFeatures = vl_covdet_get_num_features(covdet) ; VlCovDetFeature const * feature = vl_covdet_get_features(covdet); const char* names[] = { "gss", "css", "peakScores", "edgeScores", "orientationScore", "laplacianScaleScore" }; mxArray * gss_array = _createArrayFromScaleSpace(vl_covdet_get_gss(covdet)) ; mxArray * css_array = _createArrayFromScaleSpace(vl_covdet_get_css(covdet)) ; mxArray * peak_array = mxCreateNumericMatrix(1,numFeatures,mxSINGLE_CLASS,mxREAL) ; mxArray * edge_array = mxCreateNumericMatrix(1,numFeatures,mxSINGLE_CLASS,mxREAL) ; mxArray * orientation_array = mxCreateNumericMatrix(1,numFeatures,mxSINGLE_CLASS,mxREAL) ; mxArray * laplacian_array = mxCreateNumericMatrix(1,numFeatures,mxSINGLE_CLASS,mxREAL) ; float * peak = mxGetData(peak_array) ; float * edge = mxGetData(edge_array) ; float * orientation = mxGetData(orientation_array) ; float * laplacian = mxGetData(laplacian_array) ; for (i = 0 ; i < (signed)numFeatures ; ++i) { peak[i] = feature[i].peakScore ; edge[i] = feature[i].edgeScore ; orientation[i] = feature[i].orientationScore ; laplacian[i] = feature[i].laplacianScaleScore ; } OUT(INFO) = mxCreateStructMatrix(1, 1, 6, names) ; mxSetFieldByNumber(OUT(INFO), 0, 0, gss_array) ; mxSetFieldByNumber(OUT(INFO), 0, 1, css_array) ; mxSetFieldByNumber(OUT(INFO), 0, 2, peak_array) ; mxSetFieldByNumber(OUT(INFO), 0, 3, edge_array) ; mxSetFieldByNumber(OUT(INFO), 0, 4, orientation_array) ; mxSetFieldByNumber(OUT(INFO), 0, 5, laplacian_array) ; } /* cleanup */ vl_covdet_delete (covdet) ; } if (patchXY) mxFree(patchXY) ; if (patch) mxFree(patch) ; }
/* driver */ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum { MANIP_STATE, RUN_GENERATOR } mode ; VlRand * rand ; VL_USE_MATLAB_ENV ; rand = vl_get_rand() ; /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (nout > 1) { vlmxError(vlmxErrTooManyInputArguments, NULL) ; } if (nin > 0 && ! mxIsNumeric(in[0])) { mode = MANIP_STATE ; } else { mode = RUN_GENERATOR ; } switch (mode) { case RUN_GENERATOR: { enum { maxNumDimensions = 30 } ; vl_size numDimensions = 2, n ; vl_uindex k ; mwSize dimensions [maxNumDimensions] = {1, 1} ; double * x ; if (nin > 1) { /* TWISTER(N1 N2 ...) style */ if (nin >= maxNumDimensions) { vlmxError(vlmxErrTooManyInputArguments, "Too many dimensions specified.") ; } for (k = 0 ; k < (unsigned)nin ; ++k) { if (! vlmxIsPlainScalar(in[k])) { vlmxError(vlmxErrInvalidArgument, "The %d-th argument is not a plain scalar.", k + 1) ; } if (mxGetScalar(in[k]) < 0) { vlmxError(vlmxErrInvalidArgument, "The %d-th argument is negative.", k + 1) ; } dimensions[k] = mxGetScalar(in[k]) ; } numDimensions = k ; } else if (nin == 1) { /* TWISTER([N1 N2 ...]) style */ if (! vlmxIsPlainVector(in[0], -1)) { vlmxError(vlmxErrInvalidArgument, "The argument is not a plain vector.") ; } x = mxGetPr(in[0]) ; n = mxGetNumberOfElements(in[0]) ; numDimensions = VL_MAX(2, n) ; if (numDimensions > maxNumDimensions) { vlmxError(vlmxErrInvalidArgument, "Too many dimensions specified.") ; } if (n == 1) { if (*x < 0) { vlmxError(vlmxErrInvalidArgument, "The specified dimension is negative.") ; } dimensions[0] = dimensions[1] = *x ; } else { for (k = 0 ; k < n ; ++k) { if (x[k] < 0) { vlmxError(vlmxErrInvalidArgument, "One of the specified dimensions is negative.") ; } dimensions[k] = x[k] ; } } } out[0] = mxCreateNumericArray (numDimensions, dimensions, mxDOUBLE_CLASS, mxREAL) ; n = mxGetNumberOfElements (out[0]) ; x = mxGetPr (out[0]) ; for (k = 0 ; k < n ; ++k) { x[k] = vl_rand_res53(rand) ; } } break ; case MANIP_STATE: { enum { buff_size = 32 } ; char buff [buff_size] ; /* check for 'state' string */ if (! vlmxIsString(in[0], -1) || mxGetString(in[0], buff, buff_size) || vl_string_casei_cmp ("state", buff) != 0 ) { vlmxError(vlmxErrInvalidArgument, NULL) ; } /* TWISTER('state') */ if (nin == 1) { vl_uindex i ; vl_uint32 * data ; out[0] = mxCreateNumericMatrix (625, 1, mxUINT32_CLASS, mxREAL) ; data = mxGetData(out[0]) ; for (i = 0 ; i < 624 ; ++i) data[i] = rand->mt[i] ; data[624] = (vl_uint32) rand->mti ; } else { if (vlmxIsPlainScalar(in[1])) { /* TWISTER('state', X) */ vl_uint32 x = (vl_uint32) mxGetScalar(in[1]) ; vl_rand_seed (rand, x) ; } else if (mxIsNumeric(in[1]) && mxGetClassID(in[1]) == mxUINT32_CLASS && mxGetNumberOfElements(in[1]) == 624+1 && ((vl_uint32 const*)mxGetData(in[1]))[624] <= 624 ) { /* TWISTER('state', STATE) */ vl_uindex i ; vl_uint32 * data = mxGetData(in[1]) ; for (i = 0 ; i < 624 ; ++i) rand->mt[i] = data[i] ; rand->mti = data [624] ; } else if (mxIsNumeric(in[1]) && mxGetClassID(in[1]) == mxDOUBLE_CLASS && mxGetNumberOfElements(in[1]) <= 624) { /* TWISTER('state', KEY) */ vl_uint32 key [624] ; double const * x = mxGetPr(in[1]) ; vl_size n = mxGetNumberOfElements(in[1]) ; vl_uindex k ; for (k = 0 ; k < n ; ++k) { key [k] = x [k] ; } vl_rand_seed_by_array (rand, key, n) ; } } } break ; default: abort() ; } }
void vl_hog_extract (VlHog * self, float * features) { vl_index x, y ; vl_uindex k ; vl_size hogStride = self->hogWidth * self->hogHeight ; assert(features) ; #define at(x,y,k) (self->hog[(x) + (y) * self->hogWidth + (k) * hogStride]) #define atNorm(x,y) (self->hogNorm[(x) + (y) * self->hogWidth]) /* Computes the squared L2 norm of each HOG cell. This is the norm of the undirected orientation histogram, counting only numOrientations. This histogram is obtained by folding the 2*numOrientations directed orientations that are computed. */ { float const * iter = self->hog ; for (k = 0 ; k < self->numOrientations ; ++k) { float * niter = self->hogNorm ; float * niterEnd = self->hogNorm + self->hogWidth * self->hogHeight ; vl_size stride = self->hogWidth*self->hogHeight*self->numOrientations ; while (niter != niterEnd) { float h1 = *iter ; float h2 = *(iter + stride) ; float h = h1 + h2 ; *niter += h * h ; niter++ ; iter++ ; } } } /* HOG block-normalisation. For each cell, there are four 2x2 blocks covering it. For example, the cell number 5 in the following scheme is covered by the four blocks 1245, 2356, 4578, 5689. +---+---+---+ | 1 | 2 | 3 | +---+---+---+ | 4 | 5 | 6 | +---+---+---+ | 7 | 8 | 9 | +---+---+---+ In the Dalal-Triggs implementation, one forms all possible 2x2 blocks of cells, computes a descriptor vector for each by stacking the corresponding 2x2 HOG cells, and L2 normalizes (and truncates) the result. Thus each HOG cell appears in four blocks. These are then decomposed again to produce descriptors for each cell. Each descriptor is simply the stacking of the portion of each block descriptor that arised from that cell. This process result in a descriptor of each cell which contains four copies of the original HOG, with four different normalization factors. @remark By stacking together the cell descriptors for a large retangular block of cells, one effectively stacks together the block descriptors of an equal number of blocks (except for the boundaries, for which blocks are only partially included). Since blocks are L2 normalized (up to truncation), this implies that the L2 norm of the resulting vector is approximately equal to the area of the region. */ { float const * iter = self->hog ; for (y = 0 ; y < (signed)self->hogHeight ; ++y) { for (x = 0 ; x < (signed)self->hogWidth ; ++x) { /* norm of upper-left, upper-right, ... blocks */ vl_index xm = VL_MAX(x - 1, 0) ; vl_index xp = VL_MIN(x + 1, (signed)self->hogWidth - 1) ; vl_index ym = VL_MAX(y - 1, 0) ; vl_index yp = VL_MIN(y + 1, (signed)self->hogHeight - 1) ; double norm1 = atNorm(xm,ym) ; double norm2 = atNorm(x,ym) ; double norm3 = atNorm(xp,ym) ; double norm4 = atNorm(xm,y) ; double norm5 = atNorm(x,y) ; double norm6 = atNorm(xp,y) ; double norm7 = atNorm(xm,yp) ; double norm8 = atNorm(x,yp) ; double norm9 = atNorm(xp,yp) ; double factor1, factor2, factor3, factor4 ; double t1 = 0 ; double t2 = 0 ; double t3 = 0 ; double t4 = 0 ; float * oiter = features + x + self->hogWidth * y ; /* each factor is the inverse of the l2 norm of one of the 2x2 blocks surrounding cell x,y */ #if 0 if (self->transposed) { /* if the image is transposed, y and x are swapped */ factor1 = 1.0 / VL_MAX(sqrt(norm1 + norm2 + norm4 + norm5), 1e-10) ; factor3 = 1.0 / VL_MAX(sqrt(norm2 + norm3 + norm5 + norm6), 1e-10) ; factor2 = 1.0 / VL_MAX(sqrt(norm4 + norm5 + norm7 + norm8), 1e-10) ; factor4 = 1.0 / VL_MAX(sqrt(norm5 + norm6 + norm8 + norm9), 1e-10) ; } else { factor1 = 1.0 / VL_MAX(sqrt(norm1 + norm2 + norm4 + norm5), 1e-10) ; factor2 = 1.0 / VL_MAX(sqrt(norm2 + norm3 + norm5 + norm6), 1e-10) ; factor3 = 1.0 / VL_MAX(sqrt(norm4 + norm5 + norm7 + norm8), 1e-10) ; factor4 = 1.0 / VL_MAX(sqrt(norm5 + norm6 + norm8 + norm9), 1e-10) ; } #else /* as implemented in UOCTTI code */ if (self->transposed) { /* if the image is transposed, y and x are swapped */ factor1 = 1.0 / sqrt(norm1 + norm2 + norm4 + norm5 + 1e-4) ; factor3 = 1.0 / sqrt(norm2 + norm3 + norm5 + norm6 + 1e-4) ; factor2 = 1.0 / sqrt(norm4 + norm5 + norm7 + norm8 + 1e-4) ; factor4 = 1.0 / sqrt(norm5 + norm6 + norm8 + norm9 + 1e-4) ; } else { factor1 = 1.0 / sqrt(norm1 + norm2 + norm4 + norm5 + 1e-4) ; factor2 = 1.0 / sqrt(norm2 + norm3 + norm5 + norm6 + 1e-4) ; factor3 = 1.0 / sqrt(norm4 + norm5 + norm7 + norm8 + 1e-4) ; factor4 = 1.0 / sqrt(norm5 + norm6 + norm8 + norm9 + 1e-4) ; } #endif for (k = 0 ; k < self->numOrientations ; ++k) { double ha = iter[hogStride * k] ; double hb = iter[hogStride * (k + self->numOrientations)] ; double hc ; double ha1 = factor1 * ha ; double ha2 = factor2 * ha ; double ha3 = factor3 * ha ; double ha4 = factor4 * ha ; double hb1 = factor1 * hb ; double hb2 = factor2 * hb ; double hb3 = factor3 * hb ; double hb4 = factor4 * hb ; double hc1 = ha1 + hb1 ; double hc2 = ha2 + hb2 ; double hc3 = ha3 + hb3 ; double hc4 = ha4 + hb4 ; ha1 = VL_MIN(0.2, ha1) ; ha2 = VL_MIN(0.2, ha2) ; ha3 = VL_MIN(0.2, ha3) ; ha4 = VL_MIN(0.2, ha4) ; hb1 = VL_MIN(0.2, hb1) ; hb2 = VL_MIN(0.2, hb2) ; hb3 = VL_MIN(0.2, hb3) ; hb4 = VL_MIN(0.2, hb4) ; hc1 = VL_MIN(0.2, hc1) ; hc2 = VL_MIN(0.2, hc2) ; hc3 = VL_MIN(0.2, hc3) ; hc4 = VL_MIN(0.2, hc4) ; t1 += hc1 ; t2 += hc2 ; t3 += hc3 ; t4 += hc4 ; switch (self->variant) { case VlHogVariantUoctti : ha = 0.5 * (ha1 + ha2 + ha3 + ha4) ; hb = 0.5 * (hb1 + hb2 + hb3 + hb4) ; hc = 0.5 * (hc1 + hc2 + hc3 + hc4) ; *oiter = ha ; *(oiter + hogStride * self->numOrientations) = hb ; *(oiter + 2 * hogStride * self->numOrientations) = hc ; break ; case VlHogVariantDalalTriggs : *oiter = hc1 ; *(oiter + hogStride * self->numOrientations) = hc2 ; *(oiter + 2 * hogStride * self->numOrientations) = hc3 ; *(oiter + 3 * hogStride * self->numOrientations) = hc4 ; break ; } oiter += hogStride ; } /* next orientation */ switch (self->variant) { case VlHogVariantUoctti : oiter += 2 * hogStride * self->numOrientations ; *oiter = (1.0f/sqrtf(18.0f)) * t1 ; oiter += hogStride ; *oiter = (1.0f/sqrtf(18.0f)) * t2 ; oiter += hogStride ; *oiter = (1.0f/sqrtf(18.0f)) * t3 ; oiter += hogStride ; *oiter = (1.0f/sqrtf(18.0f)) * t4 ; oiter += hogStride ; break ; case VlHogVariantDalalTriggs : break ; } ++iter ; } /* next x */ } /* next y */ } /* block normalization */ }
/** ------------------------------------------------------------------ ** @internal ** @brief MEX driver **/ void mexFunction (int nout, mxArray * out[], int nin, const mxArray * in[]) { vl_uint8 *data ; enum {IN_DATA = 0, IN_K, IN_NLEAVES, IN_END} ; enum {OUT_TREE = 0, OUT_ASGN} ; int M, N, K = 2, depth = 0 ; int opt ; int next = IN_END ; mxArray const *optarg ; int nleaves = 1 ; int method_type = VL_IKM_LLOYD ; int max_niters = 200 ; int verb = 0 ; VlHIKMTree* tree ; VL_USE_MATLAB_ENV ; /* ------------------------------------------------------------------ * Check the arguments * --------------------------------------------------------------- */ if (nin < 3) { mexErrMsgTxt ("At least three arguments required."); } else if (nout > 2) { mexErrMsgTxt ("Too many output arguments."); } if (mxGetClassID (in[IN_DATA]) != mxUINT8_CLASS) { mexErrMsgTxt ("DATA must be of class UINT8."); } if (! vlmxIsPlainScalar (in[IN_NLEAVES]) || (nleaves = (int) *mxGetPr (in[IN_NLEAVES])) < 1) { mexErrMsgTxt ("NLEAVES must be a scalar not smaller than 2.") ; } M = mxGetM (in[IN_DATA]); /* n of components */ N = mxGetN (in[IN_DATA]); /* n of elements */ if (! vlmxIsPlainScalar (in[IN_K]) || (K = (int) *mxGetPr (in[IN_K])) > N ) { mexErrMsgTxt ("Cannot have more clusters than data.") ; } data = (vl_uint8 *) mxGetPr (in[IN_DATA]) ; while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) { char buf [1024] ; switch (opt) { case opt_verbose : ++ verb ; break ; case opt_max_niters : if (!vlmxIsPlainScalar(optarg) || (max_niters = (int) *mxGetPr(optarg)) < 1) { mexErrMsgTxt("MaxNiters must be not smaller than 1.") ; } break ; case opt_method : if (!vlmxIsString (optarg, -1)) { mexErrMsgTxt("'Method' must be a string.") ; } if (mxGetString (optarg, buf, sizeof(buf))) { mexErrMsgTxt("Option argument too long.") ; } if (strcmp("lloyd", buf) == 0) { method_type = VL_IKM_LLOYD ; } else if (strcmp("elkan", buf) == 0) { method_type = VL_IKM_ELKAN ; } else { mexErrMsgTxt("Unknown cost type.") ; } break ; default : abort() ; break ; } } /* --------------------------------------------------------------- * Do the job * ------------------------------------------------------------ */ depth = VL_MAX(1, ceil (log (nleaves) / log(K))) ; tree = vl_hikm_new (method_type) ; if (verb) { mexPrintf("hikmeans: # dims: %d\n", M) ; mexPrintf("hikmeans: # data: %d\n", N) ; mexPrintf("hikmeans: K: %d\n", K) ; mexPrintf("hikmeans: depth: %d\n", depth) ; } vl_hikm_set_verbosity (tree, verb) ; vl_hikm_init (tree, M, K, depth) ; vl_hikm_train (tree, data, N) ; out[OUT_TREE] = hikm_to_matlab (tree) ; if (nout > 1) { vl_uint *asgn ; int j ; out [OUT_ASGN] = mxCreateNumericMatrix (vl_hikm_get_depth (tree), N, mxUINT32_CLASS, mxREAL) ; asgn = mxGetData(out[OUT_ASGN]) ; vl_hikm_push (tree, asgn, data, N) ; for (j = 0 ; j < N*depth ; ++ j) asgn [j] ++ ; } if (verb) { mexPrintf("hikmeans: done.\n") ; } /* vl_hikm_delete (tree) ; */ }
VL_EXPORT void VL_XCAT(vl_imconvcol_v, SFX) (T* dst, vl_size dst_stride, T const* src, vl_size src_width, vl_size src_height, vl_size src_stride, T const* filt, vl_index filt_begin, vl_index filt_end, int step, unsigned int flags) { vl_index x = 0 ; vl_index y ; vl_index dheight = (src_height - 1) / step + 1 ; vl_bool transp = flags & VL_TRANSPOSE ; vl_bool zeropad = (flags & VL_PAD_MASK) == VL_PAD_BY_ZERO ; /* dispatch to accelerated version */ #ifndef VL_DISABLE_SSE2 if (vl_cpu_has_sse2() && vl_get_simd_enabled()) { VL_XCAT3(_vl_imconvcol_v,SFX,_sse2) (dst,dst_stride, src,src_width,src_height,src_stride, filt,filt_begin,filt_end, step,flags) ; return ; } #endif /* let filt point to the last sample of the filter */ filt += filt_end - filt_begin ; while (x < (signed)src_width) { /* Calculate dest[x,y] = sum_p image[x,p] filt[y - p] * where supp(filt) = [filt_begin, filt_end] = [fb,fe]. * * CHUNK_A: y - fe <= p < 0 * completes VL_MAX(fe - y, 0) samples * CHUNK_B: VL_MAX(y - fe, 0) <= p < VL_MIN(y - fb, height - 1) * completes fe - VL_MAX(fb, height - y) + 1 samples * CHUNK_C: completes all samples */ T const *filti ; vl_index stop ; for (y = 0 ; y < (signed)src_height ; y += step) { T acc = 0 ; T v = 0, c ; T const* srci ; filti = filt ; stop = filt_end - y ; srci = src + x - stop * src_stride ; if (stop > 0) { if (zeropad) { v = 0 ; } else { v = *(src + x) ; } while (filti > filt - stop) { c = *filti-- ; acc += v * c ; srci += src_stride ; } } stop = filt_end - VL_MAX(filt_begin, y - (signed)src_height + 1) + 1 ; while (filti > filt - stop) { v = *srci ; c = *filti-- ; acc += v * c ; srci += src_stride ; } if (zeropad) v = 0 ; stop = filt_end - filt_begin + 1 ; while (filti > filt - stop) { c = *filti-- ; acc += v * c ; } if (transp) { *dst = acc ; dst += 1 ; } else { *dst = acc ; dst += dst_stride ; } } /* next y */ if (transp) { dst += 1 * dst_stride - dheight * 1 ; } else { dst += 1 * 1 - dheight * dst_stride ; } x += 1 ; } /* next x */ }
void quickshift(image_t im, float sigma, float tau, float * map, float * gaps, float * E) { int verb = 1 ; float *M = 0, *n = 0; float tau2; int K, d; int N1,N2, i1,i2, j1,j2, R, tR; int medoid = 0 ; float const * I = im.I; N1 = im.N1; N2 = im.N2; K = im.K; d = 2 + K ; /* Total dimensions include spatial component (x,y) */ tau2 = tau*tau; if (medoid) { /* n and M are only used in mediod shift */ M = (float *) calloc(N1*N2*d, sizeof(float)) ; n = (float *) calloc(N1*N2, sizeof(float)) ; } R = (int) ceil (3 * sigma) ; tR = (int) ceil (tau) ; if (verb) { printf("quickshift: [N1,N2,K]: [%d,%d,%d]\n", N1,N2,K) ; printf("quickshift: type: %s\n", medoid ? "medoid" : "quick"); printf("quickshift: sigma: %g\n", sigma) ; /* R is ceil(3 * sigma) and determines the window size to accumulate * similarity */ printf("quickshift: R: %d\n", R) ; printf("quickshift: tau: %g\n", tau) ; printf("quickshift: tR: %d\n", tR) ; } /* ----------------------------------------------------------------- * n * -------------------------------------------------------------- */ /* If we are doing medoid shift, initialize n to the inner product of the * image with itself */ if (n) { for (i2 = 0 ; i2 < N2 ; ++ i2) { for (i1 = 0 ; i1 < N1 ; ++ i1) { n [i1 + N1 * i2] = inner(I,N1,N2,K, i1,i2, i1,i2) ; } } } unsigned int Etimer; cutilCheckError( cutCreateTimer(&Etimer) ); cutilCheckError( cutResetTimer(Etimer) ); cutilCheckError( cutStartTimer(Etimer) ); /* ----------------------------------------------------------------- * E = - [oN'*F]', M * -------------------------------------------------------------- */ /* D_ij = d(x_i,x_j) E_ij = exp(- .5 * D_ij / sigma^2) ; F_ij = - E_ij E_i = sum_j E_ij M_di = sum_j X_j F_ij E is the parzen window estimate of the density 0 = dissimilar to everything, windowsize = identical */ for (i2 = 0 ; i2 < N2 ; ++ i2) { for (i1 = 0 ; i1 < N1 ; ++ i1) { float Ei = 0; int j1min = VL_MAX(i1 - R, 0 ) ; int j1max = VL_MIN(i1 + R, N1-1) ; int j2min = VL_MAX(i2 - R, 0 ) ; int j2max = VL_MIN(i2 + R, N2-1) ; /* For each pixel in the window compute the distance between it and the * source pixel */ for (j2 = j2min ; j2 <= j2max ; ++ j2) { for (j1 = j1min ; j1 <= j1max ; ++ j1) { float Dij = distance(I,N1,N2,K, i1,i2, j1,j2) ; /* Make distance a similarity */ float Fij = exp(- Dij / (2*sigma*sigma)) ; /* E is E_i above */ Ei += Fij; if (M) { /* Accumulate votes for the median */ int k ; M [i1 + N1*i2 + (N1*N2) * 0] += j1 * Fij ; M [i1 + N1*i2 + (N1*N2) * 1] += j2 * Fij ; for (k = 0 ; k < K ; ++k) { M [i1 + N1*i2 + (N1*N2) * (k+2)] += I [j1 + N1*j2 + (N1*N2) * k] * Fij ; } } } /* j1 */ } /* j2 */ /* Normalize */ E [i1 + N1 * i2] = Ei / ((j1max-j1min)*(j2max-j2min)); /*E [i1 + N1 * i2] = Ei ; */ } /* i1 */ } /* i2 */ cutilCheckError( cutStopTimer(Etimer) ); float ETime = cutGetTimerValue(Etimer); printf("ComputeE: %fms\n", ETime); unsigned int Ntimer; cutilCheckError( cutCreateTimer(&Ntimer) ); cutilCheckError( cutResetTimer(Ntimer) ); cutilCheckError( cutStartTimer(Ntimer) ); /* ----------------------------------------------------------------- * Find best neighbors * -------------------------------------------------------------- */ if (medoid) { /* Qij = - nj Ei - 2 sum_k Gjk Mik n is I.^2 */ /* medoid shift */ for (i2 = 0 ; i2 < N2 ; ++i2) { for (i1 = 0 ; i1 < N1 ; ++i1) { float sc_best = 0 ; /* j1/j2 best are the best indicies for each i */ float j1_best = i1 ; float j2_best = i2 ; int j1min = VL_MAX(i1 - R, 0 ) ; int j1max = VL_MIN(i1 + R, N1-1) ; int j2min = VL_MAX(i2 - R, 0 ) ; int j2max = VL_MIN(i2 + R, N2-1) ; for (j2 = j2min ; j2 <= j2max ; ++ j2) { for (j1 = j1min ; j1 <= j1max ; ++ j1) { float Qij = - n [j1 + j2 * N1] * E [i1 + i2 * N1] ; int k ; Qij -= 2 * j1 * M [i1 + i2 * N1 + (N1*N2) * 0] ; Qij -= 2 * j2 * M [i1 + i2 * N1 + (N1*N2) * 1] ; for (k = 0 ; k < K ; ++k) { Qij -= 2 * I [j1 + j2 * N1 + (N1*N2) * k] * M [i1 + i2 * N1 + (N1*N2) * (k + 2)] ; } if (Qij > sc_best) { sc_best = Qij ; j1_best = j1 ; j2_best = j2 ; } } } /* map_i is the linear index of j which is the best pair (in matlab * notation * gaps_i is the score of the best match */ map [i1 + N1 * i2] = j1_best + N1 * j2_best ; /*+ 1 ; */ gaps[i1 + N1 * i2] = sc_best ; } } } else { /* Quickshift assigns each i to the closest j which has an increase in the * density (E). If there is no j s.t. Ej > Ei, then gaps_i == inf (a root * node in one of the trees of merges). */ for (i2 = 0 ; i2 < N2 ; ++i2) { for (i1 = 0 ; i1 < N1 ; ++i1) { float E0 = E [i1 + N1 * i2] ; float d_best = INF ; float j1_best = i1 ; float j2_best = i2 ; int j1min = VL_MAX(i1 - tR, 0 ) ; int j1max = VL_MIN(i1 + tR, N1-1) ; int j2min = VL_MAX(i2 - tR, 0 ) ; int j2max = VL_MIN(i2 + tR, N2-1) ; for (j2 = j2min ; j2 <= j2max ; ++ j2) { for (j1 = j1min ; j1 <= j1max ; ++ j1) { if (E [j1 + N1 * j2] > E0) { float Dij = distance(I,N1,N2,K, i1,i2, j1,j2) ; if (Dij <= tau2 && Dij < d_best) { d_best = Dij ; j1_best = j1 ; j2_best = j2 ; } } } } /* map is the index of the best pair */ /* gaps_i is the minimal distance, inf implies no Ej > Ei within * distance tau from the point */ map [i1 + N1 * i2] = j1_best + N1 * j2_best ; /* + 1 ; */ if (map[i1 + N1 * i2] != i1 + N1 * i2) gaps[i1 + N1 * i2] = sqrt(d_best) ; else gaps[i1 + N1 * i2] = d_best; /* inf */ } } } if (M) free(M) ; if (n) free(n) ; cutilCheckError( cutStopTimer(Ntimer) ); float NTime = cutGetTimerValue(Ntimer); printf("ComputeN: %fms\n", NTime); }
VL_EXPORT void vl_irodrigues(double* om_pt, double* dom_pt, const double* R_pt) { /* tr R - 1 1 [ R32 - R23 ] th = cos^{-1} --------, r = ------ [ R13 - R31 ], w = th r. 2 2 sth [ R12 - R21 ] sth = sin(th) dw th*cth-sth dw th [di3 dj2 - di2 dj3] ---- = ---------- r, ---- = ----- [di1 dj3 - di3 dj1]. dRii 2 sth^2 dRij 2 sth [di1 dj2 - di2 dj1] trace(A) < -1 only for small num. errors. */ #define OM(i) om_pt[(i)] #define DOM(i,j) dom_pt[(i)+3*(j)] #define R(i,j) R_pt[(i)+3*(j)] #define W(i,j) W_pt[(i)+3*(j)] const double small = 1e-6 ; double th = acos (0.5*(VL_MAX(R(0,0)+R(1,1)+R(2,2),-1.0) - 1.0)) ; double sth = sin(th) ; double cth = cos(th) ; if(fabs(sth) < small && cth < 0) { /* we have this singularity when the rotation is about pi (or -pi) we use the fact that in this case hat( sqrt(1-cth) * r )^2 = W = (0.5*(R+R') - eye(3)) which gives (1-cth) rx^2 = 0.5 * (W(1,1)-W(2,2)-W(3,3)) (1-cth) ry^2 = 0.5 * (W(2,2)-W(3,3)-W(1,1)) (1-cth) rz^2 = 0.5 * (W(3,3)-W(1,1)-W(2,2)) */ double W_pt [9], x, y, z ; W_pt[0] = 0.5*( R(0,0) + R(0,0) ) - 1.0 ; W_pt[1] = 0.5*( R(1,0) + R(0,1) ) ; W_pt[2] = 0.5*( R(2,0) + R(0,2) ); W_pt[3] = 0.5*( R(0,1) + R(1,0) ); W_pt[4] = 0.5*( R(1,1) + R(1,1) ) - 1.0; W_pt[5] = 0.5*( R(2,1) + R(1,2) ); W_pt[6] = 0.5*( R(0,2) + R(2,0) ) ; W_pt[7] = 0.5*( R(1,2) + R(2,1) ) ; W_pt[8] = 0.5*( R(2,2) + R(2,2) ) - 1.0 ; /* these are only absolute values */ x = sqrt( 0.5 * (W(0,0)-W(1,1)-W(2,2)) ) ; y = sqrt( 0.5 * (W(1,1)-W(2,2)-W(0,0)) ) ; z = sqrt( 0.5 * (W(2,2)-W(0,0)-W(1,1)) ) ; /* set the biggest component to + and use the element of the ** matrix W to determine the sign of the other components ** then the solution is either (x,y,z) or its opposite */ if( x >= y && x >= z ) { y = (W(1,0) >=0) ? y : -y ; z = (W(2,0) >=0) ? z : -z ; } else if( y >= x && y >= z ) { z = (W(2,1) >=0) ? z : -z ; x = (W(1,0) >=0) ? x : -x ; } else { x = (W(2,0) >=0) ? x : -x ; y = (W(2,1) >=0) ? y : -y ; } /* we are left to chose between (x,y,z) and (-x,-y,-z) ** unfortunately we cannot (as the rotation is too close to pi) and ** we just keep what we have. */ { double scale = th / sqrt( 1 - cth ) ; OM(0) = scale * x ; OM(1) = scale * y ; OM(2) = scale * z ; if( dom_pt ) { int k ; for(k=0; k<3*9; ++k) dom_pt [k] = VL_NAN_D ; } return ; } } else { double a = (fabs(sth) < small) ? 1 : th/sin(th) ; double b ; OM(0) = 0.5*a*(R(2,1) - R(1,2)) ; OM(1) = 0.5*a*(R(0,2) - R(2,0)) ; OM(2) = 0.5*a*(R(1,0) - R(0,1)) ; if( dom_pt ) { if( fabs(sth) < small ) { a = 0.5 ; b = 0 ; } else { a = th/(2*sth) ; b = (th*cth - sth)/(2*sth*sth)/th ; } DOM(0,0) = b*OM(0) ; DOM(1,0) = b*OM(1) ; DOM(2,0) = b*OM(2) ; DOM(0,1) = 0 ; DOM(1,1) = 0 ; DOM(2,1) = a ; DOM(0,2) = 0 ; DOM(1,2) = -a ; DOM(2,2) = 0 ; DOM(0,3) = 0 ; DOM(1,3) = 0 ; DOM(2,3) = -a ; DOM(0,4) = b*OM(0) ; DOM(1,4) = b*OM(1) ; DOM(2,4) = b*OM(2) ; DOM(0,5) = a ; DOM(1,5) = 0 ; DOM(2,5) = 0 ; DOM(0,6) = 0 ; DOM(1,6) = a ; DOM(2,6) = 0 ; DOM(0,7) = -a ; DOM(1,7) = 0 ; DOM(2,7) = 0 ; DOM(0,8) = b*OM(0) ; DOM(1,8) = b*OM(1) ; DOM(2,8) = b*OM(2) ; } } #undef OM #undef DOM #undef R #undef W }
static vl_size VL_XCAT(_vl_fisher_encode_, SFX) (TYPE * enc, TYPE const * means, vl_size dimension, vl_size numClusters, TYPE const * covariances, TYPE const * priors, TYPE const * data, vl_size numData, int flags) { vl_size dim; vl_index i_cl, i_d; vl_size numTerms = 0 ; TYPE * posteriors ; TYPE * sqrtInvSigma; assert(numClusters >= 1) ; assert(dimension >= 1) ; posteriors = vl_malloc(sizeof(TYPE) * numClusters * numData); sqrtInvSigma = vl_malloc(sizeof(TYPE) * dimension * numClusters); memset(enc, 0, sizeof(TYPE) * 2 * dimension * numClusters) ; for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { for(dim = 0; dim < dimension; dim++) { sqrtInvSigma[i_cl*dimension + dim] = sqrt(1.0 / covariances[i_cl*dimension + dim]); } } VL_XCAT(vl_get_gmm_data_posteriors_, SFX)(posteriors, numClusters, numData, priors, means, dimension, covariances, data) ; /* sparsify posterior assignments with the FAST option */ if (flags & VL_FISHER_FLAG_FAST) { for(i_d = 0; i_d < (signed)numData; i_d++) { /* find largest posterior assignment for datum i_d */ vl_index best = 0 ; TYPE bestValue = posteriors[i_d * numClusters] ; for (i_cl = 1 ; i_cl < (signed)numClusters; ++ i_cl) { TYPE p = posteriors[i_cl + i_d * numClusters] ; if (p > bestValue) { bestValue = p ; best = i_cl ; } } /* make all posterior assignments zero but the best one */ for (i_cl = 0 ; i_cl < (signed)numClusters; ++ i_cl) { posteriors[i_cl + i_d * numClusters] = (TYPE)(i_cl == best) ; } } } #if defined(_OPENMP) #pragma omp parallel for default(shared) private(i_cl, i_d, dim) num_threads(vl_get_max_threads()) reduction(+:numTerms) #endif for(i_cl = 0; i_cl < (signed)numClusters; ++ i_cl) { TYPE uprefix; TYPE vprefix; TYPE * uk = enc + i_cl*dimension ; TYPE * vk = enc + i_cl*dimension + numClusters * dimension ; for(i_d = 0; i_d < (signed)numData; i_d++) { TYPE p = posteriors[i_cl + i_d * numClusters] ; if (p < 1e-6) continue ; numTerms += 1; for(dim = 0; dim < dimension; dim++) { TYPE diff = data[i_d*dimension + dim] - means[i_cl*dimension + dim] ; diff *= sqrtInvSigma[i_cl*dimension + dim] ; *(uk + dim) += p * diff ; *(vk + dim) += p * (diff * diff - 1); } } uprefix = 1/(numData*sqrt(priors[i_cl])); vprefix = 1/(numData*sqrt(2*priors[i_cl])); for(dim = 0; dim < dimension; dim++) { *(uk + dim) = *(uk + dim) * uprefix; *(vk + dim) = *(vk + dim) * vprefix; } } vl_free(posteriors); vl_free(sqrtInvSigma) ; if (flags & VL_FISHER_FLAG_SQUARE_ROOT) { for(dim = 0; dim < 2 * dimension * numClusters ; dim++) { TYPE z = enc [dim] ; if (z >= 0) { enc[dim] = VL_XCAT(vl_sqrt_, SFX)(z) ; } else { enc[dim] = - VL_XCAT(vl_sqrt_, SFX)(- z) ; } } } if (flags & VL_FISHER_FLAG_NORMALIZED) { TYPE n = 0 ; for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) { TYPE z = enc [dim] ; n += z * z ; } n = VL_XCAT(vl_sqrt_, SFX)(n) ; n = VL_MAX(n, 1e-12) ; for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) { enc[dim] /= n ; } } return numTerms ; }
void vl_ikm_set_verbosity (VlIKMFilt *f, int verb) { f-> verb = VL_MAX(0,verb) ; }
void vl_hog_put_image (VlHog * self, float const * image, vl_size width, vl_size height, vl_size numChannels, vl_size cellSize) { vl_size hogStride ; vl_size channelStride = width * height ; vl_index x, y ; vl_uindex k ; assert(self) ; assert(image) ; /* clear features */ vl_hog_prepare_buffers(self, width, height, cellSize) ; hogStride = self->hogWidth * self->hogHeight ; #define at(x,y,k) (self->hog[(x) + (y) * self->hogWidth + (k) * hogStride]) /* compute gradients and map the to HOG cells by bilinear interpolation */ for (y = 1 ; y < (signed)height - 1 ; ++y) { for (x = 1 ; x < (signed)width - 1 ; ++x) { float gradx = 0 ; float grady = 0 ; float grad ; float orientationWeights [2] = {0,0} ; vl_index orientationBins [2] = {-1,-1} ; vl_index orientation = 0 ; float hx, hy, wx1, wx2, wy1, wy2 ; vl_index binx, biny, o ; /* Compute the gradient at (x,y). The image channel with the maximum gradient at each location is selected. */ { float const * iter = image + y * width + x ; float grad2 = 0 ; for (k = 0 ; k < numChannels ; ++k) { float gradx_ = *(iter + 1) - *(iter - 1) ; float grady_ = *(iter + width) - *(iter - width) ; float grad2_ = gradx_ * gradx_ + grady_ * grady_ ; if (grad2_ > grad2) { gradx = gradx_ ; grady = grady_ ; grad2 = grad2_ ; } iter += channelStride ; } grad = sqrtf(grad2) ; gradx /= VL_MAX(grad, 1e-10) ; grady /= VL_MAX(grad, 1e-10) ; } /* Map the gradient to the closest and second closets orientation bins. There are numOrientations orientation in the interval [0,pi). The next numOriantations are the symmetric ones, for a total of 2*numOrientation directed orientations. */ for (k = 0 ; k < self->numOrientations ; ++k) { float orientationScore_ = gradx * self->orientationX[k] + grady * self->orientationY[k] ; vl_index orientationBin_ = k ; if (orientationScore_ < 0) { orientationScore_ = - orientationScore_ ; orientationBin_ += self->numOrientations ; } if (orientationScore_ > orientationWeights[0]) { orientationBins[1] = orientationBins[0] ; orientationWeights[1] = orientationWeights[0] ; orientationBins[0] = orientationBin_ ; ; orientationWeights[0] = orientationScore_ ; } else if (orientationScore_ > orientationWeights[1]) { orientationBins[1] = orientationBin_ ; orientationWeights[1] = orientationScore_ ; } } if (self->useBilinearOrientationAssigment) { /* min(1.0,...) guards against small overflows causing NaNs */ float angle0 = acosf(VL_MIN(orientationWeights[0],1.0)) ; orientationWeights[1] = angle0 / (VL_PI / self->numOrientations) ; orientationWeights[0] = 1 - orientationWeights[1] ; } else { orientationWeights[0] = 1 ; orientationBins[1] = -1 ; } for (o = 0 ; o < 2 ; ++o) { /* Accumulate the gradient. hx is the distance of the pixel x to the cell center at its left, in units of cellSize. With this parametrixation, a pixel on the cell center has hx = 0, which gradually increases to 1 moving to the next center. */ orientation = orientationBins[o] ; if (orientation < 0) continue ; /* (x - (w-1)/2) / w = (x + 0.5)/w - 0.5 */ hx = (x + 0.5) / cellSize - 0.5 ; hy = (y + 0.5) / cellSize - 0.5 ; binx = vl_floor_f(hx) ; biny = vl_floor_f(hy) ; wx2 = hx - binx ; wy2 = hy - biny ; wx1 = 1.0 - wx2 ; wy1 = 1.0 - wy2 ; wx1 *= orientationWeights[o] ; wx2 *= orientationWeights[o] ; wy1 *= orientationWeights[o] ; wy2 *= orientationWeights[o] ; /*VL_PRINTF("%d %d - %d %d %f %f - %f %f %f %f - %d \n ",x,y,binx,biny,hx,hy,wx1,wx2,wy1,wy2,o);*/ if (binx >= 0 && biny >=0) { at(binx,biny,orientation) += grad * wx1 * wy1 ; } if (binx < (signed)self->hogWidth - 1 && biny >=0) { at(binx+1,biny,orientation) += grad * wx2 * wy1 ; } if (binx < (signed)self->hogWidth - 1 && biny < (signed)self->hogHeight - 1) { at(binx+1,biny+1,orientation) += grad * wx2 * wy2 ; } if (binx >= 0 && biny < (signed)self->hogHeight - 1) { at(binx,biny+1,orientation) += grad * wx1 * wy2 ; } } /* next o */ } /* next x */ } /* next y */ }
static void VL_XCAT(_vl_fisher_encode_, SFX) (TYPE * enc, TYPE const * means, vl_size dimension, vl_size numClusters, TYPE const * covariances, TYPE const * priors, TYPE const * data, vl_size numData, int flags) { vl_size dim; vl_index i_cl, i_d; TYPE * posteriors ; TYPE * sqrtInvSigma; posteriors = vl_malloc(sizeof(TYPE) * numClusters * numData); sqrtInvSigma = vl_malloc(sizeof(TYPE) * dimension * numClusters); memset(enc, 0, sizeof(TYPE) * 2 * dimension * numClusters) ; for (i_cl = 0 ; i_cl < (signed)numClusters ; ++i_cl) { for(dim = 0; dim < dimension; dim++) { sqrtInvSigma[i_cl*dimension + dim] = sqrt(1.0 / covariances[i_cl*dimension + dim]); } } VL_XCAT(vl_get_gmm_data_posteriors_, SFX)(posteriors, numClusters, numData, priors, means, dimension, covariances, data) ; #if defined(_OPENMP) #pragma omp parallel for default(shared) private(i_cl, i_d, dim) num_threads(vl_get_max_threads()) #endif for(i_cl = 0; i_cl < (signed)numClusters; ++ i_cl) { TYPE uprefix; TYPE vprefix; TYPE * uk = enc + i_cl*dimension ; TYPE * vk = enc + i_cl*dimension + numClusters * dimension ; if (priors[i_cl] < 1e-6) { continue ; } for(i_d = 0; i_d < (signed)numData; i_d++) { TYPE p = posteriors[i_cl + i_d * numClusters] ; if (p == 0) continue ; for(dim = 0; dim < dimension; dim++) { TYPE diff = data[i_d*dimension + dim] - means[i_cl*dimension + dim] ; diff *= sqrtInvSigma[i_cl*dimension + dim] ; *(uk + dim) += p * diff ; *(vk + dim) += p * (diff * diff - 1); } } uprefix = 1/(numData*sqrt(priors[i_cl])); vprefix = 1/(numData*sqrt(2*priors[i_cl])); for(dim = 0; dim < dimension; dim++) { *(uk + dim) = *(uk + dim) * uprefix; *(vk + dim) = *(vk + dim) * vprefix; } } vl_free(posteriors); vl_free(sqrtInvSigma) ; if (flags & VL_FISHER_FLAG_SQUARE_ROOT) { for(dim = 0; dim < 2 * dimension * numClusters ; dim++) { TYPE z = enc [dim] ; if (z >= 0) { enc[dim] = VL_XCAT(vl_sqrt_, SFX)(z) ; } else { enc[dim] = - VL_XCAT(vl_sqrt_, SFX)(- z) ; } } } if (flags & VL_FISHER_FLAG_NORMALIZED) { TYPE n = 0 ; for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) { TYPE z = enc [dim] ; n += z * z ; } n = VL_XCAT(vl_sqrt_, SFX)(n) ; n = VL_MAX(n, 1e-12) ; for(dim = 0 ; dim < 2 * dimension * numClusters ; dim++) { enc[dim] /= n ; } } }
void vl_slic_segment (vl_uint32 * segmentation, float const * image, vl_size width, vl_size height, vl_size numChannels, vl_size regionSize, float regularization, vl_size minRegionSize) { vl_index i, x, y, u, v, k, region ; vl_uindex iter ; vl_size const numRegionsX = (vl_size) ceil((double) width / regionSize) ; vl_size const numRegionsY = (vl_size) ceil((double) height / regionSize) ; vl_size const numRegions = numRegionsX * numRegionsY ; vl_size const numPixels = width * height ; float * centers ; float * edgeMap ; float previousEnergy = VL_INFINITY_F ; float startingEnergy ; vl_uint32 * masses ; vl_size const maxNumIterations = 100 ; assert(segmentation) ; assert(image) ; assert(width >= 1) ; assert(height >= 1) ; assert(numChannels >= 1) ; assert(regionSize >= 1) ; assert(regularization >= 0) ; #define atimage(x,y,k) image[(x)+(y)*width+(k)*width*height] #define atEdgeMap(x,y) edgeMap[(x)+(y)*width] edgeMap = vl_calloc(numPixels, sizeof(float)) ; masses = vl_malloc(sizeof(vl_uint32) * numPixels) ; centers = vl_malloc(sizeof(float) * (2 + numChannels) * numRegions) ; /* compute edge map (gradient strength) */ for (k = 0 ; k < (signed)numChannels ; ++k) { for (y = 1 ; y < (signed)height-1 ; ++y) { for (x = 1 ; x < (signed)width-1 ; ++x) { float a = atimage(x-1,y,k) ; float b = atimage(x+1,y,k) ; float c = atimage(x,y+1,k) ; float d = atimage(x,y-1,k) ; atEdgeMap(x,y) += (a - b) * (a - b) + (c - d) * (c - d) ; } } } /* initialize K-means centers */ i = 0 ; for (v = 0 ; v < (signed)numRegionsY ; ++v) { for (u = 0 ; u < (signed)numRegionsX ; ++u) { vl_index xp ; vl_index yp ; vl_index centerx = 0 ; vl_index centery = 0 ; float minEdgeValue = VL_INFINITY_F ; x = (vl_index) vl_round_d(regionSize * (u + 0.5)) ; y = (vl_index) vl_round_d(regionSize * (v + 0.5)) ; x = VL_MAX(VL_MIN(x, (signed)width-1),0) ; y = VL_MAX(VL_MIN(y, (signed)height-1),0) ; /* search in a 3x3 neighbourhood the smallest edge response */ for (yp = VL_MAX(0, y-1) ; yp <= VL_MIN((signed)height-1, y+1) ; ++ yp) { for (xp = VL_MAX(0, x-1) ; xp <= VL_MIN((signed)width-1, x+1) ; ++ xp) { float thisEdgeValue = atEdgeMap(xp,yp) ; if (thisEdgeValue < minEdgeValue) { minEdgeValue = thisEdgeValue ; centerx = xp ; centery = yp ; } } } /* initialize the new center at this location */ centers[i++] = (float) centerx ; centers[i++] = (float) centery ; for (k = 0 ; k < (signed)numChannels ; ++k) { centers[i++] = atimage(centerx,centery,k) ; } } } /* run k-means iterations */ for (iter = 0 ; iter < maxNumIterations ; ++iter) { float factor = regularization / (regionSize * regionSize) ; float energy = 0 ; /* assign pixels to centers */ for (y = 0 ; y < (signed)height ; ++y) { for (x = 0 ; x < (signed)width ; ++x) { vl_index u = floor((double)x / regionSize - 0.5) ; vl_index v = floor((double)y / regionSize - 0.5) ; vl_index up, vp ; float minDistance = VL_INFINITY_F ; for (vp = VL_MAX(0, v) ; vp <= VL_MIN((signed)numRegionsY-1, v+1) ; ++vp) { for (up = VL_MAX(0, u) ; up <= VL_MIN((signed)numRegionsX-1, u+1) ; ++up) { vl_index region = up + vp * numRegionsX ; float centerx = centers[(2 + numChannels) * region + 0] ; float centery = centers[(2 + numChannels) * region + 1] ; float spatial = (x - centerx) * (x - centerx) + (y - centery) * (y - centery) ; float appearance = 0 ; float distance ; for (k = 0 ; k < (signed)numChannels ; ++k) { float centerz = centers[(2 + numChannels) * region + k + 2] ; float z = atimage(x,y,k) ; appearance += (z - centerz) * (z - centerz) ; } distance = appearance + factor * spatial ; if (minDistance > distance) { minDistance = distance ; segmentation[x + y * width] = (vl_uint32)region ; } } } energy += minDistance ; } } /* VL_PRINTF("vl:slic: iter %d: energy: %g\n", iter, energy) ; */ /* check energy termination conditions */ if (iter == 0) { startingEnergy = energy ; } else { if ((previousEnergy - energy) < 1e-5 * (startingEnergy - energy)) { break ; } } previousEnergy = energy ; /* recompute centers */ memset(masses, 0, sizeof(vl_uint32) * width * height) ; memset(centers, 0, sizeof(float) * (2 + numChannels) * numRegions) ; for (y = 0 ; y < (signed)height ; ++y) { for (x = 0 ; x < (signed)width ; ++x) { vl_index pixel = x + y * width ; vl_index region = segmentation[pixel] ; masses[region] ++ ; centers[region * (2 + numChannels) + 0] += x ; centers[region * (2 + numChannels) + 1] += y ; for (k = 0 ; k < (signed)numChannels ; ++k) { centers[region * (2 + numChannels) + k + 2] += atimage(x,y,k) ; } } } for (region = 0 ; region < (signed)numRegions ; ++region) { float mass = VL_MAX(masses[region], 1e-8) ; for (i = (2 + numChannels) * region ; i < (signed)(2 + numChannels) * (region + 1) ; ++i) { centers[i] /= mass ; } } } vl_free(masses) ; vl_free(centers) ; vl_free(edgeMap) ; /* elimiate small regions */ { vl_uint32 * cleaned = vl_calloc(numPixels, sizeof(vl_uint32)) ; vl_uindex * segment = vl_malloc(sizeof(vl_uindex) * numPixels) ; vl_size segmentSize ; vl_uint32 label ; vl_uint32 cleanedLabel ; vl_size numExpanded ; vl_index const dx [] = {+1, -1, 0, 0} ; vl_index const dy [] = { 0, 0, +1, -1} ; vl_index direction ; vl_index pixel ; for (pixel = 0 ; pixel < (signed)numPixels ; ++pixel) { if (cleaned[pixel]) continue ; label = segmentation[pixel] ; numExpanded = 0 ; segmentSize = 0 ; segment[segmentSize++] = pixel ; /* find cleanedLabel as the label of an already cleaned region neighbor of this pixel */ cleanedLabel = label + 1 ; cleaned[pixel] = label + 1 ; x = pixel % width ; y = pixel / width ; for (direction = 0 ; direction < 4 ; ++direction) { vl_index xp = x + dx[direction] ; vl_index yp = y + dy[direction] ; vl_index neighbor = xp + yp * width ; if (0 <= xp && xp < (signed)width && 0 <= yp && yp < (signed)height && cleaned[neighbor]) { cleanedLabel = cleaned[neighbor] ; } } /* expand the segment */ while (numExpanded < segmentSize) { vl_index open = segment[numExpanded++] ; x = open % width ; y = open / width ; for (direction = 0 ; direction < 4 ; ++direction) { vl_index xp = x + dx[direction] ; vl_index yp = y + dy[direction] ; vl_index neighbor = xp + yp * width ; if (0 <= xp && xp < (signed)width && 0 <= yp && yp < (signed)height && cleaned[neighbor] == 0 && segmentation[neighbor] == label) { cleaned[neighbor] = label + 1 ; segment[segmentSize++] = neighbor ; } } } /* change label to cleanedLabel if the segment is too small */ if (segmentSize < minRegionSize) { while (segmentSize > 0) { cleaned[segment[--segmentSize]] = cleanedLabel ; } } } /* restore base 0 indexing of the regions */ for (pixel = 0 ; pixel < (signed)numPixels ; ++pixel) cleaned[pixel] -- ; memcpy(segmentation, cleaned, numPixels * sizeof(vl_uint32)) ; vl_free(cleaned) ; vl_free(segment) ; } }
VL_EXPORT void vl_quickshift_process(VlQS * q) { vl_qs_type const *I = q->image; int *parents = q->parents; vl_qs_type *E = q->density; vl_qs_type *dists = q->dists; vl_qs_type *M = 0, *n = 0 ; vl_qs_type sigma = q->sigma ; vl_qs_type tau = q->tau; vl_qs_type tau2 = tau*tau; int K = q->channels, d; int N1 = q->height, N2 = q->width; int i1,i2, j1,j2, R, tR; d = 2 + K ; /* Total dimensions include spatial component (x,y) */ if (q->medoid) { /* n and M are only used in mediod shift */ M = (vl_qs_type *) vl_calloc(N1*N2*d, sizeof(vl_qs_type)) ; n = (vl_qs_type *) vl_calloc(N1*N2, sizeof(vl_qs_type)) ; } R = (int) ceil (3 * sigma) ; tR = (int) ceil (tau) ; /* ----------------------------------------------------------------- * n * -------------------------------------------------------------- */ /* If we are doing medoid shift, initialize n to the inner product of the * image with itself */ if (n) { for (i2 = 0 ; i2 < N2 ; ++ i2) { for (i1 = 0 ; i1 < N1 ; ++ i1) { n [i1 + N1 * i2] = vl_quickshift_inner(I,N1,N2,K, i1,i2, i1,i2) ; } } } /* ----------------------------------------------------------------- * E = - [oN'*F]', M * -------------------------------------------------------------- */ /* D_ij = d(x_i,x_j) E_ij = exp(- .5 * D_ij / sigma^2) ; F_ij = - E_ij E_i = sum_j E_ij M_di = sum_j X_j F_ij E is the parzen window estimate of the density 0 = dissimilar to everything, windowsize = identical */ for (i2 = 0 ; i2 < N2 ; ++ i2) { for (i1 = 0 ; i1 < N1 ; ++ i1) { int j1min = VL_MAX(i1 - R, 0 ) ; int j1max = VL_MIN(i1 + R, N1-1) ; int j2min = VL_MAX(i2 - R, 0 ) ; int j2max = VL_MIN(i2 + R, N2-1) ; /* For each pixel in the window compute the distance between it and the * source pixel */ for (j2 = j2min ; j2 <= j2max ; ++ j2) { for (j1 = j1min ; j1 <= j1max ; ++ j1) { vl_qs_type Dij = vl_quickshift_distance(I,N1,N2,K, i1,i2, j1,j2) ; /* Make distance a similarity */ vl_qs_type Fij = - exp(- Dij / (2*sigma*sigma)) ; /* E is E_i above */ E [i1 + N1 * i2] -= Fij ; if (M) { /* Accumulate votes for the median */ int k ; M [i1 + N1*i2 + (N1*N2) * 0] += j1 * Fij ; M [i1 + N1*i2 + (N1*N2) * 1] += j2 * Fij ; for (k = 0 ; k < K ; ++k) { M [i1 + N1*i2 + (N1*N2) * (k+2)] += I [j1 + N1*j2 + (N1*N2) * k] * Fij ; } } } /* j1 */ } /* j2 */ } /* i1 */ } /* i2 */ /* ----------------------------------------------------------------- * Find best neighbors * -------------------------------------------------------------- */ if (q->medoid) { /* Qij = - nj Ei - 2 sum_k Gjk Mik n is I.^2 */ /* medoid shift */ for (i2 = 0 ; i2 < N2 ; ++i2) { for (i1 = 0 ; i1 < N1 ; ++i1) { vl_qs_type sc_best = 0 ; /* j1/j2 best are the best indicies for each i */ vl_qs_type j1_best = i1 ; vl_qs_type j2_best = i2 ; int j1min = VL_MAX(i1 - R, 0 ) ; int j1max = VL_MIN(i1 + R, N1-1) ; int j2min = VL_MAX(i2 - R, 0 ) ; int j2max = VL_MIN(i2 + R, N2-1) ; for (j2 = j2min ; j2 <= j2max ; ++ j2) { for (j1 = j1min ; j1 <= j1max ; ++ j1) { vl_qs_type Qij = - n [j1 + j2 * N1] * E [i1 + i2 * N1] ; int k ; Qij -= 2 * j1 * M [i1 + i2 * N1 + (N1*N2) * 0] ; Qij -= 2 * j2 * M [i1 + i2 * N1 + (N1*N2) * 1] ; for (k = 0 ; k < K ; ++k) { Qij -= 2 * I [j1 + j2 * N1 + (N1*N2) * k] * M [i1 + i2 * N1 + (N1*N2) * (k + 2)] ; } if (Qij > sc_best) { sc_best = Qij ; j1_best = j1 ; j2_best = j2 ; } } } /* parents_i is the linear index of j which is the best pair * dists_i is the score of the best match */ parents [i1 + N1 * i2] = j1_best + N1 * j2_best ; dists[i1 + N1 * i2] = sc_best ; } } } else { /* Quickshift assigns each i to the closest j which has an increase in the * density (E). If there is no j s.t. Ej > Ei, then dists_i == inf (a root * node in one of the trees of merges). */ for (i2 = 0 ; i2 < N2 ; ++i2) { for (i1 = 0 ; i1 < N1 ; ++i1) { vl_qs_type E0 = E [i1 + N1 * i2] ; vl_qs_type d_best = VL_QS_INF ; vl_qs_type j1_best = i1 ; vl_qs_type j2_best = i2 ; int j1min = VL_MAX(i1 - tR, 0 ) ; int j1max = VL_MIN(i1 + tR, N1-1) ; int j2min = VL_MAX(i2 - tR, 0 ) ; int j2max = VL_MIN(i2 + tR, N2-1) ; for (j2 = j2min ; j2 <= j2max ; ++ j2) { for (j1 = j1min ; j1 <= j1max ; ++ j1) { if (E [j1 + N1 * j2] > E0) { vl_qs_type Dij = vl_quickshift_distance(I,N1,N2,K, i1,i2, j1,j2) ; if (Dij <= tau2 && Dij < d_best) { d_best = Dij ; j1_best = j1 ; j2_best = j2 ; } } } } /* parents is the index of the best pair */ /* dists_i is the minimal distance, inf implies no Ej > Ei within * distance tau from the point */ parents [i1 + N1 * i2] = j1_best + N1 * j2_best ; dists[i1 + N1 * i2] = sqrt(d_best) ; } } } if (M) vl_free(M) ; if (n) vl_free(n) ; }
VlHomogeneousKernelMap * vl_homogeneouskernelmap_new (VlHomogeneousKernelType kernelType, double gamma, vl_size order, double period, VlHomogeneousKernelMapWindowType windowType) { int tableWidth, tableHeight ; VlHomogeneousKernelMap * self = vl_malloc(sizeof(VlHomogeneousKernelMap)) ; if (! self) return NULL ; assert(gamma > 0) ; assert(kernelType == VlHomogeneousKernelIntersection || kernelType == VlHomogeneousKernelChi2 || kernelType == VlHomogeneousKernelJS) ; assert(windowType == VlHomogeneousKernelMapWindowUniform || windowType == VlHomogeneousKernelMapWindowRectangular) ; if (period < 0) { switch (windowType) { case VlHomogeneousKernelMapWindowUniform: switch (kernelType) { case VlHomogeneousKernelChi2: period = 5.86 * sqrt(order + 0) + 3.65 ; break ; case VlHomogeneousKernelJS: period = 6.64 * sqrt(order + 0) + 7.24 ; break ; case VlHomogeneousKernelIntersection: period = 2.38 * log(order + 0.8) + 5.6 ; break ; } break ; case VlHomogeneousKernelMapWindowRectangular: switch (kernelType) { case VlHomogeneousKernelChi2: period = 8.80 * sqrt(order + 4.44) - 12.6 ; break ; case VlHomogeneousKernelJS: period = 9.63 * sqrt(order + 1.00) - 2.93; break ; case VlHomogeneousKernelIntersection: period = 2.00 * log(order + 0.99) + 3.52 ; break ; } break ; } period = VL_MAX(period, 1.0) ; } self->kernelType = kernelType ; self->windowType = windowType ; self->gamma = gamma ; self->order = order ; self->period = period ; self->numSubdivisions = 8 + 8*order ; self->subdivision = 1.0 / self->numSubdivisions ; self->minExponent = -20 ; self->maxExponent = 8 ; tableHeight = (int) (2*self->order + 1) ; tableWidth = (int) (self->numSubdivisions * (self->maxExponent - self->minExponent + 1)) ; self->table = vl_malloc (sizeof(double) * (tableHeight * tableWidth + 2*(1+self->order))) ; if (! self->table) { vl_free(self) ; return NULL ; } { vl_index exponent ; vl_uindex i, j ; double * tablep = self->table ; double * kappa = self->table + tableHeight * tableWidth ; double * freq = kappa + (1+self->order) ; double L = 2.0 * VL_PI / self->period ; /* precompute the sampled periodicized spectrum */ j = 0 ; i = 0 ; while (i <= self->order) { freq[i] = j ; kappa[i] = vl_homogeneouskernelmap_get_smooth_spectrum(self, j * L) ; ++ j ; if (kappa[i] > 0 || j >= 3*i) ++ i ; } /* fill table */ for (exponent = self->minExponent ; exponent <= self->maxExponent ; ++ exponent) { double x, Lxgamma, Llogx, xgamma ; double sqrt2kappaLxgamma ; double mantissa = 1.0 ; for (i = 0 ; i < self->numSubdivisions ; ++i, mantissa += self->subdivision) { x = ldexp(mantissa, (int)exponent) ; xgamma = pow(x, self->gamma) ; Lxgamma = L * xgamma ; Llogx = L * log(x) ; *tablep++ = sqrt(Lxgamma * kappa[0]) ; for (j = 1 ; j <= self->order ; ++j) { sqrt2kappaLxgamma = sqrt(2.0 * Lxgamma * kappa[j]) ; *tablep++ = sqrt2kappaLxgamma * cos(freq[j] * Llogx) ; *tablep++ = sqrt2kappaLxgamma * sin(freq[j] * Llogx) ; } } /* next mantissa */ } /* next exponent */ } return self ; }
/** ------------------------------------------------------------------- ** @brief Process image ** ** The functions calculates the Maximally Stable Extremal Regions ** (MSERs) of image @a im using the MSER filter @a f. ** ** The filter @a f must have been initialized to be compatible with ** the dimensions of @a im. ** ** @param f MSER filter. ** @param im image data. **/ VL_EXPORT void vl_mser_process (VlMserFilt* f, vl_mser_pix const* im) { /* shortcuts */ vl_uint nel = f-> nel ; vl_uint *perm = f-> perm ; vl_uint *joins = f-> joins ; int ndims = f-> ndims ; int *dims = f-> dims ; int *subs = f-> subs ; int *dsubs = f-> dsubs ; int *strides = f-> strides ; VlMserReg *r = f-> r ; VlMserExtrReg *er = f-> er ; vl_uint *mer = f-> mer ; int delta = f-> delta ; int njoins = 0 ; int ner = 0 ; int nmer = 0 ; int nbig = 0 ; int nsmall = 0 ; int nbad = 0 ; int ndup = 0 ; int i, j, k ; /* delete any previosuly computed ellipsoid */ f-> nell = 0 ; /* ----------------------------------------------------------------- * Sort pixels by intensity * -------------------------------------------------------------- */ { vl_uint buckets [ VL_MSER_PIX_MAXVAL ] ; /* clear buckets */ memset (buckets, 0, sizeof(vl_uint) * VL_MSER_PIX_MAXVAL ) ; /* compute bucket size (how many pixels for each intensity value) */ for(i = 0 ; i < (int) nel ; ++i) { vl_mser_pix v = im [i] ; ++ buckets [v] ; } /* cumulatively add bucket sizes */ for(i = 1 ; i < VL_MSER_PIX_MAXVAL ; ++i) { buckets [i] += buckets [i-1] ; } /* empty buckets computing pixel ordering */ for(i = nel ; i >= 1 ; ) { vl_mser_pix v = im [ --i ] ; vl_uint j = -- buckets [v] ; perm [j] = i ; } } /* initialize the forest with all void nodes */ for(i = 0 ; i < (int) nel ; ++i) { r [i] .parent = VL_MSER_VOID_NODE ; } /* ----------------------------------------------------------------- * Compute regions and count extremal regions * -------------------------------------------------------------- */ /* In the following: idx : index of the current pixel val : intensity of the current pixel r_idx : index of the root of the current pixel n_idx : index of the neighbors of the current pixel nr_idx : index of the root of the neighbor of the current pixel */ /* process each pixel by increasing intensity */ for(i = 0 ; i < (int) nel ; ++i) { /* pop next node xi */ vl_uint idx = perm [i] ; vl_mser_pix val = im [idx] ; vl_uint r_idx ; /* add the pixel to the forest as a root for now */ r [idx] .parent = idx ; r [idx] .shortcut = idx ; r [idx] .area = 1 ; r [idx] .height = 1 ; r_idx = idx ; /* convert the index IDX into the subscript SUBS; also initialize DSUBS to (-1,-1,...,-1) */ { vl_uint temp = idx ; for(k = ndims - 1 ; k >= 0 ; --k) { dsubs [k] = -1 ; subs [k] = temp / strides [k] ; temp = temp % strides [k] ; } } /* examine the neighbors of the current pixel */ while (1) { vl_uint n_idx = 0 ; vl_bool good = 1 ; /* Compute the neighbor subscript as NSUBS+SUB, the corresponding neighbor index NINDEX and check that the neighbor is within the image domain. */ for(k = 0 ; k < ndims && good ; ++k) { int temp = dsubs [k] + subs [k] ; good &= (0 <= temp) && (temp < dims [k]) ; n_idx += temp * strides [k] ; } /* The neighbor should be processed if the following conditions are met: 1. The neighbor is within image boundaries. 2. The neighbor is indeed different from the current node (the opposite happens when DSUB=(0,0,...,0)). 3. The neighbor is already in the forest, meaning that it has already been processed. */ if (good && n_idx != idx && r [n_idx] .parent != VL_MSER_VOID_NODE ) { vl_mser_pix nr_val = 0 ; vl_uint nr_idx = 0 ; /* Now we join the two subtrees rooted at R_IDX = ROOT( IDX) NR_IDX = ROOT(N_IDX). Note that R_IDX = ROOT(IDX) might change as we process more neighbors, so we need keep updating it. */ r_idx = climb(r, idx) ; nr_idx = climb(r, n_idx) ; int hgt = r [ r_idx] .height ; int n_hgt = r [nr_idx] .height ; /* At this point we have three possibilities: (A) ROOT(IDX) == ROOT(NR_IDX). In this case the two trees have already been joined and we do not do anything. (B) I(ROOT(IDX)) == I(ROOT(NR_IDX)). In this case the pixel IDX is extending an extremal region with the same intensity value. Since ROOT(NR_IDX) will NOT be an extremal region of the full image, ROOT(IDX) can be safely added as children of ROOT(NR_IDX) if this reduces the height according to the union rank heuristic. (C) I(ROOT(IDX)) > I(ROOT(NR_IDX)). In this case the pixel IDX is starting a new extremal region. Thus ROOT(NR_IDX) WILL be an extremal region of the final image and the only possibility is to add ROOT(NR_IDX) as children of ROOT(IDX), which becomes parent. */ if( r_idx != nr_idx ) { /* skip if (A) */ nr_val = im [nr_idx] ; if( nr_val == val && hgt < n_hgt ) { /* ROOT(IDX) becomes the child */ r [r_idx] .parent = nr_idx ; r [r_idx] .shortcut = nr_idx ; r [nr_idx] .area += r [r_idx] .area ; r [nr_idx] .height = VL_MAX(n_hgt, hgt+1) ; joins [njoins++] = r_idx ; } else { /* cases ROOT(IDX) becomes the parent */ r [nr_idx] .parent = r_idx ; r [nr_idx] .shortcut = r_idx ; r [r_idx] .area += r [nr_idx] .area ; r [r_idx] .height = VL_MAX(hgt, n_hgt + 1) ; joins [njoins++] = nr_idx ; /* count if extremal */ if (nr_val != val) ++ ner ; } /* check b vs c */ } /* check a vs b or c */ } /* neighbor done */ /* move to next neighbor */ k = 0 ; while(++ dsubs [k] > 1) { dsubs [k++] = -1 ; if(k == ndims) goto done_all_neighbors ; } } /* next neighbor */ done_all_neighbors : ; } /* next pixel */ /* the last root is extremal too */ ++ ner ; /* save back */ f-> njoins = njoins ; f-> stats. num_extremal = ner ; /* ----------------------------------------------------------------- * Extract extremal regions * -------------------------------------------------------------- */ /* Extremal regions are extracted and stored into the array ER. The structure R is also updated so that .SHORTCUT indexes the corresponding extremal region if any (otherwise it is set to VOID). */ /* make room */ if (f-> rer < ner) { if (er) vl_free (er) ; f->er = er = vl_malloc (sizeof(VlMserExtrReg) * ner) ; f->rer = ner ; } ; /* save back */ f-> nmer = ner ; /* count again */ ner = 0 ; /* scan all regions Xi */ for(i = 0 ; i < (int) nel ; ++i) { /* pop next node xi */ vl_uint idx = perm [i] ; vl_mser_pix val = im [idx] ; vl_uint p_idx = r [idx] .parent ; vl_mser_pix p_val = im [p_idx] ; /* is extremal ? */ vl_bool is_extr = (p_val > val) || idx == p_idx ; if( is_extr ) { /* if so, add it */ er [ner] .index = idx ; er [ner] .parent = ner ; er [ner] .value = im [idx] ; er [ner] .area = r [idx] .area ; /* link this region to this extremal region */ r [idx] .shortcut = ner ; /* increase count */ ++ ner ; } else { /* link this region to void */ r [idx] .shortcut = VL_MSER_VOID_NODE ; } } /* ----------------------------------------------------------------- * Link extremal regions in a tree * -------------------------------------------------------------- */ for(i = 0 ; i < ner ; ++i) { vl_uint idx = er [i] .index ; do { idx = r[idx] .parent ; } while (r[idx] .shortcut == VL_MSER_VOID_NODE) ; er[i] .parent = r[idx] .shortcut ; er[i] .shortcut = i ; } /* ----------------------------------------------------------------- * Compute variability of +DELTA branches * -------------------------------------------------------------- */ /* For each extremal region Xi of value VAL we look for the biggest * parent that has value not greater than VAL+DELTA. This is dubbed * `top parent'. */ for(i = 0 ; i < ner ; ++i) { /* Xj is the current region the region and Xj are the parents */ int top_val = er [i] .value + delta ; int top = er [i] .shortcut ; /* examine all parents */ while (1) { int next = er [top] .parent ; int next_val = er [next] .value ; /* Break if: * - there is no node above the top or * - the next node is above the top value. */ if (next == top || next_val > top_val) break ; /* so next could be the top */ top = next ; } /* calculate branch variation */ { int area = er [i ] .area ; int area_top = er [top] .area ; er [i] .variation = (float) (area_top - area) / area ; er [i] .max_stable = 1 ; } /* Optimization: since extremal regions are processed by * increasing intensity, all next extremal regions being processed * have value at least equal to the one of Xi. If any of them has * parent the parent of Xi (this comprises the parent itself), we * can safely skip most intermediate node along the branch and * skip directly to the top to start our search. */ { int parent = er [i] .parent ; int curr = er [parent] .shortcut ; er [parent] .shortcut = VL_MAX (top, curr) ; } } /* ----------------------------------------------------------------- * Select maximally stable branches * -------------------------------------------------------------- */ nmer = ner ; for(i = 0 ; i < ner ; ++i) { vl_uint parent = er [i ] .parent ; vl_mser_pix val = er [i ] .value ; float var = er [i ] .variation ; vl_mser_pix p_val = er [parent] .value ; float p_var = er [parent] .variation ; vl_uint loser ; /* Notice that R_parent = R_{l+1} only if p_val = val + 1. If not, this and the parent region coincide and there is nothing to do. */ if(p_val > val + 1) continue ; /* decide which one to keep and put that in loser */ if(var < p_var) loser = parent ; else loser = i ; /* make loser NON maximally stable */ if(er [loser] .max_stable) { -- nmer ; er [loser] .max_stable = 0 ; } } f-> stats. num_unstable = ner - nmer ; /* ----------------------------------------------------------------- * Further filtering * -------------------------------------------------------------- */ /* It is critical for correct duplicate detection to remove regions * from the bottom (smallest one first). */ { float max_area = (float) f-> max_area * nel ; float min_area = (float) f-> min_area * nel ; float max_var = (float) f-> max_variation ; float min_div = (float) f-> min_diversity ; /* scan all extremal regions (intensity value order) */ for(i = ner-1 ; i >= 0L ; --i) { /* process only maximally stable extremal regions */ if (! er [i] .max_stable) continue ; if (er [i] .variation >= max_var ) { ++ nbad ; goto remove ; } if (er [i] .area > max_area) { ++ nbig ; goto remove ; } if (er [i] .area < min_area) { ++ nsmall ; goto remove ; } /* * Remove duplicates */ if (min_div < 1.0) { vl_uint parent = er [i] .parent ; int area, p_area ; float div ; /* check all but the root mser */ if((int) parent != i) { /* search for the maximally stable parent region */ while(! er [parent] .max_stable) { vl_uint next = er [parent] .parent ; if(next == parent) break ; parent = next ; } /* Compare with the parent region; if the current and parent * regions are too similar, keep only the parent. */ area = er [i] .area ; p_area = er [parent] .area ; div = (float) (p_area - area) / (float) p_area ; if (div < min_div) { ++ ndup ; goto remove ; } } /* remove dups end */ } continue ; remove : er [i] .max_stable = 0 ; -- nmer ; } /* check next region */ f-> stats .num_abs_unstable = nbad ; f-> stats .num_too_big = nbig ; f-> stats .num_too_small = nsmall ; f-> stats .num_duplicates = ndup ; } /* ----------------------------------------------------------------- * Save the result * -------------------------------------------------------------- */ /* make room */ if (f-> rmer < nmer) { if (mer) vl_free (mer) ; f->mer = mer = vl_malloc( sizeof(vl_uint) * nmer) ; f->rmer = nmer ; } /* save back */ f-> nmer = nmer ; j = 0 ; for (i = 0 ; i < ner ; ++i) { if (er [i] .max_stable) mer [j++] = er [i] .index ; } }
void r3d_vl_liopdesc_process (VlLiopDesc * self, float * desc, float const * patch) { vl_index i,t ; vl_index offset,numPermutations ; vl_index spatialBinArea, spatialBinEnd, spatialBinIndex ; float threshold ; memset(desc, 0, sizeof(float) * self->dimension) ; /* * Sort pixels in the patch by increasing intensity. */ for (i = 0 ; i < (signed)self->patchSize ; ++i) { vl_index pixel = self->patchPixels[i] ; self->patchIntensities[i] = patch[pixel] ; self->patchPermutation[i] = i ; } patch_sort(self, self->patchSize) ; /* * Tune the threshold if needed. */ if (self->intensityThreshold < 0) { i = self->patchPermutation[0] ; t = self->patchPermutation[self->patchSize-1] ; threshold = - self->intensityThreshold * (self->patchIntensities[t] - self->patchIntensities[i]); } else { threshold = self->intensityThreshold ; } /* * Process pixels in order of increasing intenisity, dividing them into * spatial bins on the fly. */ numPermutations = factorial(self->numNeighbours) ; spatialBinArea = self->patchSize / self->numSpatialBins ; spatialBinEnd = spatialBinArea ; spatialBinIndex = 0 ; offset = 0 ; for (i = 0 ; i < (signed)self->patchSize ; ++i) { vl_index permIndex ; double *sx, *sy ; /* advance to the next spatial bin if needed */ if (i >= (signed)spatialBinEnd && spatialBinIndex < (signed)self->numSpatialBins - 1) { spatialBinEnd += spatialBinArea ; spatialBinIndex ++ ; offset += numPermutations ; } /* get intensities of neighbours of the current patch element and sort them */ sx = self->neighSamplesX + self->numNeighbours * self->patchPermutation[i] ; sy = self->neighSamplesY + self->numNeighbours * self->patchPermutation[i] ; for (t = 0 ; t < self->numNeighbours ; ++t) { double x = *sx++ ; double y = *sy++ ; /* bilinear interpolation */ vl_index ix = vl_floor_d(x) ; vl_index iy = vl_floor_d(y) ; double wx = x - ix ; double wy = y - iy ; double a = 0, b = 0, c = 0, d = 0 ; int L = (int) self->patchSideLength ; if (ix >= 0 && iy >= 0 ) { a = patch[ix + iy * L] ; } if (ix < L-1 && iy >= 0 ) { b = patch[ix+1 + iy * L] ; } if (ix >= 0 && iy < L-1) { c = patch[ix + (iy+1) * L] ; } if (ix < L-1 && iy < L-1) { d = patch[ix+1 + (iy+1) * L] ; } self->neighPermutation[t] = t; self->neighIntensities[t] = (1.0 - wy) * (a + (b - a) * wx) + wy * (c + (d - c) * wx) ; } neigh_sort (self, self->numNeighbours) ; /* get permutation index */ permIndex = get_permutation_index(self->neighPermutation, self->numNeighbours); /* * Compute weight according to difference in intensity values and * accumulate. */ { int k, t ; float weight = 0 ; for(k = 0; k < self->numNeighbours ; ++k) { for(t = k + 1; t < self->numNeighbours; ++t){ float a = self->neighIntensities[k] ; float b = self->neighIntensities[t] ; weight += (a > b + threshold || b > a + threshold) ; } } desc[permIndex + offset] += weight ; } } /* normalization */ { float norm = 0; for(i = 0; i < (signed)self->dimension; i++) { norm += desc[i]*desc[i]; } norm = VL_MAX(sqrt(norm), 1e-12) ; for(i = 0; i < (signed)self->dimension; i++){ desc[i] /= norm ; } } }
/** @brief Driver. ** ** @param nount number of output arguments. ** @param out output arguments. ** @param nin number of input arguments. ** @param in input arguments. **/ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum { IN_ID, IN_NEXT, IN_K, IN_X } ; enum { OUT_SEL } ; vl_uint32 const * next ; vl_uint32 * sel ; vl_uint8 const * id ; vl_uint8 const * x ; unsigned int K, i, N, res, last, ndims ; /* ----------------------------------------------------------------- * Check arguments * -------------------------------------------------------------- */ if( nin != 4 ) { mexErrMsgTxt("Four arguments required") ; } else if (nout > 1) { mexErrMsgTxt("At most one output argument.") ; } if(! mxIsNumeric(in[IN_NEXT])|| mxGetClassID(in[IN_NEXT])!= mxUINT32_CLASS) { mexErrMsgTxt("NEXT must be UINT32.") ; } if(! mxIsNumeric(in[IN_X]) || mxGetClassID(in[IN_X])!= mxUINT8_CLASS) { mexErrMsgTxt("X must be UINT8") ; } if (mxGetM(in[IN_NEXT]) != 1) { mexErrMsgTxt("NEXT must be a row vector") ; } if(! mxIsNumeric(in[IN_ID]) || mxGetClassID(in[IN_ID])!= mxUINT8_CLASS) { mexErrMsgTxt("ID must be UINT8.") ; } ndims = mxGetM(in[IN_ID]) ; res = mxGetN(in[IN_ID]) ; if(res != mxGetN(in[IN_NEXT])) { mexErrMsgTxt("ID, NEXT must have the same number of columns") ; } if(ndims != mxGetM(in[IN_X])) { mexErrMsgTxt("ID and X must havethe same number of rows") ; } if(! vlmxIsPlainScalar(in[IN_K])) { mexErrMsgTxt("K must be a scalar") ; } K = (unsigned int) *mxGetPr(in[IN_K]) ; N = mxGetN(in[IN_X]) ; id = mxGetData(in[IN_ID]) ; next = mxGetData(in[IN_NEXT]) ; x = mxGetData(in[IN_X]) ; out[OUT_SEL] = mxCreateNumericMatrix (1, N, mxUINT32_CLASS, mxREAL) ; sel = mxGetData (out[OUT_SEL]) ; /* search for last occupied slot */ last = res ; for (i = 0 ; i < res ; ++i) last = VL_MAX(last, next [i]) ; /* REMARK: last and next are 1 based */ if (K > res) { mexErrMsgTxt("K cannot be larger then the size of H") ; } if (last > res) { mexErrMsgTxt("An element of NEXT is greater than the size of the table") ; } /* ----------------------------------------------------------------- * Do job * -------------------------------------------------------------- */ for (i = 0 ; i < N ; ++i) { /* hash */ unsigned int h1, h2 ; unsigned int j, p = 0 ; if (is_null (x + i * ndims, ndims)) { *sel++ = 0 ; continue ; } h1 = fnv_hash(x + i * ndims, ndims) % K ; h2 = h1 | 0x1 ; /* this needs to be odd */ /* search first free or matching position */ p = h1 % K ; for (j = 0 ; j < K ; ++j) { if (is_null (id + p * ndims, ndims) || is_equal(id + p * ndims, x + i * ndims, ndims)) break ; h1 += h2 ; p = h1 % K ; } /* handle extended table */ while (! is_null (id + p * ndims, ndims) && ! is_equal(id + p * ndims, x + i * ndims, ndims)) { if (next[p] == 0) break ; p = next [p] - 1 ; } /* found or not ? */ if (is_equal(id + p * ndims, x + i * ndims, ndims)) { /* found */ *sel++ = p + 1 ; } else { /* not found */ *sel++ = 0 ; } } /* next guy to search for */ }
static void VL_XCAT(_vl_vlad_encode_, SFX) (TYPE * enc, TYPE const * means, vl_size dimension, vl_size numClusters, TYPE const * data, vl_size numData, TYPE const * assignments, int flags) { vl_uindex dim ; vl_index i_cl, i_d ; memset(enc, 0, sizeof(TYPE) * dimension * numClusters) ; #if defined(_OPENMP) #pragma omp parallel for default(shared) private(i_cl,i_d,dim) num_threads(vl_get_max_threads()) #endif for (i_cl = 0; i_cl < (signed)numClusters; i_cl++) { double clusterMass = 0 ; for (i_d = 0; i_d < (signed)numData; i_d++) { if (assignments[i_d*numClusters + i_cl] > 0) { double q = assignments[i_d*numClusters+i_cl] ; clusterMass += q ; for(dim = 0; dim < dimension; dim++) { enc [i_cl * dimension + dim] += q * data [i_d * dimension + dim] ; } } } if (clusterMass > 0) { if (flags & VL_VLAD_FLAG_NORMALIZE_MASS) { for(dim = 0; dim < dimension; dim++) { enc[i_cl*dimension + dim] /= clusterMass ; enc[i_cl*dimension + dim] -= means[i_cl*dimension+dim]; } } else { for(dim = 0; dim < dimension; dim++) { enc[i_cl*dimension + dim] -= clusterMass * means[i_cl*dimension+dim]; } } } if (flags & VL_VLAD_FLAG_SQUARE_ROOT) { for(dim = 0; dim < dimension; dim++) { TYPE z = enc[i_cl*dimension + dim] ; if (z >= 0) { enc[i_cl*dimension + dim] = VL_XCAT(vl_sqrt_, SFX)(z) ; } else { enc[i_cl*dimension + dim] = - VL_XCAT(vl_sqrt_, SFX)(- z) ; } } } if (flags & VL_VLAD_FLAG_NORMALIZE_COMPONENTS) { TYPE n = 0 ; dim = 0 ; for(dim = 0; dim < dimension; dim++) { TYPE z = enc[i_cl*dimension + dim] ; n += z * z ; } n = VL_XCAT(vl_sqrt_, SFX)(n) ; n = VL_MAX(n, 1e-12) ; for(dim = 0; dim < dimension; dim++) { enc[i_cl*dimension + dim] /= n ; } } } if (! (flags & VL_VLAD_FLAG_UNNORMALIZED)) { TYPE n = 0 ; for(dim = 0 ; dim < dimension * numClusters ; dim++) { TYPE z = enc [dim] ; n += z * z ; } n = VL_XCAT(vl_sqrt_, SFX)(n) ; n = VL_MAX(n, 1e-12) ; for(dim = 0 ; dim < dimension * numClusters ; dim++) { enc[dim] /= n ; } } }
VL_INLINE void VL_XCAT(_vl_imsmooth_smooth_, SFX) (T * outputImage, vl_size numOutputRows, vl_size numOutputColumns, T const * inputImage, vl_size numRows, vl_size numColumns, vl_size numChannels, int kernel, double sigma, int step, int flags) { T * tempImage = (T*) mxMalloc (sizeof(T) * numRows * numOutputColumns) ; vl_uindex k ; vl_index j ; /* Note that MATLAB uses a column major ordering, while VLFeat a row major (standard) ordering for the image data. Effectively, VLFeat is operating on a transposed image, but this is fine since filters are symmetric. Therefore: input image width = numRows input image height = numColumns output image width = numOutputRows (downsamped rows) outout image height = numOutputColumns (downsampled columns) In addition a temporary buffer is used. This is an image that is obtained from the input image by convolving and downsampling along the height and saving the result transposed: temp image width = numOutputColumns temp image height = numRows */ switch (kernel) { case GAUSSIAN : { vl_size W = ceil (4.0 * sigma) ; T * filter = (T*) mxMalloc (sizeof(T) * (2 * W + 1)) ; T acc = 0 ; for (j = 0 ; j < (signed)(2 * W + 1) ; ++j) { T z = ( (T) j - W) / (sigma + VL_EPSILON_F) ; filter[j] = exp(- 0.5 * (z*z)) ; acc += filter[j] ; } for (j = 0 ; j < (signed)(2 * W + 1) ; ++j) { filter[j] /= acc ; } for (k = 0 ; k < numChannels ; ++k) { IMCONVCOL (tempImage, numOutputColumns, inputImage, numRows, numColumns, numRows, filter, -W, W, step, flags) ; IMCONVCOL (outputImage, numOutputRows, tempImage, numOutputColumns, numRows, numOutputColumns, filter, -W, W, step, flags) ; inputImage += numRows * numColumns ; outputImage += numOutputRows * numOutputColumns ; } mxFree (filter) ; break ; } case TRIANGULAR: { unsigned int W = VL_MAX((unsigned int) sigma, 1) ; for (k = 0 ; k < numChannels ; ++k) { IMCONVCOLTRI (tempImage, numOutputColumns, inputImage, numRows, numColumns, numRows, W, step, flags) ; IMCONVCOLTRI (outputImage, numOutputRows, tempImage, numOutputColumns, numRows, numOutputColumns, W, step, flags) ; inputImage += numRows * numColumns ; outputImage += numOutputRows * numOutputColumns ; } break ; } default: abort() ; } mxFree (tempImage) ; }
void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum {IN_I=0, IN_END} ; enum {OUT_FRAMES=0, OUT_DESCRIPTORS} ; int verbose = 0 ; int opt ; int next = IN_END ; mxArray const *optarg ; float const *data ; int M, N ; int step [2] = {1,1} ; vl_bool norm = 0 ; vl_bool floatDescriptors = VL_FALSE ; vl_bool useFlatWindow = VL_FALSE ; double windowSize = -1.0 ; double *bounds = NULL ; double boundBuffer [4] ; VlDsiftDescriptorGeometry geom ; VL_USE_MATLAB_ENV ; geom.numBinX = 4 ; geom.numBinY = 4 ; geom.numBinT = 8 ; geom.binSizeX = 3 ; geom.binSizeY = 3 ; /* ----------------------------------------------------------------- * Check the arguments * -------------------------------------------------------------- */ if (nin < 1) { vlmxError(vlmxErrNotEnoughInputArguments, NULL) ; } else if (nout > 2) { vlmxError(vlmxErrTooManyOutputArguments, NULL) ; } if (mxGetNumberOfDimensions (in[IN_I]) != 2 || mxGetClassID (in[IN_I]) != mxSINGLE_CLASS ) { vlmxError(vlmxErrInvalidArgument, "I must be a matrix of class SINGLE.") ; } data = (float*) mxGetData (in[IN_I]) ; M = mxGetM (in[IN_I]) ; N = mxGetN (in[IN_I]) ; while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) { switch (opt) { case opt_verbose : ++ verbose ; break ; case opt_fast : useFlatWindow = 1 ; break ; case opt_norm : norm = 1 ; break ; case opt_bounds : if (!vlmxIsPlainVector(optarg, 4)) { mexErrMsgTxt("BOUNDS must be a 4-dimensional vector.") ; } bounds = boundBuffer ; bounds [0] = mxGetPr(optarg)[0] - 1 ; bounds [1] = mxGetPr(optarg)[1] - 1 ; bounds [2] = mxGetPr(optarg)[2] - 1 ; bounds [3] = mxGetPr(optarg)[3] - 1 ; break ; case opt_size : if (!vlmxIsPlainVector(optarg,-1)) { vlmxError(vlmxErrInvalidArgument,"SIZE is not a plain vector.") ; } if (mxGetNumberOfElements(optarg) == 1) { geom.binSizeX = (int) mxGetPr(optarg)[0] ; geom.binSizeY = (int) mxGetPr(optarg)[0] ; } else if (mxGetNumberOfElements(optarg) == 2) { geom.binSizeX = (int) mxGetPr(optarg)[1] ; geom.binSizeY = (int) mxGetPr(optarg)[0] ; } else { vlmxError(vlmxErrInvalidArgument,"SIZE is neither a scalar or a 2D vector.") ; } if (geom.binSizeX < 1 || geom.binSizeY < 1) { vlmxError(vlmxErrInvalidArgument,"SIZE value is invalid.") ; } break ; case opt_step : if (!vlmxIsPlainVector(optarg,-1)) { vlmxError(vlmxErrInvalidArgument,"STEP is not a plain vector.") ; } if (mxGetNumberOfElements(optarg) == 1) { step[0] = (int) mxGetPr(optarg)[0] ; step[1] = (int) mxGetPr(optarg)[0] ; } else if (mxGetNumberOfElements(optarg) == 2) { step[0] = (int) mxGetPr(optarg)[1] ; step[1] = (int) mxGetPr(optarg)[0] ; } else { vlmxError(vlmxErrInvalidArgument,"STEP is neither a scalar or a 2D vector.") ; } if (step[0] < 1 || step[1] < 1) { vlmxError(vlmxErrInvalidArgument,"STEP value is invalid.") ; } break ; case opt_window_size : if (!vlmxIsPlainScalar(optarg) || (windowSize = *mxGetPr(optarg)) < 0) { vlmxError(vlmxErrInvalidArgument,"WINDOWSIZE is not a scalar or it is negative.") ; } break ; case opt_float_descriptors : floatDescriptors = VL_TRUE ; break ; case opt_geometry : if (!vlmxIsPlainVector(optarg,3)) { vlmxError(vlmxErrInvalidArgument, "GEOMETRY is not a 3D vector.") ; } geom.numBinY = (int)mxGetPr(optarg)[0] ; geom.numBinX = (int)mxGetPr(optarg)[1] ; geom.numBinT = (int)mxGetPr(optarg)[2] ; if (geom.numBinX < 1 || geom.numBinY < 1 || geom.numBinT < 1) { vlmxError(vlmxErrInvalidArgument, "GEOMETRY value is invalid.") ; } break ; default : abort() ; } } /* ----------------------------------------------------------------- * Do job * -------------------------------------------------------------- */ { int numFrames ; int descrSize ; VlDsiftKeypoint const *frames ; float const *descrs ; int k, i ; VlDsiftFilter *dsift ; /* note that the image received from MATLAB is transposed */ dsift = vl_dsift_new (M, N) ; vl_dsift_set_geometry(dsift, &geom) ; vl_dsift_set_steps(dsift, step[0], step[1]) ; if (bounds) { vl_dsift_set_bounds(dsift, VL_MAX(bounds[1], 0), VL_MAX(bounds[0], 0), VL_MIN(bounds[3], M - 1), VL_MIN(bounds[2], N - 1)); } vl_dsift_set_flat_window(dsift, useFlatWindow) ; if (windowSize >= 0) { vl_dsift_set_window_size(dsift, windowSize) ; } numFrames = vl_dsift_get_keypoint_num (dsift) ; descrSize = vl_dsift_get_descriptor_size (dsift) ; geom = *vl_dsift_get_geometry (dsift) ; if (verbose) { int stepX ; int stepY ; int minX ; int minY ; int maxX ; int maxY ; vl_bool useFlatWindow ; vl_dsift_get_steps (dsift, &stepY, &stepX) ; vl_dsift_get_bounds (dsift, &minY, &minX, &maxY, &maxX) ; useFlatWindow = vl_dsift_get_flat_window(dsift) ; mexPrintf("vl_dsift: image size [W, H] = [%d, %d]\n", N, M) ; mexPrintf("vl_dsift: bounds: [minX,minY,maxX,maxY] = [%d, %d, %d, %d]\n", minX+1, minY+1, maxX+1, maxY+1) ; mexPrintf("vl_dsift: subsampling steps: stepX=%d, stepY=%d\n", stepX, stepY) ; mexPrintf("vl_dsift: num bins: [numBinT, numBinX, numBinY] = [%d, %d, %d]\n", geom.numBinT, geom.numBinX, geom.numBinY) ; mexPrintf("vl_dsift: descriptor size: %d\n", descrSize) ; mexPrintf("vl_dsift: bin sizes: [binSizeX, binSizeY] = [%d, %d]\n", geom.binSizeX, geom.binSizeY) ; mexPrintf("vl_dsift: flat window: %s\n", VL_YESNO(useFlatWindow)) ; mexPrintf("vl_dsift: window size: %g\n", vl_dsift_get_window_size(dsift)) ; mexPrintf("vl_dsift: num of features: %d\n", numFrames) ; } vl_dsift_process (dsift, data) ; frames = vl_dsift_get_keypoints (dsift) ; descrs = vl_dsift_get_descriptors (dsift) ; /* --------------------------------------------------------------- * Create output arrays * ------------------------------------------------------------ */ { mwSize dims [2] ; dims [0] = descrSize ; dims [1] = numFrames ; if (floatDescriptors) { out[OUT_DESCRIPTORS] = mxCreateNumericArray (2, dims, mxSINGLE_CLASS, mxREAL) ; } else { out[OUT_DESCRIPTORS] = mxCreateNumericArray (2, dims, mxUINT8_CLASS, mxREAL) ; } dims [0] = norm ? 3 : 2 ; out[OUT_FRAMES] = mxCreateNumericArray (2, dims, mxDOUBLE_CLASS, mxREAL) ; } /* --------------------------------------------------------------- * Copy back * ------------------------------------------------------------ */ { float *tmpDescr = mxMalloc(sizeof(float) * descrSize) ; double *outFrameIter = mxGetPr(out[OUT_FRAMES]) ; void *outDescrIter = mxGetData(out[OUT_DESCRIPTORS]) ; for (k = 0 ; k < numFrames ; ++k) { *outFrameIter++ = frames[k].y + 1 ; *outFrameIter++ = frames[k].x + 1 ; /* We have an implied / 2 in the norm, because of the clipping below */ if (norm) *outFrameIter++ = frames [k].norm ; vl_dsift_transpose_descriptor (tmpDescr, descrs + descrSize * k, geom.numBinT, geom.numBinX, geom.numBinY) ; if (floatDescriptors) { for (i = 0 ; i < descrSize ; ++i) { float * pt = (float*) outDescrIter ; *pt++ = VL_MIN(512.0F * tmpDescr[i], 255.0F) ; outDescrIter = pt ; } } else { for (i = 0 ; i < descrSize ; ++i) { vl_uint8 * pt = (vl_uint8*) outDescrIter ; *pt++ = (vl_uint8) (VL_MIN(512.0F * tmpDescr[i], 255.0F)) ; outDescrIter = pt ; } } } mxFree(tmpDescr) ; } vl_dsift_delete (dsift) ; } }