【问题标题】:Sobel edge detection using opencv使用opencv进行Sobel边缘检测
【发布时间】:2018-12-12 13:07:05
【问题描述】:

我在 openCV 中使用内置的 Sobel 边缘运算来进行某些图像处理,但结果与该函数的预期不符。

sobel=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
cv2.imshow('Sobel Image',sobel)

我附上了输入图像的示例图像和我得到的结果输出。 请帮助我解决这个问题。 左边是输入图像,右边是结果图像。

【问题讨论】:

  • 我对@9​​87654325@了解不多,但是很多这种类型的图像显示都假设浮点数据在[0,1]范围内。在您的情况下,它要大得多(输入图像在 [0,255] 范围内),因此显示器无法正确显示图像。您想在显示之前将图像强度缩放到适当的范围。
  • imshow() 接受整数(8uint、16uint 或 32int)和浮点数(32 位和 64 位)。除 8uint 外,其他的在显示前映射到 [0-255] 范围。查看更多关于 opencv 文档:docs.opencv.org/4.2.0/d7/dfc/…
  • 请提供您的输入图片,以便其他用户测试

标签: image opencv image-processing sobel


【解决方案1】:

您必须进行两次 sobel 运算并将它们混合。另外,请确保您正在处理灰度图像,否则我认为它会分别处理每个通道..

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

grad_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
grad_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)

abs_grad_x = cv2.convertScaleAbs(grad_x)
abs_grad_y = cv2.convertScaleAbs(grad_y)

grad = cv2.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)

cv2.imshow('grad X',grad_x)
cv2.imshow('grad Y',grad_y)
cv2.imshow('Sobel Image',grad)
cv2.waitKey()

xy 和混合图像的结果是:

如果您需要降低噪点,可以应用高斯模糊。参考:https://docs.opencv.org/4.2.0/d2/d2c/tutorial_sobel_derivatives.html

【讨论】:

  • cv2.convertScaleAbs的目的是什么?
  • @Haidepzai 它从 Sobel 操作中获取输出并将其转换回 8 位图像(CV_8U 类型)。
【解决方案2】:

Sobel 算子为您提供 x 或 y 方向的梯度。对于基于 Sobel 的边缘检测,您将梯度的大小与阈值进行比较,以确定哪些像素是边缘。下面的代码展示了如何计算梯度(幅度)并将其标准化显示。

import cv2
import numpy as np

def sobel_edge_detector(img):
    grad_x = cv2.Sobel(img, cv2.CV_64F, 1, 0)
    grad_y = cv2.Sobel(img, cv2.CV_64F, 0, 1)
    grad = np.sqrt(grad_x**2 + grad_y**2)
    grad_norm = (grad * 255 / grad.max()).astype(np.uint8)
    cv2.imshow('Edges', grad_norm)
    cv2.waitKey(0)

注意:OpenCV 的 tutorial page on Sobel Derivatives 使用以下计算,但它们都不正确。

// converting back to CV_8U
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
...
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);

【讨论】:

  • 这是一个很好的解释,应该是公认的答案。
  • 你能解释一下为什么convertScaleAbs不正确
  • @Ankit tutorial page 声明“有时使用以下更简单的方程”,并给出绝对梯度分量的总和作为梯度幅度计算的近似值。即便如此,代码使用convertScaleAbs,由于转换为 8 位,可能会导致值剪裁,然后取平均梯度分量,而不是总和。结果值可以有用地可视化以指示梯度幅度,但它不是严格意义上的梯度幅度,甚至不是一个近似值。
【解决方案3】:

对于这张图片,需要先对图片进行阈值处理,然后再使用Sobel算子去噪。

image = cv2.imread('image.jpg',cv2.IMREAD_UNCHANGED)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

ret,binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)

H = cv2.Sobel(binary, cv2.CV_8U, dx=0, dy=1, ksize=3)
V = cv2.Sobel(binary, cv2.CV_8U, dx=1, dy=0, ksize=3)

【讨论】:

  • 您需要在使用 Sobel 算子之前对图像进行二值化处理。不,它也适用于灰度图像。
  • @JeruLuke 确实如此。我必须改写自己。我的意思是,在 OP 的情况下,他/她需要在使用 Sobel 之前对图像进行阈值处理以减少噪声。
  • 阈值不会降低噪音。此外,您的输出仍然不正确,因为梯度应该具有正值和负值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
相关资源
最近更新 更多