FPGA人脸识别检测(先获取人脸图像以及灰度二值化)

读取图片的方式按照博客咸鱼里的方式来做,如下。

1、先用matlab将图片转换成txt数据,代码如下 

%==========================================================================
%                 彩色图片转为txt文本,格式为24bit的hex数据
%==========================================================================
clc;
clear all;
%--------------------------------------------------------------------------
pre_img = imread('pre_img.jpg');   %读取图片文件
[ROW,COL,N] = size(pre_img);       %获得图片尺寸[高度,长度,维度]
RGB_ij = uint64(zeros(ROW,COL));   %定义32位宽的RGB变量
%--------------------------------------------------------------------------
fid = fopen('pre_img.txt','w');    %打开文件
for i = 1:ROW
    for j = 1:COL
        R = double(pre_img(i,j,1));
        G = double(pre_img(i,j,2));
        B = double(pre_img(i,j,3));
        %-------------------------------------
        RGB          = R*(2^16) + G*(2^8) + B;
        RGB_ij(i,j)  = RGB;
        RGB_hex      = dec2hex(RGB);
        %-------------------------------------
        fprintf(fid,'%s\n',RGB_hex); %将字符打印到txt文件
    end
end
fclose(fid);
%--------------------------------------------------------------------------
imshow(pre_img),title('处理前');      %查看处理前的图片

2、FPGA读取txt数据 

`timescale 1 ns/1 ns

module img_gen
//========================< 参数 >==========================================
//					  640x480 @60Hz 25Mhz
#(
parameter H_ADDR			= 640					,	//行有效数据	  
parameter H_SYNC			= 96					,	//行同步  
parameter H_BACK			= 48					,	//行显示后沿
parameter H_TOTAL			= H_ADDR+H_SYNC+H_BACK	,	//行扫描周期
parameter V_ADDR			= 480					,	//场有效数据	  
parameter V_SYNC			= 2						,	//场同步	
parameter V_BACK			= 33					,	//场显示后沿
parameter V_TOTAL			= V_ADDR+V_SYNC+V_BACK		//场扫描周期
)
//========================< 端口 >==========================================
(
//system --------------------------------------------
input	wire				clk						,	//时钟
input	wire				rst_n					,	//复位,低电平有效
//img output ----------------------------------------
output	wire				img_hsync				,	//img行信号
output	wire				img_vsync				,	//img场信号
output	reg  	[23:0]		img_data				,	//img数据信号
output	reg					img_de						//img数据有效指示信号
);
//========================< 信号 >==========================================
reg	  	[15:0]				cnt_h				 	;
wire						add_cnt_h				;
wire						end_cnt_h				;
reg	  	[15:0]				cnt_v					;
wire						add_cnt_v				;
wire						end_cnt_v				;
//---------------------------------------------------
reg  	[23:0] 				ram [H_ADDR*V_ADDR-1:0]	;
reg 	[31:0] 				i						;
//==========================================================================
//==	行、场计数
//==========================================================================
always @(posedge clk or negedge rst_n) begin
	if(!rst_n)
		cnt_h <= 0;
	else if(add_cnt_h) begin
		if(end_cnt_h)
			cnt_h <= 0;
		else
			cnt_h <= cnt_h + 1;
	end
end

assign add_cnt_h = 1;
assign end_cnt_h = add_cnt_h && cnt_h==H_TOTAL-1;
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin 
	if(!rst_n)
		cnt_v <= 0;
	else if(add_cnt_v) begin
		if(end_cnt_v)
			cnt_v <= 0;
		else
			cnt_v <= cnt_v + 1;
	end
end

assign add_cnt_v = end_cnt_h;
assign end_cnt_v = add_cnt_v && cnt_v==V_TOTAL-1;
//==========================================================================
//==	输出
//==========================================================================
//行场同步
//---------------------------------------------------
assign img_hsync = (cnt_h <= H_SYNC - 1) ? 0 : 1;
assign img_vsync = (cnt_v <= V_SYNC - 1) ? 0 : 1;

//数据请求
assign img_req = (cnt_h >= H_SYNC + H_BACK - 1) && (cnt_h < H_SYNC + H_BACK + H_ADDR - 1) &&
				 (cnt_v >= V_SYNC + V_BACK	  ) && (cnt_v < V_SYNC + V_BACK + V_ADDR    );

//读取txt文件到raw数组中,格式为16进制
//---------------------------------------------------
initial begin
	$readmemh("C:/Users/xiaozhou/Desktop/people_face/matlab/pre_img.txt", ram);
end

//数据输出
//---------------------------------------------------
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)begin
		img_data <= 24'd0;
		i <= 0;
	end
	else if(img_req) begin
		img_data <= ram[i];
		i <= i + 1;
	end
	else if(i==H_ADDR*V_ADDR) begin
		img_data <= 24'd0;
		i <= 0;
	end
end

//数据使能
always @(posedge clk) begin 
	img_de <= img_req;
end


endmodule

由于顶层模块传给img_gen的H_ADDR和V_ADDR分别是480和272(而不是原来的640和480),在行计数器在96+48=144和480+96+48-1=623之间,以及场计数器33+2=35和272+33+2-1=306之间的时候,使能信号拉高。 

当行计数器为0~95时为低电平(行同步期间), 当行计数器为0~1时为低电平(场同步期间)。

3、FPGA灰度二值化 


module RGB565_YCbCr444_face
//========================< 端口 >==========================================
(
input   wire                clk                     ,
input   wire                rst_n                   ,
//input ---------------------------------------------
input   wire                RGB_de                  ,
input   wire                RGB_hsync               ,
input   wire                RGB_vsync               ,
input   wire    [15:0]      RGB_data                , //RGB像素
//output --------------------------------------------
output  wire                face_de                 ,
output  wire                face_hsync              ,
output  wire                face_vsync              ,
output  reg     [15:0]      face_data                 //灰度像素
);
//========================< 信号 >==========================================
wire    [ 7:0]              R0, G0, B0              ;
reg     [15:0]              R1, G1, B1              ;
reg     [15:0]              R2, G2, B2              ;
reg     [15:0]              R3, G3, B3              ;
reg     [15:0]              Y1, Cb1, Cr1            ;
reg     [ 7:0]              Y2, Cb2, Cr2            ;
reg     [ 3:0]              RGB_de_r                ;
reg     [ 3:0]              RGB_hsync_r             ;
reg     [ 3:0]              RGB_vsync_r             ;
//==========================================================================
//==    RGB565转RGB888
//==========================================================================
assign R0 = {RGB_data[15:11],RGB_data[13:11]};
assign G0 = {RGB_data[10: 5],RGB_data[ 6: 5]};
assign B0 = {RGB_data[ 4: 0],RGB_data[ 2: 0]};
//==========================================================================
//==    RGB888转YCbCr
//==========================================================================
//clk 1
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        {R1,G1,B1} <= {16'd0, 16'd0, 16'd0};
        {R2,G2,B2} <= {16'd0, 16'd0, 16'd0};
        {R3,G3,B3} <= {16'd0, 16'd0, 16'd0};
    end
    else begin
        {R1,G1,B1} <= { {R0 * 16'd77},  {G0 * 16'd150}, {B0 * 16'd29 } };
        {R2,G2,B2} <= { {R0 * 16'd43},  {G0 * 16'd85},  {B0 * 16'd128} };
        {R3,G3,B3} <= { {R0 * 16'd128}, {G0 * 16'd107}, {B0 * 16'd21 } };
    end
end

//clk 2
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        Y1  <= 16'd0;
        Cb1 <= 16'd0;
        Cr1 <= 16'd0;
    end
    else begin
        Y1  <= R1 + G1 + B1;
        Cb1 <= B2 - R2 - G2 + 16'd32768; //128扩大256倍
        Cr1 <= R3 - G3 - B3 + 16'd32768; //128扩大256倍
    end
end

//clk 3,除以256即右移8位,即取高8位
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        Y2  <= 8'd0;
        Cb2 <= 8'd0;
        Cr2 <= 8'd0;
    end
    else begin
        Y2  <= Y1[15:8];  
        Cb2 <= Cb1[15:8];
        Cr2 <= Cr1[15:8];
    end
end

//clk 4,人脸肤色检测
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        face_data <= 'h0;
    end
    else if( (Cb2 > 77) && (Cb2 < 127) && (Cr2 > 133) && (Cr2 < 173) ) begin
        face_data <= 16'hffff;
    end
    else begin
        face_data <= 'h0;
    end
end
//==========================================================================
//==    信号同步
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        RGB_de_r    <= 4'b0;
        RGB_hsync_r <= 4'b0;
        RGB_vsync_r <= 4'b0;
    end
    else begin  
        RGB_de_r    <= {RGB_de_r[2:0],    RGB_de};
        RGB_hsync_r <= {RGB_hsync_r[2:0], RGB_hsync};
        RGB_vsync_r <= {RGB_vsync_r[2:0], RGB_vsync};
    end
end

assign face_de    = RGB_de_r[3];
assign face_hsync = RGB_hsync_r[3];
assign face_vsync = RGB_vsync_r[3];



endmodule

  

使能信号和行场同步信号,均打了四拍 (上两图)。

RGB转YCbCr打了三拍(上图);二值化打了一拍(下图)。加起来总共打了四拍。

4、FPGA顶层模块及仿真

`timescale 1 ns/1 ns

module top
//========================< 参数 >==========================================
#(
parameter 		 			IMG_H = 480				,	//图像长度
parameter 		 			IMG_V = 272		 			//图像高度
)
//========================< 端口 >==========================================
(
input   wire                clk                 	, 	//时钟
input   wire                rst_n               	, 	//复位,低电平有效
//---------------------------------------------------
output	wire				VGA_hsync				,	//VGA行同步
output	wire				VGA_vsync				,	//VGA场同步
output  wire    [23:0]      VGA_data				,	//数据
output	wire				VGA_de						//数据有效
);
//========================< 信号 >==========================================
wire                        img_hsync				;
wire                        img_vsync				;
wire    [23:0]              img_data				;
wire                        img_de					;
//face ----------------------------------------------
wire                        face_de                 ;
wire                        face_hsync              ;
wire                        face_vsync              ;
wire    [15:0]              face_data               ;

//==========================================================================
//==                        图像数据产生
//==========================================================================
img_gen
#(
	.H_ADDR					(IMG_H					),	//图像宽度
	.V_ADDR					(IMG_V					)	//图像高度
)
u_img_gen
(
    .clk                    (clk              		), 
    .rst_n                  (rst_n					),
    //-----------------------------------------------
    .img_hsync              (img_hsync              ),  //img输出行同步
    .img_vsync              (img_vsync              ),  //img输出场同步
    .img_data               (img_data               ),  //img输出数据
	.img_de					(img_de					)	//img输出数据有效指示
);
//==========================================================================
//==            RGB565转YCbCr444,再转人脸肤色检测
//==========================================================================
RGB565_YCbCr444_face u_RGB565_YCbCr444_face
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    //原图 ------------------------------------------
    .RGB_de                 (img_de                 ),
    .RGB_hsync              (img_hsync              ),
    .RGB_vsync              (img_vsync              ),
    .RGB_data               ({img_data[23:19],img_data[15:10],img_data[7:3]}),
    //肤色图 ----------------------------------------
    .face_de                (face_de                ),
    .face_hsync             (face_hsync             ),
    .face_vsync             (face_vsync             ),
    .face_data              (face_data              )
);

assign VGA_de 		= 		face_de;
assign VGA_hsync 	= 		face_hsync;
assign VGA_vsync 	= 		face_vsync;

assign VGA_data  	= 		{	face_data[15:11],face_data[13:11],
								face_data[10: 5],face_data[ 7: 5],
								face_data[ 4: 0],face_data[ 2: 0]
							};




endmodule
`timescale 1ns/1ns  //时间精度
`define    Clock 20 //时钟周期
//--------------------------------------------------------------------------------RGB转YCbCr------------------------------------------------------------------------------
module top_tb;
//========================< 参数 >==========================================
parameter                   IMG_H = 480         	;   //图像长度
parameter                   IMG_V = 272         	;   //图像高度
//========================< 信号 >==========================================
reg                         clk                     ; //时钟,50Mhz
reg                         rst_n                   ; //复位,低电平有效
wire                        VGA_hsync               ; //VGA行同步
wire                        VGA_vsync               ; //VGA场同步
wire    [23:0]              VGA_data                ; //数据
wire                        VGA_de                  ; //数据有效
//==========================================================================
//==    模块例化
//==========================================================================
top
#(
    .IMG_H                  (IMG_H                  ),
    .IMG_V                  (IMG_V                  )
)
u_top
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .VGA_hsync              (VGA_hsync              ),
    .VGA_vsync              (VGA_vsync              ),
    .VGA_data               (VGA_data               ),
    .VGA_de                 (VGA_de                 )
);
//==========================================================================
//==    时钟信号和复位信号
//==========================================================================
initial begin
    clk = 1;
    forever
        #(`Clock/2) clk = ~clk;
end

initial begin
    rst_n = 0; #(`Clock*20+1);
    rst_n = 1;
end
//==========================================================================
//==    图像数据转变为txt文本
//==========================================================================

//打开post_img.txt文件
//---------------------------------------------------
integer post_img_txt;

initial begin
    post_img_txt = $fopen("C:/Users/xiaozhou/Desktop/people_face/matlab/gray_img.txt");
end

//像素写入到txt中
//---------------------------------------------------
reg [20:0] pixel_cnt;

always @(posedge clk) begin
    if(!rst_n) begin
        pixel_cnt <= 0;
    end
    else if(VGA_de) begin
        pixel_cnt = pixel_cnt + 1;
        $fdisplay(post_img_txt,"%h",VGA_data);
		
        if(pixel_cnt == IMG_H*IMG_V)
            $stop;
    end
end


endmodule

5、通过modelsim将操作后的图片数据写入gray_img.txt里面后,用matlab将txt转成图片。代码如下

%==========================================================================
%                txt文本中24bit数据还原为彩色图片
%==========================================================================
clear all;
clc;
%--------------------------------------------------------------------------
ROW = 272;  %高度
COL = 480;  %宽度
N   = 3;    %维度
post_img = uint8(zeros(ROW,COL,N));
%--------------------------------------------------------------------------
fid = fopen('gray_img.txt','r');
for i = 1:ROW
    for j = 1:COL
        value = fscanf(fid,'%s',1);
        %------------------------------------------
        post_img(i,j,1) = uint8(hex2dec(value(1:2)));
        post_img(i,j,2) = uint8(hex2dec(value(3:4)));
        post_img(i,j,3) = uint8(hex2dec(value(5:6)));  
    end 
end
fclose(fid);
%--------------------------------------------------------------------------
pre_img = imread('pre_img.jpg');
subplot(121);imshow(pre_img), title('处理前');
subplot(122);imshow(post_img),title('处理后');
%--------------------------------------------------------------------------
imwrite(post_img,'gray_img.jpg');   %处理后的图片输出为jpg格式

以下是效果图: 

由于图片有空洞、噪声等缺陷,所以后面要进行中值滤波、闭运算(先膨胀后腐蚀)等算法处理,然后再对人脸进行框选,最后显示出来。

中值滤波图片 

 

闭运算(先膨胀后腐蚀)图片 

 

框选后,最终的成像是下面这样的。

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值