#include
#include "mex.h"
//for windows platform
int round(float a)
{
float tmp = a-(int)a;
if(tmp>=0.5)
return(int)a+1;
else
return (int)a;
}
// small value, used to avoid division by zero
#define eps 0.0001
// unit vectors used to compute gradient orientation
//uu[9]为90 70 50 30 10 -10 -30 -50 -70的sin值,这些角度值为每一个bin的中心角度,每20°一个bin
double uu[9] = {1.0000,
0.9397,
0.7660,
0.500,
0.1736,
-0.1736,
-0.5000,
-0.7660,
-0.9397};
//vv[9]为90 70 50 30 10 -10 -30 -50 -70的cos值
double vv[9] = {0.0000,
0.3420,
0.6428,
0.8660,
0.9848,
0.9848,
0.8660,
0.6428,
0.3420};
static inline double min(double x, double y) { return (x <= y ? x : y); }
static inline double max(double x, double y) { return (x <= y ? y : x); }
static inline int min(int x, int y) { return (x <= y ? x : y); }
static inline int max(int x, int y) { return (x <= y ? y : x); }
// matlab entry point
// [ImageO ImageG] = imGradient(image, bin)
// input: image
// bin
//output: orientations
// gradients
// image should be color with double values
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 2)
mexErrMsgTxt("Wrong number of inputs");
if (nlhs != 2)
mexErrMsgTxt("Wrong number of outputs");
if(mxGetClassID(prhs[0])!=mxDOUBLE_CLASS)
mexErrMsgTxt("The Class of inputs must be double!");
//const mxArray *mximage;
//const mxArray *mxsbin;
//mximage = prhs[0];
//mxsbin = prhs[1];
double *im = mxGetPr(prhs[0]);
const int *dims = mxGetDimensions(prhs[0]);
if (mxGetNumberOfDimensions(prhs[0]) != 3 ||
dims[2] != 3 ||
mxGetClassID(prhs[0]) != mxDOUBLE_CLASS)
mexErrMsgTxt("Invalid input");
int sbin = (int)mxGetScalar(prhs[1]);
// compute the numbers of block
int blocks[2];
blocks[0] = (int)round((double)dims[0]/(double)sbin);
blocks[1] = (int)round((double)dims[1]/(double)sbin);
int visible[2];
visible[0] = blocks[0]*sbin;
visible[1] = blocks[1]*sbin;
int out[2];
out[0] = max(visible[0]-2,0);
out[1] = max(visible[1]-2,0);
mxArray *mxOrientation = mxCreateNumericArray(2,out,mxINT8_CLASS,mxREAL);
mxArray *mxGradientV = mxCreateNumericArray(2,out,mxDOUBLE_CLASS,mxREAL);
//memory for gradient and orientations
int *ImgO = (int *)mxGetPr(mxOrientation);
double *ImgV = (double *)mxGetPr(mxGradientV);
for (int x = 1; x < visible[1]-1; x++)
{
for (int y = 1; y < visible[0]-1; y++)
{
// first color channel
double *s = im + min(x, dims[1]-2)*dims[0] + min(y, dims[0]-2);
double dy = *(s+1) - *(s-1);
double dx = *(s+dims[0]) - *(s-dims[0]);
double v = dx*dx + dy*dy;
// second color channel
s += dims[0]*dims[1];
double dy2 = *(s+1) - *(s-1);
double dx2 = *(s+dims[0]) - *(s-dims[0]);
double v2 = dx2*dx2 + dy2*dy2;
// third color channel
s += dims[0]*dims[1];
double dy3 = *(s+1) - *(s-1);
double dx3 = *(s+dims[0]) - *(s-dims[0]);
double v3 = dx3*dx3 + dy3*dy3;
// pick channel with strongest gradient
if (v2 > v)
{
v = v2;
dx = dx2;
dy = dy2;
}
if (v3 > v)
{
v = v3;
dx = dx3;
dy = dy3;
}
// snap to one of 18 orientations
double best_dot = 0;
int best_o = 0;
for (int o = 0; o < 9; o++)
{
double dot = uu[o]*dx + vv[o]*dy;
if (dot > best_dot)
{
best_dot = dot;
best_o = o;
}
else if (-dot > best_dot)
{
best_dot = -dot;
best_o = o+9;
}
}
ImgO[(x-1)*(visible[0]-2)+(y-1)]=best_o;
ImgV[(x-1)*(visible[0]-2)+(y-1)] =v;
}
}
plhs[0] = mxOrientation;//orientation
plhs[1] = mxGradientV; //gradient
}