• OpenCV颜色转换和皮肤检测


    本笔记重点记录OpenCV中的颜色转换和利用色彩空间的特性进行皮肤检测

    颜色转换

    实现原理

    之所以要引入色调/饱和度/亮度的色彩空间概念,是因为人们喜欢凭直觉分辨各种颜色,而它与这种方式吻合。实际上,人类更喜欢用色彩、彩度、亮度等直观的属性来描述颜色,而大多 数直觉色彩空间正是基于这三个属性。

    • 色调(hue)表示主色,我们使用的颜色名称(例如绿色、 黄色和红色)就对应了不同的色调值;
    • 饱和度(saturation)表示颜色的鲜艳程度,柔和的颜色饱 和度较低,而彩虹的颜色饱和度就很高
    • 亮度(brightness)是一个主观的属性,表示某种 颜色的光亮程度。

    其他直觉色彩空间使用颜色明度(value)或颜色亮度(lightness)的概念描述 有关颜色的强度。

    利用这些颜色概念,能尽可能地模拟人类对颜色的直观感知。因此,它们没有标准的定义。 根据文献资料,色调、饱和度和亮度都有多种不同的定义和计算公式。OpenCV 建议的两种直觉 色彩空间的实现是 HSV 和 HLS 色彩空间,它们的转换公式略有不同,但是结果非常相似。

    亮度成分可能是最容易解释的。在 OpenCV 对 HSV 的实现中,它被定义为三个 BGR 成分中 的最大值,以非常简化的方式实现了亮度的概念。为了让定义更符合人类视觉系统,应该使用均 匀感知的色彩空间 Lab和 Luv的 L 通道。举个例子,L 通道已经考虑到了,在强度相同的 情况下,人们会觉得绿色比蓝色等颜色的亮度更高。

    OpenCV 用一个公式来计算饱和度,该公式基于 BGR 组件的最小值和最大值:

    其原理是:灰度颜色包含的 R、G、B 的成分是相等的,相当于一种极不饱和的颜色,因此 它的饱和度是 0(饱和度是一个 0~1.0 的值)。对于 8 位图像,饱和度被调节成一个 0~255 的值, 并且作为灰度图像显示的时候,较亮区域对应的颜色具有较高的饱和度。

    利用opencv把RGB图片像HSV颜色空间转变(CV_BGR2HSV)的时候,

    H通道的值范围为: 0-180

    S: 0-255

    V:0-255

    实现代码

    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    #include <iostream>
    #include <vector>
    
    int main()
    {
        // 读入图像
        cv::Mat image= cv::imread("boldt.jpg");
        if (!image.data)
            return 0;
    
        // 原始图像
        cv::namedWindow("Original image");
        cv::imshow("Original image",image);
    
        // 转换成HSV色彩空间
        cv::Mat hsv;
        cv::cvtColor(image, hsv, CV_BGR2HSV);
    
        // 把三个通道分割进三幅图像中
        std::vector<cv::Mat> channels;
        cv::split(hsv,channels);
        // channels[0] 色调
        // channels[1] 饱和度
        // channels[2] 亮度
    
        // 亮度
        cv::namedWindow("Value");
        cv::imshow("Value",channels[2]);
    
        // display 饱和度
        cv::namedWindow("Saturation");
        cv::imshow("Saturation",channels[1]);
    
        // display 色调
        cv::namedWindow("Hue");
        cv::imshow("Hue",channels[0]);
        cv::waitKey();
    }
    

    实现效果

    皮肤检测

    8 位版本的色调在 0~180,饱和度在 0~255

    实现原理

    在对特定物体做初步检测时,颜色信息非常有用。例如辅助驾驶程序中的路标检测功能,就要凭借标准路标的颜色快速识别可能是路标的信息。另一个例子是肤色检测,检测到的皮肤区域 可作为图像中有人存在的标志。手势识别就经常使用肤色检测确定手的位置。

    肤色检测领域的大量研究已经表明,来自不同人种的人群的皮肤颜色,可以在色调、饱和度、色彩空间中很好地归类。

    实现代码

    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    #include <iostream>
    #include <vector>
    
    void detectHScolor(const cv::Mat& image,       // input image
                       double minHue, double maxHue,   // Hue interval
                       double minSat, double maxSat,   // saturation interval
                       cv::Mat& mask) {             // output mask
    
        // convert into HSV space
        cv::Mat hsv;
        cv::cvtColor(image, hsv, CV_BGR2HSV);
    
        // split the 3 channels into 3 images
        std::vector<cv::Mat> channels;
        cv::split(hsv, channels);
        // channels[0] is the Hue
        // channels[1] is the Saturation
        // channels[2] is the Value
    
        // Hue masking
        cv::Mat mask1; // below maxHue
        cv::threshold(channels[0], mask1, maxHue, 255, cv::THRESH_BINARY_INV);
        cv::Mat mask2; // over minHue
        cv::threshold(channels[0], mask2, minHue, 255, cv::THRESH_BINARY);
    
        cv::Mat hueMask; // hue mask
        if (minHue < maxHue)
            hueMask = mask1 & mask2;
        else // if interval crosses the zero-degree axis
            hueMask = mask1 | mask2;
    
        // Saturation masking
        // below maxSat
        cv::threshold(channels[1], mask1, maxSat, 255, cv::THRESH_BINARY_INV);
        // over minSat
        cv::threshold(channels[1], mask2, minSat, 255, cv::THRESH_BINARY);
    
        cv::Mat satMask; // saturation mask
        satMask = mask1 & mask2;
    
        // combined mask
        mask = hueMask&satMask;
    }
    
    int main()
    {
        // 读入图像
        cv::Mat image= cv::imread("girl.jpg");
        if (!image.data)
            return 0;
        // show original image
        cv::namedWindow("Original image");
        cv::imshow("Original image",image);
        // detect skin tone
        cv::Mat mask;
        detectHScolor(image,
                  160, 10, // hue from 320 degrees to 20 degrees
                  25, 166, // saturation from ~0.1 to 0.65
                  mask);
    // show masked image
        cv::Mat detected(image.size(), CV_8UC3, cv::Scalar(0, 0, 0));
        image.copyTo(detected, mask);
        cv::imshow("Detection result",detected);
        cv::waitKey();
    }
    
    

    实现效果

    可改进的地方

    在检测时没有考虑颜色的亮度。在实际应用中,排除较高亮度的颜色可以降低把明亮的淡红色误认为皮肤的可能性。所以要想对皮肤颜色进行可靠和准确的检测, 还需要更加精确的分析。对不同的图像进行检测,也很难保证效果都好,因为摄影时影响彩色再 现的因素有很多,如白平衡和光照条件等。

    1
  • 相关阅读:
    蓝桥杯 买不到的数目(动态规划)
    部分ftp登不上原因
    glColor3f()函数 表示颜色
    三维模型(X,Y,Z)坐标,UV坐标
    找不到 Windows SDK 版本10.0.18362.0的解决办法
    头文件中的ifndef/define/endif有什么作用?
    pycharm 出现opencv(4.4.0)等等错误如何解决
    灵敏度分析与误差分析
    死磕Spring之AOP篇
    死磕Spring之IoC篇
  • 原文地址:https://www.cnblogs.com/GeekHuman/p/9938906.html
Copyright © 2020-2023  润新知