如何在JavaCV中获取区域的大小

时间:2012-06-26 16:41:18

标签: image-processing opencv javacv

在我的项目中,我希望从特定颜色的最大均匀区域获得大小(在我的示例中,它是蓝天)。

我的第一个想法是转换原始图像:

original image

到二进制图像,检测天空颜色并使用此区域创建遮罩: mask image

但是如何获得这些白色像素的大小和位置?我想要一种有效的方法,如果图片在图片的上1/3处有蓝天,则表示正确。 有任何想法吗?我应该创建一个“全局掩码”(参见注释中的图像3)并将其与二进制图片进行比较吗?或者有更简单的方法吗?

谢谢。

1 个答案:

答案 0 :(得分:6)

算法如下:

  1. 将输入图像转换为YCbCr color space,这样可以检测蓝色(以及红色): YCrCb image 要将某些图像转换为另一个颜色空间,请使用cvtColor
  2. 从中提取蓝色通道: Blue image 使用函数extractChannel来提取所需的频道。
  3. 检测蓝色最大值 [0-255] 的区域。我使用函数minMaxIdx,然后在 0.8 (这是阈值)上乘以最大值。您可以使用更复杂的方法,如直方图分析。
  4. 制作蓝色面具: binary 为此,我使用了threshold函数,并在步骤3中计算了阈值(作为参数)。
  5. 找到面具中的所有蓝色轮廓。在OpenCV中,它很简单 - 只需使用findContours
  6. 最后,检测最大方块的轮廓并找到其坐标(中心)。要计算具有最大方形的轮廓,您可以使用函数contourArea
  7. 除了 1-4 步骤,您还可以将图片转换为HSV并使用inRange检测蓝色。

    这是我的c ++命令:

    Mat inMat = imread("input.jpg"), blueMat, threshMat;
    
    cvtColor(inMat, blueMat, CV_BGR2YCrCb);//convert to YCrCb color space
    
    extractChannel(blueMat, blueMat, 2);//get blue channel
    
    //find max value of blue color
    //or you can use histograms
    //or more complex mathod
    double blueMax;
    minMaxIdx(blueMat, 0, &blueMax);
    
    blueMax *= 0.8;
    //make binary mask
    threshold(blueMat, threshMat, blueMax, 255, THRESH_BINARY);
    
    //finding all blue contours:
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(blueMat, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    
    double maxSquare = 0;
    vector<Point> maxContour;
    //finding contours with biggest square:
    for (size_t i=0; i<contours.size(); i++)
    {
        double square = contourArea(contours[i]);
        if (square > maxSquare)
        {
            maxContour = contours[i];
            maxSquare = square;
        }
    }
    
    //output results:
    Point center = centerPolygon(maxContour);
    cout << "square = " << maxSquare << endl;
    cout << "position: x: " << center.x << ", y: " << center.y << endl;
    

    这是centerPolygon函数:

    Point centerPolygon(const vector<Point>& points)
    {
        int x=0, y=0;
    
        for (size_t i=0; i<points.size(); i++)
        {
            x += points[i].x;
            y += points[i].y;
        }
    
        return Point(x/points.size(), y/points.size());
    }
    

    程序的输出是下一个:

    square = 263525
    position: x: 318, y: 208
    

    您可以将此代码转换为JavaCV - 请参阅this tutorial