【新】opencv肤色检测源码

简介: 【新】opencv肤色检测源码
//第一种:RGB color space 
// skin region location using rgb limitation
void ImageSkin::ImageSkinRGB(const Mat& rgb, Mat& _dst)
{
    assert(rgb.channels() == 3 && _dst.channels() == 3);
    static const int R=2;
    static const int G=1;
    static const int B=0;
    Mat dst = Mat(_dst.size(), _dst.type(), 3);
    dst.setTo(Scalar(0, 0, 0));
    for (int h=0; h<rgb.rows; h++)
    {
        for (int w=0; w<rgb.cols; w++)
        {
      // 数组的一份拷贝
      Vec3b prgb = rgb.at<Vec3b>(h, w);
      Vec3b pdst = dst.at<Vec3b>(h, w);
      //auto* pdst111 = &dst.at<Vec3b>(h, w);
            if ((prgb[R]>95 && prgb[G]>40 && prgb[B]>20 &&
                    prgb[R]-prgb[B]>15 && prgb[R]-prgb[G]>15) || //uniform illumination
                    (prgb[R]>200 && prgb[G]>210 && prgb[B]>170 &&
                     abs(prgb[R]-prgb[B])<=15 && prgb[R]>prgb[B] && prgb[G]>prgb[B])
               )
            {
        // 赋值切不可用pdst!
                memcpy(&dst.at<Vec3b>(h, w), &prgb/*rgb.at<Vec3b>(h, w)*/, 3);
        // 同上
        //dst.at<Vec3b>(h, w)[R] = rgb.at<Vec3b>(h, w)[R];
        //dst.at<Vec3b>(h, w)[G] = rgb.at<Vec3b>(h, w)[G];
        //dst.at<Vec3b>(h, w)[B] = rgb.at<Vec3b>(h, w)[B];
            }
        }
    }
  dst.copyTo(_dst);
  dst.release();
}
//第二种:RG color space 
// skin detection in rg space 
void ImageSkin::ImageSkinRG(const Mat& rgb, Mat& gray)
{
    assert(rgb.channels() == 3 && gray.channels() == 1);
    const int R=2;
    const int G=1;
    const int B=0;
    double Aup=-1.8423;
    double Bup=1.5294;
    double Cup=0.0422;
    double Adown=-0.7279;
    double Bdown=0.6066;
    double Cdown=0.1766;
    for (int h=0; h<rgb.rows; h++)
    {
        for (int w=0; w<rgb.cols; w++)
        {
      auto* pGray = &gray.at<uchar>(h, w);
      auto pRGB = rgb.at<Vec3b>(h, w);
            int s=pRGB[R]+pRGB[G]+pRGB[B];
            double r=(double)pRGB[R]/s;
            double g=(double)pRGB[G]/s;
            double Gup=Aup*r*r+Bup*r+Cup;
            double Gdown=Adown*r*r+Bdown*r+Cdown;
            double Wr=(r-0.33)*(r-0.33)+(g-0.33)*(g-0.33);
            if (g<Gup && g>Gdown && Wr>0.004)
            {
                *pGray=255;
            }
            else
            {
                *pGray=0;
            }
        }
    }
}
//
//第三种:otsu阈值化【仅限单通道】
// reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB
void ImageSkin::ImageThresholdOtsu(const Mat& src, Mat& dst)
{
    int height=src.rows;
    int width=src.cols;
    // 统计直方图
    float histogram[256]= {0};
    for(int i=0; i<height; i++)
    {
        for(int j=0; j<width; j++)
        {
      uchar p = src.at<uchar>(i, j);
            histogram[p]++;
        }
    }
    // 直方图归一化
    int size=height*width;
    for(int i=0; i<256; i++)
    {
        histogram[i]=histogram[i]/size;
    }
    // 求像素平均值
    float avgValue=0;
    for(int i=0; i<256; i++)
    {
        avgValue+=i*histogram[i];
    }
    int tH;
    float maxVariance=0;
    float w=0,u=0;
    for(int i=0; i<256; i++)
    {
        w+=histogram[i];
        u+=i*histogram[i];
        float t=avgValue*w-u;
        float variance=t*t/(w*(1-w));
        if(variance>maxVariance)
        {
            maxVariance=variance;
            tH=i;
        }
    }
    threshold(src, dst, tH, 255, CV_THRESH_BINARY);
}
//
//第四种:Ycrcb之cr分量+otsu阈值化 
void ImageSkin::ImageSkinOtsu(const Mat& src, Mat& dst)
{
    assert(dst.channels() == 1 && src.channels() == 3);
    Mat ycrcb = Mat(src.size(), src.type(), 3);
  Mat yCRcb[3];
    cvtColor(src, ycrcb, CV_BGR2YCrCb);
    split(ycrcb, yCRcb);
    ImageThresholdOtsu(yCRcb[1], yCRcb[1]);
  yCRcb[1].copyTo(dst);
  yCRcb[1].release();
  ycrcb.release();
}
//
//第五种:YCrCb中133<=Cr<=173 77<=Cb<=127 
void ImageSkin::ImageSkinYUV(const Mat& src, Mat& dst)
{
    Mat ycrcb = Mat(src.size(), src.type(), 3);
    cvtColor(src, ycrcb, CV_BGR2YUV); // CV_BGR2YCrCb
    static const int Cb=2;
    static const int Cr=1;
    static const int Y=0;
  dst.setTo(Scalar(0, 0, 0));
    for (int h=0; h<src.rows; h++)
    {
        for (int w=0; w<src.cols; w++)
        {
      const Vec3b* pycrcb = &ycrcb.at<Vec3b>(h, w);
      const Vec3b* psrc = &src.at<Vec3b>(h, w);
      //const uchar* pdst = &dst.at<uchar>(h, w);
            if ((*pycrcb)[Cr]>=133 && (*pycrcb)[Cr]<=173 && (*pycrcb)[Cb]>=77 && (*pycrcb)[Cb]<=127)
            {
                memcpy(&dst.at<Vec3b>(h, w), psrc, 3);
            }
        }
    }
}

测试代码:

int _tmain(int argc, _TCHAR* argv[])
{
  Mat img = imread("..\\test.png", 1);        
  Mat dstRGB = Mat(img.size(), CV_8UC3);    
  Mat dstRG = Mat(img.size(), CV_8UC1);     
  Mat dst_crotsu = Mat(img.size(), CV_8UC1);       
  Mat dst_YUV = Mat(img.size(), CV_8UC3);       
  namedWindow("Original WIN", CV_WINDOW_AUTOSIZE);      
  imshow("Original WIN", img);   
  waitKey(0);      
  ImageSkin ImgS;  
  ImgS.ImageSkinRGB(img, dstRGB);   
  namedWindow("ImageSkinRGB WIN", CV_WINDOW_AUTOSIZE);      
  imshow("ImageSkinRGB WIN", dstRGB);  
  imwrite("..//ImageSkinRGB.jpg", dstRGB);
  waitKey(0);  
  ImgS.ImageSkinRG(img, dstRG);    
  namedWindow("ImageSkinRG WIN", CV_WINDOW_AUTOSIZE);      
  imshow("ImageSkinRG WIN", dstRG);
  imwrite("..//ImageSkinRG.jpg", dstRG);
  waitKey(0);   
  ImgS.ImageSkinOtsu(img, dst_crotsu);      
  namedWindow("ImageSkinOtsu WIN", CV_WINDOW_AUTOSIZE);      
  imshow("ImageSkinOtsu WIN", dst_crotsu); 
  imwrite("..//ImageSkinOtsu.jpg", dst_crotsu);
  waitKey(0);  
  ImgS.ImageSkinYUV(img, dst_YUV);      
  namedWindow("ImageSkinYUV WIN", CV_WINDOW_AUTOSIZE);      
  imshow("ImageSkinYUV WIN", dst_YUV);  
  imwrite("..//ImageSkinYUV.jpg", dst_YUV);
  waitKey(0);  
  return 0;
}

结果显示如图:

image.png

本文代码参考了这位大牛的博客点击打开链接,我将它们修改为C++风格,便于自己和其他也习惯C++风格的朋友使用

目录
相关文章
|
1月前
|
机器学习/深度学习 监控 算法
基于计算机视觉(opencv)的运动计数(运动辅助)系统-源码+注释+报告
基于计算机视觉(opencv)的运动计数(运动辅助)系统-源码+注释+报告
52 3
|
1月前
|
计算机视觉
Opencv学习笔记(八):如何通过cv2读取视频和摄像头来进行人脸检测(jetson nano)
如何使用OpenCV库通过cv2模块读取视频和摄像头进行人脸检测,并提供了相应的代码示例。
96 1
|
1月前
|
缓存 并行计算 Ubuntu
Jetson 学习笔记(十一):jetson agx xavier 源码编译ffmpeg(3.4.1)和opencv(3.4.0)
本文是关于在Jetson AGX Xavier上编译FFmpeg(3.4.1)和OpenCV(3.4.0)的详细教程,包括编译需求、步骤、测试和可能遇到的问题及其解决方案。还提供了Jetson AGX Xavier编译CUDA版本的OpenCV 4.5.0的相关信息。
73 4
Jetson 学习笔记(十一):jetson agx xavier 源码编译ffmpeg(3.4.1)和opencv(3.4.0)
|
1月前
|
Ubuntu 应用服务中间件 nginx
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
本文是关于Ubuntu系统中使用ffmpeg 3.2.16源码编译OpenCV 3.4.0的安装笔记,包括安装ffmpeg、编译OpenCV、卸载OpenCV以及常见报错处理。
158 2
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
|
1月前
|
机器学习/深度学习 计算机视觉
目标检测笔记(六):如何结合特定区域进行目标检测(基于OpenCV的人脸检测实例)
本文介绍了如何使用OpenCV进行特定区域的目标检测,包括人脸检测实例,展示了两种实现方法和相应的代码。
65 1
目标检测笔记(六):如何结合特定区域进行目标检测(基于OpenCV的人脸检测实例)
|
1月前
|
Ubuntu 编译器 计算机视觉
Ubuntu系统编译OpenCV4.8源码
【10月更文挑战第17天】只要三步即可搞定,第一步是下载指定版本的源码包;第二步是安装OpenCV4.8编译需要的编译器与第三方库支持;第三步就是编译OpenCV源码包生成安装文件并安装。
|
1月前
|
算法 计算机视觉 Python
圆形检测算法-基于颜色和形状(opencv)
该代码实现了一个圆检测算法,用于识别视频中的红色、白色和蓝色圆形。通过将图像从RGB转换为HSV颜色空间,并设置对应颜色的阈值范围,提取出目标颜色的区域。接着对这些区域进行轮廓提取和面积筛选,使用霍夫圆变换检测圆形,并在原图上绘制检测结果。
81 0
|
4月前
|
Ubuntu 编译器 计算机视觉
Ubuntu系统下编译OpenCV4.8源码
在Ubuntu上源码安装OpenCV 4.8分为三步:1) 下载源码包,使用`wget`命令;2) 安装依赖,如`g++`, `cmake`, `make`等;3) 创建编译目录,运行`cmake`配置,接着`make`编译,最后`sudo make install`安装。安装完成后,通过编写和运行一个简单的OpenCV C++程序来验证环境配置正确性。
138 10
|
4月前
|
计算机视觉 iOS开发 C++
【OpenCV】在MacOS上源码编译OpenCV
【7月更文挑战第9天】在MacOS上源码编译OpenCV需分步进行: 1. 准备工作: 安装Xcode, Command Line Tools及依赖如CMake, Homebrew. 2. 获取OpenCV源码: 从官网下载并解压所需版本. 3. 编译OpenCV. 4. 安装OpenCV: 编译后使用`sudo make install`进行安装. 5. 验证安装: 编写简单C++程序测试OpenCV功能, 如读取并显示图片.
168 1
|
4月前
|
机器学习/深度学习 传感器 算法
OpenCV4工业缺陷检测的六种方法
OpenCV4工业缺陷检测的六种方法
下一篇
无影云桌面