函数功能:canny边缘检测,并与原图做边缘和背景取舍
canny实现步骤:
1.高斯滤波平滑图像,因为噪声和边缘同为高频信息,如果不进行去噪,直接进行边缘检测,会对噪声比较敏感;
2.使用sobel算子分别计算x,y方向的梯度,并求实际梯度值和梯度方向;
3.非极大值抑制,对求出的梯度图像,遍历图像的每个点,求出每个点梯度方向上和其八邻域的交点,交点可能是虚拟点,需要通过线性插值求出虚拟点,然后将该点与
梯度方向上的上下两点进行比较,如果为三点中的最大值,则保留该点的梯度。
4.高低双阈值筛选进行边缘连接,遍历非极大值抑制后的图像,如果某一点的梯度值大于高阈值则直接将该点像素值赋值为255,同时将被赋值为强边缘的像素点进栈,
以便后面做边缘连接使用如果小于设置的低阈值,则直接赋值为零,对于处于中间值的,先不做处理,遍历完后,图像就只剩下那些255的强边缘和一些伪边缘;然后将
强边缘一个个出栈,判断其周围八邻域是否有与强边缘连接的弱边缘点,如果有,则将其赋值为255,连接成强边缘,遍历完后,就基本完成了;最后一步,遍历上面得到的结果图像
把不是0和255的像素点都赋值为零。
# -*- coding: utf-8 -*-
# @Time: 2021/1/24 13:10
# @Author: Min
import cv2
def nothing(x):
pass
def mythreshold(image):
# open image
kernel_size = 3
img = cv2.imread(image)
# transe image to gray
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
cv2.namedWindow("image")
cv2.createTrackbar("threshold", "image", 0, 255, nothing)
cv2.createTrackbar("mthreshold", "image", 0, 255, nothing)
while True:
#获取调节杆的实时值
lowThreshold = cv2.getTrackbarPos("threshold", "image")
highThreshold = cv2.getTrackbarPos("mthreshold", "image")
#高斯平滑去噪,提高后续canny对边缘提取的性能,canny算子好像已经封装了高斯平滑,所以这一步
#可要可不要
detect_edges = cv2.GaussianBlur(gray, (3, 3), 0)
#canny检测图像边缘
detect_edges = cv2.Canny(detect_edges, lowThreshold, highThreshold, apertureSize=kernel_size)
#将检测到的边缘信息和原图进行原图边缘保留
dst = cv2.bitwise_and(img, img, mask=detect_edges)
cv2.imshow("image", dst)
if cv2.waitKey(10) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
def main():
path = "lenna.png"
mythreshold(path)
if __name__ == '__main__':
main()
效果展示:
左图为canny边缘检测效果图
右侧为canny边缘与原图做bitwise_and后的原图边缘保留效果图