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

Posted 铁杆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
}

结果如下:

 

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

 

以上是关于OpenCV——基于颜色的物体检测系统的主要内容,如果未能解决你的问题,请参考以下文章

opencv进阶-基于coco数据集训练好的模型,修改类别显示代码,实现自定义检测物体

Opencv颜色识别与追踪

用opencv做一个物品识别,请讲下基本思路。

opencv 头发识别

物体追踪实战:使用 OpenCV实现对指定颜色的物体追踪

怎样使用opencv识别数字和有限的英文字母以及字符的颜色