【发布时间】: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.1 和 4.1.1)的文档显示两者之间没有明显区别。
类似问题
C++ 和 Python 之间的拉普拉斯变体在 SO 上很常见,但对此没有任何用处。我读到:
- Laplacian does not give desired output
- OpenCV - laplacian different results in Python and C++
- opencv 2.4.0 laplacian different results depending on API used?
编辑 - 升级 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<uchar>,但数据不是uchar,而是int16_t。我看到你在 之后 进行投射,但那时它已经被错误地解释了。您基本上只是读取两个字节值的第一个字节并将其解释为无符号uint8_t,然后将该值转换为不会更改值的int16_t。所以我相信你只会看到 [0, 255] 中的值,即使你应该看到 [−32768, 32767] 中的值 -
@alkasm
int16_t帮助了。我认为uchar是我的x和y坐标值的类型。您应该将此添加为答案。您也可以将其添加到:answers.opencv.org/question/231134/… 以获得奖励积分。 -
@WesH 我只是不确定这是否是您唯一的问题/完整的答案,因为我无法验证它。但是,我稍微倾向于将这个问题作为一个错字来结束,因为即使答案可能有帮助,但这个问题实际上假设还有很多事情发生,这些事情是不相关的,而且不太可能被发现/有用供未来的读者阅读。