使用OpenCV进行多颜色对象检测 [英] Multiple color object detection using OpenCV

查看:648
本文介绍了使用OpenCV进行多颜色对象检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试检测图片中红色墙壁和白色正方形的位置,如下图所示,这两个白色墙壁有红色的上衣和白色的贴子:



>



我的方法是做阈值以找到红色的墙壁,我现在可以从这个输出轻松检测:





现在我的问题是检测白色方块的位置,但是这更难考虑白色墙壁。如果我基于白色的阈值仍然保留白色方形柱子之间不需要的白色墙壁。



任何帮助将非常感激。

解决方案

一种方法包含使用 cv :: inRange ()

  cv :: Mat image = cv :: imread(argv [1]) ; 
if(image.empty())
{
std :: cout< !!! Failed imread()<< std :: endl;
return -1;
}

cv :: Mat red_image;
cv :: inRange(image,cv :: Scalar(40,0,180),cv :: Scalar(135,110,255),red_image);
//cv::imwrite(\"out1.png,red_image);

输出



>



使用 cv :: findContours 检索阈值化图像的轮廓,以便能够为它们创建边界框,由两个相对的 cv :: Point 对象,所以我们在这个向量上迭代创建一个由 cv :: Point 对象组成的新向量:

  //两个相对的cv :: Point可以用来绘制一个矩形。 
//在cv :: Rect向量上迭代并检索所有cv :: Point
//并将它们存储在cv :: Point向量中。
std :: vector< cv :: Point> rect_points;
for(int i = 0; i {
rect_points.push_back(boundRect [i] .tl());
rect_points.push_back(boundRect [i] .br());
}

// cv :: Mat drawing = cv :: Mat :: zeros(red_image.size(),CV_8UC3);
cv :: Mat drawing = image.clone();

找到白色方块的逻辑是:假设彼此25x25距离内的2个像素定义白色正方形:

  //当2点小于25x25像素时绘制矩形
//距离每个其他
for(int i = 0; i {
for(int j = 0; j< rect_points.size(); j ++)
{
if(i == j)
continue;

int x_distance =(rect_points [i] .x - rect_points [j] .x);
if(x_distance <0)
x_distance * = -1;

int y_distance =(rect_points [i] .y - rect_points [j] .y);
if(y_distance< 0)
y_distance * = -1;

if((x_distance< 25)&&(y_distance< 25))
{
std :: cout< 绘制矩形<< i<< from
<< rect_points [i]< to<< rect_points [j]
<< distance:< x_distance<< x< y_distance<< std :: endl;

cv :: rectangle(drawing,
rect_points [i],
rect_points [j],
cv :: Scalar(255,50,0),
2);
break;
}
}

}

//cv::imwrite(\"out3.png,drawing);
cv :: imshow(white rectangularangles,drawing);
cv :: waitKey();

输出



>



此演算法是非常原始的,错过了底部的2个白色正方形,因为它们下面没有红色的墙壁,只有它们之上。



所以我留给你来改善这个方法:)



祝你好运。


I am attempting to detect the position in the image of both the red walls and the white squares in the picture below of two white wall with red tops and white "posts":

My approach was to do thresholding to find the red walls which I can now easily detect from this output:

Now my problem is detecting the locations of the white squares, but this is more difficult considering the white walls. If I threshold based on white I still retain the undesired white walls in between the white square posts.

Any help would be greatly appreciated.

解决方案

One approach consists in thresholding the input image with cv::inRange():

cv::Mat image = cv::imread(argv[1]);
if (image.empty())
{
    std::cout << "!!! Failed imread()" << std::endl;
    return -1;
}

cv::Mat red_image;
cv::inRange(image, cv::Scalar(40, 0, 180), cv::Scalar(135, 110, 255), red_image);
//cv::imwrite("out1.png", red_image);

Outputs:

We can use cv::findContours to retrieve the contours of the thresholded image to be able to create bounding boxes for them, which is a technique described here:

std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours( red_image, 
                  contours, 
                  hierarchy, 
                  CV_RETR_TREE, 
                  CV_CHAIN_APPROX_SIMPLE, 
                  cv::Point(0, 0) );

std::vector<std::vector<cv::Point> > contours_poly( contours.size() );
std::vector<cv::Rect> boundRect( contours.size() );
for( int i = 0; i < contours.size(); i++ )
    { 
        cv::approxPolyDP( cv::Mat(contours[i]), contours_poly[i], 3, true );
        boundRect[i] = cv::boundingRect( cv::Mat(contours_poly[i]) );
    }   


// Debug purposes: draw bonding rects
//cv::Mat tmp = cv::Mat::zeros( red_image.size(), CV_8UC3 );
//for( int i = 0; i< contours.size(); i++ )
//  rectangle( tmp, boundRect[i].tl(), boundRect[i].br(), cv::Scalar(0, 255, 0), 2, 8, 0 );
//cv::imwrite("out2.png", tmp);  

Output:

All the rectangles displayed in the image above are stored as cv::Rect object inside the boundRect vector. Each rectangle is made of 2 opposite cv::Point objects, so we iterate on this vector to create a new vector made up of cv::Point objects only:

// Two opposite cv::Point can be used to draw a rectangle.
// Iterate on the cv::Rect vector and retrieve all cv::Point 
// and store them in a cv::Point vector.
std::vector<cv::Point> rect_points; 
for( int i = 0; i < contours.size(); i++ )
{
    rect_points.push_back(boundRect[i].tl());
    rect_points.push_back(boundRect[i].br());
}

//cv::Mat drawing = cv::Mat::zeros( red_image.size(), CV_8UC3 );
cv::Mat drawing = image.clone();

The logic to find the white squares is: assume that 2 pixels within 25x25 distance of each other define a white square:

// Draw a rectangle when 2 points are less than 25x25 pixels of 
// distance from each other
for( int i = 0; i < rect_points.size(); i++ )
{
    for( int j = 0; j < rect_points.size(); j++ )
    {
        if (i == j) 
            continue;

        int x_distance = (rect_points[i].x - rect_points[j].x);
        if (x_distance < 0) 
            x_distance *= -1;

        int y_distance = (rect_points[i].y - rect_points[j].y);
        if (y_distance < 0) 
            y_distance *= -1;

        if ( (x_distance < 25) && (y_distance < 25) )
        {
            std::cout << "Drawing rectangle " << i << " from " 
                      << rect_points[i] << " to " << rect_points[j] 
                      << " distance: " << x_distance << "x" << y_distance << std::endl;

            cv::rectangle( drawing, 
                           rect_points[i], 
                           rect_points[j], 
                           cv::Scalar(255, 50, 0), 
                           2 );
            break;
        }
    }

}

    //cv::imwrite("out3.png", drawing);
cv::imshow("white rectangles", drawing);    
cv::waitKey();

Output:

This algorithm is pretty raw and misses the 2 white squares at the bottom because there are no red walls below them, only above them.

So I leave it up to you to improve this approach :)

Good luck.

这篇关于使用OpenCV进行多颜色对象检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆