欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在OpenCV里实现Roberts算子

程序员文章站 2022-07-14 11:16:16
...

前面学习了使用梯度来提取边缘,其实还有很多方法是用来提取边缘的。因为边缘的信息非常重要,神经学和心理学的研究表明,图像中突变的位置对图像感知很重要,甚至有时候只要看到边缘就可以理解图像的内容。当前AI最高端技术莫过于深度学习,而图像方面的深度学习建模所需要的特征,很多是从边缘为起点,不断向上构成更高层次的特征描述。

 

定义:边缘是不同区域的分界线,是周围(局部)像素有显著变化的像素的集合,有幅值与方向两个属性。这个不是绝对的定义,主要记住边缘是局部特征以及周围像素显著变化产生边缘。

提示:轮廓和边缘的关系,一般认为轮廓是对物体的完整边界的描述,边缘点一个个连接起来构成轮廓。边缘可以是一段边缘,而轮廓一般是完整的。人眼视觉特性,看物体时一般是先获取物体的轮廓信息,再获取物体中的细节信息,比如看到几个人站在那,我们一眼看过去马上能知道的是每个人的高矮胖瘦,然后才获取脸和衣着等信息。

 

人类视觉系统认识目标的过程分为两步:首先,把图像边缘与背景分离出来;然后,才能知觉到图像的细节,辨认出图像的轮廓。计算机视觉正是模仿人类视觉的这个过程。因此在检测物体边缘时,先对其轮廓点进行粗略检测,然后通过链接规则把原来检测到的轮廓点连接起来,同时也检测和连接遗漏的边界点及去除虚假的边界点。图像的边缘是图像的重要特征,是计算机视觉、模式识别等的基础,因此边缘检测是图象处理中一个重要的环节。然而,边缘检测又是图象处理中的一个难题,由于实际景物图像的边缘往往是各种类型的边缘及它们模糊化后结果的组合,且实际图像信号存在着噪声。噪声和边缘都属于高频信号,很难用频带做取舍。在实际的图像分割中,往往只用到一阶和二阶导数,虽然原理上,可以用更高阶的导数,但是因为噪声的影响,在纯粹二阶的导数操作中就会出现对噪声的敏感现象,三阶以上的导数信息往往失去了应用价值。二阶导数还可以说明灰度突变的类型。在某些情况下,如灰度变化均匀的图像,只利用一阶导数可能找不到边界,此时二阶导数就能提供很有用的信息。二阶导数对噪声也比较敏感,解决的方法是先对图像进行平滑滤波,消除部分噪声,再进行边缘检测。不过,利用二阶导数信息的算法是基于过零检测的,因此得到的边缘点数比较少,有利于后继的处理和识别工作。

 

Roberts算子,又称罗伯茨算子,是一种最简单的算子,是一种利用局部差分算子寻找边缘的算子。他采用对角线方向相邻两象素之差近似梯度幅值检测边缘。检测垂直边缘的效果好于斜向边缘,定位精度高,对噪声敏感,无法抑制噪声的影响。1963年,Roberts提出了这种寻找边缘的算子。Roberts边缘算子是一个2x2的模板,采用的是对角方向相邻的两个像素之差。从图像处理的实际效果来看,边缘定位较准,对噪声敏感。

在OpenCV里实现Roberts算子

Roberts算子是采用上图的卷积核,为了计算方便,一般扩充为3X3的卷积核。当输入图像与这两个卷积核进行计算之后,就会生成两个计算结果,这两个结果要生成输出边缘图像有四种方法:取对应位置绝对值的和、取对应位置平方和的开方、取对应位置绝对值的最大值、插值法。这四种方法里,最好效果的是平方和的开方,因为这样计算量也是最大的。下面用例子来演示:

#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import cv2
import numpy as np
from scipy import signal

#图片的路径
imgname = "edge1.png"

#读取图片
image = cv2.imread(imgname, cv2.IMREAD_GRAYSCALE)

#图片的高度和宽度
h,w = image.shape[:2]
print('imagesize={}-{}'.format(w,h))

#显示原图
cv2.imshow("Image",image)

#roberts算子
roberts_cross_v = np.array( [[ 0, 0, 0 ],
                             [ 0, 1, 0 ],
                             [ 0, 0,-1 ]] )

roberts_cross_h = np.array( [[ 0, 0, 0 ],
                             [ 0, 0, 1 ],
                             [ 0,-1, 0 ]] )
#
vertical = signal.convolve2d(image, roberts_cross_v,boundary='symm')
vertical1 = vertical.astype(np.uint8)
cv2.imshow("vertical",vertical1)

horizontal  = signal.convolve2d(image, roberts_cross_h,boundary='symm')
horizontal1  = horizontal .astype(np.uint8)
cv2.imshow("horizontal",horizontal1)

output_image = np.sqrt( np.square(horizontal) + np.square(vertical))
output_image  = output_image.astype(np.uint8)
cv2.imshow("output_image",output_image)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果输出如下:

在OpenCV里实现Roberts算子

输入图片

在OpenCV里实现Roberts算子

输出垂直边缘

在OpenCV里实现Roberts算子

输出水平边缘

在OpenCV里实现Roberts算子

输出边缘图片

由于Roberts边缘检测使用了很少的邻域像素来近似边缘强度,因此对图像中的噪声具有高度敏感性,一般情况要先进行平滑之后再使用。

https://blog.csdn.net/caimouse/article/details/51749579