sobel的由来是求导公式即:
f'(x) = lim(h→0)[f(x+h)-f(x-h)]/2h,
通过高等数学的知识易得,这个公式可以通过求微分来取得数值变化的大小。
而要对图像使用的情况下由于求极限也只能趋于1,则取近似为f'(x) = [f(x+1)-f(x-1)]/2,通常sobel核的范围是3x3,而其中的中间需要加权一倍。
整体呈现:(来自百度百科)
verilog实现方法:
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
kernel_1 <= 'd0;
kernel_2 <= 'd0;
kernel_3 <= 'd0;
end else if(flag_kernel) begin
kernel_1 <= { kernel_1 , data_receive };
kernel_2 <= { kernel_2 , RD_DATA_OUT_2};
kernel_3 <= { kernel_3 , RD_DATA_OUT_1};
end
end
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
dx <= 'd0;
dy <= 'd0;
end else if(flag_Conv == 1'b1) begin
dx <= (kernel_1[15:8] - data_receive)
+ ((kernel_2[15:8] - RD_DATA_OUT_2)<<1)
+ (kernel_3[15:8] - RD_DATA_OUT_1);
dy <= (RD_DATA_OUT_1 - data_receive)
+ ((kernel_3[ 7:0] - kernel_1[7:0])<<1)
+ (kernel_3[15:8] - kernel_1[15:8]);
end else begin
dx <= dx;
dy <= dy;
end
end
整体图像处理思路:
1.接收图像数据,准备两个FIFO,存储两行图像数据。
2.利用输入的第三行数据与前两行数据做sobel计算,获得sobel像素。
3.把sobel像素存进RAM里,等待VGA时序合适的时候调取。
具体操作:首先第一个FIFO存下第一行数据,第二个FIFO存下第二行数据:
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
WR_EN_IN_1 <= 1'b0;
end else if(row_cnt == 'd0
&& rx_done) begin
WR_EN_IN_1 <= 1'b1;
end else begin
WR_EN_IN_1 <= RP2_WR_EN_IN_1;
end
end
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
RP1_WR_EN_IN_1 <= 1'b0;
end else if(row_cnt >= 'd2
&& rx_done
&& row_cnt <= image_y -2'd2) begin
RP1_WR_EN_IN_1 <= 1'b1;
end else begin
RP1_WR_EN_IN_1 <= 1'b0;
end
end
always @(posedge Sys_clk) begin
RP2_WR_EN_IN_1 <= RP1_WR_EN_IN_1;
end
//WR_EN_IN_2
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
WR_EN_IN_2 <= 1'b0;
end else if(row_cnt >= 'd1
&& rx_done
&& row_cnt <= image_y -2'd2) begin
WR_EN_IN_2 <= 1'b1;
end else begin
WR_EN_IN_2 <= 1'b0;
end
end
其中,FIFO1存入的是第0行输入数据,以及row_cnt >1以后FIFO2读出的数据,所以row_cnt >1以后FIFO1的写信号将有所延迟。(也可以用FIFO1的读信号延迟一拍得到)
FIFO2存入的是第一行以后的输入数据,并且不断读出给FIFO1写入,这样就持续存有两行数据了。
数据输入:
//WR_DATA_IN_1
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
WR_DATA_IN_1 <= 'd0;
end else if(row_cnt == 'd0) begin
WR_DATA_IN_1 <= data_receive;
end else begin
WR_DATA_IN_1 <= RD_DATA_OUT_2;
end
end
//WR_DATA_IN_2
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
WR_DATA_IN_2 <= 'd0;
end else if (row_cnt >= 'd1
&& row_cnt <= image_y -2'd2) begin
WR_DATA_IN_2 <= data_receive;
end
end
读使能:
//RD
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
RD_EN_IN_1 <= 1'b0;
end else if(row_cnt >= 'd2
&& rx_done
&& row_cnt <= image_y -1'b1) begin
RD_EN_IN_1 <= 1'b1;
end else begin
RD_EN_IN_1 <= 1'b0;
end
end
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
RD_EN_IN_2 <= 1'b0;
end else if(row_cnt >= 'd2
&& rx_done
&& row_cnt <= image_y -1'b1) begin
RD_EN_IN_2 <= 1'b1;
end else begin
RD_EN_IN_2 <= 1'b0;
end
end
/--------------------对比-------------------------------/
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
RP1_WR_EN_IN_1 <= 1'b0;
end else if(row_cnt >= 'd2
&& rx_done
&& row_cnt <= image_y -2'd2) begin
RP1_WR_EN_IN_1 <= 1'b1;
end else begin
RP1_WR_EN_IN_1 <= 1'b0;
end
end
always @(posedge Sys_clk) begin
RP2_WR_EN_IN_1 <= RP1_WR_EN_IN_1;
end
对比可知:
row_cnt >1以后FIFO1的写信号将有所延迟。(也可以用FIFO1的读信号延迟一拍得到)
SOBEL计算:
1.实现SOBEL算子
always@(posedge Sys_clk) begin
if(flag_kernel) begin
{ data_receive_d ,data_receive_dd } = { data_receive ,data_receive_d };
{ RD_DATA_OUT_1_d,RD_DATA_OUT_1_dd } = { RD_DATA_OUT_1,RD_DATA_OUT_1_d };
{ RD_DATA_OUT_2_d,RD_DATA_OUT_2_dd } = { RD_DATA_OUT_2,RD_DATA_OUT_2_d };
end
end
//dx dy
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
dx <= 'd0;
dy <= 'd0;
end else if(flag_Conv == 1'b1) begin
dx <= (data_receive_dd - data_receive )
+ ((RD_DATA_OUT_2_dd - RD_DATA_OUT_2)<<1)
+ (RD_DATA_OUT_1_d - RD_DATA_OUT_1);
dy <= (RD_DATA_OUT_1 - data_receive )
+ ((RD_DATA_OUT_1_d - data_receive_d)<<1)
+ (RD_DATA_OUT_1_dd - data_receive_dd);
end else begin
dx <= dx;
dy <= dy;
end
end
2.利用补码求绝对值:
最高位为1:负数,则按位取反得到绝对值。
最高位为0:正数,直接使用。
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
abs_dx <= 'd0;
end else if(flag_abs == 1'b1 && dx[7] == 1'b1) begin
abs_dx <= ~(dx) + 1'b1;
end else if(flag_abs == 1'b1 && dx[7] == 1'b0) begin
abs_dx <= dx;
end
end
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
abs_dy <= 'd0;
end else if(flag_abs == 1'b1 && dy[7] == 1'b1) begin
abs_dy <= ~(dy) + 1'b1;
end else if(flag_abs == 1'b1 && dy[7] == 1'b0) begin
abs_dy <= dy;
end
end
3.绝对值求和。
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
dxy_sum <= 'd0;
end else if(flag_dxy == 1'b1) begin
dxy_sum <= abs_dy + abs_dx;
end
end
4.设置阈值并判断
always@(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
tx_data <= 'd0;
end else if(flag_gate == 1'b1 && dxy_sum > gate) begin
tx_data <= black;
end else if(flag_gate == 1'b1 && dxy_sum <= gate) begin
tx_data <= white;
end else begin
tx_data <= tx_data;
end
end
[1]威三学院FPGA教程
[2]小梅哥AC620V2教程