python - 什么是 Sobel 算子?
问题描述
我在 Python 中尝试了 5 种不同的 Sobel 运算符实现,其中一种是我自己实现的,结果完全不同。
我的问题与此类似,但与其他实现仍然存在我不理解的差异。
Sobel算子的定义是否有任何一致的定义,它是否总是“图像梯度”的同义词?
甚至 Sobel 内核的定义也因源而异,根据 Wikipedia,它是[[1, 0, -1],[2, 0, -2],[1, 0, -1]]
,但根据其他来源,它是[[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]]
。
这是我尝试不同技术的代码:
from scipy import ndimage
import numpy as np
import cv2 as cv
from scipy import ndimage
from PIL import Image, ImageFilter
img = np.random.randint(0, 255, [10, 10]).astype(np.uint8)
def sobel_x(img) :
return ndimage.convolve(img, np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]]))
my_sobel = sobel_x(img)
_, numpy_sobel = np.gradient(img)
opencv_sobel = cv.Sobel(img, cv.CV_8UC1, 1, 0)
ndimage_sobel = ndimage.sobel(img, axis=0, mode="constant")
pil_sobel = np.array(Image.fromarray(img).filter(ImageFilter.Kernel((3, 3), (-1, 0, 1, -2, 0, 2, -1, 0, 1), 1, 0)))
print(my_sobel)
print(numpy_sobel)
print(opencv_sobel)
print(ndimage_sobel)
print(pil_sobel)
解决方案
Sobel 算子估计导数。
Sobel算子估计水平导数的正确定义是:
| 1 0 -1 |
| 2 0 -2 | / 8
| 1 0 -1 |
除以 8 对于获得正确的幅度很重要。人们经常忽略它,因为他们不关心实际的导数,他们关心的是比较同一图像不同位置的梯度。将所有内容乘以 8 在那里没有任何区别,因此省略了/8
使事情变得简单。
您将在某些地方看到用反号定义的内核。这些是通过相关而不是卷积应用内核的情况(通过内核的镜像而不同),例如 OpenCV 的情况。这些也可能是人们在不理解内容的情况下复制内容的情况,从而导致带有错误符号的渐变。
但话又说回来,Sobel算子主要用于获得梯度幅度(水平和垂直导数的平方和的平方根)。在这种情况下,反转标志不再重要。
请注意,这np.gradient(img)
与与 进行卷积相当[1,0,-1]/2
。这是估计导数的另一种方法。Sobel 在垂直方向添加正则化(==平滑)。
如果您使用更有意义的测试图像,您将对每个实现有更好的理解。例如,尝试一个黑色图像,中间有一个白色方块。您将能够比较估计梯度的强度、它们的方向(我假设一些库使用不同的 x 和 y 轴定义),并且您将能够看到正则化的效果。
推荐阅读
- html - htmlspecialchars 没有显示在所见即所得的 html 富文本编辑器上?
- mysql - 如何在一个查询中使用 2 个表数据并使用 MySQL 根据 2 个表数据创建一个新列
- java - AccessibilityInsights 未检测到基于 Java Swing 的 Windows 桌面应用程序
- visual-studio-code - Ubuntu 20.04.2 LTS 上的 VS Code 更新
- kubernetes - 在 Web UI 中看不到 Kubernetes 服务或入口
- javascript - 打字稿:从嵌套模块导入
- java - 用于处理对 alpha vantage API 的响应的 Java 类
- python - 查找一系列像素值并将其替换为 HSV 图像中的另一个值
- c# - C#拆分忽略输入字符串中的逗号
- python - 无监督聚类的神经网络实现