使用 OpenCV 的边界框

Posted

技术标签:

【中文标题】使用 OpenCV 的边界框【英文标题】:Bounding box using OpenCV 【发布时间】:2010-09-08 15:57:19 【问题描述】:

我想使用 opencv BoundingRect 在白色背景上获得一个实心黑色圆圈的边界框。我使用了来自http://cgi.cse.unsw.edu.au/~cs4411/wiki/index.php?title=OpenCV_Guide#Finding_bounding_boxes_around_regions_of_a_binary_image 的示例代码,但未能获取边界框的属性并将其绘制到图像中。我认为应该是一个简单的问题,但我仍然失败了......

如果你能写一些示例代码就好了。

谢谢。


我现在使用的图片是 1392x1040 像素的图像,中间有一个黑色的大圆圈(直径大约 1000 像素),图像的其余部分是白色的。

我的源代码是:

#include <iostream>
#include <vector>
#include <cv.h>
#include <highgui.h>

using namespace std;

int main(int argc, char** argv)


IplImage* img_in = cvLoadImage("Schwarzer_Kreis.png",1);


IplImage* img_working = cvCreateImage(cvGetSize(img_in), 8, 1);
cvCvtColor(img_in, img_working, CV_BGR2GRAY);

CvSeq* seq;

vector<CvRect> boxes;

CvMemStorage* storage = cvCreateMemStorage(0);
cvClearMemStorage(storage);

cvFindContours(img_working, storage, &seq, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(600,200));

CvRect boundbox ;

for(; seq; seq = seq->h_next) 
 boundbox = cvBoundingRect(seq);
 boxes.push_back(boundbox);


for (int ii=0; ii<boxes.size(); ii++) 
cout << boxes[ii].x << endl;
cout << boxes[ii].y << endl;
cout << boxes[ii].width << endl;
cout << boxes[ii].height << endl;



cvWaitKey(0);

return 0;



我从程序中得到的输出是:

601

201

1390

1038

【问题讨论】:

发布你的代码 - 这样这里的人可以帮助你让它工作。还要更详细地描述问题 - 特别是它是如何失败的。 您的问题中有一个死链接。 【参考方案1】:

此代码使用 OpenCV 2.1“findContours”和“boundingRect”的函数来获取二值化图像 (0-255) 的边界框,该边界框绘制在边界框上。通过计算最大区域形状周围的边界框来避免噪音。

更多信息http://www.davidlopez.es/?p=65

// Declares a vector of vectors for store the contours
vector<vector<Point> > v;

Mat originalimage;
Mat image;

// Loads the original image
originalimage = imread("original.ppm");
// Converts original image to an 8UC1 image
cvtColor(originalimage, image, CV_BGR2GRAY);

// Finds contours
findContours(image,v,CV_RETR_LIST,CV_CHAIN_APPROX_NONE);

// Finds the contour with the largest area
int area = 0;
int idx;
for(int i=0; i<v.size();i++) 
    if(area < v[i].size())
        idx = i; 


// Calculates the bounding rect of the largest area contour
Rect rect = boundingRect(v[idx]);
Point pt1, pt2;
pt1.x = rect.x;
pt1.y = rect.y;
pt2.x = rect.x + rect.width;
pt2.y = rect.y + rect.height;
// Draws the rect in the original image and show it
rectangle(originalimage, pt1, pt2, CV_RGB(255,0,0), 1);

cvNamedWindow( "Ejemplo", CV_WINDOW_AUTOSIZE );
imshow("Ejemplo", originalimage );
cvWaitKey(0);

cvDestroyWindow("Ejemplo" );

【讨论】:

您在检查area &lt; v[i].size()if 语句中是否缺少area = v[i].size(); -1。在循环中找到最大面积,你在哪里计算轮廓的面积?【参考方案2】:

我自己编写了计算边界框的代码:

int* get_boundingbox(
        IplImage* img_input)

int width     = img_input->width;
int height    = img_input->height;

int* Output = NULL;
Output = new int[4];


//----- Top boundary -----
for(int ii = 0 ; ii < height ; ii++ )

    int value;

    for(int jj = 0 ; jj < width ; jj++ ) 

        value = static_cast<int>(cvGetReal2D(img_input,1039-ii,jj));

        if (value == 0) 
            Output[1] = 1039-ii; // upper left corner, y-value
            break;
      
    if (value == 0) break;
    



//----- Left boundary -----
for(int ii = 0 ; ii < width ; ii++ )

    int value;

    for(int jj = 0 ; jj < height ; jj++ ) 

        value = static_cast<int>(cvGetReal2D(img_input,jj,1391-ii));

        if (value == 0) 
            Output[0] = 1391-ii; //upper left corner. x-value
            break;
      
    if (value == 0) break;
    



//----- Right boundary -----
for(int ii = 0 ; ii < width ; ii++ )

    int value;

    for(int jj = 0 ; jj < height ; jj++ ) 

        value = static_cast<int>(cvGetReal2D(img_input,jj,ii));

        if (value == 0) 
            Output[2] = ii+1; // lower right corner, x-value
            break;
      
    if (value == 0) break;
    



//----- Bottom boundary -----
for(int ii = 0 ; ii < height ; ii++ )

    int value;

    for(int jj = 0 ; jj < width ; jj++ ) 

        value = static_cast<int>(cvGetReal2D(img_input,ii,jj));

        if (value == 0) 
            Output[3] = ii+1; // lower right corner, y-value
            break;
      
    if (value == 0) break;
    



Output[2] = Output[2] - Output[0] + 1; // width
Output[3] = Output[3] - Output[1] + 1; // height

return Output;
delete []Output;


【讨论】:

【参考方案3】:

你可以用

boundingRect=cvBoundingRect(seq,0); 
cvRectangle(contourImage,cvPoint(boundingRect.x,boundingRect.y),
                    cvPoint(boundingRect.x+boundingRect.width,
                    boundingRect.y+boundingRect.height),
                    _GREEN,1,8,0);

【讨论】:

我试过这段代码,但工作程序给了我一个错误。然后我把你的示例代码从程序中取出,它工作了。我使用 cvShowImage 给出结果,当给出轮廓图像时,我得到了一张非常奇怪的图片。整个画面是黑色的,只有一部分圆圈边缘被涂成白色......我认为程序应该找到整个圆圈,但实际上它现在没有这样做。 @supergranu:因为 seq 中的这些点来自 cvFindContours,它为您提供连接组件的边缘。因此,您将圆形边缘涂成白色。【参考方案4】:

您可以考虑拍摄您拥有的图像的底片(圆圈是黑色背景上的白色),然后尝试您的代码。命令是 cvNot(src, dst)。

某些 OpenCV 函数要求背景为黑色。

【讨论】:

以上是关于使用 OpenCV 的边界框的主要内容,如果未能解决你的问题,请参考以下文章

Python - opencv 在 Canny 边缘图像周围绘制边界框

Python 和 OpenCV:如何裁剪半成形的边界框

opencv-python:为啥检测到不正确的边界框(几个边界框)?

带有opencv的手写数字边界框

聚类边界框并在其上画线(OpenCV,Python)

如何在python opencv中简单地裁剪边界框[重复]