3种python3的canny边缘检测之静态,可调节和自适应
off999 2024-09-20 22:50 44 浏览 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 自己总结和整理,分享出来,希望对大家有帮助。
相关推荐
- 电脑动不动就卡住不动怎么回事
-
可能出现卡死原因:1、病毒引起,使你的电脑检测通过的程序太多,CPU主频性能不能充分发挥出来。2、温度过高,散热不好,使CPU性能下降。3、内存条太小,内存缺陷。5、可能设置了开机后自动登陆太多,自动...
- 笔记本风扇声音大怎么办(笔记本风扇声音非常大)
-
1.清理笔记本风扇灰尘一般而言,新买来的风扇总是噪声较小,而使用一段时间后会明显变大。其实,灰尘是造成风扇噪音上升的重要原因之一,因为无孔不入的灰尘总能钻进不完全密闭的机箱。当CPU风扇高速旋转时,漩...
- 如何添加无线网络打印机(如何添加无线网络打印机连接)
-
要添加网络打印机,您可以按照以下步骤进行操作:1.确保网络设置:首先,请确保您的计算机和打印机都已连接到同一个局域网或无线网络中,并且网络连接正常。确保您已经知道网络打印...
- 戴尔电脑一键重装系统(戴尔怎么一键重装系统)
-
若您需要重装戴尔系统,可以按照以下步骤进行操作:首先备份重要数据,然后获取系统安装介质,可以是光盘或USB驱动器。接下来,进入BIOS设置,将启动顺序调整为从安装介质启动。重启电脑后,按照屏幕提示进行...
- 电脑ip地址配置异常怎么修复
-
如果您发现IP地址配置异常,可以按照以下步骤尝试解决:1.检查网络连接:首先检查计算机、路由器或交换机等设备的网线、电源和连接状态是否正常,并确保网络设备正确连接。2.确认IP地址:检查您的计算机...
- 怎么把win7电脑恢复出厂设置
-
1.首先我们打开电脑找到“计算机”点击打开。2.进入页面然后我们点击“Windows7(C:)”打开C盘。3.我们在C盘界面找到Windows7并点击打开。4.进入到Win7文件夹中找到并双击“Sys...
- ctrl c 和 ctrl v 怎么按(一键复制粘贴)
-
左手小指按Ctrl键,食指按C键或者V键具体在按Ctrl+C的时候,无名指放在Z键上,中指放在X键上,食指按C键如果你也用这种方式的话,可能和我一样,第一次按的时候不习惯手指这样去分工的感觉,但是你...
- 玩游戏cpu温度多少正常(玩游戏cpu温度多少正常 贴吧)
-
在游戏过程中,CPU温度的正常范围通常在40°C至80°C之间。然而,具体的正常温度取决于CPU型号、散热系统和环境条件等因素。一般来说,如果CPU温度超过80°C,就可能存在过热的风险,需要采取措施...
- idm下载器(如何卸载idm下载器)
-
截至2023年9月3日,IDM(InternetDownloadManager)是一款非常受欢迎的下载工具,但它并没有被禁用。IDM可以帮助用户更快速、稳定地下载文件,提供了多线程下载、断点续传等...
- 电脑按f8后无法开机,三个键搞定
-
电脑开机按F8没有反应可能有多种原因,以下是一些可能的解决方法:尝试重启电脑:有时候,系统会出现临时问题,重启可能有助于解决。检查键盘连接和状态:确保键盘连接正常,没有故障。如果在其他地方测试过键盘是...
- 重装win7系统不能正常启动(win7重装系统后进不了系统)
-
1、点击Win10正式版桌面找到“此电脑”图标,右击并从弹出的右键菜单中选择“属性”项。2、此时将打开“控制”窗口,在左侧找到“高级系统设置”按钮点击进入详细设置界面。3、待打开“系统属性”窗口后,切...
- win7professional是什么版本
-
Windows7Professional是专业版。Windows7包含6个版本,分别为Windows7Starter(初级版)、Windows7HomeBasic(家庭普通版)、Win...
- tplink路由器怎么管理(tplink路由器管理app叫什么)
-
1、进入到路由器的管理界面,点击设置向导然后点下一步。2、选择工作模式,选择AP:接入点模式,点击下一步1.AP是WirelessAccessPoint的简称,中文名称:无线接入点;AP模式也...
- 怎样把wifi网速调到最快(怎样把wifi网速调到最快速度)
-
解决的方式很多,试试以下方法: 一、路由器摆放位置不正确 为了让自家的房间显得干净、整洁,很多人会选择将路由器放在不显眼的地方,比如门后、墙角、电脑桌下面,这样确实不影响美观,但是网络信号容易被...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
慕ke 前端工程师2024「完整」
-
失业程序员复习python笔记——条件与循环
-
- 最近发表
- 标签列表
-
- 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)
