机器人视觉—以箱子为目标的跟踪检测

来源:互联网 发布:python lxml etree 编辑:程序博客网 时间:2024/05/16 05:48

这是我在CSDN上第一次尝试写文章,有点兴奋,有点紧张。
那就正式开始吧。以下,enjoy:

要解决的问题

地面可移动机器人的车体摄像头捕捉一个方形箱子,类似于我们平时见到的大一点的快递箱子。我需要做的工作是在识别这个箱子并在视频中跟踪检测这个箱子。
待检测的某帧图像

解决问题的思路

1.图像经过均值滤波处理和Canny边缘检测之后,箱子是一个白色的矩形。所以我只要把这个白色矩形找到就可以了。
处理后得到的灰度图
但是问题来了,我怎么判断这个箱子在图像的哪个位置呢?毕竟图像中白色闭合矩形可能不止一个。
2.第一帧图像需要人眼识别箱子并在箱子所在区域点击一个小红点,大概确定了箱子的位置。往后判断出箱子矩形区域后,取中心点坐标作为下一帧图像的箱子区域坐标判断起点。
小红点确定箱子大概位置

算法实现

先贴上代码,备注比较详细,应该容易看懂,对于不熟悉Opencv相关函数的同学,百度一下也就懂了。

#include <iostream>#include <stdio.h>#include <math.h>#include <cstdlib> #include "cv.h"                              #include "cvaux.h"  #include "cxcore.h"  #include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>using namespace cv;using namespace std;//定义全局变量Mat img,tmp,img1;static Point pre_pt = (-1,-1);//初始坐标  static Point cur_pt = (-1,-1);//实时坐标  static Point avg_pt = (-1,-1);//鼠标响应函数void on_mouse(int event,int x,int y,int flags,void *ustc)//event鼠标事件代号,x,y鼠标坐标,flags拖拽和键盘操作的代号  {      char pre_temp[16],cur_temp[16];    if (event == CV_EVENT_LBUTTONDOWN)//左键按下,读取初始坐标,并在图像上该点处划圆      {           img1.copyTo(img);        sprintf_s(pre_temp,"(%d,%d)",x,y);         pre_pt = Point(x,y);          putText(img,pre_temp,pre_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255),1,8);//在窗口上显示坐标          circle(img,pre_pt,2,Scalar(0,0,255),CV_FILLED,CV_AA,0);//划圆          imshow("image",img);      }      else if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))//左键按下时,鼠标移动,则在图像上划矩形      {           img1.copyTo(tmp);        sprintf_s(cur_temp,"(%d,%d)",x,y);         cur_pt = Point(x,y);          putText(tmp,cur_temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));          rectangle(tmp,pre_pt,cur_pt,Scalar(0,0,255),1,8,0);//在临时图像上实时显示鼠标拖动时形成的矩形          imshow("image",tmp);      }      else if (event == CV_EVENT_LBUTTONUP)//左键松开,将在图像上划矩形      {           sprintf_s(cur_temp,"(%d,%d)",x,y);         cur_pt = Point(x,y);          putText(img,cur_temp,cur_pt,FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,0,255));          rectangle(img,pre_pt,cur_pt,Scalar(0,0,255),1,8,0);//根据初始点和结束点,将矩形画到img上          imshow("image",img);        }  } int main(void){    Mat dst,edge,image;    int k=1;    int xflag,yflag;    //导入视频    VideoCapture capture("CarCamera.avi");    if (!capture.isOpened())    {       cout << "ERRO:cannot open the video"<<endl;        return -1;    }    double rate= capture.get(CV_CAP_PROP_FPS);      bool stop(false);      int delay= int(1000/rate);      while(!stop)    {        //逐帧导入图片         if (!capture.read(image))           {  cout<<"ERRO: cannot open the image"<<endl;            return -1;            break;          }         //处理第一帧,等待人眼找出箱子大致位置         //框出箱子大概位置,保证方框中心点落在箱子上,按下任意键继续         //或者在箱子上点击一个点,按下任意键继续         if(k==1)         {           image.copyTo(img1);           namedWindow("image");           imshow("image",image);           setMouseCallback("image",on_mouse,0);           waitKey(0);            k++;         }        //均值滤波和Canny边缘检测        blur( image,edge,Size(4,4));         Canny(edge,dst,150,100);        //逐帧判断箱子位置        Point temp_pt;        avg_pt.x=int(ceil(double(((pre_pt.x+cur_pt.x)/2))));//找出中心坐标点        avg_pt.y=int(ceil(double(((pre_pt.y+cur_pt.y)/2))));        temp_pt=avg_pt;        xflag=yflag=10;        while(dst.at<uchar>(temp_pt)!=255)//找到箱子边缘线        {            temp_pt.x--;        }        if(abs(pre_pt.x-temp_pt.x)<xflag)//前后两帧箱子区域差别不会太大,防止出现白色矩形没有封闭的特殊情况           pre_pt.x=temp_pt.x;        temp_pt.x=avg_pt.x;        while(dst.at<uchar>(temp_pt)!=255)        {            temp_pt.x++;        }        if(abs(cur_pt.x-temp_pt.x)<xflag)           cur_pt.x=temp_pt.x;        temp_pt.x=avg_pt.x;        temp_pt.y=avg_pt.y;        while(dst.at<uchar>(temp_pt)!=255)        {            temp_pt.y--;        }        if(abs(pre_pt.y-temp_pt.y)<yflag)           pre_pt.y=temp_pt.y;        temp_pt.y=avg_pt.y;        while(dst.at<uchar>(temp_pt)!=255)        {            temp_pt.y++;        }        if(abs(cur_pt.y-temp_pt.y)<yflag)          cur_pt.y=temp_pt.y;        //框出当前箱子位置        rectangle(image,pre_pt,cur_pt,Scalar(0,0,255),1,8,0);        imshow("image",image);        namedWindow("grey image");        imshow("grey image",dst);        if (waitKey(delay)>=0)           stop= true;      }    capture.release();      cvDestroyAllWindows();    return 0;}
readme.txt#该程序功能:跟踪检测视频中的箱子#该程序使用说明:1.需把视频放在工程文件夹中;2.程序运行后,第一帧画面会停留,等待用户操作,  用户需用肉眼观测并在箱子所处区域用鼠标左键点击一下,  或者大概框出箱子所处区域并使方框中心落在箱子上,  按任意键继续;3.后续视频中自动检测并框出箱子区域#该程序算法原理1、原图像经过均值滤波和Canny边缘检测后,得到的为一张灰度图,   箱子所处的区域理想情况下为一个封闭的白色矩形;2、前后两帧图像中箱子的中心点变化不大,即位置变化较小。#该程序测试结果1、测试环境:VS2010+Opencv2.4.92、测试结果基本满足要求3、存在问题:摄像头距离箱子太近时,箱子底部边缘和环境融合在一起,检测不出来。

远距离

中距离
这里写图片描述

Done. 2017.7.20.21.09
#不足之处欢迎留言批评指正,谢谢#