The main issue is that the type of (cx > 0.5)
is CV_8U
and not CV_32F
.
Take a look at the following code sample:
//Initialize 3x3 matrix for example
cv::Mat cx = (cv::Mat_<float>(3, 3) << 5.0f, 0, 0, 0, 5.0f, 0, 0, 0, 5.0f);
//The type of "logical matrix" result of (cx > 0.5f) is UINT8 (255 where true).
cv::Mat cx_above05 = (cx > 0.5f);
I am using Image Watch and Visual Studio 2017 for convenience.
Here is the result of cv::Mat cx_above05 = (cx > 0.5f)
:

As you can see, the type is UINT8
and the value is 255
where cx>0.5
and 0
where not.
You can use convertTo for converting the type to CV_32F
and dividing by 255
:
cx_above05.convertTo(cx_above05 , CV_32F, 1.0/255.0); //Convert type to float (1.0f where true).
Result:

As you can see, the type is FLOAT32
, and 255
values goes to 1.0f
Complete code sample:
cv::Mat cx = (cv::Mat_<float>(3, 3) << 5.0f, 0, 0, 0, 5.0f, 0, 0, 0, 5.0f); //Initialize 3x3 matrix for example
cv::Mat cx_above05 = (cx > 0.5f); //The type of "logical matrix" result of (cx > 0.5f) is UINT8 (255 where true).
cx_above05.convertTo(cx_above05 , CV_32F, 1.0/255.0); //Convert type to float (1.0f where true).
cv::Mat c0 = cx_above05.mul((cx - 0.5f) * 2.0f);
Result:

Instead of multiplying by the mask we can use the trick described in OpenCV pow
documentation:
cv::Mat cx = (cv::Mat_<float>(3, 3) << 5.0f, 0, 0, 0, 5.0f, 0, 0, 0, 5.0f); //Initialize 3x3 matrix for example
cv::Mat mask = (cx <= 0.5f); //The type of "logical matrix" result of (cx <= 0.5f) is UINT8 (255 where true).
cv::Mat c0 = (cx - 0.5f) * 2.0f;
cv::subtract(c0, c0, c0, mask);
I found a more elegant solution here (using setTo):
cv::Mat c0 = (cx - 0.5f) * 2.0f;
c0.setTo(0, cx <= 0.5f);
One line solution:
The type of the expression ((cx - 0.5f) * 2.0f)
is cv::MatExpr
, and we can cast it to cv::Mat
:
cv::Mat c0 = ((cv::Mat)((cx - 0.5f) * 2.0f)).setTo(0, cx <= 0.5f);