仅过滤出一个轮廓在OpenCV中C / C ++(Filter out only one conto

2019-08-01 10:10发布

我试图让一个程序来检测使用基于坎尼过滤器和轮廓的发现功能的摄像机/摄像头的任何形状的物体。 下面是我的程序:

int main( int argc, char** argv )
{
CvCapture *cam;
CvMoments moments;
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours = NULL;
CvSeq* contours2 = NULL;
CvPoint2D32f center;
int i;

cam=cvCaptureFromCAM(0);
if(cam==NULL){
    fprintf(stderr,"Cannot find any camera. \n");
    return -1;
}
while(1){
    IplImage *img=cvQueryFrame(cam);
    if(img==NULL){return -1;}
    IplImage *src_gray= cvCreateImage( cvSize(img->width,img->height), 8, 1);
    cvCvtColor( img, src_gray, CV_BGR2GRAY );
    cvSmooth( src_gray,  src_gray, CV_GAUSSIAN, 5, 11);
    cvCanny(src_gray, src_gray, 70, 200, 3);

    cvFindContours( src_gray, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(0,0));
    if(contours==NULL){ contours=contours2;}
    contours2=contours;
    cvMoments(contours, &moments, 1);

    double m_00 = cvGetSpatialMoment( &moments, 0, 0 );
    double m_10 = cvGetSpatialMoment( &moments, 1, 0 );
    double m_01 = cvGetSpatialMoment( &moments, 0, 1 );
    float gravityX = (m_10 / m_00)-150;
    float gravityY = (m_01 / m_00)-150;
    if(gravityY>=0&&gravityX>=0){
        printf("center point=(%.f, %.f) \n",gravityX,gravityY); }

    for (; contours != 0; contours = contours->h_next){
        CvScalar color = CV_RGB(250,0,0);
        cvDrawContours(img,contours,color,color,-1,-1, 8, cvPoint(0,0));
    }

    cvShowImage( "Input", img );
    cvShowImage( "Contours", src_gray );
    cvClearMemStorage(storage);
    if(cvWaitKey(33)>=0) break;
}
cvDestroyWindow("Contours");
cvDestroyWindow("Source");
cvReleaseCapture(&cam);
}

此程序将检测由照相机捕获的所有轮廓和轮廓的平均坐标将被打印。 我的问题是如何筛选出只有一个对象/轮廓,所以我可以得到更精确的(X,Y)的物体的位置 ? 如果可能的话,任何人都可以告诉我如何标记对象的使用中心(X,Y)坐标

提前致谢。 干杯

P / S:很抱歉我不能上传截图还,但如果有什么帮助,这里的链接 。

编辑:为了使我的问题更加清晰:

  • 例如,如果我只想要过滤出从上面我的截图广场,我该怎么办?
  • 我想筛选出的对象具有最大的轮廓区域,最重要的形状(任意形状),而不是一个直线或曲线
  • 我仍然与光滑和精明的试验值,所以如果有人有使用我的程序,请更改值检测轮廓的问题。

Answer 1:

我认为它可以解决相当容易的。 我建议轮廓检测之前的一些形态学操作。 另外,我建议过滤“出”更小的元素,并且在图像中获得最大的元素作为唯一一个仍在。

我建议:

  • 用于滤除线路 (直线或曲线):你必须决定什么你自己考虑一个“行”和“形”之间的边界。 比方说,你考虑的厚度为5像素以上的所有对象是对象,而小于5个像素的那些对面是线。 使用5×5正方形的形态开或3像素尺寸的金刚石的形状的结构化元素将采取的订单。

  • 对于一般的过滤掉小物件 :如果对象是任意形状的,纯粹的形态开不会做:你必须做一个代数开幕 。 一种特殊类型的代数的开孔是一个区域开口:即删除具有(像素)区域小于给定阈值的图像中的所有连接的组件的操作。 如果您对无趣的对象的大小,或对有趣的尺寸下限 上限 ,该值应作为阈值。 你也许可以得到一个大形态开一个类似的效果,但它不会那么灵活。

  • 用于滤除除了最大所有对象 :这听起来像从最小的到最大的一个应该努力消除连接组件。 尝试标记所连接的部件 。 上的二进制(黑白图像),该图像变换的工作方式是创建一个灰度图像,标记的背景为0(黑色),并用不同的各成分,增加灰度值。 在结束时,每个目标的象素是由一个不同的值标记。 现在,您可以简单地看一下灰度直方图,并找到具有最多像素的灰度值。 设置所有的其它灰度级为0(黑色),和左图像中的唯一目的是最大的一个。

该建议是从最简单的写入到最复杂的。 不过,我认为的OpenCV可以帮助任何这些。 形态学腐蚀,膨胀,开启和关闭在OpenCV的实现。 我想你可能需要构建你自己的代数开放运营商(或结合OpenCV的基本形态播放),但我敢肯定的OpenCV可以帮助您与两种标记的连接组件和分析所显示的灰度图像的直方图。

最后,从一个对象只像素离开的时候,你做的坎尼轮廓检测。



Answer 2:

这是一个blob处理问题,即不能由自身的OpenCV(容易)解决。 看一看cvBlobsLib。 该库是具有用于连通分量标记功能/类延伸的OpenCV。

http://opencv.willowgarage.com/wiki/cvBlobsLib



文章来源: Filter out only one contour in OpenCV C/C++