大符目标检测-2016大疆Robomasters比赛

概述

这是2016年大疆RoboMaster机器人竞赛的一个题目,当时在系里面的RoboMaster竞赛队伍中接触到的。

任务要求:

  • 实时检测出视频中的所有九个区域,用矩形框将格子区域框出;
  • 实时检测出视频中大符的目标区域和非目标区域,目标区域即为姿态形状一直发生变化的小人儿所在的格子区域,小人儿所在的格子每隔1.5秒换一次,所以检测速度尽量要快;

我的思路

当然,可以用运动检测、运动跟踪的论文方法来尝试,不过速度上可能不一定达到要求。所以我就想着能否用图像预处理的一些基本算法结合目标的变化特性来检测。

根据视频素材,对图片做了一些预处理,发现小人儿虽然一直在变化,但是其矩形长宽比基本都是最大的那个(在排除噪声的情况下),所以可以利用这一点来进行对目标区域的检测。

我的算法如下:

中间结果

hsv处理之后的中间结果图:

腐蚀膨胀之后的中间结果图:

最终检测结果图:

其他情况下的检测结果:

视频检测结果

i5上速度达到55-60帧,tk1上没测过,实时性很好,而且检测也很准确,没有出现误检情况。

见链接:https://v.youku.com/v_show/id_XMzc4MDA0NDM2NA==.html?spm=a2hzp.8253869.0.0

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
#include<vector>
#include<time.h>

using namespace cv;
using namespace std;

int main()
{
VideoCapture capture("video.mp4");
while (1)
{
clock_t start,finish;
double totaltime;
start=clock();

Mat frame,img_hsv,img_hsv2;//定义一个Mat变量,用于存储每一帧的图像
capture >> frame; //读取当前帧
if(frame.empty()) continue;

imshow("原图",frame);
cvtColor(frame,img_hsv,CV_BGR2HSV);
Scalar lowerb = Scalar(105, 43, 176);
Scalar upperb = Scalar(113, 255, 255);
inRange(img_hsv, lowerb, upperb, img_hsv2);
imshow("img_hsv2",img_hsv2);

Mat element=getStructuringElement(MORPH_RECT,Size(11,11));
morphologyEx(img_hsv2,img_hsv2,MORPH_ERODE,element);
Mat element2=getStructuringElement(MORPH_RECT,Size(16,17));
morphologyEx(img_hsv2,img_hsv2,MORPH_DILATE,element2);//直接膨胀,九宫格中的图案会没了。所以先腐蚀再膨胀
imshow("腐蚀膨胀",img_hsv2);

vector<vector<Point>> contours;//定义轮廓的点集
vector<Vec4i> hierarchy;
findContours(img_hsv2,contours,hierarchy,CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
vector<Rect> boundRect(contours.size()); //定义包围点集的最小矩形vector 要加上(contours.size()),不然会超出vector范围
int a=0;float b=0;

//Mat drawing = Mat::zeros( frame.size(), CV_8UC3 );//创建空白的Mat图像(算法调试用)
for(unsigned int i=0; i<contours.size();i++)
//此处定义为unsigned int i=0 若只定义为int i=0,编译时会出现 warning C4018 “<” 有符号/无符号不匹配。contours是一个Vector容器,contours.size()在容器中被定义为: unsigned int 类型
{
if(hierarchy[i][3]!=-1)//提取内轮廓
{
boundRect[i] = boundingRect( Mat(contours[i]) ); //计算目标图案的小矩形数组
if( (float)boundRect[i].height/boundRect[i].width>1 ) //也可以用长宽比限制(float)boundRect[i].width/boundRect[i].height>1.2 && (float)boundRect[i].width/boundRect[i].height<1.6
{
if((float)boundRect[i].height/boundRect[i].width>b)
{
b=(float)boundRect[i].height/boundRect[i].width; a=i; }//(视频倾斜时的影响)当有多个宽比长高的矩形时,利用目标对象的宽长比最大来筛选
}
}
}
}
// rectangle( frame, boundRect[a].tl(), boundRect[a].br(), Scalar(0,0,255) ,4);//画出目标图案的小矩形框,tl矩形左上角top left,br右下角(两个参数为对角线上的点)

vector<Rect> boundRect2(contours.size()); //用于定位和画九宫格的矩形数组
for(unsigned int i=0; i<contours.size();i++)
{
boundRect2[i] = boundingRect( Mat(contours[i]) );
if(boundRect2[i].height>30)
if( boundRect[a].x > boundRect2[i].x && boundRect[a].x < (boundRect2[i].x+boundRect2[i].width) && boundRect[a].y > boundRect2[i].y && boundRect[a].y < (boundRect2[i].y+boundRect2[i].height ))
rectangle( frame, boundRect2[i].tl(), boundRect2[i].br(), Scalar(0,0,255),4 );
}
imshow("输出",frame);

finish=clock();
totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
cout<<"帧率"<<1/totaltime<<endl;
waitKey(1);
cout<<"************************************************************"<<endl;
}
cin.get();
return 0;
}