一、既然用两帧连续的肤色图像,则需要对图像延迟一拍,以此来得到人脸图像的开始标志和介素标志。
//==========================================================================
//== 帧开始标志pos_vsync和帧结束标志neg_vsync
//==========================================================================
always @(posedge clk) begin
face_vsync_r <= face_vsync;
end
assign pos_vsync = face_vsync && ~face_vsync_r;
assign neg_vsync = ~face_vsync && face_vsync_r;
二、利用行场计数器,得到人脸图像的横纵坐标。
//==========================================================================
//== 帧差图像的行场计数器
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
face_x <= 10'd0;
else if(add_face_x) begin
if(end_face_x)
face_x <= 10'd0;
else
face_x <= face_x + 10'd1;
end
end
assign add_face_x = face_de;
assign end_face_x = add_face_x && face_x== COL-10'd1;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
face_y <= 10'd0;
else if(add_face_y) begin
if(end_face_y)
face_y <= 10'd0;
else
face_y <= face_y + 10'd1;
end
end
assign add_face_y = end_face_x;
assign end_face_y = add_face_y && face_y== ROW-10'd1;
三、 根据上面所得的人脸图像的横纵坐标,从而可确定出框的四个顶点坐标。
//==========================================================================
//== 帧运行:人脸框选
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
x_min <= COL;
end
else if(pos_vsync) begin
x_min <= COL;
end
else if(face_data==16'hffff && x_min > face_x && face_de) begin
x_min <= face_x;
end
end
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
x_max <= 0;
end
else if(pos_vsync) begin
x_max <= 0;
end
else if(face_data==16'hffff && x_max < face_x && face_de) begin
x_max <= face_x;
end
end
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
y_min <= ROW;
end
else if(pos_vsync) begin
y_min <= ROW;
end
else if(face_data==16'hffff && y_min > face_y && face_de) begin
y_min <= face_y;
end
end
//---------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
y_max <= 0;
end
else if(pos_vsync) begin
y_max <= 0;
end
else if(face_data==16'hffff && y_max < face_y && face_de) begin
y_max <= face_y;
end
end
四、保存上面所得的四个顶点坐标值(利用前一帧到当前帧的间隙来保存坐标值,从而供当前帧来实时使用)。
//==========================================================================
//== 帧结束:保存坐标值
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
x_min_r <= 0;
x_max_r <= 0;
y_min_r <= 0;
y_max_r <= 0;
end
else if(neg_vsync) begin
x_min_r <= x_min;
x_max_r <= x_max;
y_min_r <= y_min;
y_max_r <= y_max;
end
end
至此,便得到了人脸框啦。
五、原图的行场计数器
//==========================================================================
//== 原图的行场计数器
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
RGB_x <= 10'd0;
else if(add_RGB_x) begin
if(end_RGB_x)
RGB_x <= 10'd0;
else
RGB_x <= RGB_x + 10'd1;
end
end
assign add_RGB_x = face_de;
assign end_RGB_x = add_RGB_x && RGB_x== COL-10'd1;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
RGB_y <= 10'd0;
else if(add_RGB_y) begin
if(end_RGB_y)
RGB_y <= 10'd0;
else
RGB_y <= RGB_y + 10'd1;
end
end
assign add_RGB_y = end_RGB_x;
assign end_RGB_y = add_RGB_y && RGB_y== ROW-10'd1;
六、人脸框和原图输出
用按键来控制识别效果,一种是原图的人脸检测,一种是二值化中值滤波、膨胀腐蚀后的人脸检测效果。
//==========================================================================
//== 最终数据输出:包围盒+图像
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
key_num <= 1'b0;
else if(key_vld)
key_num <= ~key_num;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
TFT_de <= 1'b0;
TFT_hsync <= 1'b0;
TFT_vsync <= 1'b0;
TFT_data <= 16'b0;
end
else if(key_num==1'b0) begin //按键按下的时候得到白色方框和原图
if((RGB_y >= y_min_r-1 && RGB_y <= y_min_r+1) && RGB_x >= x_min_r && RGB_x <= x_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else if((RGB_y >= y_max_r-1 && RGB_y <= y_max_r+1) && RGB_x >= x_min_r && RGB_x <= x_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else if((RGB_x >= x_min_r-1 && RGB_x <= x_min_r+1) && RGB_y >= y_min_r && RGB_y <= y_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else if((RGB_x >= x_max_r-1 && RGB_x <= x_max_r+1) && RGB_y >= y_min_r && RGB_y <= y_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else begin
TFT_de <= RGB_de;
TFT_hsync <= RGB_hsync;
TFT_vsync <= RGB_vsync;
TFT_data <= RGB_data;
end
end
else if(key_num==1'b1) begin //按键释放的时候得到白色方框和二值化腐蚀膨胀后的图像数据
if((face_y >= y_min_r-1 && face_y <= y_min_r+1) && face_x >= x_min_r && face_x <= x_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else if((face_y >= y_max_r-1 && face_y <= y_max_r+1) && face_x >= x_min_r && face_x <= x_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else if((face_x >= x_min_r-1 && face_x <= x_min_r+1) && face_y >= y_min_r && face_y <= y_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else if((face_x >= x_max_r-1 && face_x <= x_max_r+1) && face_y >= y_min_r && face_y <= y_max_r) begin
TFT_data <= 16'b11111_000000_00000;
end
else begin
TFT_de <= face_de;
TFT_hsync <= face_hsync;
TFT_vsync <= face_vsync;
TFT_data <= face_data;
end
end
end