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 相关文章推荐
django1.8使用表单上传文件的实现方法
Nov 04 Python
python 动态加载的实现方法
Dec 22 Python
python selenium 获取标签的属性值、内容、状态方法
Jun 22 Python
python查找指定文件夹下所有文件并按修改时间倒序排列的方法
Oct 21 Python
pycharm 解除默认unittest模式的方法
Nov 30 Python
python return逻辑判断表达式实现解析
Dec 02 Python
Django框架配置mysql数据库实现过程
Apr 22 Python
pandas.DataFrame.drop_duplicates 用法介绍
Jul 06 Python
Pycharm2020.1安装无法启动问题即设置中文插件的方法
Aug 07 Python
python xlwt模块的使用解析
Apr 13 Python
python 中的jieba分词库
Nov 23 Python
Python可视化神器pyecharts之绘制箱形图
Jul 07 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中取得URL的根域名的代码
2011/03/23 PHP
一个PHP缓存类代码(附详细说明)
2011/06/09 PHP
深入Memcache的Session数据的多服务器共享详解
2013/06/13 PHP
PHP 断点续传实例详解
2017/11/11 PHP
laravel5.1框架model类查询的实现方法
2019/10/08 PHP
Js的MessageBox
2006/12/03 Javascript
Javascript remove 自定义数组删除方法
2009/10/20 Javascript
javascript 处理null及null值示例
2014/06/09 Javascript
javascript基于HTML5 canvas制作画箭头组件
2014/06/25 Javascript
javascript实现避免页面按钮重复提交
2015/01/08 Javascript
JavaScript 匿名函数和闭包介绍
2015/04/13 Javascript
jquery判断单选按钮radio是否选中的方法
2015/05/05 Javascript
Jquery简单分页实现方法
2015/07/24 Javascript
网页挂马方式整理及详细介绍
2016/11/03 Javascript
利用jquery实现下拉框的禁用与启用
2016/12/07 Javascript
JavaScript中动态向表格添加数据
2017/01/24 Javascript
AngularJS动态添加数据并删除的实例
2018/02/27 Javascript
vue中Axios的封装与API接口的管理详解
2018/08/09 Javascript
详解webpack引入第三方库的方式以及注意事项
2019/01/15 Javascript
浅谈layui 绑定form submit提交表单的注意事项
2019/10/25 Javascript
[06:16]第十四期-国士无双绝地翻盘之撼地神牛
2014/06/24 DOTA
[00:47]TI7不朽珍藏III——沙王不朽展示
2017/07/15 DOTA
[50:58]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 Mineski vs EG
2018/04/03 DOTA
详解python中自定义超时异常的几种方法
2019/07/29 Python
python获取Linux发行版名称
2019/08/30 Python
pytorch 图像预处理之减去均值,除以方差的实例
2020/01/02 Python
Python使用qrcode二维码库生成二维码方法详解
2020/02/17 Python
python实现可下载音乐的音乐播放器
2020/02/25 Python
Python设计密码强度校验程序
2020/07/30 Python
HTML5中的Article和Section元素认识及使用
2013/03/22 HTML / CSS
领导失职检讨书
2014/02/24 职场文书
餐饮商业计划书范文
2014/04/29 职场文书
新手上路标语
2014/06/20 职场文书
社保委托书怎么写
2014/08/02 职场文书
学校2014重阳节活动策划方案
2014/09/16 职场文书
eclipse创建项目没有dynamic web的解决方法
2021/06/24 Java/Android