版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第Python利用Canny算法检测硬币边缘目录一、问题背景二、Canny算法(一)、高斯平滑(二)Sobel算子计算梯度(三)非极大化抑制(四)滞后边缘跟踪
一、问题背景
纸面上有一枚一元钱的银币,你能在Canny和Hough的帮助下找到它的坐标方程吗?
确定一个圆的坐标方程,首先我们要检测到其边缘,然后求出其在纸面上的相对位置以及半径大小。
在这篇文章中我们使用Canny算法来检测出纸面上银币的边缘。
二、Canny算法
Canny可以用于拿到图像中物体的边缘,其步骤如下
进行高斯平滑计算图像梯度(记录其强度、方向)进行非极大化抑制进行滞后边缘跟踪
进行上面的四步之后,我们拿到的纸面上硬币边缘提取效果图如下
(一)、高斯平滑
classGaussianSmoothingNet(nn.Module):
def__init__(self)-None:
super(GaussianSmoothingNet,self).__init__()
filter_size=5
#shape为(1,5),方差为1.0的高斯滤波核
generated_filters=gaussian(filter_size,std=1.0).reshape([1,filter_size])
#GFH(V):gaussianfilterofhorizontal(vertical)水平(竖直)方向的高斯滤波核
self.GFH=nn.Conv2d(1,1,kernel_size=(1,filter_size),padding=(0,filter_size//2))
self.GFV=nn.Conv2d(1,1,kernel_size=(filter_size,1),padding=(filter_size//2,0))
#设置w的值为高斯平滑核,b的值为0.0
init_parameter(self.GFH,generated_filters,np.array([0.0]))
init_parameter(self.GFV,generated_filters.T,np.array([0.0]))
defforward(self,img):
img_r=img[:,0:1]#取出RGB三个通道的数据
img_g=img[:,1:2]
img_b=img[:,2:3]
#对图片的三个通道进行水平、垂直滤波
blurred_img_r=self.GFV(self.GFH(img_r))
blurred_img_g=self.GFV(self.GFH(img_g))
blurred_img_b=self.GFV(self.GFH(img_b))
#合并成一张图
blurred_img=torch.stack([blurred_img_r,blurred_img_g,blurred_img_b],dim=1)
blurred_img=torch.stack([torch.squeeze(blurred_img)])
returnblurred_img
进行高斯平滑(模糊)之后的图片较原图更为模糊如下图右侧银币所示
完整代码见:gaussian_smoothing
(二)Sobel算子计算梯度
PAI=3.1415926
classSobelFilterNet(nn.Module):
def__init__(self)-None:
super(SobelFilterNet,self).__init__()
sobel_filter=np.array([[-1,0,1],
[-2,0,2],
[-1,0,1]])
self.SFH=nn.Conv2d(1,1,kernel_size=sobel_filter.shape,padding=sobel_filter.shape[0]//2)
self.SFV=nn.Conv2d(1,1,kernel_size=sobel_filter.shape,padding=sobel_filter.shape[0]//2)
init_parameter(self.SFH,sobel_filter,np.array([0.0]))
init_parameter(self.SFV,sobel_filter.T,np.array([0.0]))
defforward(self,img):
img_r=img[:,0:1]
img_g=img[:,1:2]
img_b=img[:,2:3]
##SFH(V):sobelfilterofhorizontal(vertical)水平(竖直)方向的Sobel滤波
grad_r_x=self.SFH(img_r)#通道R的x方向梯度
grad_r_y=self.SFV(img_r)
grad_g_x=self.SFH(img_g)
grad_g_y=self.SFV(img_g)
grad_b_x=self.SFH(img_b)
grad_b_y=self.SFV(img_b)
#计算强度(magnitude)和方向(orientation)
magnitude_r=torch.sqrt(grad_r_x**2+grad_r_y**2)#Gr^2=Grx^2+Gry^2
magnitude_g=torch.sqrt(grad_g_x**2+grad_g_y**2)
magnitude_b=torch.sqrt(grad_b_x**2+grad_b_y**2)
grad_magnitude=magnitude_r+magnitude_g+magnitude_b
grad_y=grad_r_y+grad_g_y+grad_b_y
grad_x=grad_r_x+grad_g_x+grad_b_x
#tanθ=grad_y/grad_x转化为角度(方向角)
grad_orientation=(torch.atan2(grad_y,grad_x)*(180.0/PAI))
grad_orientation=torch.round(grad_orientation/45.0)*45.0#转化为45的倍数
returngrad_magnitude,grad_orientation
将梯度强度当作图片进行输出,得到右下图最右侧图片,可知硬币的边缘区域梯度值较大(越大越亮)
完整代码见:sobel_filter
(三)非极大化抑制
非极大化抑制(NMS)的过程为:
将梯度强度矩阵grad_magnitude的每一点都作为中心像素点,与其同向或者反向的两个相邻点(共有8个)的梯度强度进行比较。若中心点的梯度小于这两个方向上的梯度,则点中心的的梯度值设为0
进过上面的两个步骤,可以用一个像素的宽度替代了梯度屋脊效应,同时保留了屋脊的梯度强度(最大的梯度)。
classNonMaxSupression(nn.Module):
def__init__(self)-None:
super(NonMaxSupression,self).__init__()
all_orient_magnitude=np.stack([filter_0,filter_45,filter_90,filter_135,filter_180,filter_225,filter_270,filter_315])
directional_filter功能见下面详细说明
self.directional_filter=nn.Conv2d(1,8,kernel_size=filter_0.shape,padding=filter_0.shape[-1]//2)
init_parameter(self.directional_filter,all_filters[:,None,...],np.zeros(shape=(all_filters.shape[0],)))
defforward(self,grad_magnitude,grad_orientation):
all_orient_magnitude=self.directional_filter(grad_magnitude)#当前点梯度分别与其其他8个方向邻域点做差(相当于二阶梯度)
\3|2/
\|/
4\|/1
-----------|------------
5/|\8
/|\
/6|7\
注:各个区域都是45度
positive_orient=(grad_orientation/45)%8#设置正方向的类型,一共有八种不同类型的方向
negative_orient=((grad_orientation/45)+4)%8#+4=4*45=180即旋转180度(如1-(+4)-5)
height=positive_orient.size()[2]#得到图片的宽高
width=positive_orient.size()[3]
pixel_count=height*width#计算图片所有的像素点数
pixel_offset=torch.FloatTensor([range(pixel_count)])
position=(positive_orient.view(-1).data*pixel_count+pixel_offset).squeeze()#角度*像素数+像素所在位置
#拿到图像中所有点与其正向邻域点的梯度的梯度(当前点梯度-正向邻域点梯度,根据其值与0的大小判断当前点是不是邻域内最大的)
channel_select_filtered_positive=all_orient_magnitude.view(-1)[position.long()].view(1,height,width)
position=(negative_orient.view(-1).data*pixel_count+pixel_offset).squeeze()
#拿到图像中所有点与其反向邻域点的梯度的梯度
channel_select_filtered_negative=all_orient_magnitude.view(-1)[position.long()].view(1,height,width)
#组合成两个通道
channel_select_filtered=torch.stack([channel_select_filtered_positive,channel_select_filtered_negative])
is_max=channel_select_filtered.min(dim=0)[0]0.0#如果min{当前梯度-正向点梯度,当前梯度-反向点梯度}0,则当前梯度最大
is_max=torch.unsqueeze(is_max,dim=0)
thin_edges=grad_magnitude.clone()
thin_edges[is_max==0]=0.0
returnthin_edges
directional_filter的用处是什么?
#输入
tensor([[[[1.,1.,1.],
[1.,1.,1.],
[1.,1.,1.]]]])
tensor([[[[0.,0.,1.],
[0.,0.,1.],
[0.,0.,1.]],
[[0.,0.,1.],
[0.,0.,1.],
[1.,1.,1.]],
[[0.,0.,0.],
[0.,0.,0.],
[1.,1.,1.]],
[[1.,0.,0.],
[1.,0.,0.],
[1.,1.,1.]],
[[1.,0.,0.],
[1.,0.,0.],
[1.,0.,0.]],
[[1.,1.,1.],
[1.,0.,0.],
[1.,0.,0.]],
[[1.,1.,1.],
[0.,0.,0.],
[0.,0.,0.]],
[[1.,1.,1.],
[0.,0.,1.],
[0.,0.,1.]]]],grad_fn=ThnnConv2DBackward0)
可知其获取输入的八个方向的梯度值(在当前项目的代码中,为获取当前点梯度与其它8个方向梯度之差)
根据梯度的强度和方向,将方向分成8个类别(即对于每一点有八个可能方向),如上代码中米型图所示。
下面给出计算当前点正向邻域的相邻点的梯度强度的过程(反向同理)
梯度方向grad_orientation:0,1,,2,3,4,5,6,7(共有8哥方向)
各方向梯度强度all_orient_magnitude:[[..方向0的梯度..],[..方向1的梯度..],...,[..方向7的梯度..]]
故对于方向为i的点,其在梯度强度中的位置为all_orient_magnitude[i][x,y],将all_orient_magnitude变化为一维向量后,对应的位置为position=current_orientpixel_count+pixel_offset,我们就可以根据这个位置信息拿到当前点与其正向邻域点梯度强度之差(同理也可以拿到反向的)。
以下为辅助图示:
最后效果如下右侧图所示(左侧为未进行最大化抑制的图)
完整代码见:nonmax_supression
(四)滞后边缘跟踪
我们思考后发现,到目前为止仍有如下几个问题:
如果图像中有噪声,可能会出现边缘无关的点(伪边)边缘点时阴时明
所以最后我们就需要进行滞后边缘跟踪了,其步骤如下:
设定两个阈值(一高一低),将梯度强度小于低阈值的像素点的梯度强度设为0,得到图像A将梯度强度小于高阈值的像素点的梯度强度设为0,得到图像B
我们知道由于A的阈值较低,故边缘保留较完整,连续性较好,但是伪边可能也较多,B正好与A相反。
据此我们设想以B为基础,A为补充,通过递归追踪来补全B中边缺失的像素点。
to_bw=lambdaimage:(image0.0).astype(float)
classHysteresisThresholding(nn.Module):
def__init__(self,low_threshold=1.0,high_threshold=3.0)-None:
super(HysteresisThresholding,self).__init__()
self.low_threshold=low_threshold
self.high_threshold=high_threshold
defthresholding(self,low_thresh:torch.Tensor,high_thresh:torch.Tensor):
died=torch.zeros_like(low_thresh).squeeze()
low_thresh=low_thresh.squeeze()
final_image=high_thresh.squeeze().clone()
height=final_image.shape[0]-1
width=final_image.shape[1]-1
defconnected(x,y,gap=1):
right=x+gap
bottom=y+gap
left=x-gap
top=y-gap
ifleft0ortop0orright=widthorbottom=height:
returnFalse
returnfinal_image[top,left]0orfinal_image[top,x]0orfinal_image[top,right]0\
orfinal_image[y,left]0orfinal_image[y,right]0\
orfinal_image[bottom,left]0orfinal_image[bottom,x]0orfinal_image[bottom,right]0
#先高再宽
deftrace(x:int,y:int):
right=x+1
bottom=y+1
left=x-1
top=y-1
ifleft0ortop0orright=widthorbottom=heightordied[y,x]orfinal_image[y,x]0:
return
pass_high=final_image[y,x]0.0
pass_low=low_thresh[y,x]0.0
died[y,x]=True
ifpass_high:
died[y,x]=False
elifpass_lowandnotpass_high:
ifconnected(x,y)orconnected(x,y,2):#如果其他方向有连接
final_image[y,x]=low_thresh[y,x]
died[y,x]=False
#往回
iffinal_image[y,x]0.0:#当前点有连接
iflow_thresh[top,left]0:trace(left,top)
iflow_thresh[top,x]0:trace(x,top)
iflow_thresh[top,right]0:trace(right,top)
iflow_th
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 城市轨道交通车站机电设备运用课件-自动售检票系统
- 2026年专利代理人能力测试备考题附参考答案详解【夺分金卷】
- 2026年英语八年级英语语法填空训练专项练习题能力检测试卷及参考答案详解(基础题)
- 2026年神经内科考前冲刺练习题库附参考答案详解(典型题)
- 【低空经济】高速公路低空经济应用方案
- 2026学年历史八年级下学期第三单元-改革开放与中国特色社会主义的开创专项训练题(含答案)
- 2026年如何看待幼儿园个性幼儿
- 2026年捐衣物幼儿园
- 2026及未来5年中国EVA电子包装产品市场数据分析及竞争策略研究报告
- 2025福建省闽西南水资源开发有限责任公司招聘5人笔试参考题库附带答案详解
- 衍纸基础教学课件
- “王川同”诺贝尔文学奖作品:《苍穹隆稻华甸》文‖王川同中国籍、湖南、邵阳市洞口县、水东、文田村、王
- 【《像天使一样美丽》歌剧咏叹调的艺术特点与演唱技巧分析案例2600字(论文)】
- 校外教育杯教师论文
- 语文 《登岳阳楼》《望岳》《登高》比较阅读教学设计 2024-2025学年统编版高一语文必修下册
- 医疗行业腐败案例警示教育心得体会
- T/CSPSTC 103-2022氢气管道工程设计规范
- 广州2025年上半年广州开发区黄埔区事业单位招聘18人笔试历年参考题库附带答案详解
- 蜜雪冰城转让店协议合同
- 马克思主义基本原理全套课件
- 测量劳务合同5篇
评论
0/150
提交评论