基礎學習筆記之opencv(21):一個簡單有趣的皮膚檢測代碼


 

  前言 

  最近課題研究上想采用皮膚信息,但是個人總是對皮膚信息應用在目標檢測和目標識別上有排斥,認為皮膚信息完全不足以勝任這個工作。其實計算機視覺的最終實現是一個長期的過程,是AI領域一個經典的問題,所以在AI完全突破之前,任何對CV有用的信息都值得去深入研究,除非有一種算法能夠在所有情況下都工作。好了,廢話不扯了,進入正題,有偏見但是還是得使用它。皮膚模型中有單高斯,混合高斯,貝葉斯模型和橢圓模型等。經過前人學者大量的皮膚統計信息可以知道,如果將皮膚信息映射到YCrCb空間,則在CrCb二維空間中這些皮膚像素點近似成一個橢圓分布。因此如果我們得到了一個CrCb的橢圓,下次來一個坐標(Cr, Cb)我們只需判斷它是否在橢圓內(包括邊界),如果是,則可以判斷其為皮膚,否則就是非皮膚像素點。

  開發環境:OpenCV2.4.3+QtCreator2.5.1

 

  實驗基礎

  本實驗是參考小短文A super-simple skin detector in OpenCV,該文章里面首先直接給出了一個比較合理的橢圓,即該橢圓能夠代表大部分人的皮膚信息CrCb的分布。橢圓的分布如下:

  

  說它比較有趣是因為我們是用一副圖像來存儲上面的橢圓的,而不是直接采用橢圓數學方程。該圖像是二值圖像,即橢圓區域內部為白色,其它地方為黑色。所以當其需要判斷其它像素點時,只需將該像素點轉換成Cr,Cb兩個坐標,然后在上面的橢圓中找到該坐標的值,如果非0,則為皮膚,反之亦然。

  在實際代碼中,該橢圓是采用繪畫函數繪制到圖片上的,一句代碼而已:

ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);

  void ellipse(Mat& img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar&color, int thickness=1, int lineType=8, int shift=0)

  該函數是用來在指定圖片上繪制橢圓弧線的。

  參數image為需要繪制橢圓的圖像;

  參數center是該橢圓的中心點坐標;

  參數axes是該橢圓的長半軸和短半軸;

  參數angle是該橢圓和水平方向上的旋轉夾角;

  參數startAngle表示繪制橢圓弧線相對該橢圓自己的水平軸的起始角度;

  參數endAngel表示繪制橢圓弧線相對該橢圓自己的水平軸的終止角度;

  后面的參數比較普通就不介紹了。

  繪制橢圓曲線的示意圖如下所示:

  

 

 

  實驗結果

  檢測前的圖像:

  

 

  利用該算法進行皮膚檢測后的二值圖:

  

 

  實驗代碼及注釋

  main.cpp:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/contrib/contrib.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat input_image;
Mat output_mask;
Mat output_image;

void main()
{
    VideoCapture cam(0);
    if(!cam.isOpened())
        return;

    namedWindow("input image");
    namedWindow("output mask");
    namedWindow("output image");
    /*橢圓皮膚模型*/
    Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);
    ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);

    while(true) {
        cam >> input_image;
        if(input_image.empty())
            return ;

        Mat ycrcb_image;
        output_mask = Mat::zeros(input_image.size(), CV_8UC1);
        cvtColor(input_image, ycrcb_image, CV_BGR2YCrCb); //首先轉換成到YCrCb空間
        for(int i = 0; i < input_image.cols; i++)   //利用橢圓皮膚模型進行皮膚檢測
            for(int j = 0; j < input_image.rows; j++){
            Vec3b ycrcb = ycrcb_image.at<Vec3b>(j, i);
            if(skinCrCbHist.at<uchar>(ycrcb[1], ycrcb[2]) > 0)
                output_mask.at<uchar>(j, i) = 255;
        }
        input_image.copyTo(output_image, output_mask);

        imshow("input image", input_image);
        imshow("output mask", output_mask);
        imshow("output image", output_image);
        output_image.setTo(0);
        if(27 == waitKey(30))
            return;
    }
    return;
}

 

 

  實驗總結: 皮膚的橢圓模型確實可以用來做皮膚檢測,一旦確定好了該橢圓就可以用來做皮膚檢測了。

 

 

  參考文獻:

     A super-simple skin detector in OpenCV

     皮膚檢測與克服光線影響的連通域尋找

 http://docs.opencv.org/modules/core/doc/drawing_functions.html?highlight=ellipse#cv.Ellipse

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM