python实现canny边缘检测


Posted in Python onSeptember 14, 2020

canny边缘检测原理

canny边缘检测共有5部分组成,下边我会分别来介绍。

1 高斯模糊(略)

2 计算梯度幅值和方向。

可选用的模板:soble算子、Prewitt算子、Roberts模板等等;

一般采用soble算子,OpenCV也是如此,利用soble水平和垂直算子与输入图像卷积计算dx、dy:

python实现canny边缘检测

进一步可以得到图像梯度的幅值:

python实现canny边缘检测

为了简化计算,幅值也可以作如下近似:

python实现canny边缘检测

角度为:

python实现canny边缘检测

如下图表示了中心点的梯度向量、方位角以及边缘方向(任一点的边缘与梯度向量正交) :

python实现canny边缘检测

θ = θm = arctan(dy/dx)(边缘方向)
α = θ + 90= arctan(dy/dx) + 90(梯度方向)

3、根据角度对幅值进行非极大值抑制

划重点:是沿着梯度方向对幅值进行非极大值抑制,而非边缘方向,这里初学者容易弄混。

例如:3*3区域内,边缘可以划分为垂直、水平、45°、135°4个方向,同样,梯度反向也为四个方向(与边缘方向正交)。因此为了进行非极大值,将所有可能的方向量化为4个方向,如下图:

python实现canny边缘检测

python实现canny边缘检测

即梯度方向分别为

α = 90

α = 45

α = 0

α = -45

非极大值抑制即为沿着上述4种类型的梯度方向,比较3*3邻域内对应邻域值的大小:

python实现canny边缘检测

在每一点上,领域中心 x 与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置0,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。

4、用双阈值算法检测和连接边缘

1选取系数TH和TL,比率为2:1或3:1。(一般取TH=0.3或0.2,TL=0.1);

2 将小于低阈值的点抛弃,赋0;将大于高阈值的点立即标记(这些点为确定边缘 点),赋1或255;

3将小于高阈值,大于低阈值的点使用8连通区域确定(即:只有与TH像素连接时才会被接受,成为边缘点,赋 1或255)

python 实现

import cv2
import numpy as np
m1 = np.array([[1, 0, -1], [2, 0, -2], [1, 0, -1]])
m2 = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
from matplotlib import pyplot as plt
# 第一步:完成高斯平滑滤波
img = cv2.imread("B9064CF1D57871735CE11A0F368DCF27.jpg", 0)
sobel = cv2.Canny(img, 50, 100)
cv2.namedWindow('5', 0)
cv2.resizeWindow("5", 640, 480)
cv2.imshow("5", sobel) # 角度值灰度图
img = cv2.GaussianBlur(img, (3, 3), 2)
# 第二步:完成一阶有限差分计算,计算每一点的梯度幅值与方向
img1 = np.zeros(img.shape, dtype="uint8") # 与原图大小相同
theta = np.zeros(img.shape, dtype="float") # 方向矩阵原图像大小
img = cv2.copyMakeBorder(img, 1, 1, 1, 1, borderType=cv2.BORDER_REPLICATE)
rows, cols = img.shape
for i in range(1, rows - 1):
for j in range(1, cols - 1):
Gy = [np.sum(m2 * img[i - 1:i + 2, j - 1:j + 2])]
#Gy = (np.dot(np.array([1, 1, 1]), (m2 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]]))
Gx = [np.sum(m1 * img[i - 1:i + 2, j - 1:j + 2])]
#Gx = (np.dot(np.array([1, 1, 1]), (m1 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]]))
if Gx[0] == 0:
theta[i - 1, j - 1] = 90
continue
else:
temp = ((np.arctan2(Gy[0], Gx[0])) * 180 / np.pi)+90
if Gx[0] * Gy[0] > 0:
if Gx[0] > 0:
# 第一象线
theta[i - 1, j - 1] = np.abs(temp)
else:
# 第三象线
theta[i - 1, j - 1] = (np.abs(temp) - 180)
if Gx[0] * Gy[0] < 0:
if Gx[0] > 0:
# 第四象线
theta[i - 1, j - 1] = (-1) * np.abs(temp)
else:
# 第二象线
theta[i - 1, j - 1] = 180 - np.abs(temp)

img1[i - 1, j - 1] = (np.sqrt(Gx[0] ** 2 + Gy[0] ** 2))
for i in range(1, rows - 2):
for j in range(1, cols - 2):
if (((theta[i, j] >= -22.5) and (theta[i, j] < 22.5)) or
((theta[i, j] <= -157.5) and (theta[i, j] >= -180)) or
((theta[i, j] >= 157.5) and (theta[i, j] < 180))):
theta[i, j] = 0.0
elif (((theta[i, j] >= 22.5) and (theta[i, j] < 67.5)) or
((theta[i, j] <= -112.5) and (theta[i, j] >= -157.5))):
theta[i, j] = -45.0
elif (((theta[i, j] >= 67.5) and (theta[i, j] < 112.5)) or
((theta[i, j] <= -67.5) and (theta[i, j] >= -112.5))):
theta[i, j] = 90.0
elif (((theta[i, j] >= 112.5) and (theta[i, j] < 157.5)) or
((theta[i, j] <= -22.5) and (theta[i, j] >= -67.5))):
theta[i, j] = 45.0
'''
for i in range(1, rows - 1):
for j in range(1, cols - 1):
Gy = [np.sum(m2 * img[i - 1:i + 2, j - 1:j + 2])]
#Gy = (np.dot(np.array([1, 1, 1]), (m2 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]]))
Gx = [np.sum(m1 * img[i - 1:i + 2, j - 1:j + 2])]
#Gx = (np.dot(np.array([1, 1, 1]), (m1 * img[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]]))
if Gx[0] == 0:
theta[i - 1, j - 1] = 90
continue
else:
temp = (np.arctan2(Gy[0], Gx[0])) * 180 / np.pi)
if Gx[0] * Gy[0] > 0:
if Gx[0] > 0:
# 第一象线
theta[i - 1, j - 1] = np.abs(temp)
else:
# 第三象线
theta[i - 1, j - 1] = (np.abs(temp) - 180)
if Gx[0] * Gy[0] < 0:
if Gx[0] > 0:
# 第四象线
theta[i - 1, j - 1] = (-1) * np.abs(temp)
else:
# 第二象线
theta[i - 1, j - 1] = 180 - np.abs(temp)

img1[i - 1, j - 1] = (np.sqrt(Gx[0] ** 2 + Gy[0] ** 2))
for i in range(1, rows - 2):
for j in range(1, cols - 2):
if (((theta[i, j] >= -22.5) and (theta[i, j] < 22.5)) or
((theta[i, j] <= -157.5) and (theta[i, j] >= -180)) or
((theta[i, j] >= 157.5) and (theta[i, j] < 180))):
theta[i, j] = 90.0
elif (((theta[i, j] >= 22.5) and (theta[i, j] < 67.5)) or
((theta[i, j] <= -112.5) and (theta[i, j] >= -157.5))):
theta[i, j] = 45.0
elif (((theta[i, j] >= 67.5) and (theta[i, j] < 112.5)) or
((theta[i, j] <= -67.5) and (theta[i, j] >= -112.5))):
theta[i, j] = 0.0
elif (((theta[i, j] >= 112.5) and (theta[i, j] < 157.5)) or
((theta[i, j] <= -22.5) and (theta[i, j] >= -67.5))):
theta[i, j] = -45.0

'''
# 第三步:进行 非极大值抑制计算
img2 = np.zeros(img1.shape) # 非极大值抑制图像矩阵

for i in range(1, img2.shape[0] - 1):
for j in range(1, img2.shape[1] - 1):
# 0度j不变
if (theta[i, j] == 0.0) and (img1[i, j] == np.max([img1[i, j], img1[i + 1, j], img1[i - 1, j]])):
img2[i, j] = img1[i, j]

if (theta[i, j] == -45.0) and img1[i, j] == np.max([img1[i, j], img1[i - 1, j - 1], img1[i + 1, j + 1]]):
img2[i, j] = img1[i, j]

if (theta[i, j] == 90.0) and img1[i, j] == np.max([img1[i, j], img1[i, j + 1], img1[i, j - 1]]):
img2[i, j] = img1[i, j]

if (theta[i, j] == 45.0) and img1[i, j] == np.max([img1[i, j], img1[i - 1, j + 1], img1[i + 1, j - 1]]):
img2[i, j] = img1[i, j]

# 第四步:双阈值检测和边缘连接
img3 = np.zeros(img2.shape) # 定义双阈值图像
# TL = 0.4*np.max(img2)
# TH = 0.5*np.max(img2)
TL = 50
TH = 100
# 关键在这两个阈值的选择
for i in range(1, img3.shape[0] - 1):
for j in range(1, img3.shape[1] - 1):
if img2[i, j] < TL:
img3[i, j] = 0
elif img2[i, j] > TH:
img3[i, j] = 255
elif ((img2[i + 1, j] < TH) or (img2[i - 1, j] < TH) or (img2[i, j + 1] < TH) or
(img2[i, j - 1] < TH) or (img2[i - 1, j - 1] < TH) or (img2[i - 1, j + 1] < TH) or
(img2[i + 1, j + 1] < TH) or (img2[i + 1, j - 1] < TH)):
img3[i, j] = 255

cv2.namedWindow('1', 0)
cv2.resizeWindow("1", 640, 480)
cv2.namedWindow('2', 0)
cv2.resizeWindow("2", 640, 480)
cv2.namedWindow('3', 0)
cv2.resizeWindow("3", 640, 480)
cv2.namedWindow('4', 0)
cv2.resizeWindow("4", 640, 480)
cv2.imshow("1", img) # 原始图像
cv2.imshow("2", img1) # 梯度幅值图
cv2.imshow("3", img2) # 非极大值抑制灰度图
cv2.imshow("4", img3) # 最终效果图
cv2.waitKey(0)

运行结果如下

python实现canny边缘检测

python实现canny边缘检测

以上就是python实现canny边缘检测的详细内容,更多关于canny边缘检测的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python3简单实现微信爬虫
Apr 09 Python
Python抓取淘宝下拉框关键词的方法
Jul 08 Python
Python编程中time模块的一些关键用法解析
Jan 19 Python
Python实现PS图像抽象画风效果的方法
Jan 23 Python
Python实现去除列表中重复元素的方法小结【4种方法】
Apr 27 Python
Django实战之用户认证(初始配置)
Jul 16 Python
python基于paramiko将文件上传到服务器代码实现
Jul 08 Python
Python实现微信机器人的方法
Sep 06 Python
python获取全国城市pm2.5、臭氧等空气质量过程解析
Oct 12 Python
浅谈keras的深度模型训练过程及结果记录方式
Jan 24 Python
详解Python常用的魔法方法
Jun 03 Python
Python Flask请求扩展与中间件相关知识总结
Jun 11 Python
Python gevent协程切换实现详解
Sep 14 #Python
通过实例了解python__slots__使用方法
Sep 14 #Python
python如何遍历指定路径下所有文件(按按照时间区间检索)
Sep 14 #Python
详解python实现可视化的MD5、sha256哈希加密小工具
Sep 14 #Python
Python利用pip安装tar.gz格式的离线资源包
Sep 14 #Python
Python tkinter制作单机五子棋游戏
Sep 14 #Python
python安装cx_Oracle和wxPython的方法
Sep 14 #Python
You might like
php实现简单文件下载的方法
2015/01/30 PHP
PHP中TP5 上传文件的实例详解
2017/07/31 PHP
又一个小巧的图片预加载类
2007/05/05 Javascript
ECMAScript 创建自己的js类库
2012/11/22 Javascript
关于include标签导致js路径找不到的问题分析及解决
2013/07/09 Javascript
angularJS 入门基础
2015/02/09 Javascript
javascript常用的方法分享
2015/07/01 Javascript
jquery模拟多级复选框效果的简单实例
2016/06/08 Javascript
使用递归遍历对象获得value值的实现方法
2016/06/14 Javascript
Augularjs-起步详解
2016/07/08 Javascript
Angularjs 自定义服务的三种方式(推荐)
2016/08/02 Javascript
Bootstrap Search Suggest使用例子
2016/12/21 Javascript
详解JavaScript常量定义
2017/01/03 Javascript
jquery滚动条插件slimScroll使用方法
2017/02/09 Javascript
JavaScript实现获取select下拉框中第一个值的方法
2018/02/06 Javascript
JointJS流程图的绘制方法
2018/12/03 Javascript
Nodejs核心模块之net和http的使用详解
2019/04/02 NodeJs
ant design vue datepicker日期选择器中文化操作
2020/10/28 Javascript
[57:22]完美世界DOTA2联赛PWL S2 FTD vs PXG 第二场 11.27
2020/12/01 DOTA
python使用rabbitmq实现网络爬虫示例
2014/02/20 Python
python计算对角线有理函数插值的方法
2015/05/07 Python
如何在Python中编写并发程序
2016/02/27 Python
python Opencv将图片转为字符画
2021/02/19 Python
Python下调用Linux的Shell命令的方法
2018/06/12 Python
对python实时得到鼠标位置的示例讲解
2018/10/14 Python
python 保存float类型的小数的位数方法
2018/10/17 Python
Python 硬币兑换问题
2019/07/29 Python
Python生成六万个随机,唯一的8位数字和数字组成的随机字符串实例
2020/03/03 Python
详解Python IO口多路复用
2020/06/17 Python
学生喝酒检讨书
2014/02/06 职场文书
售前工程师职业生涯规划
2014/03/02 职场文书
经典而简洁的婚礼主持词
2014/03/13 职场文书
企业标语大全
2014/07/01 职场文书
学生违纪检讨书200字
2014/10/21 职场文书
2014年小学体育工作总结
2014/12/11 职场文书
Rust中的Struct使用示例详解
2022/08/14 Javascript