Python与FPGA——sobel边缘检测

本文介绍了Sobel边缘检测的基本原理,包括其原理、Python中的代码实现以及在FPGA上的应用。通过比较,展示了FPGA在处理速度上的优势,但可能存在噪声,需后续处理。
摘要由CSDN通过智能技术生成

文章目录

  • 前言
  • 一、sobel边缘检测
  • 二、Python sobel边缘检测
  • 三、FPGA sobel边缘检测
  • 总结


前言

  边缘存在于目标、背景区域之间,它是图像分割所依赖的较重要的依据,也是图像匹配的重要特征。边缘检测在图像处理和计算机视觉中,尤其在图像的特征提前、对象检测以及模式识别等方面都有重要的作用。


一、sobel边缘检测

  下图是Gx的计算,Gy的计算类似。
在这里插入图片描述
  为什么要乘以一个像Gx的矩阵呢?其实就是在求上图中像素6周围像素的变化率,求导的另外一种表示方法就是变化率。
▽ f ( x , y ) = ( ∂ f ∂ x , ∂ f ∂ y ) = ( ∂ f ∂ x ) 2 + ( ∂ f ∂ y ) 2 \bigtriangledown f(x, y) = \Big(\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}\Big) = \sqrt{\Big(\frac{\partial f}{\partial x}\Big)^2 + \Big(\frac{\partial f}{\partial y}\Big)^2} f(x,y)=(xf,yf)=(xf)2+(yf)2

G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] G_x = \begin{bmatrix} -1 & 0 & 1\\ -2 & 0 & 2\\ -1 & 0 & 1 \end{bmatrix} \quad\quad\quad G_y = \begin{bmatrix} -1 & -2 & -1\\ 0 & 0 & 0\\ 1 & 2 & 1 \end{bmatrix} Gx=121000121Gy=101202101
  Gx与Gy算出了过后,再进行如下运算,计算出G。设置一个阈值threshold,如果G>=threshold,就将窗口中心对应的图像像素设置为255,否则设置为0。
G = G x 2 + G y 2 G = \sqrt{G_x^2 + G_y^2} G=Gx2+Gy2

二、Python sobel边缘检测

import numpy as np
import matplotlib.pyplot as plt
img = plt.imread("lenna.png")
gray = 0.299 * img[:, :, 0] + 0.587 * img[:, :, 1] + 0.114 * img[:, :, 2] 
gray = gray * 255#图像是[0-1]--->[0-255]

def kernel_mutiply(win, kernel):
    value = np.sum(np.multiply(win, kernel))
    return value
    
def sobel_detect(gray, gx, gy, threshold):
    h, w = gray.shape
    n, n = gx.shape
    m = int((n - 1) / 2)
    sobel_image = np.zeros((h, w))
    for i in range(m, h - m):
        for j in range(m, w - m):
            gx2 = (kernel_mutiply(gray[i - m: i + m + 1, j - m: j + m + 1], gx)) ** 2
            gy2 = (kernel_mutiply(gray[i - m: i + m + 1, j - m: j + m + 1], gy)) ** 2
            value = np.sqrt(gx2 + gy2)
            if value >= threshold:
                sobel_image[i, j] = 255
            else:
                sobel_image[i, j] = 0
    return sobel_image.astype(np.uint8)
    
gx = np.array([[-1, 0, 1],
               [-2, 0, 2],
               [-1, 0, 1]])
gy = np.array([[-1, -2, -1],
               [0, 0, 0],
               [1, 2, 1]])
sobel_image = sobel_detect(gray, gx, gy, 95)
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 2, 1)
ax.set_title("gray image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(gray, cmap="gray")
ax = fig.add_subplot(1, 2, 2)
ax.set_title("sobel image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(sobel_image, cmap="gray")

在这里插入图片描述

三、FPGA sobel边缘检测

  在FPGA的sobel边缘检测中,增加了移位寄存器IP,sqrt数学运算IP。

//3*3图像
//P11   P12   P13
//P21   P22   P23
//P31   P32   P33

//Gx算子
//-1     0     1
//-2     0     2
//-1     0     1
//Gx = -P11 + P13 - 2*P21 + 2*P23 - P31 + P33
//Gx = (P13 - P11) + 2*(P23 - P21) + (P33 - P31)

//Gy算子
//1      2     1
//0      0     0
//-1     -2    -1
//Gy = P11 + 2*P12 + P13 - P31 - 2*P32 - P33
//Gy = (P11 - P31) + 2*(P12 - P32) + (P13 - P33)
module  ycbcr_to_sobel
(
	input	wire			sys_clk		,	//系统时钟,频率为50MHZ
	input	wire			sys_rst_n	,	//系统复位,低电平有效
	input	wire			rgb_valid	,	//RGB565图像显示有效信号
	input	wire	[7:0]	th_data		,	//阈值数据
	input	wire	[7:0]	y_data		,	//Y分量
	input	wire	[11:0]	pixel_x		,	//有效显示区域横坐标
	input	wire	[11:0]	pixel_y		,	//有效显示区域纵坐标
	
	output	reg		[15:0]	sobel_data		//Sobel算法处理后的图像数据
);

reg				y_valid		;	//Y分量有效信号
//shift ram
wire	[7:0]	data_row1	;	//移位寄存器第一行数据
wire	[7:0]	data_row2	;	//移位寄存器第二行数据
wire	[7:0]	data_row3	;	//移位寄存器第三行数据
//3*3像素数据,左上角至右下角共9个数据
reg		[7:0]	p11			;	//3*3第1个像素数据
reg		[7:0]	p12			;	//3*3第2个像素数据
reg		[7:0]	p13			;	//3*3第3个像素数据
reg		[7:0]	p21			;	//3*3第4个像素数据
reg		[7:0]	p22			;	//3*3第5个像素数据
reg		[7:0]	p23			;	//3*3第6个像素数据
reg		[7:0]	p31			;	//3*3第7个像素数据
reg		[7:0]	p32			;	//3*3第8个像素数据
reg		[7:0]	p33			;	//3*3第9个像素数据
//Sobel算子
wire	[15:0]	Gx			;	//水平梯度值
wire	[15:0]	Gy			;	//数值梯度值
wire	[7:0]	Gxy			;	//总体梯度值

assign  data_row3 = y_data  ;
assign  Gx = (p13 - p11) + 2*(p23 - p21) + (p33 - p31)  ;
assign  Gy = (p11 - p31) + 2*(p12 - p32) + (p13 - p33)  ;

//设定第一行、第二行,第一列、第二列显示全白色
always@(*)
	if((pixel_y == 12'd0)||(pixel_y == 12'd1)||(pixel_x == 12'd2)||(pixel_x == 12'd3))
		sobel_data = 16'hffff  ;
	else
		sobel_data = (Gxy >= th_data) ? 16'hffff : 16'd0  ;	

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		y_valid  <=  1'b0  ;
	else
		y_valid  <=  rgb_valid  ;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		begin
			{p11,p12,p13}  <=  24'd0  ;
			{p21,p22,p23}  <=  24'd0  ;
			{p31,p32,p33}  <=  24'd0  ;
		end
	else  if(y_valid == 1'b1)
		begin
			{p11,p12,p13}  <= {p12,p13,data_row1}  ;
			{p21,p22,p23}  <= {p22,p23,data_row2}  ;
			{p31,p32,p33}  <= {p32,p33,data_row3}  ;
		end	
	else
		begin
			{p11,p12,p13}  <=  24'd0  ;
			{p21,p22,p23}  <=  24'd0  ;
			{p31,p32,p33}  <=  24'd0  ;
		end		

shift_ram_gen  shift_ram_gen_inst
(
	.clock 		(sys_clk	),
	.shiftin	(data_row3	),
	.shiftout 	(			),
	.taps0x 	(data_row2	),
	.taps1x 	(data_row1	)
);

sqrt_gen  sqrt_gen_inst 
(
	.radical	(Gx*Gx + Gy*Gy),
	.q 			(Gxy	),
	.remainder 	()
);

endmodule

  阈值还是保持95,和Python中的阈值设置一样。处理结果如下。

在这里插入图片描述


总结

  sobel边缘检测就到此结束,可以看到FPGA处理过后存在噪音,可以采用中值滤波进行处理,感兴趣的小伙伴自行实现。下一期带来膨胀腐蚀算法,敬请期待。

  • 32
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值