前言
边缘存在于目标、背景区域之间,它是图像分割所依赖的较重要的依据,也是图像匹配的重要特征。边缘检测在图像处理和计算机视觉中,尤其在图像的特征提前、对象检测以及模式识别等方面都有重要的作用。
一、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)=(∂x∂f,∂y∂f)=(∂x∂f)2+(∂y∂f)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=⎣⎡−1−2−1000121⎦⎤Gy=⎣⎡−101−202−101⎦⎤
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中的阈值设置一样。处理结果如下。
文章来源:https://www.toymoban.com/news/detail-840509.html
总结
sobel边缘检测就到此结束,可以看到FPGA处理过后存在噪音,可以采用中值滤波进行处理,感兴趣的小伙伴自行实现。下一期带来膨胀腐蚀算法,敬请期待。文章来源地址https://www.toymoban.com/news/detail-840509.html
到了这里,关于Python与FPGA——sobel边缘检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!