项目简述
我们上一篇文章讲解了MATLABl利用肤色检测模型进行人脸检测,也给出了完整的MATLAB代码。同学们学习本篇博客的时候一定要先学习上篇文章,因为上篇文章介绍了整个算法的流程,比看FPGA的实现要简单的多。
本篇博客,我们将利用FPGA实现一副图片中的人脸检测:PC机通过千兆网发送一幅图片经过肤色检测、腐蚀、定位之后将定位信息传递给USB3.0驱动端,再将原始图像转存到DDR3中,然后经过USB3.0将定位后的原始图像发送到上位机显示。
本次实验所用到的软硬件环境如下:
1、VIVADO2019.1软件环境
2、Modelsim10.7c仿真环境
3.米联客MA7035FA(100T)开发板
4、米联客USB3.0上位机软件
5、V3学院千兆网上位机
整个项目的流程图如上图,我们利用上面的程序框图进行书写便可以完成图像定位。
肤色检测
肤色检测的原理我们上一篇博客已经进行了介绍,首先将RGB分量信息转换成YYCrCb信息,其中Y是亮度信息、Cr表示红色信息、Cb表示绿色信息。然后利用红色分量、绿色分量信息进行肤色定位。
肤色检测代码
这里原理相信大家经过上篇博客的学习已经学会,这里我们直接给出相应的代码供大家学习:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website :
// Module Name : face_test.v
// Create Time : 2020-04-11 10:57:34
// Editor : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module face_test(
//System Interfaces
input sclk ,
input rst_n ,
//Communication Interfaces
input [23:0] ycbcr_data ,
input ycbcr_flag ,
output reg [ 7:0] face_data ,
output reg face_flag
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter CB_LOWER = 77;
parameter CB_UPPER = 127;
parameter CR_LOWER = 133;
parameter CR_UPPER = 173;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
face_data <= 8'd0;
else if(ycbcr_data[15:8] > CB_LOWER && ycbcr_data[15:8] < CB_UPPER && ycbcr_data[7:0] > CR_LOWER && ycbcr_data[7:0] < CR_UPPER)
face_data <= 8'd255;
else
face_data <= 8'd0;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
face_flag <= 1'b0;
else
face_flag <= ycbcr_flag;
endmodule
肤色检测结果
我们会在最后给出最终工程的代码,这里为了简洁性不再给出部分代码。整体的实验结果图如下:
腐蚀图像
从上面的肤色检测图中,我们可以看出肤色检测之后有许多噪点,那么我们便使用腐蚀操作将上面的噪点腐蚀掉。其实最好的操作是先腐蚀再膨胀,这样可以将图像定位的更准确,但是我们因为简洁行的原因没有使用膨胀操作。其次这里我们使用的矩阵式1313的矩阵,并没有使用33的矩阵,因为矩阵太小没办法腐蚀掉全部的噪点。
腐蚀图像代码
这里我们直接给出相应的代码:
13*13矩阵模块代码,mat_13x13模块:
`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author : zhangningning
// Email : [email protected]
// Website :
// Module Name : mat_13x13.v
// Create Time : 2020-04-11 22:13:48
// Editor : sublime text3, tab size (2)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date By Version Change Description
// -----------------------------------------------------------------------
// XXXX zhangningning 1.0 Original
//
// *********************************************************************************
module mat_13x13(
//System Interfaces
input sclk ,
input rst_n ,
//Communication Interfaces
input [ 7:0] rx_data ,
input pi_flag ,
output wire [ 7:0] mat_row1 ,
output wire [ 7:0] mat_row2 ,
output wire [ 7:0] mat_row3 ,
output wire [ 7:0] mat_row4 ,
output wire [ 7:0] mat_row5 ,
output wire [ 7:0] mat_row6 ,
output wire [ 7:0] mat_row7 ,
output wire [ 7:0] mat_row8 ,
output wire [ 7:0] mat_row9 ,
output wire [ 7:0] mat_row10 ,
output wire [ 7:0] mat_row11 ,
output wire [ 7:0] mat_row12 ,
output wire [ 7:0] mat_row13 ,
output wire mat_flag
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter COL_NUM = 1024 ;
parameter ROW_NUM = 768 ;
reg [10:0] col_cnt ;
reg [10:0] row_cnt ;
wire wr_en1 ;
wire wr_en2 ;
wire wr_en3 ;
wire wr_en4 ;
wire wr_en5 ;
wire wr_en6 ;
wire wr_en7 ;
wire wr_en8 ;
wire wr_en9 ;
wire wr_en10 ;
wire wr_en11 ;
wire wr_en12 ;
wire wr_en13 ;
wire rd_en1 ;
wire rd_en2 ;
wire rd_en3 ;
wire rd_en4 ;
wire rd_en5 ;
wire rd_en6 ;
wire rd_en7 ;
wire rd_en8 ;
wire rd_en9 ;
wire rd_en10 ;
wire rd_en11 ;
wire rd_en12 ;
wire rd_en13 ;
wire [ 7:0] fifo1_rd_data ;
wire [ 7:0] fifo2_rd_data ;
wire [ 7:0] fifo3_rd_data ;
wire [ 7:0] fifo4_rd_data ;
wire [ 7:0] fifo5_rd_data ;
wire [ 7:0] fifo6_rd_data ;
wire [ 7:0] fifo7_rd_data ;
wire [ 7:0] fifo8_rd_data ;
wire [ 7:0] fifo9_rd_data ;
wire [ 7:0] fifo10_rd_data ;
wire [ 7:0] fifo11_rd_data ;
wire [ 7:0] fifo12_rd_data ;
wire [ 7:0] fifo13_rd_data ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
assign wr_en1 = pi_flag;
assign wr_en2 = row_cnt >= 11'd1 ? pi_flag : 1'b0;
assign wr_en3 = row_cnt >= 11'd2 ? pi_flag : 1'b0;
assign wr_en4 = row_cnt >= 11'd3 ? pi_flag : 1'b0;
assign wr_en5 = row_cnt >= 11'd4 ? pi_flag : 1'b0;
assign wr_en6 = row_cnt >= 11'd5 ? pi_flag : 1'b0;
assign wr_en7 = row_cnt >= 11'd6 ? pi_flag : 1'b0;
assign wr_en8 = row_cnt >= 11'd7 ? pi_flag : 1'b0;
assign wr_en9 = row_cnt >= 11'd8 ? pi_flag : 1'b0;
assign wr_en10 = row_cnt >= 11'd9 ? pi_flag : 1'b0;
assign wr_en11 = row_cnt >= 11'd10 ? pi_flag : 1'b0;
assign wr_en12 = row_cnt >= 11'd11 ? pi_flag : 1'b0;
assign wr_en13 = row_cnt >= 11'd12 ? pi_flag : 1'b0;
assign rd_en1 = wr_en2;
assign rd_en2 = wr_en3;
assign rd_en3 = wr_en4;
assign rd_en4 = wr_en5;
assign rd_en5 = wr_en6;
assign rd_en6 = wr_en7;
assign rd_en7 = wr_en8;
assign rd_en8 = wr_en9;
assign rd_en9 = wr_en10;
assign rd_en10 = wr_en11;
assign rd_en11 = wr_en12;
assign rd_en12 = wr_en13;
assign rd_en13 = mat_flag;
assign mat_flag = row_cnt >= 11'd13 ? pi_flag : 1'b0;
assign mat_row1 = fifo1_rd_data;
assign mat_row2 = fifo2_rd_data;
assign mat_row3 = fifo3_rd_data;
assign mat_row4 = fifo4_rd_data;
assign mat_row5 = fifo5_rd_data;
assign mat_row6 = fifo6_rd_data;
assign mat_row7 = fifo7_rd_data;
assign mat_row8 = fifo8_rd_data;
assign mat_row9 = fifo9_rd_data;
assign mat_row10 = fifo10_rd_data;
assign mat_row11 = fifo11_rd_data;
assign mat_row12 = fifo12_rd_data;
assign mat_row13 = fifo13_rd_data;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
col_cnt <= 11'd0;
else if(col_cnt == COL_NUM-1 && pi_flag == 1'b1)
col_cnt <= 11'd0;
else if(pi_flag == 1'b1)
col_cnt <= col_cnt + 1'b1;
else
col_cnt <= col_cnt;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
row_cnt <= 11'd0;
else if(row_cnt == ROW_NUM-1 && col_cnt == COL_NUM-1 && pi_flag == 1'b1)
row_cnt <= 11'd0;
else if(col_cnt == COL_NUM-1 && pi_flag == 1'b1)
row_cnt <= row_cnt + 1'b1;
fifo_generator_4 mat_fifo1 (
.clk (sclk ), // input wire clk
.srst (~rst_n ), // input wire srst
.din (rx_data ), // input wire [7 : 0] din
.wr_en (wr_en1 ), // input wire wr_en
.rd_en (rd_en1 ), // input wire rd_en
.dout (fifo1_rd_data ), // output wire [7 : 0] dout
.full ( ), // output wire full
.empty ( ) // output wire empty
);
fifo_generator_4 mat_fifo2 (
.clk (sclk ), // input wire clk
.srst (~rst_n ), // input wire srst
.din (fifo1_rd_data ), // input wire [7 : 0] din
.wr_en (wr_en2 ), // input wire wr_en
.rd_en (rd_en2 ), // input wire rd_en
.dout (fifo2_rd_data ), // output wire [7 : 0] dout
.full ( ), // output wire full
.empty ( ) // output wire empty
);
fifo_generator_4 mat_fifo3 (
.clk (sclk ), // input wire clk
.srst (~rst_n ), // input wire srst
.din (fifo2_rd_data ), // input wire [7 : 0] din
.wr_en (wr_en3 ), // input wire wr_en
.rd_en (rd_en3 ), // input wire rd_en
.dout (fifo3_rd_data ), // output wire [7 : 0] dout
.full ( ), // output wire full
.empty ( ) // output wire empty
);
fifo_generator_4 mat_fifo4 (
.clk (sclk ), // input wire clk
.srst (~rst_n ), // input wire srst
.din (fifo3_rd_data ), // input wire [7 : 0] din
.wr_en (wr_en4 ), // input wire wr_en
.rd_en (rd_en4 ), // input wire rd_en
.dout (fifo4_rd_data ), // output wire [7 : 0] dout
.full ( ), // output wire full
.empty ( ) // output wire empty
);
fifo_generator_4 mat_fifo5 (
.clk (sclk ), // input wire clk
.srst (~rst_n ), // input wire srst
.din (fifo4_rd_data ), // input wire [7 : 0] din
.wr_en (wr_en5 ), // input wire wr_en
.rd_en (rd_en5 ), // input wire rd_en
.dout (fifo5_rd_data ), // output wire [7 : 0] dout
.full ( ), // output wire full
.empty ( ) // output wire empty
);
fifo_generator_4 mat_fifo6 (
.clk (sclk ), // input wire clk
.srst (~rst_n ), // input wire srst
.din (fifo5_rd_data ), // input wire [7 : 0] din
.wr_en (wr_en6 ), // input wire wr_en
.rd_en (rd_en6 ), // input wire rd_en
.dout (fifo6_rd_data ), // output wire [7 : 0] dout
.full ( ), // output wire full
.empty ( ) // output wire empty
);
fifo_generator_4 mat_fifo7