OpenCV——基於顏色的物體檢測系統


這次區別於證件照,我試着編寫了一下在復雜背景下分離純色物體的系統,因為只是簡單的編程,所以結果有待優化,先分析一下實驗環境:

這次的背景雜亂,雖然主體是粉色主導,但是因為光照不統一,色域跨度較大,倒影中也有粉色痕跡,杯壁上有花紋,這種情況下邊緣檢測誤差很大。

為了讓計算機更好的識別主體顏色,要先將RGB色域轉換為HSV色域,在HSV色域中,紅色的H值在(0,3)U(156,180)中。粉色的S值飽和度不高,但是比白色要高很多,區間在(50,150)以內。

V代表Value,只有黑色或偏黑的顏色V值會偏低,這里我們只要設定一個稍高的閾值就可以了。

第一步是大體分離出主體部分,滿足條件的顏色區域會被標記為白色(255)其余為黑色(0):

左邊這張圖是Hue單通道的檢測,因為在Opencv中,Hue通道的取值范圍是0-180,紅色在180左右的位置,所以發白,而杯體其他部分的紅色較深,集中在0-5內,所以顯示為黑色。

將兩個區域相並,並加上對value與Saturation的限制,右圖既是HSVmask的結果。

void ToHSV(cv::Mat image, cv::Mat result)  //產出是一個mask
{
    cv::Mat hsv_image;        //轉HSV
    hsv_image.create(image.size(), image.type());
    cv::cvtColor(image, hsv_image, CV_BGR2HSV);

    vector<cv::Mat> channels;
    cv::split(hsv_image, channels);


    int num_row = image.rows;
    int num_col = image.cols;

    for (int r = 0; r < num_row; r++)
    {
        const cv::Vec3b* curr_r_image = image.ptr<const cv::Vec3b>(r);
        const uchar* curr_r_hue = channels[0].ptr<const uchar>(r);
        const uchar* curr_r_satur = channels[1].ptr<const uchar>(r);
        const uchar* curr_r_value = channels[2].ptr<const uchar>(r);
        uchar* curr_r_result = result.ptr<uchar>(r);
        for (int c = 0; c < num_col; c++)
        {
            if (((curr_r_hue[c] <= 2 && curr_r_hue[c] >= 0) || (curr_r_hue[c] <= 180 && curr_r_hue[c] >= 150)) && curr_r_value[c]>130 && curr_r_satur[c]>35 && curr_r_satur[c]<150) //找顏色
            {
                curr_r_result[c] = 255;
            }
            else
            {
                curr_r_result[c] = 0;
            }

        }
    }
}

這個方法中,參數第一個為3通道RGB圖像,第二個參數為單通道的灰度二值圖像。

因為這個mask還有一些瑕疵,為了去除這部分瑕疵我們需要使用形態學濾波器:

void Homography(cv::Mat image, cv::Mat Opened) //mask
{
    cv::Mat element_9(9, 9, CV_8U, cv::Scalar(1));
    cv::morphologyEx(image, Opened, cv::MORPH_OPEN, element_9);
}

形態學濾波只針對二值圖像,因此輸入輸出都是二值圖像,structure element為9X9,意味着長寬不足9的像素塊會被抹去,結果如下:

將mask運用到原圖像上:

void copymask(cv::Mat image, cv::Mat openmask, cv::Mat result)
{
    int num_row = image.rows;
    int num_col = image.cols;
    for (int r = 0; r < num_row; r++)
    {
        uchar* curr_r_open = openmask.ptr<uchar>(r);
        cv::Vec3b* curr_r_image = image.ptr<cv::Vec3b>(r);
        cv::Vec3b* curr_r_result = result.ptr<cv::Vec3b>(r);
        for (int c = 0; c < num_col; c++)
        {
            if (curr_r_open[c] ==255)
            {
                curr_r_result[c] = curr_r_image[c];
            }

        }
    }
}

結果如下:

可以看到損失了一部分,損失的這部分就是原圖中的高光區域,這些區域的顏色因為光的照射變為白色,不好從顏色上區分,也是這種方法的一個盲點。

還有一種區分的辦法為邊緣檢測,在OpenCV中,邊緣檢測極易實現,但是圖片背景過於復雜的話則會產生許多干擾:

void edgedetection(cv::Mat image, cv::Mat edge)
{
    cv::morphologyEx(image, edge, cv::MORPH_GRADIENT, cv::Mat());
    int threshold =240;
    cv::threshold(edge, edge, threshold, 255, cv::THRESH_BINARY);
}

結果如下:

 

 可以看到被子的倒影對於邊緣檢測產生了很大的影響,若杯體本身跟后邊背景的顏色差異不大的話,也很難被檢測到。

 


免責聲明!

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



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