基于EBAZ4205矿板的图像处理:12二值化图像的膨胀与腐蚀
先看效果
注意:我的项目中的膨胀和腐蚀是对二值化图像中的像素值为255的像素进行处理,而我的图像中255为白色,0为黑色,所以是对颜色为白色的像素点进行的膨胀和腐蚀,别看错了。
如上图所见,膨胀效果能够消除图像中的毛刺,将区域连通,扩大了数据。
腐蚀效果能够抹除部分像素数据,放大图像中的毛刺,让区域变得不连通。
算法讲解
这里不对膨胀和腐蚀算法本身进行介绍,有的是讲的好的。
本项目中,是对一个滑动窗口内的所有像素进行统计,统计像素值为255的点,计为data_sum。
而膨胀算法就是当data_sum大于等于3(或者更小)时,就让该滑动窗口的中心点的像素值为255.
而腐蚀算法就是当data_sum大于等于6(或者更大)时,才让该滑动窗口的中心点的像素值为255
算法的FPGA部署
这里就是先进行图像的局部阈值二值化,将图像变为二值化图像,然后对二值化图像进行膨胀腐蚀操作。膨胀腐蚀系数这里,我直接开辟了一个端口出来,让它和局部阈值二值化系数一样都可以通过ps端进行调节。
然后在ps端,我是通过使用UART接受中断来接受用户通过串口发送的数据,用户可以通过串口动态调整局部阈值二值化系数和膨胀腐蚀系数。
block design
AXILiteCtrlThreshold模块
这个模块就是一个能让PS端能通过AXILIte总线读写PL端reg的模块,从而能动态调整局部二值化阈值和膨胀腐蚀系数阈值。
我的上一篇和上上篇都讲过怎么创建了。这里不说了。
项目代码
图像处理总模块
//作者:抢公主的大魔王
//日期:24.5.15
module video_processor(
(* X_INTERFACE_IGNORE = "true" *) input frame_clk, //cmos 像素时钟
(* X_INTERFACE_IGNORE = "true" *) input frame_rst_n,
//预处理图像
(* X_INTERFACE_IGNORE = "true" *) input pre_vsync, //预处理图像场同步信号
(* X_INTERFACE_IGNORE = "true" *) input [23:0] pre_data, //预处理图像数据
(* X_INTERFACE_IGNORE = "true" *) input pre_href, //预处理图像数据有效信号
(* X_INTERFACE_IGNORE = "true" *) input pre_frame_ce, //预处理图像时钟使能信号
//阈值控制
(* X_INTERFACE_IGNORE = "true" *) input [7:0 ] loc_bin_thresh_coefficient, //来自PS端的局部二值化阈值系数
(* X_INTERFACE_IGNORE = "true" *) input [7:0 ] expa_corr_thresh,
//处理后图像
(* X_INTERFACE_IGNORE = "true" *) output pos_vsync, //处理后图像场同步信号
(* X_INTERFACE_IGNORE = "true" *) output [23:0] pos_data, //处理后图像数据
(* X_INTERFACE_IGNORE = "true" *) output pos_href, //处理后图像数据有效信号
(* X_INTERFACE_IGNORE = "true" *) output pos_frame_ce //处理后图像时钟使能信号
);
//wire define
wire [7:0] gray_data ;
wire gray_vsync;
wire gray_frame_ce;
wire gray_href;
//*****************************************************
//** main code
//*****************************************************
//rgb转ycbcr模块
rgb2gray u_rgb2gray(
.cmos_frame_clk (frame_clk ),
.cmos_rstn (frame_rst_n ),//同步复位
.cmos_frame_vsync (pre_vsync ),
.cmos_frame_data (pre_data ),
.cmos_frame_href (pre_href ),
.cmos_frame_ce (pre_frame_ce ),
.dataout_frame_vsync(gray_vsync ),
.dataout_frame_data (gray_data ),
.dataout_frame_href (gray_href ),
.dataout_frame_ce (gray_frame_ce )
);
//wire define
wire matrix_frame_vsync;
wire matrix_frame_href;
wire matrix_frame_ce;
wire [7:0] matrix_p11; //3X3 矩阵数据
wire [7:0] matrix_p12;
wire [7:0] matrix_p13;
wire [7:0] matrix_p21;
wire [7:0] matrix_p22;
wire [7:0] matrix_p23;
wire [7:0] matrix_p31;
wire [7:0] matrix_p32;
wire [7:0] matrix_p33;
// wire [7:0] mid_value ;
// wire [7:0] pos_img_Y;
//*****************************************************
//** main code
//*****************************************************
// assign pos_img_Y = pos_gray_href ? mid_value : 8'd0;
// assign pos_pixel_data = {pos_img_Y,pos_img_Y,pos_img_Y};
VIP_matrix_generate_3x3_8bit u0_VIP_matrix_generate_3x3_8bit(
.clk (frame_clk ),
.rst_n (frame_rst_n ),
.per_frame_vsync (gray_vsync ),
.per_frame_href (gray_href ),
.per_frame_ce (gray_frame_ce ),
.per_img_Y (gray_data ),
//输出3x3矩阵
.matrix_frame_vsync (matrix_frame_vsync ),
.matrix_frame_href (matrix_frame_href ),
.matrix_frame_ce (matrix_frame_ce ),
.matrix_p11 (matrix_p11),
.matrix_p12 (matrix_p12),
.matrix_p13 (matrix_p13),
.matrix_p21 (matrix_p21),
.matrix_p22 (matrix_p22),
.matrix_p23 (matrix_p23),
.matrix_p31 (matrix_p31),
.matrix_p32 (matrix_p32),
.matrix_p33 (matrix_p33)
);
region_binary u_region_binary(
.clk (frame_clk ),
.rst_n (frame_rst_n ),
.matrix_img_vsync (matrix_frame_vsync ),
.matrix_img_href (matrix_frame_href ),
.matrix_frame_ce (matrix_frame_ce ),
.loc_bin_thresh_coefficient (loc_bin_thresh_coefficient ),
.matrix_p11 (matrix_p11 ),
.matrix_p12 (matrix_p12 ),
.matrix_p13 (matrix_p13 ),
.matrix_p21 (matrix_p21 ),
.matrix_p22 (matrix_p22 ),
.matrix_p23 (matrix_p23 ),
.matrix_p31 (matrix_p31 ),
.matrix_p32 (matrix_p32 ),
.matrix_p33 (matrix_p33 ),
.dataout_vsync (bin_vsync ), // processed Image data vsync valid signal
.dataout_href (bin_href ), // processed Image data href vaild signal
.dataout_gray (bin_data ), // processed Image brightness output
.dataout_frame_ce (bin_frame_ce ));
wire bin_vsync ;
wire bin_href ;
wire [23:0] bin_data ;
wire bin_frame_ce;
wire bin_matrix_frame_vsync;
wire bin_matrix_frame_href;
wire bin_matrix_frame_ce;
wire [7:0] bin_matrix_p11; //3X3 矩阵数据
wire [7:0] bin_matrix_p12;
wire [7:0] bin_matrix_p13;
wire [7:0] bin_matrix_p21;
wire [7:0] bin_matrix_p22;
wire [7:0] bin_matrix_p23;
wire [7:0] bin_matrix_p31;
wire [7:0] bin_matrix_p32;
wire [7:0] bin_matrix_p33;
VIP_matrix_generate_3x3_8bit u1_VIP_matrix_generate_3x3_8bit(
.clk (frame_clk ),
.rst_n (frame_rst_n ),
.per_frame_vsync (bin_vsync ),
.per_frame_href (bin_href ),
.per_frame_ce (bin_frame_ce ),
.per_img_Y (bin_data[23:16]),
//输出3x3矩阵
.matrix_frame_vsync (bin_matrix_frame_vsync ),
.matrix_frame_href (bin_matrix_frame_href ),
.matrix_frame_ce (bin_matrix_frame_ce ),
.matrix_p11 (bin_matrix_p11),
.matrix_p12 (bin_matrix_p12),
.matrix_p13 (bin_matrix_p13),
.matrix_p21 (bin_matrix_p21),
.matrix_p22 (bin_matrix_p22),
.matrix_p23 (bin_matrix_p23),
.matrix_p31 (bin_matrix_p31),
.matrix_p32 (bin_matrix_p32),
.matrix_p33 (bin_matrix_p33)
);
bin_expa_corr u_bin_expa_corr(
.clk (frame_clk ),
.rst_n (frame_rst_n ),
.matrix_img_vsync (bin_matrix_frame_vsync),
.matrix_img_href (bin_matrix_frame_href ),
.matrix_frame_ce (bin_matrix_frame_ce ),
.expa_corr_thresh (expa_corr_thresh ),
.matrix_p11 (bin_matrix_p11 ),
.matrix_p12 (bin_matrix_p12 ),
.matrix_p13 (bin_matrix_p13 ),
.matrix_p21 (bin_matrix_p21 ),
.matrix_p22 (bin_matrix_p22 ),
.matrix_p23 (bin_matrix_p23 ),
.matrix_p31 (bin_matrix_p31 ),
.matrix_p32 (bin_matrix_p32 ),
.matrix_p33 (bin_matrix_p33 ),
.dataout_vsync (pos_vsync ), // processed Image data vsync valid signal
.dataout_href (pos_href ), // processed Image data href vaild signal
.dataout_gray (pos_data ), // processed Image brightness output
.dataout_frame_ce (pos_frame_ce ));
endmodule
rgb565转gray模块
//作者:抢公主的大魔王
//日期:24.5.15
`timescale 1ns / 1ps
module rgb2gray(
(* X_INTERFACE_IGNORE = "true" *) input cmos_frame_vsync,
(* X_INTERFACE_IGNORE = "true" *) input [23:0] cmos_frame_data,
(* X_INTERFACE_IGNORE = "true" *) input cmos_frame_href,
(* X_INTERFACE_IGNORE = "true" *) input cmos_frame_clk,
(* X_INTERFACE_IGNORE = "true" *) input cmos_rstn,//同步复位
(* X_INTERFACE_IGNORE = "true" *) input cmos_frame_ce,
(* X_INTERFACE_IGNORE = "true" *) output dataout_frame_vsync,
(* X_INTERFACE_IGNORE = "true" *) output [7:0] dataout_frame_data,
// (* X_INTERFACE_IGNORE = "true" *) output [23:0] dataout_frame_data,
(* X_INTERFACE_IGNORE = "true" *) output dataout_frame_href,
(* X_INTERFACE_IGNORE = "true" *) output dataout_frame_ce
);
// Y = 0.299R +0.587G + 0.114B
// Y = (77 *R + 150*G + 29 *B)>>8
reg [15:0] r_gray1;
reg [15:0] g_gray1;
reg [15:0] b_gray1;
reg [15:0] y1;
reg [7:0] y2;
reg [2:0] dataout_frame_vsync_r;
reg [2:0] dataout_frame_href_r;
reg [2:0] dataout_frame_ce_r;
always@(posedge cmos_frame_clk)begin
if(!cmos_rstn)begin
r_gray1 <= 8'h00;
g_gray1 <= 8'h00;
b_gray1 <= 8'h00;
end
else begin
r_gray1 <= cmos_frame_data[23:16] * 8'd77 ;
g_gray1 <= cmos_frame_data[15:8] * 8'd150;
b_gray1 <= cmos_frame_data[7:0] * 8'd29 ;
end
end
always@(posedge cmos_frame_clk)begin
if(!cmos_rstn)begin
y1 <= 16'h0000;
end
else begin
y1 <= r_gray1 + g_gray1 + b_gray1;
end
end
always@(posedge cmos_frame_clk)begin
if(!cmos_rstn)begin
y2 <= 8'h0000;
end
else begin
y2 <= y1[15:8];
end
end
always@(posedge cmos_frame_clk)begin
if(!cmos_rstn)begin
dataout_frame_ce_r <= 3'b000;
dataout_frame_vsync_r <= 3'b000;
dataout_frame_href_r <= 3'b000;
end
else begin
dataout_frame_ce_r <= {dataout_frame_ce_r[1:0] ,cmos_frame_ce};
dataout_frame_vsync_r <= {dataout_frame_vsync_r[1:0] ,cmos_frame_vsync};
dataout_frame_href_r <= {dataout_frame_href_r[1:0] ,cmos_frame_href};
end
end
// assign dataout_frame_data = {y2,y2,y2};
assign dataout_frame_data = y2;
assign dataout_frame_ce = dataout_frame_ce_r[2];
assign dataout_frame_vsync = dataout_frame_vsync_r[2];
assign dataout_frame_href = dataout_frame_href_r[2];
endmodule
滑动窗口数据输出模块和局部阈值二值化模块
滑动窗口数据输出模块和局部阈值二值化模块,上一篇博客已给出,没有变化,这里就不再粘贴了
二值化图像膨胀腐蚀模块
`timescale 1ns / 1ps
//作者:抢公主的大魔王
//日期:24.5.15
module bin_expa_corr(
(* X_INTERFACE_IGNORE = "true" *)input wire clk ,
(* X_INTERFACE_IGNORE = "true" *)input wire rst_n ,
(* X_INTERFACE_IGNORE = "true" *)input wire [3:0] expa_corr_thresh ,
(* X_INTERFACE_IGNORE = "true" *)input wire matrix_img_vsync ,
(* X_INTERFACE_IGNORE = "true" *)input wire matrix_img_href ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p11 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p12 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p13 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p21 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p22 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p23 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p31 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p32 ,
(* X_INTERFACE_IGNORE = "true" *)input wire [7:0] matrix_p33 ,
(* X_INTERFACE_IGNORE = "true" *)input wire matrix_frame_ce ,
(* X_INTERFACE_IGNORE = "true" *)output reg dataout_href,
(* X_INTERFACE_IGNORE = "true" *)output reg [23:0] dataout_gray,
(* X_INTERFACE_IGNORE = "true" *)output reg dataout_vsync,
(* X_INTERFACE_IGNORE = "true" *)output reg dataout_frame_ce
);
//----------------------------------------------------------------------
// calc sum of [p11,p12,p13;p21,p22,p23;p31,p32,p33]
reg [1:0] data_sum1;//0~3
reg [1:0] data_sum2;
reg [1:0] data_sum3;
reg [3:0] data_sum;//0~9
always @(posedge clk)
begin
data_sum1 <= matrix_p11[0] + matrix_p12[0] + matrix_p13[0] ;
data_sum2 <= matrix_p21[0] + matrix_p22[0] + matrix_p23[0] ;
data_sum3 <= matrix_p31[0] + matrix_p32[0] + matrix_p33[0] ;
data_sum <= data_sum1 + data_sum2 + data_sum3;
end
//----------------------------------------------------------------------
// lag 2 clocks signal sync
reg [1:0] matrix_img_vsync_r1;
reg [1:0] matrix_img_href_r1;
reg [1:0] matrix_edge_flag_r1;
reg [1:0] matrix_frame_ce_r1;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
matrix_img_vsync_r1 <= 2'b0;
matrix_img_href_r1 <= 2'b0;
matrix_frame_ce_r1 <= 2'b0;
end
else
begin
matrix_img_vsync_r1 <= {matrix_img_vsync_r1[0],matrix_img_vsync};
matrix_img_href_r1 <= {matrix_img_href_r1[0],matrix_img_href};
matrix_frame_ce_r1 <= {matrix_frame_ce_r1[0],matrix_frame_ce};
end
end
//----------------------------------------------------------------------
// result output
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
dataout_gray <= 24'd0;
else if(data_sum >= expa_corr_thresh)
dataout_gray <= {8'd255,8'd255,8'd255};
else
dataout_gray <= 24'd0;
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
dataout_vsync <= 1'b0;
dataout_href <= 1'b0;
dataout_frame_ce<= 1'b0;
end
else
begin
dataout_vsync <= matrix_img_vsync_r1[1];
dataout_href <= matrix_img_href_r1[1];
dataout_frame_ce<=matrix_frame_ce_r1[1];
end
end
endmodule