trayres
trayres

Reputation: 530

Matlab MEX file - index correct, incorrect UINT32 values

This is the next step of my previous question here

With the same Matlab testmatrix as in my question:

testmatrix code here:

%Create a 4D array 2x,2y, rgb(3), framenumber(from 1 to 5)
%Framenumber from 1 to 5

testmatrix(1,1,1,1) = 0;
testmatrix(1,1,1,2) = 1;
testmatrix(1,1,1,3) = 2;
testmatrix(1,1,1,4) = 3;
testmatrix(1,1,1,5) = 4;

testmatrix(1,1,2,1) = 5;
testmatrix(1,1,2,2) = 6;
testmatrix(1,1,2,3) = 7;
testmatrix(1,1,2,4) = 8;
testmatrix(1,1,2,5) = 9;

testmatrix(1,1,3,1) = 10;
testmatrix(1,1,3,2) = 11;
testmatrix(1,1,3,3) = 12;
testmatrix(1,1,3,4) = 13;
testmatrix(1,1,3,5) = 14;

testmatrix(1,2,1,1) = 15;
testmatrix(1,2,1,2) = 16;
testmatrix(1,2,1,3) = 17;
testmatrix(1,2,1,4) = 18;
testmatrix(1,2,1,5) = 19;

testmatrix(1,2,2,1) = 20;
testmatrix(1,2,2,2) = 21;
testmatrix(1,2,2,3) = 22;
testmatrix(1,2,2,4) = 23;
testmatrix(1,2,2,5) = 24;

testmatrix(1,2,3,1) = 25;
testmatrix(1,2,3,2) = 26;
testmatrix(1,2,3,3) = 27;
testmatrix(1,2,3,4) = 28;
testmatrix(1,2,3,5) = 29;

testmatrix(2,1,1,1) = 30;
testmatrix(2,1,1,2) = 31;
testmatrix(2,1,1,3) = 32;
testmatrix(2,1,1,4) = 33;
testmatrix(2,1,1,5) = 34;

testmatrix(2,1,2,1) = 35;
testmatrix(2,1,2,2) = 36;
testmatrix(2,1,2,3) = 37;
testmatrix(2,1,2,4) = 38;
testmatrix(2,1,2,5) = 39;

testmatrix(2,1,3,1) = 40;
testmatrix(2,1,3,2) = 41;
testmatrix(2,1,3,3) = 42;
testmatrix(2,1,3,4) = 43;
testmatrix(2,1,3,5) = 44;

testmatrix(2,2,1,1) = 45;
testmatrix(2,2,1,2) = 46;
testmatrix(2,2,1,3) = 47;
testmatrix(2,2,1,4) = 48;
testmatrix(2,2,1,5) = 49;

testmatrix(2,2,2,1) = 50;
testmatrix(2,2,2,2) = 51;
testmatrix(2,2,2,3) = 52;
testmatrix(2,2,2,4) = 53;
testmatrix(2,2,2,5) = 54;

testmatrix(2,2,3,1) = 55;
testmatrix(2,2,3,2) = 56;
testmatrix(2,2,3,3) = 57;
testmatrix(2,2,3,4) = 58;
testmatrix(2,2,3,5) = 59;

testmatrix = uint8(testmatrix);

I have created the following Mex file:

    #include <stdint.h>
#include "mex.h"

void
mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
//Check - expect 1 input, expect 1 outputs
    if (nrhs != 1) {
        mexErrMsgIdAndTxt( "MATLAB:24bit_pixel_from_uint8_rgb:invalidNumInputs",
                "One input argument required.");
    }
    if (nlhs > 1) {
        mexErrMsgIdAndTxt( "MATLAB:24bit_pixel_from_uint8_rgb:maxlhs",
                "Too many output arguments.");
    }    

    //declare variables
    mwSize *dim_array, dims;
    mxArray *a_in_m, *b_out_m;
    uint8_T *a,b;
    int X,Y,RGB,FRAMENUMBER;
    int X_INDX,Y_INDX,RGB_INDX,FRAMENUMBER_INDX;

    dims             = mxGetNumberOfDimensions(prhs[0]);
    dim_array        = mxGetDimensions(prhs[0]);   
    X                = dim_array[0];
    Y                = dim_array[1];
    RGB              = dim_array[2];
    FRAMENUMBER      = dim_array[3];
    mexPrintf("dims: %d\n",dims);
    mexPrintf("X: %d\n",X);
    mexPrintf("Y: %d\n",Y);
    mexPrintf("RGB: %d\n",RGB);
    mexPrintf("FRAMENUMBER: %d\n",FRAMENUMBER);

    a = mxGetData(prhs[0]);
    mexPrintf("a is: %d\n",a[0]); //IS zero, now the other values aren't what I expected...

    b_out_m = plhs[0] = mxCreateNumericArray(dims, dim_array, mxUINT32_CLASS, 0);
    //b = mxGetData(b_out_m);

    int linear_index = 0;
    for(X_INDX=0;X_INDX<X;X_INDX++)
    {
        for(Y_INDX=0;Y_INDX<Y;Y_INDX++)
        {
            for(RGB_INDX=0;RGB_INDX<RGB;RGB_INDX++)
            {
                for(FRAMENUMBER_INDX=0;FRAMENUMBER_INDX<FRAMENUMBER;FRAMENUMBER_INDX++)
                {
                   mexPrintf("Linear Index: %u\n",linear_index); 
                   mexPrintf("Value[%u]: %u\n",FRAMENUMBER_INDX + (RGB_INDX*FRAMENUMBER)+(Y_INDX*RGB*FRAMENUMBER)+(X_INDX*Y*RGB*FRAMENUMBER),(uint8_T)a[linear_index]);//FRAMENUMBER_INDX + (RGB_INDX*FRAMENUMBER)+(Y_INDX*RGB*FRAMENUMBER)+(X_INDX*Y*RGB*FRAMENUMBER)
                   linear_index += 1;
                }
            }
        }

    }
}

My indexing looks correct, but when I print the values out, I get the following:

>> rgb_to_uint8(testmatrix)
dims: 4
X: 2
Y: 2
RGB: 3
FRAMENUMBER: 5
a is: 755965440
Linear Index: 0
Value[0]: 755965440
Linear Index: 1
Value[1]: 840180485
Linear Index: 2
Value[2]: 924395530
Linear Index: 3
Value[3]: 772808449
...etc

I am clearly accessing something wrong; can somebody point me in the right direction? I'll edit it as I go along and see if I can figure it out.

[EDIT] I updated the code with the suggestions below - I changed to uint8_T, and it did wonders, but I expected this setup to read the array out of memory as 0,1,2,3... etc. It appears to be "skipping around", which means that the arrays aren't stored in memory as I tried to access them - I thought Matlab was column-major, so I indexed by the 4th dimension, then the third, then the second, then the first...

I'm creating another test matrix, but I'll index it the other way, and see if I get the values to read out linearly. Thanks for the notes, all, and the pointer to uint8_T (which made it start clicking along much better, and the void* cast was missing).

Upvotes: 1

Views: 220

Answers (1)

chappjc
chappjc

Reputation: 30589

Update from my comment: When you do testmatrix(:) it reads out all the elements of an array of any dimensionality in in linear order. It goes down then across and then the remaining dimensions. You are traversing the last dimension with testmatrix(1,1,1,1),testmatrix(1,1,1,2),testmatrix(1,1,1,3).


There are several issues to address, but the core of the issue is the data type, as jucestain said. When you use mxGetData, you get a void* and it is your responsibility to ensure that whatever you cast to is the actual underlying data type (in the MATLAB array).

A few notes:

  • Get used to using mxIsClass to check the input type and you won't have these problems as easily. It takes a string type for the class, one of the types listed when you type help class, just as if you were calling isa in MATLAB. Just coding the check is a good way for you to double check the intended use of the function.
  • You don't need to mxDuplicate from prhs[] to get the data. Just read the data, but don't write to it.
  • Use mxGetPr only to get a double* (and only if mxIsClass says it's a double!). If you have any other data type, use mxGetData.
  • mxGetData returns a void*, and you need and explicit cast (e.g. (uint32_t*)) to access the data, but again, it doesn't convert the underlying data so be sure it is already correct.
  • mxGetDimensions returns a const mwSize*, so remember the const.

Upvotes: 2

Related Questions