首页 > 其他分享 >FPGA图像处理学习(人脸识别、追踪、转换)

FPGA图像处理学习(人脸识别、追踪、转换)

时间:2024-02-08 11:33:05浏览次数:17  
标签:begin 人脸识别 FPGA clk face RGB 图像处理 && rst

获取人脸图像——肤色提取(Ycbcr+阈值)——滤波处理(中值、腐蚀膨胀)——人脸框选——显示

肤色提取:顾名思义,将肤色从外界环境中提取出。在肤色识别算法中,常用YCbCr颜色空间(亮度、蓝色、红色分量),因为肤色在 YCbCr 空间受亮度信息的影响较小,从而肤色类聚性好,由此,在Ycbcr空间基础上,我们用人工阈值法将肤色与非肤色区域分开,最终形成二值图像,实现肤色的提取。

滤波处理:人脸内部可能存在黑点、人脸外的某些地方也可能会被误检测为人脸,这些情况都会造成识别失败,因此加入中值滤波以及腐蚀、膨胀,这些之前都整理过,不展开说了。
先进行Ycbcr空间转换得到亮度、蓝色、红色分量,给cb和cr设置阈值,即可将肤色提取出来。(共采用四级流水线)

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
View Code

第四级肤色识别:

Cb和Cr设置阈值:Cb:77 ~ 127 ;Cr:133~173;(前人大量研究得到的经验值),最终输出的结果是二值化结果,目的是减少运算量。

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
View Code

 

RGB565原图数据,内部进行Ycbcr转换,分别得到8位的Y,Cb,Cr分量,后根据蓝红分量的阈值得到16位的二值化肤色数据face_data,阈值内为白色,阈值外为黑色

检测出肤色后,为提高图像质量,进行中值滤波、腐蚀膨胀处理。

肤色检测出人脸后,我们用行列坐标画框,将人脸框选出来,最终人脸框和图像数据同时输出,原图图像数据是16位,因此前面肤色数据face_data也用的16位。RGB信号:原图数据、使能以及行场有效信号。
face信号:人脸肤色提取后的图像数据、使能以及行场有效信号。

 因为两帧图像差别较小,因此我们将人脸肤色图像分两帧来处理,通过这两帧图像得到人脸框的坐标,这样可防止图像结果偏移的情况出现。其中第一帧得到框的四个顶点坐标,当前帧的输出即可实时的使用人脸框的四个顶点坐标。

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;
View Code

 人脸图像纵坐标:

parameter COL               = 11'd640              ; //图片长度
parameter ROW               = 11'd480              ; //图片高度
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) //数据有效且一行640像素计数完成
            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)//一行数据完成且480场计数完成(一帧图像完成)
            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;
View Code

 

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最小坐标>肤色处x坐标
        x_min <= face_x; //当前肤色x坐标就是框的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最大坐标<肤色x坐标,那肤色x坐标就是框x最大值
        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
View Code
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
View Code

原图行列技术器

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 = RGB_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;
View Code

人脸原图输出:

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
View Code

前一帧获得AB

always @(posedge clk) begin
    face_vsync_r <= face_vsync;
end
View Code

图像流经未开始或者结束的时候,最小像素值255,最大像素值0;当图像流过且像素有效时候,开始进行像素比较,得到一帧图像中的最小最大像素值。

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        max <= 8'd0;
        min <= 8'd255;
    end
    else if(Y_vsync && Y_de) begin     //像素有效时
        max <= (max > Y_data) ? max : Y_data;
        min <= (min < Y_data) ? min : Y_data;
    end
    else if(neg_Y_vsync) begin         //一帧图像结束时
        max <= 8'd0;
        min <= 8'd255;
    end
end
View Code

 

 

基于FPGA:RGB转YCBCR

//RGB分量转Gray灰度图
module RGB_Gray
//========================< 端口 >==========================================
(
input   wire                clk                        ,    //时钟
input   wire                rst_n                       ,    //复位
//原图 ----------------------------------------------
input   wire                RGB_hsync                ,
input   wire                RGB_vsync                ,
input   wire    [23:0]  RGB_data                   ,
input   wire                RGB_de                    ,
//灰度转换图 ----------------------------------------------
output  wire                gray_hsync                  , //这里的行场同步信号也就是最终的VGA行场同步信号。
output  wire                gray_vsync                , //需要根据实际消耗的时钟进行延迟
output  wire    [23:0]    gray_data                ,
output  wire                gray_de
);

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 [16:0] Y1,Cb1,Cr1;
reg [23:0]  Y2,Cb2,Cr2;

reg [7:0]  RGB_de_r     ;  
reg [7:0]  RGB_hsync_r  ;
reg [7:0]  RGB_vsync_r  ;

//将24位RGB分成三分量

assign R0 = RGB_data[23:16];
assign G0 = RGB_data[15:8];
assign B0 = RGB_data[7:0];

//=============根据RGB转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位

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 >> 8;  
        Cb2 <= Cb1>> 8;
        Cr2 <= Cr1>> 8;
    end
end

// 取YcbCr三分量中的Y分量,将其赋值给RGB888通道即可。
assign gray_data = {Y2[7:0],Y2[7:0],Y2[7:0]}; 

//=================== 信号同步==================================
//为确保图像能正常显示,要保持数据与数据使能和行场有效信号同步
//前面我们花费了三个clk来计算,因此延迟三拍


always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        RGB_de_r    <= 3'b0;
        RGB_hsync_r <= 3'b0;
        RGB_vsync_r <= 3'b0;
    end
    else begin  
        RGB_de_r    <= {RGB_de_r[1:0],    RGB_de};
        RGB_hsync_r <= {RGB_hsync_r[1:0], RGB_hsync};
        RGB_vsync_r <= {RGB_vsync_r[1:0], RGB_vsync};
    end
end


assign gray_de    = RGB_de_r[2];
assign gray_hsync = RGB_hsync_r[2];
assign gray_vsync = RGB_vsync_r[2];

endmodule
View Code

基于FPGA:运动目标检测

在Verlog里面,使用组合逻辑不能直接按上述公式(2)在计算,不然组合逻辑延时太大,导致时序不收敛,这里就需要添加寄存器来切割流水线;利用FPGA 并行处理的特点加速计算。这里分三级流水线处理:第一级流水线计算所有乘法; 第二级流水线计算所有加法,把正的和负的分开进行加法;第三级流水线计算最终的和,若为负数取0。输入到输岀有三个clock的时延仿真波形如下图所示

 

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
        {matrix_p11, matrix_p12, matrix_p13} <= 3'b0;
        {matrix_p21, matrix_p22, matrix_p23} <= 3'b0;
        {matrix_p31, matrix_p32, matrix_p33} <= 3'b0;
        end
    else if(read_frame_href)
        begin
        if(read_frame_clken)    //Shift_RAM data read clock enable
            begin
            {matrix_p11, matrix_p12, matrix_p13} <= {matrix_p12, matrix_p13, row1_data};    //1th shift input
            {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p22, matrix_p23, row2_data};    //2th shift input
            {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p32, matrix_p33, row3_data};    //3th shift input
            end
        else
            begin
            {matrix_p11, matrix_p12, matrix_p13} <= {matrix_p11, matrix_p12, matrix_p13};
            {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p21, matrix_p22, matrix_p23};
            {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p31, matrix_p32, matrix_p33};
            end    
        end
View Code

 

通过行场信号,设计行列计数器,从而可以获取图像每个像素点的坐标信息,然后设计4个寄存器分别是edg_up 、 edg_down、edg_left、edg_right目标的上下左右四个点,实时与行列计数器比较,也就是求最大值( edg_down和edg_right)和最小值(edg_up和edg_left),代码如下所示:

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
      edg_up    <=  10'd479;
      edg_down  <=  10'd0;
      edg_left  <=  10'd639;
      edg_right <=  10'd0;
     end
    else if(vsync_rising) begin
       edg_up    <=  10'd479;
      edg_down  <=  10'd0;
      edg_left  <=  10'd639;
      edg_right <=  10'd0;
    end
   else if(per_frame_clken & per_frame_href)begin
      if(per_img_Y == 1'b1) begin
         if(edg_up > v_cnt)
           edg_up  <=v_cnt ;
         else 
          edg_up  <=edg_up ;    
    
         if(edg_down < v_cnt)
           edg_down  <=v_cnt ;
         else 
          edg_down  <=edg_down ;    
             
          if(edg_left > h_cnt)
           edg_left  <= h_cnt ;
         else 
          edg_left  <=edg_left ;    
    
         if(edg_right < h_cnt)
           edg_right  <=h_cnt ;
         else 
          edg_right  <=edg_right ;             
      end
    end
end 
View Code

 

标签:begin,人脸识别,FPGA,clk,face,RGB,图像处理,&&,rst
From: https://www.cnblogs.com/shiningleo007/p/18011687

相关文章

  • FPGA图像处理(直方图均衡化)
       图像处理领域中利用图像直方图对对比度进行调整的方法。对比度是画面黑与白的比值,也就是从黑到白的渐变层次。比值越大,从黑到白的渐变层次就越多,从而色彩表现越丰富。对比度对视觉效果的影响非常关键,一般来说对比度越大,图像越清晰醒目,色彩也越鲜明艳丽;而对比度小,则会让......
  • 高级FPGA开发之基础协议之PCIe(二)
    高级FPGA开发之基础协议之PCIe(二)一、TLP报文类型在PCIe总线中,存储器读写、I/O读写和配置读写请求TLP主要由以下几类报文组成:1.1存储器读请求TLP和读完成TLP当PCIe主设备(RC或者EP)访问目标设备的存储器空间时,使用non-posted总线事务向目标设备发出存储器读请求TLP,目标设备收到这个存......
  • 全国产T3+FPGA的SPI与I2C通信方案分享
    近年来,随着中国新基建、中国制造2025规划的持续推进,单ARM处理器越来越难胜任工业现场的功能要求,特别是如今能源电力、工业控制、智慧医疗等行业,往往更需要ARM+FPGA架构的处理器平台来实现例如多路/高速AD采集、多路网口、多路串口、多路/高速并行DI/DO、高速数据并行处理等特定......
  • 一次人脸识别ViewFaceCore使用的经验分享,看我把门店淘汰下来的POS机改成了人脸考勤机
    POS软件是什么?你好意思吗,还在用老掉牙的Winform。   门店被淘汰的POS机销售终端——POS(pointofsale)是一种多功能终端,把它安装在信用卡的特约商户和受理网点中与计算机联成网络,就能实现电子资金自动转账,它具有支持消费、预授权、余额查询和转账等功能,使用起来安全、......
  • 基于yolov2网络的人脸识别系统matlab仿真,包括识别正脸,侧脸等
    1.算法运行效果图预览 2.算法运行软件版本matlab2022a 3.算法理论概述      基于YoloV2网络的面部识别系统是一种先进的实时面部识别系统,它能够识别正面、侧面等各种角度的面部。这种系统主要包括三个阶段:训练阶段、预处理阶段和识别阶段。 3.1、训练阶段 ......
  • 基于FPGA的图像RGB转CMYK实现,包含testbench和MATLAB辅助验证程序
    1.算法运行效果图预览 将仿真结果导入到matlab中,得到如下对比结果: 2.算法运行软件版本matlab2022a,vivado2019.2 3.算法理论概述       基于FPGA的图像RGB转CMYK实现是一种将RGB图像转换为CMYK图像的硬件实现方法。下面将详细介绍其原理和数学公式。 3.1、......
  • 人脸识别几个开源
    人脸识别几个开源1.OpenFaceGithub:https://github.com/TadasBaltrusaitis/OpenFaceOpenFace是一个用于计算机视觉和机器学习的工具,能够进行各种面部识别检测,包括:特征点检测、头部姿态识别、面部动作识别和眼睛注视识别。此外,它还能够从网络摄像头无需任何专业硬件实现人脸实......
  • 通过LINUX驱动控制FPGA端PWM外设(LED) 通过应用程序命令传参随意修改寄存器的值(PWM波频
    用法:先下发下面的命令让kernel信息打印到串口:echo7417>/proc/sys/kernel/printk然后增加程序可执行性:chmod777pwmdriver_app  先执行./pwmdriver_app/dev/pwm400000200然后执行./pwm_driver_app/dev/pwm400000200,可以发现LED[1]......
  • 国产RK3568J基于FSPI的ARM+FPGA通信方案分享
    近年来,随着中国新基建、中国制造2025规划的持续推进,单ARM处理器越来越难胜任工业现场的功能要求,特别是如今能源电力、工业控制、智慧医疗等行业,往往更需要ARM+FPGA架构的处理器平台来实现例如多路/高速AD采集、多路网口、多路串口、多路/高速并行DI/DO、高速数据......
  • 人工智能|使用 VGG 网络对人脸识别数据集进行训练并预测,最后对模型进行评估
    一、VGG网络对人脸识别数据集使用VGG网络对人脸识别数据集进行训练并预测,最后对模型进行评估。数据集为2019年上传的十个中国明星的人脸图片(只做学习使用,不得做与其他用途)。按照深度学习的传统,我们将训练集和测试集按照9:1的比例进行划分。自定义的数据集,首先要生成图像列......