基于python实现自适应阈值的canny边缘检测

匿名 (未验证) 提交于 2019-12-02 22:51:30

opencv中给出了canny边缘检测的接口,直接调用:

ret = cv2.canny(img,t1,t2)

即可得到边缘检测的结果ret。其中,t1,t2是需要人为设置的阈值。有不少论文研究了自动化的阈值设置方法,即算法在运行过程中能够自适应地找到较佳的分割阈值t1,t2,但是缺乏开源代码,特别是基于python3的实现几乎没有。

本文基于python3,复现一种自适应的阈值分割方法。

输入图片是:

输出结果对比如下:左图是直接用canny,右图是用本文程序自适应分割。

比较不足的是,由于自底向上重新编写,包括非最大抑制等过程。。可能耗时比较久。上面输入图像耗时27.38s,不知道其他学者研究的自适应阈值canny边缘检测方法的耗时情况如何。。程序中预处理过程中已经做了降采样,如果没有降采样的话,耗时会更长。

下面上代码:

主程序.py:

 import numpy as np import cv2, time, math from scipy.signal import convolve2d as conv2 from matplotlib import pyplot as plt from bilateralfilt import bilatfilt from dog import deroGauss import time #........................................................................................... 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 #........................................................................................... 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 #........................................................................................... 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) 	#print N1,N2,w1,w2 	try: 		u1 = np.sum(i*np.count_nonzero(np.multiply(I>i-0.5,I<=i+0.5))/N1 for i in range(threshval+1,ulim)) 		u2 = np.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 		#print u1,u2,uT,sigt 	except: 		return 0 	return sigt #........................................................................................... def get_threshold(I): 	max_sigt = 0 	opt_t = 0 	ulim = np.uint8(np.max(I)) 	print(ulim) 	for t in range(ulim+1): 		sigt = calc_sigt(I,t) 		#print t, sigt 		if sigt > max_sigt: 			max_sigt = sigt 			opt_t = t 	print ('optimal high threshold: ',opt_t) 	return opt_t 	 #........................................................................................... 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 #........................................................................................... def hysteresis(I): 	r,c = I.shape 	#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,),'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 Ipad[i-xshift,j+yshift]==255 or Ipad[i+xshift,j-yshift]==255:  				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 #........................................................................................... #Reading the image img = cv2.imread('img0030.jpg') 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) #tic = time.time() gimg = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) dim = img.shape #........................................................................................... #Bilateral filtering 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 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)) img_edge = np.max(img_edges,axis=0) lim = np.uint8(np.max(img_edge)) plt.imshow(img_edge) plt.show() #........................................................................................... #Converting to uint8 #img_edges_uint8 = np.uint8(img_edges) #........................................................................................... #Thresholding print ('Calculating Threshold...\n') th = get_threshold(gimg) the = get_threshold(img_edge) #........................................................................................... print ('\nThresholding...\n') img_edge = threshold(img_edge, the*0.25) #cv2.imshow('afterthe',img_edge) #........................................................................................... #Hysteresis print ('Applying Hysteresis...\n') #for i in xrange(nang): img_edge = nonmaxsup(hysteresis(img_edge),90) #........................................................................................... #img_edge = np.max(img_edges,axis=0) #........................................................................................... #OpenCV Canny Function img_canny = cv2.Canny(np.uint8(gimg),th/3,th) #toc = time.time() #print('自适应耗时:',toc-tic) cv2.imshow('Uncanny',img_edge) cv2.imshow('Canny',img_canny) print( 'Time taken :: ', str(time.time()-stime)+' seconds...') cv2.waitKey(0) 

dog.py:

 import numpy as np import math #Oriented Odd Symmetric Gaussian Filter :: First Derivative of Gaussian 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 #converting to radians  	dog = math.cos(angle)*dGdx + math.sin(angle)*dGdy  	return dog

bilateralfilt.py:

 import numpy as np #import cv2, time  def bilatfilt(I,w,sd,sr): 	dim = I.shape 	Iout= np.zeros(dim) 	#If the window is 5X5 then w = 5	 	wlim = (w-1)//2 	y,x = np.meshgrid(np.arange(-wlim,wlim+1),np.arange(-wlim,wlim+1)) 	#Geometric closeness 	g = np.exp(-np.sum((np.square(x),np.square(y)),axis=0)/(2*(np.float64(sd)**2))) 	#Photometric Similarity 	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

参考资料:

https://github.com/sadimanna/canny(基于python2实现自适应阈值的canny,且个别地方会报错)

算法细节,可以网上搜索查看相关文献。

文章来源: https://blog.csdn.net/lyxleft/article/details/91558726
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!