Is there a direct way to create a mask where values in a cv::Mat_<double>
are compared against NAN?
cv::Mat_<real> mat = ...
cv::Mat_<uchar> mask = (mat == NAN);
does not work because f == NAN
is always false, even if f
was assigned NAN
. And there seems to be no overload of isnan()
for matrices.
As noted by user pSoLT, if you want to determine which values are NaN
, simply compare the matrix with itself. For those elements that are not equal, those would be considered as NaN
by the standard definition. You can create a new mask using that logic:
cv::Mat mask = cv::Mat(mat != mat);
mat
here would be a matrix that contains NaN
values and mask
will be a CV_8UC1
(i.e. uchar
) type matrix with each element being 0xFF
if a value is NaN
and 0x00
otherwise.
This post on OpenCV forums may also help: http://answers.opencv.org/question/2221/create-a-mask-for-nan-cells/
As mentioned in the comments as well as one of the answers in this post, the above Boolean expression is buggy and can result in inconsistent behaviour. This is due to certain optimisation decisions that OpenCV makes. Please see this Github issue: https://github.com/opencv/opencv/issues/16465
The solution to this is to use cv::patchNaNs()
to address this problem, which converts values that are NaN
to a specific number.
To replicate creating the mask in the question, note that patchNaNs
performs an in-place replacement of the values, so you would have to make two copies of the image, use the patchNaNs
to set the NaN
values to a distinct value per image then check to see the occurrence of both values at the same locations at the same time. In other words:
cv::Mat mat1 = mat.clone();
cv::Mat mat2 = mat.clone();
cv::patchNaNs(mat1, 128);
cv::patchNaNs(mat2, 200);
cv::Mat mask = mat1 == 128 & mat2 == 200;
mask
will give you the results as expected in the original version of this answer.