【问题标题】:Multiple color object detection using OpenCV使用 OpenCV 进行多颜色对象检测
【发布时间】:2013-05-05 17:46:50
【问题描述】:

我正在尝试检测下图中红墙和白色方块的图像中的位置,即两堵带有红色顶部和白色“柱子”的白墙:

我的方法是进行阈值化以找到我现在可以从该输出中轻松检测到的红墙:

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

任何帮助将不胜感激。

【问题讨论】:

  • 好吧,白人在红军中间,不是吗?去吧。寻找红色之间的白色。或者搜索红色之间的间隙,检查是否为白色。
  • @AnderBiguri 听起来不错,我仍然对如何在 OpenCV 中实现这一点一无所知
  • 您共享的阈值图像不是处理该输入图像的结果。他们不匹配:)
  • @karlphillip 是的,很抱歉,我使用的是手持相机,当我更改代码以显示它移动的红色阈值图像时。让我看看我能不能让它更居中。
  • @salgarcia 我用 C++ 编写了一个愚蠢的想法来帮助您开始真正的解决方案。欢迎大家投票:)

标签: c++ c opencv image-processing computer-vision


【解决方案1】:

一种方法在于用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 来检索阈值图像的轮廓,以便能够为它们创建边界框,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);  

输出

上图中显示的所有矩形都作为cv::Rect 对象存储在boundRect 向量中。每个 rectangle 由 2 个相对的 cv::Point 对象组成,因此我们迭代此向量以创建一个仅由 cv::Point 对象组成的新向量:

// 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();

寻找白色方块的逻辑是:假设25x25距离内的2个像素定义一个白色方块:

// 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();

输出

这个算法非常原始,错过了底部的 2 个白色方块,因为它们下面没有红墙,只有它们上面。

所以我让你来改进这种方法:)

祝你好运。

【讨论】:

    【解决方案2】:

    场景中的所有重要信息似乎都在提取的红条的二值化图片中。我会尝试忽略这一步的原始图片,只使用矩形的几何形状来找到它们之间的区域。

    例如,您可以调用 findContours 来获取示例图片中的 8 个 blob。如果您检查它们的质心之间的线上的点,则向 pointPolygonTest 返回最小值的点是其中一个白点的中心点(或至少接近)。

    您可以使用有关场景的已知信息以及您将遇到的图像。例如,您可以将轮廓分组为“左”和“右”条,并且只在某些轮廓之间进行线搜索。但是,如果您需要更加不可知论。您的输入,您从阈值图片中导出或多或少的所有内容(场景方向、墙的数量、矩形的厚度......)应该是很有可能的。

    【讨论】:

      猜你喜欢
      • 2021-08-29
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多