为 NAN 值过滤 OpenCV Mat

Filter OpenCV Mat for NAN values

是否有直接的方法来创建掩码,其中 cv::Mat_<double> 中的值与 NAN 进行比较?

cv::Mat_<real> mat = ...
cv::Mat_<uchar> mask = (mat == NAN);

不起作用,因为 f == NAN 始终为 false,即使 f 已分配 NAN。而且矩阵似乎没有 isnan() 的重载。

如果您想测试 NaN 的值,只需将其与自身进行比较即可。根据标准 NaN 不等于任何其他数字,包括它本身 (fValue != fValue) 对于 NaN 应该是正确的。

正如用户 pSoLT 所指出的,如果您想确定哪些值是 NaN,只需将矩阵与其自身进行比较即可。对于那些不相等的元素,它们将被视为 NaN by the standard definition。您可以使用该逻辑创建一个新掩码:

cv::Mat mask = cv::Mat(mat != mat);

mat 将是一个包含 NaN 值的矩阵,而 mask 将是一个包含每个元素的 CV_8UC1(即 uchar)类型矩阵如果值为 NaN,则为 0xFF,否则为 0x00

OpenCV 论坛上的这个 post 也可能有帮助:http://answers.opencv.org/question/2221/create-a-mask-for-nan-cells/


编辑(截至 2020 年 4 月 23 日)

如评论中所述以及此 post 中的一个答案,上述布尔表达式存在错误,可能导致行为不一致。这是由于 OpenCV 做出的某些优化决策。请参阅此 Github 问题:https://github.com/opencv/opencv/issues/16465

这个问题的解决方案是使用 cv::patchNaNs() 来解决这个问题,它将 NaN 的值转换为特定数字。

要复制在问题中创建蒙版,请注意 patchNaNs 执行值的 in-place 替换,因此您必须制作两个图像副本,使用 patchNaNs 将每个图像的 NaN 值设置为不同的值,然后检查两个值是否同时出现在相同位置。换句话说:

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 将为您提供此答案原始版本中预期的结果。

我发布这个答案是为了给那些可能正在寻找如何从矩阵中过滤掉 nan 的人提供参考。

虽然这可能不是您问题的准确答案,但如果您想过滤掉那些 nan 索引,有一种快速简便的方法可以做到。

在我的例子中,我有一个 zero by zero division 在我的 float 矩阵中结束了 nans。要将这些 nan 设置为另一个值(在我的例子中是 0),可以使用以下方法:

cv::patchNaNs(mat, 0.0);

此方法查找 nan 索引并将其替换为给定值。

根据 github issue,解决方法是使用 255 - (mat == mat) 而不是 mat != mat(这通常应该有效,但目前是一个错误)。 更健壮,但带来了显着的性能缺陷。

这是一个最小的工作示例:

#include <iostream>
#include <string>


#include <opencv2/opencv.hpp>

cv::Mat1b is_nan(cv::Mat mat)
{
    return 255 - (mat == mat);
}


int main()
{
    cv::Mat mat(5, 7, CV_32FC1);
    cv::randu(mat, cv::Scalar(-1), cv::Scalar(1));
    mat.at<float>(0,0) = std::nan("");
    mat.at<float>(4,5) = std::nan("");
    
    std::cout << mat << std::endl;
    std::cout << is_nan(mat) << std::endl;
    return 0;
}

输出

[nan, -0.60148162, -0.19788112, 0.62877017, -0.12573405, -0.5024206, 0.54621011;
 0.52418745, -0.38441104, 0.40486339, -0.043105587, 0.58438003, -0.82831377, -0.8498795;
 -0.67315322, -0.40044156, 0.81130785, 0.41937166, -0.70057499, 0.53087986, -0.75143719;
 -0.9925428, 0.10302717, 0.99639863, -0.68201572, -0.6776439, -0.92362136, -0.14827734;
 0.69225526, 0.77520895, -0.47057521, -0.4584339, 0.9053328, nan, 0.62043273]
[255,   0,   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0, 255,   0]