1 /*******************************************************************************
2 * Piotr's Computer Vision Matlab Toolbox Version 3.30
3 * Copyright 2014 Piotr Dollar & Ron Appel. [pdollar-at-gmail.com]
4 * Licensed under the Simplified BSD License [see external/bsd.txt]
5 *******************************************************************************/
7 #include "wrappers.hpp"
13 #define PI 3.14159265f
15 // compute x and y gradients for just one column (uses sse)
16 void grad1( float *I, float *Gx, float *Gy, int h, int w, int x ) {
17 int y, y1; float *Ip, *In, r; __m128 *_Ip, *_In, *_G, _r;
18 // compute column of Gx
19 Ip=I-h; In=I+h; r=.5f;
20 if(x==0) { r=1; Ip+=h; } else if(x==w-1) { r=1; In-=h; }
21 if( h<4 || h%4>0 || (size_t(I)&15) || (size_t(Gx)&15) ) {
22 for( y=0; y<h; y++ ) *Gx++=(*In++-*Ip++)*r;
24 _G=(__m128*) Gx; _Ip=(__m128*) Ip; _In=(__m128*) In; _r = SET(r);
25 for(y=0; y<h; y+=4) *_G++=MUL(SUB(*_In++,*_Ip++),_r);
27 // compute column of Gy
28 #define GRADY(r) *Gy++=(*In++-*Ip++)*r;
30 // GRADY(1); Ip--; for(y=1; y<h-1; y++) GRADY(.5f); In--; GRADY(1);
31 y1=((~((size_t) Gy) + 1) & 15)/4; if(y1==0) y1=4; if(y1>h-1) y1=h-1;
32 GRADY(1); Ip--; for(y=1; y<y1; y++) GRADY(.5f);
33 _r = SET(.5f); _G=(__m128*) Gy;
34 for(; y+4<h-1; y+=4, Ip+=4, In+=4, Gy+=4)
35 *_G++=MUL(SUB(LDu(*In),LDu(*Ip)),_r);
36 for(; y<h-1; y++) GRADY(.5f); In--; GRADY(1);
40 // compute x and y gradients at each location (uses sse)
41 void grad2( float *I, float *Gx, float *Gy, int h, int w, int d ) {
42 int o, x, c, a=w*h; for(c=0; c<d; c++) for(x=0; x<w; x++) {
43 o=c*a+x*h; grad1( I+o, Gx+o, Gy+o, h, w, x );
47 // build lookup table a[] s.t. a[x*n]~=acos(x) for x in [-1,1]
49 const int n=10000, b=10; int i;
50 static float a[n*2+b*2]; static bool init=false;
51 float *a1=a+n+b; if( init ) return a1;
52 for( i=-n-b; i<-n; i++ ) a1[i]=PI;
53 for( i=-n; i<n; i++ ) a1[i]=float(acos(i/float(n)));
54 for( i=n; i<n+b; i++ ) a1[i]=0;
55 for( i=-n-b; i<n/10; i++ ) if( a1[i] > PI-1e-6f ) a1[i]=PI-1e-6f;
59 // compute gradient magnitude and orientation at each location (uses sse)
60 void gradMag( float *I, float *M, float *O, int h, int w, int d, bool full ) {
61 int x, y, y1, c, h4, s; float *Gx, *Gy, *M2; __m128 *_Gx, *_Gy, *_M2, _m;
62 float *acost = acosTable(), acMult=10000.0f;
63 // allocate memory for storing one column of output (padded so h4%4==0)
64 h4=(h%4==0) ? h : h-(h%4)+4; s=d*h4*sizeof(float);
65 M2=(float*) alMalloc(s,16); _M2=(__m128*) M2;
66 Gx=(float*) alMalloc(s,16); _Gx=(__m128*) Gx;
67 Gy=(float*) alMalloc(s,16); _Gy=(__m128*) Gy;
68 // compute gradient magnitude and orientation for each column
69 for( x=0; x<w; x++ ) {
70 // compute gradients (Gx, Gy) with maximum squared magnitude (M2)
72 grad1( I+x*h+c*w*h, Gx+c*h4, Gy+c*h4, h, w, x );
73 for( y=0; y<h4/4; y++ ) {
75 _M2[y1]=ADD(MUL(_Gx[y1],_Gx[y1]),MUL(_Gy[y1],_Gy[y1]));
77 _m = CMPGT( _M2[y1], _M2[y] );
78 _M2[y] = OR( AND(_m,_M2[y1]), ANDNOT(_m,_M2[y]) );
79 _Gx[y] = OR( AND(_m,_Gx[y1]), ANDNOT(_m,_Gx[y]) );
80 _Gy[y] = OR( AND(_m,_Gy[y1]), ANDNOT(_m,_Gy[y]) );
83 // compute gradient mangitude (M) and normalize Gx
84 for( y=0; y<h4/4; y++ ) {
85 _m = MIN( RCPSQRT(_M2[y]), SET(1e10f) );
87 if(O) _Gx[y] = MUL( MUL(_Gx[y],_m), SET(acMult) );
88 if(O) _Gx[y] = XOR( _Gx[y], AND(_Gy[y], SET(-0.f)) );
90 memcpy( M+x*h, M2, h*sizeof(float) );
91 // compute and store gradient orientation (O) via table lookup
92 if( O!=0 ) for( y=0; y<h; y++ ) O[x*h+y] = acost[(int)Gx[y]];
94 y1=((~size_t(O+x*h)+1)&15)/4; y=0;
95 for( ; y<y1; y++ ) O[y+x*h]+=(Gy[y]<0)*PI;
96 for( ; y<h-4; y+=4 ) STRu( O[y+x*h],
97 ADD( LDu(O[y+x*h]), AND(CMPLT(LDu(Gy[y]),SET(0.f)),SET(PI)) ) );
98 for( ; y<h; y++ ) O[y+x*h]+=(Gy[y]<0)*PI;
101 alFree(Gx); alFree(Gy); alFree(M2);
104 // normalize gradient magnitude at each location (uses sse)
105 void gradMagNorm( float *M, float *S, int h, int w, float norm ) {
106 __m128 *_M, *_S, _norm; int i=0, n=h*w, n4=n/4;
107 _S = (__m128*) S; _M = (__m128*) M; _norm = SET(norm);
108 bool sse = !(size_t(M)&15) && !(size_t(S)&15);
110 for(; i<n4; i++) { *_M=MUL(*_M,RCP(ADD(*_S++,_norm))); _M++; }
113 for(; i<n; i++) M[i] /= (S[i] + norm);
116 // helper for gradHist, quantize O and M into O0, O1 and M0, M1 (uses sse)
117 void gradQuantize( float *O, float *M, int *O0, int *O1, float *M0, float *M1,
118 int nb, int n, float norm, int nOrients, bool full, bool interpolate )
120 // assumes all *OUTPUT* matrices are 4-byte aligned
121 int i, o0, o1; float o, od, m;
122 __m128i _o0, _o1, *_O0, *_O1; __m128 _o, _od, _m, *_M0, *_M1;
123 // define useful constants
124 const float oMult=(float)nOrients/(full?2*PI:PI); const int oMax=nOrients*nb;
125 const __m128 _norm=SET(norm), _oMult=SET(oMult), _nbf=SET((float)nb);
126 const __m128i _oMax=SET(oMax), _nb=SET(nb);
127 // perform the majority of the work with sse
128 _O0=(__m128i*) O0; _O1=(__m128i*) O1; _M0=(__m128*) M0; _M1=(__m128*) M1;
129 if( interpolate ) for( i=0; i<=n-4; i+=4 ) {
130 _o=MUL(LDu(O[i]),_oMult); _o0=CVT(_o); _od=SUB(_o,CVT(_o0));
131 _o0=CVT(MUL(CVT(_o0),_nbf)); _o0=AND(CMPGT(_oMax,_o0),_o0); *_O0++=_o0;
132 _o1=ADD(_o0,_nb); _o1=AND(CMPGT(_oMax,_o1),_o1); *_O1++=_o1;
133 _m=MUL(LDu(M[i]),_norm); *_M1=MUL(_od,_m); *_M0++=SUB(_m,*_M1); _M1++;
134 } else for( i=0; i<=n-4; i+=4 ) {
135 _o=MUL(LDu(O[i]),_oMult); _o0=CVT(ADD(_o,SET(.5f)));
136 _o0=CVT(MUL(CVT(_o0),_nbf)); _o0=AND(CMPGT(_oMax,_o0),_o0); *_O0++=_o0;
137 *_M0++=MUL(LDu(M[i]),_norm); *_M1++=SET(0.f); *_O1++=SET(0);
139 // compute trailing locations without sse
140 if( interpolate ) for(; i<n; i++ ) {
141 o=O[i]*oMult; o0=(int) o; od=o-o0;
142 o0*=nb; if(o0>=oMax) o0=0; O0[i]=o0;
143 o1=o0+nb; if(o1==oMax) o1=0; O1[i]=o1;
144 m=M[i]*norm; M1[i]=od*m; M0[i]=m-M1[i];
145 } else for(; i<n; i++ ) {
146 o=O[i]*oMult; o0=(int) (o+.5f);
147 o0*=nb; if(o0>=oMax) o0=0; O0[i]=o0;
148 M0[i]=M[i]*norm; M1[i]=0; O1[i]=0;
152 // compute nOrients gradient histograms per bin x bin block of pixels
153 void gradHist( float *M, float *O, float *H, int h, int w,
154 int bin, int nOrients, int softBin, bool full )
156 const int hb=h/bin, wb=w/bin, h0=hb*bin, w0=wb*bin, nb=wb*hb;
157 const float s=(float)bin, sInv=1/s, sInv2=1/s/s;
158 float *H0, *H1, *M0, *M1; int x, y; int *O0, *O1; float xb, init;
159 O0=(int*)alMalloc(h*sizeof(int),16); M0=(float*) alMalloc(h*sizeof(float),16);
160 O1=(int*)alMalloc(h*sizeof(int),16); M1=(float*) alMalloc(h*sizeof(float),16);
162 for( x=0; x<w0; x++ ) {
163 // compute target orientation bins for entire column - very fast
164 gradQuantize(O+x*h,M+x*h,O0,O1,M0,M1,nb,h0,sInv2,nOrients,full,softBin>=0);
166 if( softBin<0 && softBin%2==0 ) {
167 // no interpolation w.r.t. either orienation or spatial bin
169 #define GH H1[O0[y]]+=M0[y]; y++;
170 if( bin==1 ) for(y=0; y<h0;) { GH; H1++; }
171 else if( bin==2 ) for(y=0; y<h0;) { GH; GH; H1++; }
172 else if( bin==3 ) for(y=0; y<h0;) { GH; GH; GH; H1++; }
173 else if( bin==4 ) for(y=0; y<h0;) { GH; GH; GH; GH; H1++; }
174 else for( y=0; y<h0;) { for( int y1=0; y1<bin; y1++ ) { GH; } H1++; }
177 } else if( softBin%2==0 || bin==1 ) {
178 // interpolate w.r.t. orientation only, not spatial bin
180 #define GH H1[O0[y]]+=M0[y]; H1[O1[y]]+=M1[y]; y++;
181 if( bin==1 ) for(y=0; y<h0;) { GH; H1++; }
182 else if( bin==2 ) for(y=0; y<h0;) { GH; GH; H1++; }
183 else if( bin==3 ) for(y=0; y<h0;) { GH; GH; GH; H1++; }
184 else if( bin==4 ) for(y=0; y<h0;) { GH; GH; GH; GH; H1++; }
185 else for( y=0; y<h0;) { for( int y1=0; y1<bin; y1++ ) { GH; } H1++; }
189 // interpolate using trilinear interpolation
190 float ms[4], xyd, yb, xd, yd; __m128 _m, _m0, _m1;
191 bool hasLf, hasRt; int xb0, yb0;
192 if( x==0 ) { init=(0+.5f)*sInv-0.5f; xb=init; }
193 hasLf = xb>=0; xb0 = hasLf?(int)xb:-1; hasRt = xb0 < wb-1;
194 xd=xb-xb0; xb+=sInv; yb=init; y=0;
195 // macros for code conciseness
196 #define GHinit yd=yb-yb0; yb+=sInv; H0=H+xb0*hb+yb0; xyd=xd*yd; \
197 ms[0]=1-xd-yd+xyd; ms[1]=yd-xyd; ms[2]=xd-xyd; ms[3]=xyd;
198 #define GH(H,ma,mb) H1=H; STRu(*H1,ADD(LDu(*H1),MUL(ma,mb)));
199 // leading rows, no top bin
200 for( ; y<bin/2; y++ ) {
202 if(hasLf) { H0[O0[y]+1]+=ms[1]*M0[y]; H0[O1[y]+1]+=ms[1]*M1[y]; }
203 if(hasRt) { H0[O0[y]+hb+1]+=ms[3]*M0[y]; H0[O1[y]+hb+1]+=ms[3]*M1[y]; }
205 // main rows, has top and bottom bins, use SSE for minor speedup
206 if( softBin<0 ) for( ; ; y++ ) {
207 yb0 = (int) yb; if(yb0>=hb-1) break; GHinit; _m0=SET(M0[y]);
208 if(hasLf) { _m=SET(0,0,ms[1],ms[0]); GH(H0+O0[y],_m,_m0); }
209 if(hasRt) { _m=SET(0,0,ms[3],ms[2]); GH(H0+O0[y]+hb,_m,_m0); }
210 } else for( ; ; y++ ) {
211 yb0 = (int) yb; if(yb0>=hb-1) break; GHinit;
212 _m0=SET(M0[y]); _m1=SET(M1[y]);
213 if(hasLf) { _m=SET(0,0,ms[1],ms[0]);
214 GH(H0+O0[y],_m,_m0); GH(H0+O1[y],_m,_m1); }
215 if(hasRt) { _m=SET(0,0,ms[3],ms[2]);
216 GH(H0+O0[y]+hb,_m,_m0); GH(H0+O1[y]+hb,_m,_m1); }
218 // final rows, no bottom bin
220 yb0 = (int) yb; GHinit;
221 if(hasLf) { H0[O0[y]]+=ms[0]*M0[y]; H0[O1[y]]+=ms[0]*M1[y]; }
222 if(hasRt) { H0[O0[y]+hb]+=ms[2]*M0[y]; H0[O1[y]+hb]+=ms[2]*M1[y]; }
228 alFree(O0); alFree(O1); alFree(M0); alFree(M1);
229 // normalize boundary bins which only get 7/8 of weight of interior bins
230 if( softBin%2!=0 ) for( int o=0; o<nOrients; o++ ) {
231 x=0; for( y=0; y<hb; y++ ) H[o*nb+x*hb+y]*=8.f/7.f;
232 y=0; for( x=0; x<wb; x++ ) H[o*nb+x*hb+y]*=8.f/7.f;
233 x=wb-1; for( y=0; y<hb; y++ ) H[o*nb+x*hb+y]*=8.f/7.f;
234 y=hb-1; for( x=0; x<wb; x++ ) H[o*nb+x*hb+y]*=8.f/7.f;
238 /******************************************************************************/
240 // HOG helper: compute 2x2 block normalization values (padded by 1 pixel)
241 float* hogNormMatrix( float *H, int nOrients, int hb, int wb, int bin ) {
242 float *N, *N1, *n; int o, x, y, dx, dy, hb1=hb+1, wb1=wb+1;
243 float eps = 1e-4f/4/bin/bin/bin/bin; // precise backward equality
244 N = (float*) wrCalloc(hb1*wb1,sizeof(float)); N1=N+hb1+1;
245 for( o=0; o<nOrients; o++ ) for( x=0; x<wb; x++ ) for( y=0; y<hb; y++ )
246 N1[x*hb1+y] += H[o*wb*hb+x*hb+y]*H[o*wb*hb+x*hb+y];
247 for( x=0; x<wb-1; x++ ) for( y=0; y<hb-1; y++ ) {
248 n=N1+x*hb1+y; *n=1/float(sqrt(n[0]+n[1]+n[hb1]+n[hb1+1]+eps)); }
249 x=0; dx= 1; dy= 1; y=0; N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
250 x=0; dx= 1; dy= 0; for(y=0; y<hb1; y++) N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
251 x=0; dx= 1; dy=-1; y=hb1-1; N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
252 x=wb1-1; dx=-1; dy= 1; y=0; N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
253 x=wb1-1; dx=-1; dy= 0; for( y=0; y<hb1; y++) N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
254 x=wb1-1; dx=-1; dy=-1; y=hb1-1; N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
255 y=0; dx= 0; dy= 1; for(x=0; x<wb1; x++) N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
256 y=hb1-1; dx= 0; dy=-1; for(x=0; x<wb1; x++) N[x*hb1+y]=N[(x+dx)*hb1+y+dy];
260 // HOG helper: compute HOG or FHOG channels
261 void hogChannels( float *H, const float *R, const float *N,
262 int hb, int wb, int nOrients, float clip, int type )
264 #define GETT(blk) t=R1[y]*N1[y-(blk)]; if(t>clip) t=clip; c++;
265 const float r=.2357f; int o, x, y, c; float t;
266 const int nb=wb*hb, nbo=nOrients*nb, hb1=hb+1;
267 for( o=0; o<nOrients; o++ ) for( x=0; x<wb; x++ ) {
268 const float *R1=R+o*nb+x*hb, *N1=N+x*hb1+hb1+1;
269 float *H1 = (type<=1) ? (H+o*nb+x*hb) : (H+x*hb);
270 if( type==0) for( y=0; y<hb; y++ ) {
271 // store each orientation and normalization (nOrients*4 channels)
272 c=-1; GETT(0); H1[c*nbo+y]=t; GETT(1); H1[c*nbo+y]=t;
273 GETT(hb1); H1[c*nbo+y]=t; GETT(hb1+1); H1[c*nbo+y]=t;
274 } else if( type==1 ) for( y=0; y<hb; y++ ) {
275 // sum across all normalizations (nOrients channels)
276 c=-1; GETT(0); H1[y]+=t*.5f; GETT(1); H1[y]+=t*.5f;
277 GETT(hb1); H1[y]+=t*.5f; GETT(hb1+1); H1[y]+=t*.5f;
278 } else if( type==2 ) for( y=0; y<hb; y++ ) {
279 // sum across all orientations (4 channels)
280 c=-1; GETT(0); H1[c*nb+y]+=t*r; GETT(1); H1[c*nb+y]+=t*r;
281 GETT(hb1); H1[c*nb+y]+=t*r; GETT(hb1+1); H1[c*nb+y]+=t*r;
287 // compute HOG features
288 void hog( float *M, float *O, float *H, int h, int w, int binSize,
289 int nOrients, int softBin, bool full, float clip )
291 float *N, *R; const int hb=h/binSize, wb=w/binSize, nb=hb*wb;
293 // compute unnormalized gradient histograms
294 R = (float*) wrCalloc(wb*hb*nOrients,sizeof(float));
295 gradHist( M, O, R, h, w, binSize, nOrients, softBin, full );
296 // compute block normalization values
297 N = hogNormMatrix( R, nOrients, hb, wb, binSize );
298 // perform four normalizations per spatial block
299 hogChannels( H, R, N, hb, wb, nOrients, clip, 0 );
300 wrFree(N); wrFree(R);
303 // compute FHOG features
304 void fhog( float *M, float *O, float *H, int h, int w, int binSize,
305 int nOrients, int softBin, float clip )
307 const int hb=h/binSize, wb=w/binSize, nb=hb*wb, nbo=nb*nOrients;
308 float *N, *R1, *R2; int o, x;
309 // compute unnormalized constrast sensitive histograms
310 R1 = (float*) wrCalloc(wb*hb*nOrients*2 + 2,sizeof(float));
311 gradHist( M, O, R1, h, w, binSize, nOrients*2, softBin, true );
312 // compute unnormalized contrast insensitive histograms
313 R2 = (float*) wrCalloc(wb*hb*nOrients,sizeof(float));
314 for( o=0; o<nOrients; o++ ) for( x=0; x<nb; x++ )
315 R2[o*nb+x] = R1[o*nb+x]+R1[(o+nOrients)*nb+x];
316 // compute block normalization values
317 N = hogNormMatrix( R2, nOrients, hb, wb, binSize );
318 // normalized histograms and texture channels
319 hogChannels( H+nbo*0, R1, N, hb, wb, nOrients*2, clip, 1 );
320 hogChannels( H+nbo*2, R2, N, hb, wb, nOrients*1, clip, 1 );
321 hogChannels( H+nbo*3, R1, N, hb, wb, nOrients*2, clip, 2 );
322 wrFree(N); wrFree(R1); wrFree(R2);
325 /******************************************************************************/
326 #ifdef MATLAB_MEX_FILE
327 // Create [hxwxd] mxArray array, initialize to 0 if c=true
328 mxArray* mxCreateMatrix3( int h, int w, int d, mxClassID id, bool c, void **I ){
329 const int dims[3]={h,w,d}, n=h*w*d; int b; mxArray* M;
330 if( id==mxINT32_CLASS ) b=sizeof(int);
331 else if( id==mxDOUBLE_CLASS ) b=sizeof(double);
332 else if( id==mxSINGLE_CLASS ) b=sizeof(float);
333 else mexErrMsgTxt("Unknown mxClassID.");
334 *I = c ? mxCalloc(n,b) : mxMalloc(n*b);
335 M = mxCreateNumericMatrix(0,0,id,mxREAL);
336 mxSetData(M,*I); mxSetDimensions(M,dims,3); return M;
339 // Check inputs and outputs to mex, retrieve first input I
340 void checkArgs( int nl, mxArray *pl[], int nr, const mxArray *pr[], int nl0,
341 int nl1, int nr0, int nr1, int *h, int *w, int *d, mxClassID id, void **I )
343 const int *dims; int nDims;
344 if( nl<nl0 || nl>nl1 ) mexErrMsgTxt("Incorrect number of outputs.");
345 if( nr<nr0 || nr>nr1 ) mexErrMsgTxt("Incorrect number of inputs.");
346 nDims = mxGetNumberOfDimensions(pr[0]); dims = mxGetDimensions(pr[0]);
347 *h=dims[0]; *w=dims[1]; *d=(nDims==2) ? 1 : dims[2]; *I = mxGetPr(pr[0]);
348 if( nDims!=2 && nDims!=3 ) mexErrMsgTxt("I must be a 2D or 3D array.");
349 if( mxGetClassID(pr[0])!=id ) mexErrMsgTxt("I has incorrect type.");
352 // [Gx,Gy] = grad2(I) - see gradient2.m
353 void mGrad2( int nl, mxArray *pl[], int nr, const mxArray *pr[] ) {
354 int h, w, d; float *I, *Gx, *Gy;
355 checkArgs(nl,pl,nr,pr,1,2,1,1,&h,&w,&d,mxSINGLE_CLASS,(void**)&I);
356 if(h<2 || w<2) mexErrMsgTxt("I must be at least 2x2.");
357 pl[0]= mxCreateMatrix3( h, w, d, mxSINGLE_CLASS, 0, (void**) &Gx );
358 pl[1]= mxCreateMatrix3( h, w, d, mxSINGLE_CLASS, 0, (void**) &Gy );
359 grad2( I, Gx, Gy, h, w, d );
362 // [M,O] = gradMag( I, channel, full ) - see gradientMag.m
363 void mGradMag( int nl, mxArray *pl[], int nr, const mxArray *pr[] ) {
364 int h, w, d, c, full; float *I, *M, *O=0;
365 checkArgs(nl,pl,nr,pr,1,2,3,3,&h,&w,&d,mxSINGLE_CLASS,(void**)&I);
366 if(h<2 || w<2) mexErrMsgTxt("I must be at least 2x2.");
367 c = (int) mxGetScalar(pr[1]); full = (int) mxGetScalar(pr[2]);
368 if( c>0 && c<=d ) { I += h*w*(c-1); d=1; }
369 pl[0] = mxCreateMatrix3(h,w,1,mxSINGLE_CLASS,0,(void**)&M);
370 if(nl>=2) pl[1] = mxCreateMatrix3(h,w,1,mxSINGLE_CLASS,0,(void**)&O);
371 gradMag(I, M, O, h, w, d, full>0 );
374 // gradMagNorm( M, S, norm ) - operates on M - see gradientMag.m
375 void mGradMagNorm( int nl, mxArray *pl[], int nr, const mxArray *pr[] ) {
376 int h, w, d; float *M, *S, norm;
377 checkArgs(nl,pl,nr,pr,0,0,3,3,&h,&w,&d,mxSINGLE_CLASS,(void**)&M);
378 if( mxGetM(pr[1])!=h || mxGetN(pr[1])!=w || d!=1 ||
379 mxGetClassID(pr[1])!=mxSINGLE_CLASS ) mexErrMsgTxt("M or S is bad.");
380 S = (float*) mxGetPr(pr[1]); norm = (float) mxGetScalar(pr[2]);
381 gradMagNorm(M,S,h,w,norm);
384 // H=gradHist(M,O,[...]) - see gradientHist.m
385 void mGradHist( int nl, mxArray *pl[], int nr, const mxArray *pr[] ) {
386 int h, w, d, hb, wb, nChns, binSize, nOrients, softBin, useHog;
387 bool full; float *M, *O, *H, clipHog;
388 checkArgs(nl,pl,nr,pr,1,3,2,8,&h,&w,&d,mxSINGLE_CLASS,(void**)&M);
389 O = (float*) mxGetPr(pr[1]);
390 if( mxGetM(pr[1])!=h || mxGetN(pr[1])!=w || d!=1 ||
391 mxGetClassID(pr[1])!=mxSINGLE_CLASS ) mexErrMsgTxt("M or O is bad.");
392 binSize = (nr>=3) ? (int) mxGetScalar(pr[2]) : 8;
393 nOrients = (nr>=4) ? (int) mxGetScalar(pr[3]) : 9;
394 softBin = (nr>=5) ? (int) mxGetScalar(pr[4]) : 1;
395 useHog = (nr>=6) ? (int) mxGetScalar(pr[5]) : 0;
396 clipHog = (nr>=7) ? (float) mxGetScalar(pr[6]) : 0.2f;
397 full = (nr>=8) ? (bool) (mxGetScalar(pr[7])>0) : false;
398 hb = h/binSize; wb = w/binSize;
399 nChns = useHog== 0 ? nOrients : (useHog==1 ? nOrients*4 : nOrients*3+5);
400 pl[0] = mxCreateMatrix3(hb,wb,nChns,mxSINGLE_CLASS,1,(void**)&H);
401 if( nOrients==0 ) return;
403 gradHist( M, O, H, h, w, binSize, nOrients, softBin, full );
404 } else if(useHog==1) {
405 hog( M, O, H, h, w, binSize, nOrients, softBin, full, clipHog );
407 fhog( M, O, H, h, w, binSize, nOrients, softBin, clipHog );
411 // inteface to various gradient functions (see corresponding Matlab functions)
412 void mexFunction( int nl, mxArray *pl[], int nr, const mxArray *pr[] ) {
413 int f; char action[1024]; f=mxGetString(pr[0],action,1024); nr--; pr++;
414 if(f) mexErrMsgTxt("Failed to get action.");
415 else if(!strcmp(action,"gradient2")) mGrad2(nl,pl,nr,pr);
416 else if(!strcmp(action,"gradientMag")) mGradMag(nl,pl,nr,pr);
417 else if(!strcmp(action,"gradientMagNorm")) mGradMagNorm(nl,pl,nr,pr);
418 else if(!strcmp(action,"gradientHist")) mGradHist(nl,pl,nr,pr);
419 else mexErrMsgTxt("Invalid action.");