【问题标题】:Why do we convert laplacian to uint8 in OpenCV?为什么我们在 OpenCV 中将 laplacian 转换为 uint8?
【发布时间】:2022-02-17 20:54:40
【问题描述】:

我正在使用拉普拉斯函数来检测 OpenCV 中的边缘,当时我对代码背后的基本原理感到困惑。

documentation 的特点是我们使用以下代码读取图像并将其传递给拉普拉斯函数。

img = cv2.imread("messi5.jpg", cv2.IMREAD_GRAYSCALE)
lap = cv2.Laplacian(img, cv2.CV_32F, ksize=1)

现在,我可以很好地理解上面编写的代码了。我相信,我们读入一张图像,并计算每个像素的拉普拉斯算子。这个值可以大于或小于原始的 8 位 unsigned int 像素,因此我们将其存储在一个 32 位浮点数组中。

我的困惑始于接下来的几行代码。在文档中,使用 convertScaleAbs() 函数将图像转换回 8 位无符号整数,然后显示如下。

lap = cv2.convertScaleAbs(lap)
cv2.imshow(lap)

但是,我的导师向我展示了以下转换回 uint8 的方法:

lap = np.uint8(np.absolute(lap))
cv2.imshow(lap)

令人惊讶的是,两种解决方案都显示相同的图像。但是,我无法理解为什么会发生这种情况。从我所见, np.uint8 只是将值(浮点数等)截断为无符号的 8 位整数。例如,1025 变为 1,因为第 8 位以外的所有其他位都将被丢弃。

然而,这实际上意味着每个像素的拉普拉斯算子的任何值都会严重降低和混乱。如果一个像素的拉普拉斯算子是1024(在 x 和 y 维度上表示非零二阶导数),我们手头将有值 0(表示零的二阶导数和可能的局部最大值/ min,或者换句话说,一个边缘)。因此,按照我的逻辑,我的导师的解决方案应该会失败,但令人惊讶的是一切都很好。这是为什么呢?

另一方面,我对convertScaleAbs() 的工作原理一无所知。我将假设它与我的导师的解决方案类似,但我不确定。有人可以解释一下发生了什么吗?

【问题讨论】:

  • 在opencv中不是截断而是饱和。所以每个值 > 255 变成 255。不确定 numpy/python/...

标签: python numpy opencv


【解决方案1】:

OpenCV BGR 图像或灰度图在CV_8U 8 位对应于np.uint8more details here 时具有从0 到255 的像素值。

因此,当您使用 ddepth (Desired depth of the destination image.) 设置为 cv2.CV_32FLaplacian 函数时,您会得到:

lap = cv2.Laplacian(img, cv2.CV_32F, ksize=1)
print(np.amax(lap)) #=> 317.0
print(np.amin(lap)) #=> -315.0

所以,你需要转换回np.uint8,例如:

lap_uint8 = lap.copy()
lap_uint8[lap > 255] = 255
lap_uint8[lap < 0] = 0
lap_uint8 = lap_uint8.astype(np.uint8)

print(np.amax(lap_uint8)) #=> 255
print(np.amin(lap_uint8)) #=> 0

或者使用任何其他更直接的方法来做同样的事情。

但您也可以使用 set -1 作为 ddepthsee documentation 的参数来获取:

lap = cv2.Laplacian(img, -1, ksize=1)
print(np.amax(lap)) #=> 0
(print(np.amin(lap))) #=> 255

这样你会得到错误的结果:

lap_abs = np.absolute(lap)
print(np.amax(lap_abs)) #=> 317.0
print(np.amin(lap_abs)) #=> 0.0

【讨论】:

    猜你喜欢
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多