Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

MxArray: convert cv::Mat of type CV_8U to logical mxArray #14

Closed
amroamroamro opened this issue Sep 4, 2012 · 5 comments
Closed

MxArray: convert cv::Mat of type CV_8U to logical mxArray #14

amroamroamro opened this issue Sep 4, 2012 · 5 comments
Assignees
Labels

Comments

@amroamroamro
Copy link
Collaborator

Consider the following MEX function:

myFcn.cpp

#include "mexopencv.hpp"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    cv::Mat m(3, 3, CV_8U, cv::Scalar(255));    // 3x3 matrix filled with 255
    plhs[0] = MxArray(m, mxLOGICAL_CLASS);        // convert to logical MATLAB matrix
}

In MATLAB, this returns:

>> m = myFcn()
m =
   255   255   255
   255   255   255
   255   255   255

>> whos m
  Name      Size            Bytes  Class      Attributes
  m         3x3                 9  logical              

Even though the result is of type logical, the matrix contains values other than 0/1, which can cause some issues on comparison:

>> m(1) == true
ans =
     0
>> 1 == true
ans =
     1

The expected outcome should be:

>> m~=0
ans =
     1     1     1
     1     1     1
     1     1     1
@ghost ghost assigned kyamagu Sep 4, 2012
@kyamagu
Copy link
Owner

kyamagu commented Sep 4, 2012

Very interesting. I'll add special treating for creating mxLOGICAL_CLASS array.

@kyamagu
Copy link
Owner

kyamagu commented Sep 4, 2012

The last commit added thresholding to saturate all nonzero values to 1 in the conversion. Hope it fixes the issue.

@amroamroamro
Copy link
Collaborator Author

while your commit solves the above case, cv::threshold has a couple of issues:

  • it only works with CV_8U, CV_16S, CV_32F types. Anything else throws an exception.
  • when converting from signed types, negative values get saturated at zero (false). Note that in MATLAB, logical(-1) == logical(1) == true, and only logical(0) == false

As far as I can tell, a better solution would be:

cv::compare(input, 0, input, cv::CMP_NE); // input = uint8( 255 * (input~=0) )
cv::min(input, 1, input);                 // input = min(input,1)

by comparing the matrix against scalar zero (result is of type CV_8UC1 set to 255 where nonzero), then using cv::min to cap at 1.


Here is a test to confirm (should return: [true,false,true] ie logical([1,0,1])):

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    double x[] = {-5.0, 0.0, 5.0};
    cv::Mat m(1, 3, CV_64FC1, (void*)x);
    plhs[0] = MxArray(m, mxLOGICAL_CLASS);
}

@kyamagu
Copy link
Owner

kyamagu commented Sep 4, 2012

That makes sense. I have included the fix in the last commit, with a slight modification of the use of cv::setTo rather than cv::min.

Perhaps it's a TODO to prepare a unit test for MxArray.

@amroamroamro
Copy link
Collaborator Author

thanks, that should do it. Unit-testing the MxArray layer sounds like a good idea..

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants