[英]OpenCV Laplacian output in C++ excludes negative values, but not in Python
Performing the same Laplacian operation in C++
and Python
appears to produce different results.在C++
和Python
中执行相同的拉普拉斯运算似乎会产生不同的结果。 Notably, the C++
variant does not report negative slopes in the result matrix.值得注意的是, C++
变体不会在结果矩阵中报告负斜率。
I am using (C++):我正在使用(C++):
Laplacian(img.clone(), img, CV_16S, 1, 1, 0, BORDER_DEFAULT);
and (Python):和(Python):
img = cv2.Laplacian(img, ddepth=cv2.CV_16S, ksize=1, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
By processing the C++ data into a more friendly text format:通过将 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();
}
I can then compare the values with Numpy
.然后我可以将这些值与Numpy
进行比较。
cpp = np.loadtxt("./cpp.csv", delimiter=',')
print("python lap min:", np.min(img))
print("c++ lap min:", np.min(cpp))
This output shows us that the CPP code is not recording negative values:这个 output 向我们展示了 CPP 代码没有记录负值:
python lap min: -133 c++ lap min: 0.0
So what is happening here?那么这里发生了什么? Surely I have made some sort of error, because there must be negative values in a Laplacian transformation somewhere if the image luminosity values are not static.我肯定犯了某种错误,因为如果图像亮度值不是 static,那么在某个地方的拉普拉斯变换中肯定有负值。
The source image for each test case is a 1920x1080 full color PNG image with distinct light and dark areas.每个测试用例的源图像是 1920x1080 全彩 PNG 图像,具有明显的明暗区域。 I'm using a photo of the moon.我正在使用月亮的照片。 The image is converted to CV_8UC1 prior to the Laplace transformation.图像在拉普拉斯变换之前转换为 CV_8UC1。
I have explicitly told C++
to store data with the int16_t
type, which is implicitly signed by default, rather than just an int
.我已经明确告诉C++
使用int16_t
类型存储数据,该类型默认是隐式签名的,而不仅仅是一个int
。 This typing matches the output from the Laplacian storage matrix ( CV_16S
).此类型匹配来自拉普拉斯存储矩阵 ( CV_16S
) 的 output。 Adding an explicit "signed" to "int16_t" produces the same result.将显式“签名”添加到“int16_t”会产生相同的结果。 My understanding is that the at
function requires uchar
typing similar to this SO answer .我的理解是, at
function 需要uchar
键入类似于此 SO 答案。 This is where I was wrong!!!这就是我错了!!!
Python OpenCV version: 4.1.1 (or 4.4.0, see edit section) Python OpenCV 版本:4.1.1(或 4.4.0,见编辑部分)
C++ OpenCV version: 3.4.1 (or 4.4.0, see edit section) C++ OpenCV 版本:3.4.1(或 4.4.0,见编辑部分)
The documentation for these versions ( 3.4.1 and 4.1.1 ) shows no appreciable difference between the two.这些版本( 3.4.1和4.1.1 )的文档显示两者之间没有明显差异。
Laplacian variation between C++
and Python
appears common on SO, but nothing had anything useful for this. C++
和Python
之间的拉普拉斯变体在 SO 上似乎很常见,但对此没有任何用处。 I read:我读:
I built OpenCV
v.4.4 from git, and compiled the C++
version of the code with pkg-config --cflags --libs opencv4
.我从 git 构建OpenCV
v.4.4,并使用pkg-config --cflags --libs opencv4
编译了C++
版本的代码The same error persists.同样的错误仍然存在。 ( cv2.getBuildInformation()
says the Python is running 4.4 as well). ( cv2.getBuildInformation()
表示 Python 也在运行 4.4)。
I found a similar issue on the github repo ( here ) where the solution was storing the Laplacian result as a new Mat
.我在 github repo( here )上发现了一个类似的问题,其中解决方案是将 Laplacian 结果存储为新的Mat
。 My original code uses Laplacian(img.clone(), img, ...)
which should produce a "deep copy" of the img
matrix in place, avoiding the problem reported by the OP.我的原始代码使用Laplacian(img.clone(), img, ...)
应该在适当的位置产生img
矩阵的“深拷贝”,避免 OP 报告的问题。 I tested my code with a unique matrix anyway Laplacian(outputimg, img, ...)
and saw no change in results.无论如何,我用一个唯一的矩阵测试了我的代码Laplacian(outputimg, img, ...)
并没有看到结果的变化。
I processed the original code, this time replacing the Laplacian filter with either a Sobel and a custom filter2D
filter.我处理了原始代码,这次用 Sobel 和自定义 filter2D
过滤器替换了拉普拉斯过滤器。The same result is observed, Python
produces good values while C++
does not.观察到相同的结果, Python
产生良好的值,而C++
没有。
Since this was a simple typing error, I have crossed out most of the extraneous information.由于这是一个简单的打字错误,我已经删除了大部分无关信息。 This leaves it my original attempts readable, but it makes it obvious that they were not useful in the end.这使得我最初的尝试可读,但很明显它们最终没有用。
Your C++ implementation is calling Mat::at<uchar>
which means "interpret the data at this location as uchar
(ie uint8_t
)" but your data is of course short
(ie int16
), not uchar
.您的 C++ 实现正在调用Mat::at<uchar>
,这意味着“将此位置的数据解释为uchar
(即uint8_t
)”,但您的数据当然short
(即int16
),而不是uchar
。 From the docs on Mat::at
, note that they specify:从Mat::at
上的文档中,请注意它们指定:
If matrix is of type
CV_16S
then useMat.at<short>(y,x)
.如果矩阵是CV_16S
类型,则使用Mat.at<short>(y,x)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.