请选择 进入手机版 | 继续访问电脑版
[X]关闭
1

S04-CH04 Skin_Dection仿真实验

摘要: 本章节通过设计一个肤色检测的算法对前面几章的内容进行了巩固和验证,通过一组仿真验证了整个算法的有效性。虽然基于颜色空间转换加阈值进行肤色检测的结果有误差,但我们完全可以对算法进行优化,减小误差,本章重 ...

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

4.1 概述

      本章节通过设计一个肤色检测的算法对前面几章的内容进行了巩固和验证,通过一组仿真验证了整个算法的有效性。虽然基于颜色空间转换加阈值进行肤色检测的结果有误差,但我们完全可以对算法进行优化,减小误差,本章重点介绍的是如何设计算法,因此对算法的优化就不再介绍,感兴趣的可以尝试优化一下算法。

4.2 肤色检测原理及应用

      肤色作为人的体表显著特征之一,尽管人的肤色因为人种的不同有差异,呈现出不同的颜色,但是在排除了亮度和视觉环境等对肤色的影响后,皮肤的色调基本一致,这就为利用颜色信息来做肤色分割提供了理论的依据。   

      在肤色识别中,常用的颜色空间为YCbCr颜色空间。在YCbCr颜色空间中,Y代表亮度,Cb和Cr分别代表蓝色分量和红色分量,两者合称为色彩分量。YCbCr颜色空间具有将色度与亮度分离的特点,在YCbCr色彩空间中,肤色的聚类特性比较好,而且是两维独立分布,能够比较好地限制肤色的分布区域,并且受人种的影响不大。对比RGB颜色空间和YCbCr颜色空间,当光强发生变化时,RGB颜色空间中(R,G,B)会同时发生变化,而YCbCr颜色空间中受光强相对独立,色彩分量受光强度影响不大,因此YCbCr颜色空间更适合用于肤色识别。

      由于肤色在YCbCr空间受亮度信息的影响较小,本算法直接考虑YCbCr空间的CbCr分量,映射为两维独立分布的CbCr空间。在CbCr空间下,肤色类聚性好,利用人工阈值法将肤色与非肤色区域分开,形成二值图像。

RGB转YCbCr的公式为:

        Y = 0.257*R+0.564*G+0.098*B+16  
       Cb= -0.148*R-0.291*G+0.439*B+128  
       Cr = 0.439*R-0.368*G-0.071*B+128  

对肤色进行判定的条件常使用如下判定条件:

       Cb > 77 && Cb < 127  
       Cr > 133 && Cr < 173 

4.3 检测算法实现

4.3.1 工程创建

Step1:打开HLS,按照之前介绍的方法,创建一个新的工程,命名为Skin_Dection。

Step2:右单击Source选项,选择New File,创建一个名为Top.cpp的文件。

Step3:在打开的编辑区中,把下面的程序拷贝进去:

#include "top.h"

#include <string.h>

 

void hls::hls_skin_dection(RGB_IMAGE& src, RGB_IMAGE& dst,int rows, int cols,

int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper)

{

 

LOOp_ROWS:for(int row = 0; row < rows ; row++)

{

 

LOOp_COLS:for(int col = 0; col < cols; col++)

{

 

     //变量定义

RGB_PIXEL src_data;

     RGB_PIXEL pix;

     RGB_PIXEL dst_data;

     bool skin_region;

 

        if(row < rows && col < cols) {

         src >> src_data;

        }

 

        //获取RGB通道数据

        uchar B = src_data.val[0];

        uchar G = src_data.val[1];

        uchar R = src_data.val[2];

 

        //RGB-->YCbCr颜色空间转换

        uchar y  = (76 * R + 150 * G + 29 * B) >> 8;

        uchar cb = ((128*B -43*R - 85*G)>>8) + 128 ;

        uchar cr = ((128*R -107*G - 21 * B)>>8)+ 128 ;

 

        //肤色区域判定

        if (y > y_lower && y < y_upper && cb > cb_lower && cb < cb_upper && cr > cr_lower && cr < cr_upper)

         skin_region = 1;

        else

            skin_region = 0;

 

        uchar temp0= (skin_region == 1)? (uchar)255: B;

        uchar temp1= (skin_region == 1)? (uchar)255: G;

        uchar temp2= (skin_region == 1)? (uchar)255: R;

 

        dst_data.val[0] = temp0;

        dst_data.val[1] = temp1;

        dst_data.val[2] = temp2;

 

dst << dst_data;

    }

}

}

void ImgProcess_Top(AXI_STREAM& input, AXI_STREAM& output,int rows, int cols,

            int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper)

{

RGB_IMAGE img_0(rows, cols);

RGB_IMAGE img_1(rows, cols);

 

#pragma HLS dataflow

hls::AXIvideo2Mat(input,img_0);

hls::hls_skin_dection(img_0,img_1,rows,cols,y_lower,y_upper,cb_lower,cb_upper,cr_lower,cr_upper);

hls::Mat2AXIvideo(img_1, output);

}

同样的方法创建一个名为Top.h的文件。

#ifndef _TOP_H_

#define _TOP_H_

 

#include "hls_video.h"

// maximum image size

#define MAX_WIDTH  1920

#define MAX_HEIGHT 1080

 

typedef unsigned char uchar;

 

// I/O Image Settings

#define INPUT_IMAGE           "test_1080p.bmp"

#define OUTPUT_IMAGE          "result_1080p.bmp"

#define OUTPUT_IMAGE_GOLDEN   "result_1080p_golden.bmp"

 

// typedef video library core structures

typedef hls::stream<ap_axiu<24,1,1,1> >               AXI_STREAM;

typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3>     RGB_IMAGE;

typedef hls::Scalar<3, unsigned char>                 RGB_PIXEL;

 

//声明hls命名空间

namespace hls

{

void hls_skin_dection(RGB_IMAGE& src, RGB_IMAGE& dst,int rows, int cols,

                      int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper);

}

 

void ImgProcess_Top(AXI_STREAM& input, AXI_STREAM& output,int rows, int cols,

int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper);

 

#endif

Step4:在Test Bench中,用同样的方法添加一个名为Test.cpp的测试程序。添加如下代码:

#include "top.h"

#include "hls_opencv.h"

#include "iostream"

#include <time.h>

 

using namespace std;

using namespace cv;

 

int main (int argc, char** argv)

{

//IplImage* src = cvLoadImage(INPUT_IMAGE);

IplImage* src = cvLoadImage("test.jpg");

//IplImage* src = cvLoadImage("test_img1.jpg");

IplImage* dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);

 

AXI_STREAM  src_axi, dst_axi;

IplImage2AXIvideo(src, src_axi);

 

ImgProcess_Top(src_axi, dst_axi, src->height, src->width,0,255,75,125,131,185);

AXIvideo2IplImage(dst_axi, dst);

 

cvShowImage("src",src);

cvShowImage("dst_hls",dst);

waitKey(0);

 

return 0;

}

Step5:在Test Bench中添加一张名为test.jpg的测试图片,图片可以在我们提供的源程序中的Image文件夹中找到。完整的工程如下图所示:

4.3.2 代码综合

      了解了肤色检测的原理以后我们进行算法实现可以发现,算法的关键就是进行RGB到YCbCr颜色空间的转换,其关键算法如下,大家可以发现其实算法只需要几十行就可以很容易的实现检测算法,不过需要大家注意的是因为我们使用C++进行开发,那么为了程序的通用性以及方便团队合作开发,建议大家使用namespace命名空间,这样可以很好的解决重名问题,而且可以增加程序的可读性。

接下来,我们对项目进行代码综合。

Step1:单击Project—project settings命令。

Step2:在弹出的窗口中选择综合选项,然后在顶层函数设置区中单击右边的Browse…按钮。

Step3:选择ImgProcess_Top为顶层函数,然后单击两次OK,完成工程的设置。

Step4:单击综合快捷按钮Active Solution开始代码综合。

等待一段时间后,在未经代码优化及约束的条件下生成的综合报告如图:


路过

雷人

握手

鲜花

鸡蛋
发表评论

最新评论

引用 猪猪 2021-3-11 10:28
不错,感谢

查看全部评论(1)

本文作者
2019-9-17 10:45
  • 1
    粉丝
  • 2431
    阅读
  • 1
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
热门评论
排行榜