【问题标题】:OpenCV Laplacian output in C++ excludes negative values, but not in PythonC++ 中的 OpenCV 拉普拉斯输出不包括负值,但在 Python 中不包括
【发布时间】:2020-06-09 20:50:03
【问题描述】:

C++Python 中执行相同的拉普拉斯运算似乎会产生不同的结果。值得注意的是,C++ 变体不会在结果矩阵中报告负斜率。

我正在使用(C++):

Laplacian(img.clone(), img, CV_16S, 1, 1, 0, BORDER_DEFAULT);

和(Python):

img = cv2.Laplacian(img, ddepth=cv2.CV_16S, ksize=1, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)

通过将 C++ 数据处理成更友好的文本格式:

outfile.open("cpp.csv");
outfile.close();
for (size_t i = 0; i < img.size().width; i++) {
    outfile.open("cpp.csv", std::ios_base::app);
    for (size_t j = 0; j < img.size().height; j++) {
        outfile << (int16_t)img.at<uchar>(j, i);
        if (j < img.size().height - 1) {
            outfile << ",";
        }
    }
    outfile << std::endl;
    outfile.close();
}

然后我可以将这些值与Numpy 进行比较。

cpp = np.loadtxt("./cpp.csv", delimiter=',')
print("python lap min:", np.min(img))
print("c++    lap min:", np.min(cpp))

这个输出告诉我们 CPP 代码没有记录负值:

python lap min: -133
c++    lap min: 0.0

那么这里发生了什么?我肯定犯了某种错误,因为如果图像亮度值不是静态的,那么在某个地方的拉普拉斯变换中肯定存在负值。

图片来源

每个测试用例的源图像是 1920x1080 全彩 PNG 图像,具有明显的明暗区域。我正在使用月亮的照片。图像在拉普拉斯变换之前转换为 CV_8UC1。

严格输入

我已经明确告诉C++ 使用int16_t 类型存储数据,默认情况下该类型是隐式签名的,而不仅仅是int。此类型与拉普拉斯存储矩阵 (CV_16S) 的输出相匹配。将显式“签名”添加到“int16_t”会产生相同的结果。我的理解是at 函数需要uchar 键入类似于this SO answer这是我错了!!!

版本说明

Python OpenCV 版本:4.1.1(或 4.4.0,见编辑部分)

C++ OpenCV 版本:3.4.1(或 4.4.0,见编辑部分)

这些版本(3.4.14.1.1)的文档显示两者之间没有明显区别。

类似问题

C++Python 之间的拉普拉斯变体在 SO 上很常见,但对此没有任何用处。我读到:

编辑 - 升级 C++ OpenCV 库

我从 git 构建了OpenCV v.4.4,并使用pkg-config --cflags --libs opencv4 编译了C++ 版本的代码。同样的错误仍然存​​在。 (cv2.getBuildInformation() 表示 Python 也在运行 4.4)。

Edit2 - Git 问题的上下文:

我在 github 存储库 (here) 上发现了一个类似的问题,解决方案是将拉普拉斯结果存储为新的 Mat。我的原始代码使用Laplacian(img.clone(), img, ...),它应该生成img 矩阵的“深拷贝”,避免了OP 报告的问题。无论如何,我使用唯一矩阵 Laplacian(outputimg, img, ...) 测试了我的代码,结果没有任何变化。

Edit3 - 概括问题

我处理了原始代码,这次将 Laplacian 过滤器替换为 Sobel 和自定义 filter2D 过滤器。观察到相同的结果,Python 产生良好的值,而 C++ 没有。

Edit4 - 回答后清理

由于这是一个简单的打字错误,我已经删除了大部分无关信息。这使得我最初的尝试可读,但很明显它们最终没有用。

【问题讨论】:

  • 您是否尝试过为两种语言使用相同版本的 OpenCV?可能在某些时候对 C++ 接口进行了错误修复,以修复没有负值的问题...
  • @MattDMo 我更新到 v4.4 并且有同样的问题。
  • 您的 C++ 实现正在调用Mat.at&lt;uchar&gt;,但数据不是uchar,而是int16_t。我看到你在 之后 进行投射,但那时它已经被错误地解释了。您基本上只是读取两个字节值的第一个字节并将其解释为无符号uint8_t,然后将该值转换为不会更改值的int16_t。所以我相信你只会看到 [0, 255] 中的值,即使你应该看到 [−32768, 32767] 中的值
  • @alkasm int16_t 帮助了。我认为uchar 是我的xy 坐标值的类型。您应该将此添加为答案。您也可以将其添加到:answers.opencv.org/question/231134/… 以获得奖励积分。
  • @WesH 我只是不确定这是否是您唯一的问题/完整的答案,因为我无法验证它。但是,我稍微倾向于将这个问题作为一个错字来结束,因为即使答案可能有帮助,但这个问题实际上假设还有很多事情发生,这些事情是不相关的,而且不太可能被发现/有用供未来的读者阅读。

标签: python c++ opencv


【解决方案1】:

您的 C++ 实现正在调用Mat::at&lt;uchar&gt;,这意味着“将此位置的数据解释为uchar(即uint8_t)”但您的数据当然是short(即int16),而不是@987654327 @。从docs on Mat::at,请注意它们指定:

如果矩阵的类型为CV_16S,则使用Mat.at&lt;short&gt;(y,x)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-12
    • 2019-02-02
    • 1970-01-01
    • 2016-07-24
    • 2020-03-24
    • 2016-11-13
    • 2018-06-30
    • 1970-01-01
    相关资源
    最近更新 更多