3种python3的canny边缘检测之静态,可调节和自适应
off999 2024-09-20 22:50 57 浏览 0 评论
△ 先看高级版的python3的canny的自适应边缘检测:
△ 内容:
1 canny的边缘检测的介绍。
2 三种方法的canny的边缘检测,由浅入深地介绍:固定值的静态,可自调节的,自适应的。
△ 说明:
1 环境:python3.8、opencv4.5.3和matplotlib3.4.3。
2 图片:来自今日头条正版免费图库。
3 实现自适应阈值的canny边缘检测的参考代码和文章:
#基于python2实现自适应阈值的canny
https://github.com/sadimanna/canny
#本文基于python3,复现一种自适应的阈值分割方法。
https://blog.csdn.net/lyxleft/article/details/91558726?spm=1001.2014.3001.5501上述的代码,本机均有报错,故对代码进行修改,注释和运行。
△ 初级canny:
1 介绍:opencv中给出了canny边缘检测的接口,直接调用:
ret = cv2.canny(img,t1,t2)即可得到边缘检测的结果ret,其中,t1,t2是需要人为设置的阈值。
2 python的opencv的一行代码即可实现边缘检测。
3 Canny函数及使用:
函数:Canny edges = cv2.Canny(image, threshold1, threashold2)
参数:
image : 原始图像
threshold1 : 阈值1 (minVal)
threshold2 : 阈值2 (maxVal)
返回值:edges : 边缘图像4 Canny边缘检测流程:
去噪 --> 梯度 --> 非极大值抑制 --> 滞后阈值
Canny边缘检测算法其实非常复杂,包括4个步骤:
1 去噪:用高斯滤波器对图像进行去噪
2 梯度:计算梯度
3 NMS:在边缘上使用非极大值抑制(NMS)
4 滞后阈值:
在检测到的边缘上使用双阈值去除假阳性
分析所有的边缘及其之间的连接,以保留真正的边缘去除不明显的边缘5 代码:
import cv2
img = cv2.imread("/home/xgj/Desktop/edge_detection/snake.jpeg", cv2.IMREAD_GRAYSCALE)
cv2.imshow("snake", img)
ret1 = cv2.Canny(img, 100, 200) #人工设置固定值
cv2.imshow("result1", ret1)
ret2 = cv2.Canny(img, 20, 60) #人工设置固定值
cv2.imshow("result2", ret2)
cv2.waitKey()
cv2.destroyAllWindows()6 操作和过程:
7 原图:
8 疑问:
ret = cv2.canny(img,t1,t2),其中,t1,t2是需要人为设置的阈值,一般人怎么知道具体数值是多少,才是最佳的呀?所以,这是它的缺点。
△ 中级canny:
1 中级canny,就是可调节的阈值,找到最佳的canny边缘检测效果。
2 采用cv2.createTrackbar来调节阈值。
3 代码:
import cv2
import numpy as np
img= cv2.imread('/home/xgj/Desktop/edge_detection/3_self_canny/girl.jpeg')
cv2.namedWindow('Canny edge detect') #设置窗口,cv2.WINDOW_NORMAL表示窗口大小可自动调节
cv2.namedWindow('Original Image')
def nothing(x):
pass
# 创建两个滑动条,分别控制minVal(最小阈值)、maxVal(最大阈值).
# minVal:滑动条名称; 'Canny edge detect':窗口名; 60:滑动条默认滑动位置; 300:最大值 ; nothing:回调函数
cv2.createTrackbar('minVal','Canny edge detect',60,300,nothing)
cv2.createTrackbar('maxVal','Canny edge detect',100,400,nothing)
while(1):
#获得滑动条所在的位置
#cv2.getTrackbarPos(滑动条名称,窗口名);
minVal = cv2.getTrackbarPos('minVal','Canny edge detect')
maxVal = cv2.getTrackbarPos('maxVal','Canny edge detect')
#Canny边缘检测
#cv2.Canny函数参数解析:
# img:原图像名
# minVal:最小梯度
# maxVal:最大梯度
# 5 :5*5大小的高斯滤波器(卷积核),用来消除噪声影响
# L2gradient :求图像梯度,从而进行去除非边界上的点(非极大值抑制)
edgeImage = cv2.Canny(img,minVal,maxVal,5,L2gradient=True)
#显示图片
cv2.imshow('Original Image',img) #原图
cv2.imshow('Canny edge detect',edgeImage) # Canny检测后的图
k = cv2.waitKey(1)
if k ==ord('q')& 0xFF: # 按 q 退出
break
cv2.destroyAllWindows()#销毁窗口4 操作和效果:
5 原图:
△ 高级canny:
1 自适应canny的算法:
ret = cv2.canny(img,t1,t2)
即算法在运行过程中能够自适应地找到较佳的分割阈值t1,t2。
2 文件结构:
3 main.py代码:
# 主程序:main.py
# 第1步:模块导入
import numpy as np
import cv2, time, math
from matplotlib import pyplot as plt
from scipy.signal import convolve2d as conv2
#两个自定义模块(库)导入
from bilateralfilt import bilatfilt
from dog import deroGauss
# 第2步:函数定义
# 2-1 获取边缘函数:用高斯滤波器对图像进行去噪
def get_edges(I,sd):
dim = I.shape
Idog2d = np.zeros((nang,dim[0],dim[1]))
for i in range(nang):
dog2d = deroGauss(5,sd,angles[i])
Idog2dtemp = abs(conv2(I,dog2d,mode='same',boundary='fill'))
Idog2dtemp[Idog2dtemp<0]=0
Idog2d[i,:,:] = Idog2dtemp
return Idog2d
# 2-2 计算梯度
def calc_sigt(I,threshval):
M,N = I.shape
ulim = np.uint8(np.max(I))
N1 = np.count_nonzero(I>threshval)
N2 = np.count_nonzero(I<=threshval)
w1 = np.float64(N1)/(M*N)
w2 = np.float64(N2)/(M*N)
try:
u1 = sum(i*np.count_nonzero(np.multiply(I>i-0.5,I<=i+0.5))/N1 for i in range(threshval+1,ulim))
u2 = sum(i*np.count_nonzero(np.multiply(I>i-0.5,I<=i+0.5))/N2 for i in range(threshval+1))
uT = u1*w1+u2*w2
sigt = w1*w2*(u1-u2)**2
except:
return 0
return sigt
# 2-3 非极大值抑制(NMS)
def nonmaxsup(I,gradang):
dim = I.shape
Inms = np.zeros(dim)
xshift = int(np.round(math.cos(gradang*np.pi/180)))
yshift = int(np.round(math.sin(gradang*np.pi/180)))
Ipad = np.pad(I,(1,),'constant',constant_values = (0,0))
for r in range(1,dim[0]+1):
for c in range(1,dim[1]+1):
maggrad = [Ipad[r-xshift,c-yshift],Ipad[r,c],Ipad[r+xshift,c+yshift]]
if Ipad[r,c] == np.max(maggrad):
Inms[r-1,c-1] = Ipad[r,c]
return Inms
# 2-4-1 阈值
def threshold(I,uth):
lth = uth/2.5
Ith = np.zeros(I.shape)
Ith[I>=uth] = 255
Ith[I<lth] = 0
Ith[np.multiply(I>=lth, I<uth)] = 100
return Ith
# 2-4-2 hysteresis=滞后(效应)
def hysteresis(I):
r,c = I.shape
Ipad = np.pad(I,(1,),'edge')
c255 = np.count_nonzero(Ipad==255)
imgchange = True
for i in range(1,r+1):
for j in range(1,c+1):
if Ipad[i,j] == 100:
if np.count_nonzero(Ipad[r-1:r+1,c-1:c+1]==255)>0:
Ipad[i,j] = 255
else:
Ipad[i,j] = 0
Ih = Ipad[1:r+1,1:c+1]
return Ih
# 2-4-3 获取最佳阈值
def get_threshold(I):
max_sigt = 0
opt_t = 0
ulim = np.uint8(np.max(I))
print(ulim,'\n')
for t in range(ulim+1):
sigt = calc_sigt(I,t)
if sigt > max_sigt:
max_sigt = sigt
opt_t = t
print ('optimal high threshold: ',opt_t,'\n')
return opt_t
# 第3步:图片读取
# 读取原图
img = cv2.imread('/home/xgj/Desktop/edge_detection/3_self_canny/car.jpeg')
# 判断原图大小,如果大于多少,就调节图片大小
# 否则不调节
while img.shape[0] > 1100 or img.shape[1] > 1100:
img = cv2.resize(img,None, fx=0.5,fy=0.5,interpolation = cv2.INTER_AREA)
# 转换为gray灰度图
gimg = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
dim = img.shape #获取图片大小
# 第4步:开始图像的canny的自适应操作
#Bilateral filtering=双边滤波
print("总共有2步:有一定的耗时,与图片大小有关\n")
print("第1步:\n")
print ('Bilateral filtering...\n')
# 双边滤波:达到保边去噪
gimg = bilatfilt(gimg,5,3,10)
print ('after bilat: ',np.max(gimg),'\n')
#获取时间计时
stime = time.time()
angles = [0,45,90,135]
nang = len(angles)
#Gradient of Image=图片的梯度
print ('Calculating Gradient...\n')
img_edges = get_edges(gimg,2)
print ('after gradient: ',np.max(img_edges),'\n')
#Non-max suppression:在边缘上使用非极大值抑制(NMS)
print ('Suppressing Non-maximas...\n')
for n in range(nang):
img_edges[n,:,:] = nonmaxsup(img_edges[n,:,:],angles[n])
print ('after nms: ', np.max(img_edges),'\n')
print ('请关掉matplotlib的图形窗口,进行下一步自适应。。。\n')
img_edge = np.max(img_edges,axis=0)
lim = np.uint8(np.max(img_edge))
plt.imshow(img_edge)
plt.show()
print("第2步 函数调用:\n")
# 计算阈值
print ('Calculating Threshold...\n')
th = get_threshold(gimg)
the = get_threshold(img_edge)
# 获取阈值
print ('\nThresholding...\n')
img_edge = threshold(img_edge, the*0.25)
# 在边缘上使用非极大值抑制,滞后效应,获取自适应阈值
print ('Applying Hysteresis...\n')
img_edge = nonmaxsup(hysteresis(img_edge),90)
# 第5步:canny调用获取的自适应阈值
# 获取自适应的阈值采用canny进行边缘检测
img_canny = cv2.Canny(np.uint8(gimg),th/3,th)
cv2.imshow('Uncanny',img_edge)
cv2.imshow('Canny',img_canny)
print( 'Time taken :: ', str(time.time()-stime)+' seconds...\n')
print("结束!!")
cv2.waitKey(0)4 dog.py代码:
import numpy as np
import math
def deroGauss(w=5,s=1,angle=0):
wlim = (w-1)/2
y,x = np.meshgrid(np.arange(-wlim,wlim+1),np.arange(-wlim,wlim+1))
G = np.exp(-np.sum((np.square(x),np.square(y)),axis=0)/(2*np.float64(s)**2))
G = G/np.sum(G)
dGdx = -np.multiply(x,G)/np.float64(s)**2
dGdy = -np.multiply(y,G)/np.float64(s)**2
angle = angle*math.pi/180
dog = math.cos(angle)*dGdx + math.sin(angle)*dGdy
return dog5 bilateralfilt.py代码:
import numpy as np
# 双边滤波
def bilatfilt(I,w,sd,sr):
dim = I.shape
Iout= np.zeros(dim)
wlim = (w-1)//2
y,x = np.meshgrid(np.arange(-wlim,wlim+1),np.arange(-wlim,wlim+1))
g = np.exp(-np.sum((np.square(x),np.square(y)),axis=0)/(2*(np.float64(sd)**2)))
Ipad = np.pad(I,(wlim,),'edge')
for r in range(wlim,dim[0]+wlim):
for c in range(wlim,dim[1]+wlim):
Ix = Ipad[r-wlim:r+wlim+1,c-wlim:c+wlim+1]
s = np.exp(-np.square(Ix-Ipad[r,c])/(2*(np.float64(sr)**2)))
k = np.multiply(g,s)
Iout[r-wlim,c-wlim] = np.sum(np.multiply(k,Ix))/np.sum(k)
return Iout6 原图:
7 效果图:本文第一个gif图,此处省略。
△ 小结:
1 本文由浅入深,总结的很好,适合收藏。
2 对于理解python的opencv的canny的边缘检测,很有帮助。
3 本文高级版canny自适应的算法参考2篇文章,虽然我进行代码的删除,注释,修改,优化等操作,故我不标注原创,对原作者表达敬意。
4 自己总结和整理,分享出来,希望对大家有帮助。
相关推荐
- deepin和统信uos(统信和deepin的区别)
-
差不多。1Deepin原名LinuxDeepin、deepinos、深度操作系统,于2014年4月改名Deepin。deepin团队基于Qt/C++(用于前端)和Go(用于后端)开发了的全新深度桌...
- 三星驱动(三星驱动板)
-
驱动是必须装的,但不需要单独安装驱动。 1、电脑的所有硬件,必然要装驱动,键盘、鼠标什么的,都是有驱动的。驱动是软件和硬件结合的桥梁。但多数普通常见的硬件,驱动是widnows系统自带的,不需要用户...
- u盘启动杀毒软件(u盘杀毒系统)
-
有,但是主要是专杀工具,全面的综合杀毒软件基本上没有,因为没什么用。 1、放在U盘里的杀毒软件,就是不安装,也不监控,只杀毒的软件。 2、目前的杀毒软件的工作机制,主要是监控,监控电脑不感染病...
- 联想维修站点查询官网(联想 维修 服务网点)
-
您可以在联想的官方网站上查询到附近的授权维修服务点,或者拨打联想的客服电话寻求帮助。在维修服务点,您可以享受到专业的维修服务,包括硬件故障、软件问题、系统优化等方面的维护和维修。维修人员将会根据您的电...
- 电脑不识别移动硬盘(移动硬盘灯亮但不读取)
-
电脑不能识别移动硬盘可能是由于以下原因造成的:1.电脑和硬盘之间的连接首先,可以确保移动硬盘正确连接到电脑上,检查USB接口是否松动或损坏,可以尝试更换USB线或者尝试连接到其他USB接口看是否能够...
- 键盘的win键在哪里(电脑键盘的win键在哪里)
-
win键就是电脑键盘上显示WINDOWS标志的按键。位于CTRL键与ALT键两个键之间,win键的具体位置一般电脑键盘上有左右两个。Windows键是一种特殊的键,通常位于键盘的左下角。它的图案是一个...
- ghost全盘备份步骤图(用ghost怎么进行全盘备份)
-
可以用手动备份到指定分区。一、用一键Ghost还原中的“中文向导”备份开始-程序-一键Ghost-选出“中文向导”,Ghost中文向导-1、备份文件默认是“第1硬盘第1分区”,如果不是,将鼠标指针移...
-
- 键盘的windows键是哪一个(键盘上windows键是哪个键)
-
windows键就是电脑键盘上ctrl键和alt键之间的按键,位于左下角。它带着微软的徽标,跟开始菜单一样的图标,它属于辅助按键,主要与其它按键组合使用,实现一些特定的功能,组合成多种快捷操作方式。这里上面所知的Win键其实就是键盘上的Wi...
-
2025-12-31 10:51 off999
- win10打开设置快捷键(win10打开设置快捷键是什么)
-
1、首先打开电脑,在任务栏的语言地方点击一下再点击语言首选项。2、然后在新的界面里点击选择左侧“高级设置”按钮。3、之后在新的界面里点击选择“更改语言栏热键”按钮。4、然后在新的界面里点击选择“更改热...
- flash插件下载手机版下载安装
-
华为手机的最新系统版本已经不再支持FlashPlayer,这是由于Adobe已于2020年底停止更新和支持FlashPlayer。因此,如果您使用最新的华为手机系统,可能无法安装和使用Flash...
- 官方应用商店下载(小米官方应用商店下载)
-
1.审核和验证:应用商店会对应用进行审核和验证,确保其质量和可靠性。开发者需要满足一定的要求才能在应用商店上架应用。而官网下载的应用没有经过此类审核和验证,因此用户需要自行评估其质量和可信度。2....
- 主题软件免费(主题软件免费推荐)
-
下载主题方法:一、打开手机找到APPStore应用软件,二、点击进去在下面找到有个搜索,点击它查找主题壁纸,三、弹出来很多主题壁纸,根据下载量和个人喜欢的应用主题选择下载相应的主题,四、下载成功后即...
- 一芯fc1178bc盘量产教程(一芯量产工具使用教程)
-
fc1178bc量产工具没有显示u盘拔下U盘,关闭量产工具,再插上U盘(先要确认卸载了安国的驱动,如果不能确认,运行LoadDriver.exe卸载),然后插上U盘,右键我的电脑---属性---硬件-...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
python入门到脱坑 输入与输出—str()函数
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
失业程序员复习python笔记——条件与循环
-
系统u盘安装(win11系统u盘安装)
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
