2

我仍在研究最后一个程序,虽然我终于找到了解决问题的方法(关于如何过滤最大轮廓),但我现在有一个新问题,或者说是一个问题。

如您所见,我正在使用 Canny 算法来搜索视频中的边缘。但是我将用于检测的对象没有特定的颜色,所以当对象的颜色与周围的颜色大致相同时(例如,如果对象是银色而背景是白色),对象的边缘会消失,我无法得到物体的轮廓。

现在我将测试 OpenCV 中可用的每个边缘过滤算法,但为了缩短我的工作,我需要你的帮助来推荐比 canny 最好的(或至少更好的)算法。现在我测试了Sobel,但结果并不比canny的好。如果可能,请将我链接到一些好的示例以供参考。

编码:

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;
    CvSeq* current_contour = contours;
    double largestArea = 0;
    CvSeq* largest_contour = NULL;
    while (current_contour != NULL){
        double area = fabs(cvContourArea(current_contour,CV_WHOLE_SEQ, false));       
        if(area > largestArea){
            largestArea = area;
            largest_contour = current_contour;
        }
        current_contour = current_contour->h_next;
    }

    cvMoments(largest_contour, &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&&m_00>=3000){
        printf("center point=(%.f, %.f), Area = %.f \n",gravityX,gravityY,m_00); }


    if(m_00>=3000){
        CvScalar color = CV_RGB(250,0,0);
        cvDrawContours(img,largest_contour,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);
}

...最后,期待已久的示例图片:

一、好的(我的黑钱包) 好的一个

二、故障(橙色框) 失败

最后,另一个失败(一个白盒子) 白色失败

PS,一些注意事项:

  • 对象没有特定的形状、颜色或大小,因此 IMO 最好的选择是找到对象的边缘,而不是通过颜色过滤它。
  • 我会握住物体,所以我的手指可能会导致物体的边缘发生变化或消失。
  • 我正在开发一个视频处理程序,所以处理时间越短,所需的处理能力越少越好。
  • 我的程序将过滤掉最大的轮廓并用红色填充它(见第一张图片)。

提前致谢。干杯

4

1 回答 1

1

你的问题不是边缘检测算法。您的问题是您正在对算法参数进行硬编码,并期望它能够神奇地适用于您扔给它的所有图像。此外,cvCanny无需在使用前对图像进行平滑处理,因为 Canny 运算符已经为您执行了平滑处理。

由于您现在想要实现的目标更加清晰,因此我可以提出一个建议:使用视频而不是单独查看每一帧。如果相机是固定的,而手拿着物体在移动,那么通过背景减法来检测形状是很简单的。如果相机没有固定,您仍然可以检测到手(PDF 链接)并从那里开始工作。此外,使用您可能拥有的任何其他特定于应用程序的知识(例如项目将在屏幕中间,手将在项目下方)。

于 2012-10-22T12:28:18.527 回答