码迷,mamicode.com
首页 > 其他好文 > 详细

OpenCV——基于颜色的物体检测系统

时间:2016-10-03 19:18:02      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:

这次区别于证件照,我试着编写了一下在复杂背景下分离纯色物体的系统,因为只是简单的编程,所以结果有待优化,先分析一下实验环境:

技术分享

这次的背景杂乱,虽然主体是粉色主导,但是因为光照不统一,色域跨度较大,倒影中也有粉色痕迹,杯壁上有花纹,这种情况下边缘检测误差很大。

为了让计算机更好的识别主体颜色,要先将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);
}

结果如下:

技术分享

 

 可以看到被子的倒影对于边缘检测产生了很大的影响,若杯体本身跟后边背景的颜色差异不大的话,也很难被检测到。

 

OpenCV——基于颜色的物体检测系统

标签:

原文地址:http://www.cnblogs.com/wangxinyu0628/p/5928824.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!