void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
	int feature_dim = mxGetPr(prhs[5])[0];
	int img_h = mxGetM(prhs[0]); //imgHeight
	int img_w = mxGetN(prhs[0])/feature_dim; //imgWidth
	int N = img_h*img_w;
	int K = mxGetPr(prhs[4])[0]; //k-NN
	int dims[2] = {N, N};
	CvSparseMat* affinityMatrix = cvCreateSparseMat(2, dims, CV_32FC1);
	double *fMap = mxGetPr(prhs[0]); // feature Map
	double *rIdx = mxGetPr(prhs[1]); // min vMap rIdx
	double *cIdx = mxGetPr(prhs[2]); // min vMap cIdx
	double *gbox = mxGetPr(prhs[3]); //global proposals
	int gbox_num = mxGetM(prhs[2]);	
	mexPrintf("img_h=%d img_w=%d N=%d K=%d gbox_num=%d\n",img_h, img_w, N, K, gbox_num);

	int *c_pos = new int[gbox_num];
	int *r_pos = new int[gbox_num];
	cv::Mat1f X(gbox_num, feature_dim);
	
	double tol_d = mxGetPr(prhs[6])[0]; //LLE tolerance
	float tol;
	tol = (float)tol_d;
	mexPrintf("tol=%f \n",tol);

		for(int b=0; b<gbox_num; b++){ //gbox iteration
		int cmin = gbox[(0 + b*4)];
		int rmin = gbox[(1 + b*4)];	
		int cmax = gbox[(2 + b*4)];	
		int rmax = gbox[(3 + b*4)];
		c_pos[b] = int(rIdx[b]);
		r_pos[b] = int(cIdx[b]);
	//	mexPrintf("b=%d\n",b);
		for(int k=0; k<feature_dim; k++)
		{
			//X(b,k) = fMap[ k*img_h*img_w + r_pos[b]*img_h + c_pos[b] ];
			X(b,k) = fMap[ k*img_h*img_w + r_pos[b]*img_h + c_pos[b] ];
		}

	}
//	cv::FileStorage fileX("X.yml", cv::FileStorage::WRITE);
//	fileX << "X" << X;	
	//mexPrintf("%f %f %f %f %f %f %f %f %f %f \n",X(3,0),X(3,1),X(3,2),X(3,3),X(3,4),X(3,5),X(3,6),X(3,7),X(3,8),X(3,9));	

//	mexPrintf("Checkpoint 1\n");
	cv::Mat1f W(gbox_num, K);
	cv::Mat1i neighbors(gbox_num, K);
	LLE(X, W, neighbors, gbox_num, feature_dim, tol, K);
	
//	cv::FileStorage fileW("W.yml", cv::FileStorage::WRITE);
//	fileX << "W" << W;	
//	mexPrintf("Checkpoint 2\n");

	plhs[0] = mxCreateDoubleMatrix(gbox_num, K+1, mxREAL);
	double *neighborPixels = mxGetPr(plhs[0]);
	for(int n=0;n<gbox_num;n++) {
		int xp = r_pos[n];
		int yp = c_pos[n];
		int p = xp * img_h + yp;
		neighborPixels[n] = p + 1;
		for(int k=0;k<K;k++) {
			if(W(n, k) != 0) {
				int nIdx = neighbors(n, k);
				if(nIdx >= 0) {
					int xq = r_pos[nIdx];
					int yq = c_pos[nIdx];
					//int q = yq * img_w + xq;
					int q = xq * img_h + yq;
					((float*)cvPtr2D(affinityMatrix, p, q))[0] = W(n, k);
					neighborPixels[(k+1)*gbox_num + n] = q + 1;
				}
			}
		}
	}
	pushSparseMatrix(affinityMatrix, "LLEGLOBAL");
	cvReleaseSparseMat(&affinityMatrix);

//	mexPrintf("Checkpoint 3\n");
	delete [] c_pos;
	delete [] r_pos;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
	int feature_dim = mxGetPr(prhs[3])[0];
	int img_h = mxGetM(prhs[0]);
	int img_w = mxGetN(prhs[0])/feature_dim;
	int N = img_h*img_w;
	int K = mxGetPr(prhs[2])[0];
	int dims[2] = {N, N};
	CvSparseMat* affinityMatrix = cvCreateSparseMat(2, dims, CV_32FC1);
	double *nMap = mxGetPr(prhs[0]); // normal Map
	double *vMap = mxGetPr(prhs[1]); // variance Map
	int g_size = mxGetPr(prhs[4])[0];

	int ngrid_w = ceil(img_w / (float)g_size);
	int ngrid_h = ceil(img_h / (float)g_size);
	int Ngrid = ngrid_w * ngrid_h;
	int *x_pos = new int[Ngrid];
	int *y_pos = new int[Ngrid];
	cv::Mat1f X(Ngrid, feature_dim);
	
	for(int j=0, n=0;j<img_h;j+=g_size) { // grid iteration
		for(int i=0;i<img_w;i+=g_size) {
			double vmin = 99999;
			for(int gj=0;gj<g_size && j+gj < img_h;gj++) { // y pos in grid
				for(int gi=0;gi<g_size && i+gi < img_w;gi++) { // x pos
					double var = vMap[(i+gi)*img_h + (j+gj)];
					if(var < vmin) {
						vmin = var;
						x_pos[n] = (i+gi);
						y_pos[n] = (j+gj);
					}
				}
			}
			for(int k=0;k<feature_dim;k++)
				X(n, k) = nMap[k*img_h*img_w+x_pos[n]*img_h+y_pos[n]];
			n++;
		}
	}

	cv::Mat1f W(Ngrid, K);
	cv::Mat1i neighbors(Ngrid, K);
	LLE(X, W, neighbors, Ngrid, feature_dim, K);
	
	//plhs[0] = mxCreateDoubleMatrix(img_w, img_h, mxREAL);
	plhs[0] = mxCreateDoubleMatrix(Ngrid, K+1, mxREAL);
	double *neighborPixels = mxGetPr(plhs[0]);
	
	for(int n=0;n<Ngrid;n++) {
		int xp = x_pos[n];
		int yp = y_pos[n];
		//int p = yp * img_w + xp;
		int p = xp * img_h + yp;
		neighborPixels[n] = p + 1;
		for(int k=0;k<K;k++) {
			if(W(n, k) != 0) {
				int nIdx = neighbors(n, k);
				if(nIdx >= 0) {
					int xq = x_pos[nIdx];
					int yq = y_pos[nIdx];
					//int q = yq * img_w + xq;
					int q = xq * img_h + yq;
					((float*)cvPtr2D(affinityMatrix, p, q))[0] = W(n, k);
					neighborPixels[(k+1)*Ngrid + n] = q + 1;
				}
			}
		}
	}
	
    pushSparseMatrix(affinityMatrix, "LLENORMAL");
	cvReleaseSparseMat(&affinityMatrix);
	
	delete [] x_pos;
	delete [] y_pos;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    int h = mxGetM(prhs[0]);
    int w = mxGetN(prhs[0])/3;
    int i, j, k;
    int nx[] = {0, 0, 1, -1, -1, 1, 1, -1};
    int ny[] = {1, -1, 0, 0, -1, 1, -1, 1};
    double cp[3], cq[3];
    double *chroma = mxGetPr(prhs[0]);
    double dist;
    plhs[0] = mxCreateDoubleMatrix(h*w, 1, mxREAL);
    plhs[1] = mxCreateDoubleMatrix(h, w, mxREAL);
    int dims[2] = {h*w, h*w};
    CvSparseMat* m_refConsMat = cvCreateSparseMat(2, dims, CV_32FC1);
    float sig_c= mxGetPr(prhs[1])[0];
    float sig_i= mxGetPr(prhs[2])[0];
    double *image = mxGetPr(prhs[3]);
    double ip[3], iq[3];
    double lp, lq;

    for(j=0; j<h; j++)
    {
        for(i=0; i<w; i++)
        {
            int p = i*h+j;
            cp[0] = chroma[i*h+j];
            cp[1] = chroma[h*w+i*h+j];
            cp[2] = chroma[2*h*w+i*h+j];
            ip[0] = image[i*h+j];
            ip[1] = image[h*w+i*h+j];
            ip[2] = image[2*h*w+i*h+j];
            lp = log(MAX(sqrt(ip[0]*ip[0] + ip[1]*ip[1] + ip[2]*ip[2]), 0.0001));
            for(k=0; k<8; k++)
            {
                int qi = i + nx[k];
                int qj = j + ny[k];
                int q = qi*h+qj;
                if(qi < 0 || qj < 0 || qi >= w || qj >= h)
                {
                    continue;
                }
                cq[0] = chroma[qi*h+qj];
                cq[1] = chroma[h*w+qi*h+qj];
                cq[2] = chroma[2*h*w+qi*h+qj];
                iq[0] = image[qi*h+qj];
                iq[1] = image[h*w+qi*h+qj];
                iq[2] = image[2*h*w+qi*h+qj];
                lq = log(MAX(sqrt(iq[0]*iq[0] + iq[1]*iq[1] + iq[2]*iq[2]), 0.0001));

                dist = 2.0 * (1.0 - (cp[0]*cq[0]+cp[1]*cq[1]+cp[2]*cq[2]));
                float weight = (1 + exp(-exp(lp) * exp(lp) / (sig_i*sig_i) - exp(lq)*exp(lq) / (sig_i*sig_i)));


                weight = weight * (exp(-dist*dist/(sig_c*sig_c)));
                if(k == 2)
                    mxGetPr(plhs[1])[p] = weight;

                if(_isnan(weight)) weight = 0;
                ((float*)cvPtr2D(m_refConsMat, p, p))[0] += weight;
                ((float*)cvPtr2D(m_refConsMat, q, q))[0] += weight;
                ((float*)cvPtr2D(m_refConsMat, p, q))[0] += -weight;
                ((float*)cvPtr2D(m_refConsMat, q, p))[0] += -weight;

                float dI = lp - lq;
                mxGetPr(plhs[0])[p] += weight * dI;
                mxGetPr(plhs[0])[q] -= weight * dI;
            }
        }
    }
    pushSparseMatrix(m_refConsMat, "WRC");

    cvReleaseSparseMat(&m_refConsMat);
}