如何防止我的物体检测程序检测到不同大小的多个物体?

时间:2014-08-31 21:44:29

标签: opencv image-processing computer-vision

所以,这是我的情况。我创建了一个基于颜色对象检测的对象检测程序。我的程序检测到红色,它完美地运行。但这是我面临的问题: -

每当周围有多个红色物体时,我的程序会检测到它们,并且当时它无法真正跟踪一个物体(即它会跟踪背景中其他各种尺寸的红色物体。它显示错误& #34;背景噪音太大"。正如你在'"阈值图像"附加中看到的那样,它会检测到圆形物体(这是我的追踪物体)和我的红色帽子我希望我的程序只检测我的跟踪对象("这是一个圆形的可乐帽")。我怎样才能实现这一目标?请帮助我。我在几天内参加我的工程设计竞赛我必须在我的讲师面前演示我的程序。我的程序应该只能检测和跟踪我想要的对象。谢谢

我的objectdetection程序代码有点长。因此,我在此解释如下代码 - 我从网络摄像头帧捕获了一帧 - 将其转换为HSV-使用的HSV Inrange过滤器,以过滤掉其他颜色,但在过滤后的图像上进行红色应用的形态学操作。这一切都在我的主要功能

我的网络摄像头框架的帧分辨率为1280 * 720。它有点减慢我的程序,但这是我必须做的权衡,以执行手势控制操作。无论如何这里是我的drawobjectfunction和trackfilteredobjectfunction。

int H_MIN = 0;
int H_MAX = 256;
int S_MIN = 0;
int S_MAX = 256;
int V_MIN = 0;
int V_MAX = 256;
//default capture width and height
const int FRAME_WIDTH = 1280;
const int FRAME_HEIGHT = 720;
//max number of objects to be detected in frame
const int MAX_NUM_OBJECTS=50;
//minimum and maximum object area
const int MIN_OBJECT_AREA = 20*20;
const int MAX_OBJECT_AREA = FRAME_HEIGHT*FRAME_WIDTH/1.5;


void drawObject(int x, int y,Mat &frame){

circle(frame,Point(x,y),20,Scalar(0,255,0),2);
    if(y-25>0)
    line(frame,Point(x,y),Point(x,y-25),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(x,0),Scalar(0,255,0),2);
    if(y+25<FRAME_HEIGHT)
    line(frame,Point(x,y),Point(x,y+25),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(x,FRAME_HEIGHT),Scalar(0,255,0),2);
    if(x-25>0)
    line(frame,Point(x,y),Point(x-25,y),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(0,y),Scalar(0,255,0),2);
    if(x+25<FRAME_WIDTH)
    line(frame,Point(x,y),Point(x+25,y),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(FRAME_WIDTH,y),Scalar(0,255,0),2);

    putText(frame,intToString(x)+","+intToString(y),Point(x,y+30),1,1,Scalar(0,255,0),2);

}



void trackFilteredObject(int &x, int &y, Mat threshold, Mat &cameraFeed){

    Mat temp;
    threshold.copyTo(temp);
    //these two vectors needed for output of findContours
    vector< vector<Point> > contours;
    vector<Vec4i> hierarchy;
    //find contours of filtered image using openCV findContours function
    findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );
    //use moments method to find our filtered object
    double refArea = 0;
    bool objectFound = false;
    if (hierarchy.size() > 0) {
        int numObjects = hierarchy.size();
        //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
        if(numObjects<MAX_NUM_OBJECTS){
            for (int index = 0; index >= 0; index = hierarchy[index][0]) {

                Moments moment = moments((cv::Mat)contours[index]);
                double area = moment.m00;

                //if the area is less than 20 px by 20px then it is probably just noise
                //if the area is the same as the 3/2 of the image size, probably just a bad filter
                //we only want the object with the largest area so we safe a reference area each
                //iteration and compare it to the area in the next iteration.
                if(area>MIN_OBJECT_AREA && area<MAX_OBJECT_AREA && area>refArea){
                    x = moment.m10/area;
                    y = moment.m01/area;
                    objectFound = true;
                    refArea = area;
                }else objectFound = false;


            }
            //let user know you found an object
            if(objectFound ==true){
                putText(cameraFeed,"Tracking Object",Point(0,50),2,1,Scalar(0,255,0),2);
                //draw object location on screen
                drawObject(x,y,cameraFeed);}

        }else putText(cameraFeed,"TOO MUCH NOISE! ADJUST FILTER",Point(0,50),1,2,Scalar(0,0,255),2);
    }
}

这是图像的链接;正如你所看到的,它还会检测背景中的红帽以及可乐瓶的红色帽子。

Sample image

我的观察: - 这就是我的想法,实现我想要的目标,即不检测未知大小的红色物体。我想我必须编辑我在上面的程序中声明的最大对象区域的值(const int MAX_OBJECT_AREA = FRAME_HEIGHT * FRAME_WIDTH / 1.5;)。我想我必须改变这个值,这可能会消除对更大的连续红色图像的检测。但是,还有另一个问题,一些物体的颜色并不是完全红色,而且它们有红色和其他颜色的斑块。因此,如果检测到的区域在我的程序中指定的范围内,那么我的程序也会检测到那些红色补丁。我的意思是说我穿的是混色的T恤,当我穿着那件T恤测试我的程序时,我的程序能够检测出其他颜色的红色。现在,我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

我认为您可以尝试以下程序:

  • 获得与您感兴趣的对象具有大致相同面积的圆形内核。您可以这样做: Mat kernel = getStructuringElement(MORPH_ELLIPSE,Size(d,d)); 其中d是磁盘的直径。
  • 使用此内核执行已过滤区域图像的归一化 - 互相关或卷积(我认为归一化 - 交叉相关会更好。并在内核周围添加一个空边框。)
  • 生成的图像的峰值应该为您提供过滤图像中圆形区域的位置(如果您使用的是标准化 - 互相关,则必须添加移位)。

为了加快速度,您可以降低分辨率执行此操作。

答案 1 :(得分:0)

您可以通过检测阈值图像中的圆圈来过滤掉非圆形形状。 OpenCV提供了一种使用Hough变换检测圆的内置方法,更多信息here。您可以利用此功能仅保留半径在给定范围内的圆圈。

另一种可能性是将connected component labeling(CCL)实施到您的演示程序中。 我相信它在OpenCV的版本2.x中被删除了,但是从维基百科页面可以直接实现双遍版本。 CCL将在阈值处理后为每个对象分配唯一ID 。然后,您必须在帧(T-1)处的对象和帧(T)中的对象之间实现匹配(例如,基于某些最近距离标准)并且可能轨迹过滤或平滑,但这肯定会给你一些额外的分数。