百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

3种python3的canny边缘检测之静态,可调节和自适应

toyiye 2024-07-11 00:25 10 浏览 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 dog

5 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 Iout

6 原图:

7 效果图:本文第一个gif图,此处省略。

小结:

1 本文由浅入深,总结的很好,适合收藏。

2 对于理解python的opencv的canny的边缘检测,很有帮助。

3 本文高级版canny自适应的算法参考2篇文章,虽然我进行代码的删除,注释,修改,优化等操作,故我不标注原创,对原作者表达敬意。

4 自己总结和整理,分享出来,希望对大家有帮助。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码