Search code examples
c++cmatlabimage-processingmex

calling c function from MATLAB?


I want to call a c function from matlab, for that I tried writing a wrapper function using MEX. While compiling I am getting error C2109: subscript requires array or pointer type and error C2440: 'function' : cannot convert from 'double *' to 'double' Can anyone help me where i did the mistake??

#include "mex.h"
#include "matrix.h"
#include "CVIPtoolkit.h"
#include "CVIPtools.h"
#include "CVIPmatrix.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>


void midd(double outdata, int type, int  height, int width){
     Image *outputImage;
     byte **output;
     int r,c;

     mexPrintf("type %d\n", type);
     mexPrintf("height %d\n", height);
     mexPrintf("width %d\n", width);

     outputImage=new_Image (PGM, GRAY_SCALE, 0, height,  width, CVIP_BYTE, REAL );
     outputImage = h_image(type, height,width);

     output = getData_Image(outputImage, 0);
     for(r=0; r < height; r++) {
            for(c=0; c < width; c++)
            {
                mexPrintf("type %d\n", type);
                mexPrintf("height %d\n", height);
                mexPrintf("width %d\n", width);

                outdata[r+height*c+height*width] =output[r][c];     /* passing data back to MATLAB variable from CVIPtools variable */
             }
         }     
 }


void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    double *outdata;
    int type, height, width;

   // double *indata = (double *)mxGetData(prhs[0]);

   type = mxGetScalar(prhs[0]);
   height = mxGetScalar(prhs[1]);
   width = mxGetScalar(prhs[2]);

   mexPrintf("type %d\n", type);
   mexPrintf("height %d\n", height);
   mexPrintf("width %d\n", width);

   plhs[0] = mxCreateDoubleMatrix(height,width,mxREAL);

   outdata = mxGetData(plhs[0]);
   midd(outdata, type, height, width);

}

The c function i am trying to call is as follows:

#include "CVIPtoolkit.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>


Image *
h_image(int type, unsigned int height, unsigned int width){

    /* type = 1, Constant
     * type = 2, Fixed mask
     * type = 3, Gaussian
     */

    unsigned int r, c, hf_w = width/2, hf_h = height/2;
    Image *outimage;
    float **outdata, sum = 0.0, sigma, tmp1, tmp2, tmp;

    if (height < 3 || width < 3) {
        fprintf(stderr, "Masksize too small, at least 3x3\n");
        return (Image *)NULL;
    }

    outimage = new_Image(PGM, GRAY_SCALE, 1, height, width, CVIP_FLOAT, REAL);
    outdata = (float **)getData_Image(outimage, 0);

    switch (type) {
        case 1:
            for (r = 0; r < height; r++) 
                for (c = 0; c < width; c++) {
                    outdata[r][c] = 1.0;
                    sum += outdata[r][c];
                }
            break;
        case 2:
            for (r = 0; r < height; r++) 
                for (c = 0; c < width; c++) {
                    outdata[r][c] = 1.0;
                    sum += outdata[r][c];
                }
            outdata[height/2][width/2] = height * width;
            sum = sum - 1.0 + outdata[height/2][width/2];
            break;
        case 3:
            c = (width + height) /4;
            r = (width + height) /2;
            sigma = sqrt(c*c / (2 * log(2) + (r - 3) * log(3)));
            sigma = 1.0 / 2.0 /sigma/sigma;
            tmp = width * height;
            for (r = 0; r < height; r++) 
                for (c = 0; c < width; c++) {
                    tmp1 = (r-hf_h)*(r-hf_h); tmp2 = (c-hf_w)*(c-hf_w);
                    outdata[r][c] = tmp*exp(- (tmp1 + tmp2) * sigma);
                    sum += outdata[r][c];
                }
            break;
        default:
            fprintf(stderr, "Incorrect mask type number: %d\n", type);
            return (Image *)NULL;
    }

    return outimage;
}

Solution

  • In your main function, outdata is a pointer to a double, yet your function midd takes in an actual double itself. That's why you're getting that error in type.

    Simply change your function declaration so that the first input accepts a pointer to a double:

    void midd(double *outdata, int type, int  height, int width)
             //      ^^^^^^^^
    

    Minor Note

    I question your copying of your image data back to a MEX array here:

    outdata[r+height*c+height*width] =output[r][c];
    

    You don't need height*width as the offset. r + height*c is enough to access a single channel 2D matrix in column-major order. You only need to offset by height*width if you have a multi-channel image. That offset allows you to access image data in other channels... and since you only have single channel data (it looks like so...), this offset isn't required.

    Therefore, you simply need to do:

    outdata[r + height*c] = output[r][c];
    

    If you don't do this, I suspect you will eventually get segmentation faults because you'll eventually access parts of memory you aren't allowed to access.


    Also, once you fully test your code, get rid of the mexPrintf statements. It's going to unnecessarily flood your Command Prompt with print messages since you have it inside a nested for loop. I suspect you did this for debugging, and that's perfectly fine, but I would suggest you attach the MEX function to an actual debugger and debug your code properly instead of the print statements.

    See my post on how to get that set up here: Preventing a MEX file from crashing in MATLAB