为 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
矩阵中结束了 nan
s。要将这些 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]
是否有直接的方法来创建掩码,其中 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
矩阵中结束了 nan
s。要将这些 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]