【紫光同创PGL50H】小眼睛科技盘古50K开发板试用体验之图像Sobel边缘检测 - FPGA开发者技术社区 - 电子技术william hill官网 - 广受欢迎的专业电子william hill官网 - 威廉希尔官方网站
分享 收藏 返回

【紫光同创PGL50H】小眼睛科技盘古50K开发板试用体验之图像Sobel边缘检测

在紫光PGL50H上简单实现图像Sobel边缘检测。

01 软硬件平台

软件平台:PDS_2022.1
硬件平台:小眼睛科技盘古50K开发板

02 Sobel边缘检测算法

Sobel是图像边缘检测中的一种算法,Sobel算子分为横向和纵向3×3的卷积核,两个卷积核分别与图像作平面卷积,提取水平边缘和垂直边缘,Gx和Gy分别代表横向和纵向边缘检测的图像数据,其公式如下:

image.png

最后每一个像素点的Gx和Gy使用以下公式结合,便得到边缘信息的图像。

image.png

由于Sobel算子是平面图像的滑动卷积,使用FPGA实现是相对容易的,且具有高效率。FPGA中实现复杂的数学运算是不好处理的,G采用不开平方的近似公式实现:
image.png

03 程序设计

本设计不涉及更复杂的图像处理,所以并没有将图像数据存入DDR后再输出,一般涉及复杂或者多任务的图像处理,将图像数据存入DDR是必要的。本设计基于小眼睛科技提供的 HDMI 回环实验,对输入的RGB像素值首先转灰度,转灰度后进行二值化。然后将数据存入FIFO1,在一帧中的第二行开始,将FIFO1的数据读出,并且存入FIFO2,在一帧中的第三行开始,将FIFO2的数据读出,流水实现,当场同步时,复位FIFO1和FIFO2,避免第1行和尾行像素无效的问题。之后,将输入的像素数据和FIFO1、FIFO2输出的数据同时流水寄存三拍,形成3×3的处理像素矩阵,按照Sobel公式实现即可。最后将vs、hs、de流水延迟,与最后的输出数据对齐就可以了。

module hdmi_sobel_test(
    input wire           sys_clk,     // input system clock 50MHz

    output               rstn_out,
    output               iic_scl,
    inout                iic_sda, 
    output               iic_tx_scl,
    inout                iic_tx_sda, 
    input                pixclk_in,                            
    input                vs_in, 
    input                hs_in, 
    input                de_in,
    input     [7:0]      r_in, 
    input     [7:0]      g_in, 
    input     [7:0]      b_in,  

    output               pixclk_out,                            
    output reg           vs_out, 
    output reg           hs_out, 
    output reg           de_out,
    output reg    [7:0]  r_out, 
    output reg    [7:0]  g_out, 
    output reg    [7:0]  b_out,
    output               led_int
);

reg [15:0]  rstn_1ms       ;
wire        pix_clk        ;
wire        cfg_clk        ;
wire        locked         ;

pll u_pll(
  .clkin1       (sys_clk   ),   // input//50MHz
  .pll_lock     (locked    ),   // output
  .clkout0      (cfg_clk   )    // output//10MHz
);

ms72xx_ctl ms72xx_ctl(
    .clk         (  cfg_clk    ), //input       clk,
    .rst_n       (  rstn_out   ), //input       rstn,
   
    .init_over   (  init_over  ), //output      init_over,
    .iic_tx_scl  (  iic_tx_scl ), //output      iic_scl,
    .iic_tx_sda  (  iic_tx_sda ), //inout       iic_sda
    .iic_scl     (  iic_scl    ), //output      iic_scl,
    .iic_sda     (  iic_sda    )  //inout       iic_sda
);

assign led_int  =  init_over;
assign rstn_out = (rstn_1ms == 16'h2710);
assign pixclk_out = pixclk_in; 

always @(posedge cfg_clk) begin
	if(!locked)                    rstn_1ms <= 16'd0;
	else if(rstn_1ms == 16'h2710)  rstn_1ms <= rstn_1ms;
	else                           rstn_1ms <= rstn_1ms + 1'b1;
end
 
 
reg  [7:0]	gray		;
reg  [7:0]	value		;
reg  [7:0]  vs_temp		;
reg  [7:0]  hs_temp		;
reg  [7:0]  de_temp		;

wire 		de_pos		;		
wire 		de_neg		;

reg  [10:0]	de_pos_cnt	;
reg	 [7:0]	data0_reg0	;
reg	 [7:0]	data0_reg1	;
reg	 [7:0]  data0_reg2	;
reg	 [7:0]  data1_reg0	;
reg	 [7:0]  data1_reg1	;
reg	 [7:0]  data1_reg2	;
reg	 [7:0]  data2_reg0	;
reg	 [7:0]	data2_reg1	;	
reg	 [7:0]	data2_reg2	;

reg  [9:0]	x_data_p	;
reg  [9:0]	x_data_n	;
reg  [9:0]	y_data_p	;
reg  [9:0]	y_data_n	;
reg  [9:0]	Gx			;
reg  [9:0]	Gy			;
reg  [7:0]	s_data		;

reg			row1_we		;
reg			row1_re		;
reg  [7:0]	row1_wdata	;
reg			row2_we		;
reg			row2_re		;
reg  [7:0]	row2_wdata	;

wire [7:0]	row1_rdata	;
wire [7:0]	row2_rdata	;

 
always  @(posedge pixclk_in) begin
	if(!init_over)
		gray <= 8'd0;
	else 
		gray <= (r_in*306 + g_in*601 + b_in*117)>>10; 
end	
 
always  @(posedge pixclk_in) begin
	if(!init_over)
		value <= 8'h00;
	else if(gray >= 8'd160) 
		value <= 8'hff;
	else
		value <= 8'h00;
end
 
always  @(posedge pixclk_in) begin
	vs_temp <= {vs_temp[6:0], vs_in}; 
	hs_temp <= {hs_temp[6:0], hs_in};
	de_temp <= {de_temp[6:0], de_in};
end

always  @(posedge pixclk_in) begin
    if(!init_over)begin
        vs_out       <=  1'b0		;
        hs_out       <=  1'b0		;
        de_out       <=  1'b0		;
        r_out        <=  8'b0		;
        g_out        <=  8'b0		;
        b_out        <=  8'b0		;
    end
	else begin
        vs_out       <=  vs_temp[7]	;
        hs_out       <=  hs_temp[7]	;
        de_out       <=  de_temp[7]	;
        r_out        <=  s_data  	;
        g_out        <=  s_data  	;
        b_out        <=  s_data  	;
    end
end

assign de_pos = de_in & !de_temp[0];
assign de_neg = !de_in & de_temp[0];

always  @(posedge pixclk_in) begin
	if(!init_over)		de_pos_cnt <= 11'd0;
	else if(vs_in)		de_pos_cnt <= 11'd0;
	else if(de_pos)		de_pos_cnt <= de_pos_cnt + 1'b1;
end

always  @(posedge pixclk_in) begin
		data0_reg0 <= value		;
		data0_reg1 <= data0_reg0;
		data0_reg2 <= data0_reg1;
		data1_reg0 <= row1_rdata;
		data1_reg1 <= data1_reg0;
		data1_reg2 <= data1_reg1;
		data2_reg0 <= row2_rdata;
		data2_reg1 <= data2_reg0;
		data2_reg2 <= data2_reg1;	
end	

always  @(posedge pixclk_in) begin
	if(!init_over) begin
		x_data_p <= 10'd0;
		x_data_n <= 10'd0;
		y_data_p <= 10'd0;
		y_data_n <= 10'd0;
	end
	else if(de_temp[4]) begin
		x_data_p <= data0_reg2 + (data1_reg2 << 1) + data2_reg2;
		x_data_n <= data0_reg0 + (data1_reg0 << 1) + data2_reg0;
		y_data_p <= data2_reg0 + (data2_reg1 << 1) + data2_reg2;
		y_data_n <= data0_reg0 + (data0_reg1 << 1) + data0_reg2;
	end
	else begin
		x_data_p <= 10'd0;
		x_data_n <= 10'd0;
		y_data_p <= 10'd0;
		y_data_n <= 10'd0;
	end
end

always  @(posedge pixclk_in) begin
	if(!init_over)begin		
		Gx <= 10'd0;
		Gy <= 10'd0;
	end
	else begin
		Gx <= (x_data_p >= x_data_n) ? (x_data_p - x_data_n) : (x_data_n - x_data_p);
		Gy <= (y_data_p >= y_data_n) ? (y_data_p - y_data_n) : (y_data_n - y_data_p);
	end
end

always  @(posedge pixclk_in)
	if(!init_over)              s_data <= 8'h00;
	else if((Gx+Gy) > 10'h1f0)  s_data <= 8'hff;
	else                        s_data <= 8'h00;	

always  @(posedge pixclk_in) begin
	if(!init_over) begin
		row1_we	   <= 1'b0; 
		row1_wdata <= 8'd0;
	end
	else if(de_temp[1]) begin
		row1_we	   <= 1'b1; 
		row1_wdata <= value;
	end
	else begin
		row1_we	   <= 1'b0; 
		row1_wdata <= 8'd0;
	end	
end

always  @(posedge pixclk_in) begin
	if(!init_over) begin
		row2_we	   <= 1'b0; 
		row2_wdata <= 8'd0;
	end
	else if(de_temp[1] & de_pos_cnt > 1) begin
		row2_we	   <= 1'b1; 
		row2_wdata <= row1_rdata;
	end
	else begin
		row2_we	   <= 1'b0; 
		row2_wdata <= 8'd0;
	end	
end

always  @(posedge pixclk_in)
	if(!init_over)           row1_re <= 1'b0;
	else if(de_pos_cnt < 2)  row1_re <= 1'b0;
	else if(de_temp[0])      row1_re <= 1'b1;
	else                     row1_re <= 1'b0;
	
always  @(posedge pixclk_in)
	if(!init_over)           row2_re <= 1'b0;
	else if(de_pos_cnt < 3)  row2_re <= 1'b0;
	else if(de_temp[0])      row2_re <= 1'b1;
	else                     row2_re <= 1'b0;	

fifo_8_2048 row1_fifo(
.clk			(pixclk_in		),                      
.rst			(vs_in			), //帧同步复位fifo                     
.wr_en			(row1_we		),                  
.wr_data		(row1_wdata		),              
.wr_full		(				),              
.almost_full            (		 		),      
.rd_en			(row1_re		),                  
.rd_data		(row1_rdata		),              
.rd_empty		(				),            
.almost_empty           (				)     
);

fifo_8_2048 row2_fifo(
.clk			(pixclk_in		),                      
.rst			(vs_in			),                      
.wr_en			(row2_we		),                  
.wr_data		(row2_wdata		),              
.wr_full		(				),              
.almost_full            (				),      
.rd_en			(row2_re		),                  
.rd_data		(row2_rdata		),              
.rd_empty		(				),            
.almost_empty           (				)     
);

endmodule

04 边缘检测效果

Sobel边缘检测效果如下视频所示。

sobel_video

更多回帖

×
发帖