在RM2019赛季结束后的日子,学习了OpenCV和一点C++语言,在2019年国庆节期间初步完成了RM装甲板的识别程序。由于我是初学者,而且当时未看过队内程序,所以写的程序较为简单易懂,程序输出最佳装甲板的二维坐标。
#include
#include
#include
#include
#include "armordetection.h"
using namespace cv;
using namespace std;
ArmorDetection* armor = new ArmorDetection();
Point2f center;
int main()
{
//fps变量
double t = (double)getTickCount();
double fps;
char string[10];
char string2[10];
Mat frame;
VideoCapture capture("C:/Users/Administrator/Desktop/video/6.mp4");
if (!capture.isOpened())
{
printf("无法打开相机...\n");
return -1;
}
namedWindow("frame", CV_WINDOW_AUTOSIZE);
namedWindow("mask", CV_WINDOW_AUTOSIZE);
namedWindow("Control", CV_WINDOW_AUTOSIZE);
while (capture.read(frame))//读取当前帧
{
armor->setInputImage(frame);
armor->Pretreatment();
center = armor->GetArmorCenter();
cout << "[INFO] x = " << center.x - frame.cols / 2 << " y = " << center.y - frame.rows / 2 << endl;
//计算fps
double dt = ((double)getTickCount() - t) / (double)getTickFrequency();
fps = 1.0 / dt;
t = (double)getTickCount();
sprintf_s(string, "%.2f", fps);
std::string fpsString("FPS:");
fpsString += string;
putText(frame, fpsString, Point(5, 20), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 255, 255));
char c = waitKey(10);
if (c == 27) //"Esc"
{
break;
}
}
capture.release();//释放视频内存
waitKey(0);
return 0;
}
#include "armordetection.h"
ArmorDetection::ArmorDetection() = default;
ArmorDetection::ArmorDetection(Mat & input) {
frame = input;
}
void ArmorDetection::setInputImage(Mat input) {
frame = input;
currentCenter.x = 0;
currentCenter.y = 0;
}
//图像预处理
void ArmorDetection::Pretreatment() {
Mat input;
Point p, center;
vector<vector<Point>> contours;
vector<Vec4i> hireachy;
vector<Rect> boundRect(contours.size());
Point2f vertex[4];
//创建进度条
cvCreateTrackbar("LowH", "Control", &iLowH, 255);
cvCreateTrackbar("HighH", "Control", &iHighH, 255);
cvCreateTrackbar("LowS", "Control", &iLowS, 255);
cvCreateTrackbar("HighS", "Control", &iHighS, 255);
cvCreateTrackbar("LowV", "Control", &iLowV, 255);
cvCreateTrackbar("HighV", "Control", &iHighV, 255);
cvtColor(frame, hsv, CV_BGR2HSV);
inRange(hsv,
Scalar(iLowH, iLowS, iLowV),
Scalar(iHighH, iHighS, iHighV),
mask);
// 形态学操作
morphologyEx(mask, mask, MORPH_OPEN, kernel1, Point(-1, -1));//开操作
dilate(mask, mask, kernel2, Point(-1, -1), 1);//膨胀
//轮廓增强
Canny(mask, mask, 3, 9, 3);
imshow("mask", mask);
findContours(mask, contours, hireachy, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//筛选,去除一部分矩形
for (int i = 0; i < contours.size(); ++i) {
RotatedRect minRect = minAreaRect(Mat(contours[i]));
minRect.points(vertex);
if (minRect.size.width > minRect.size.height) {
minRect.angle += 90;
float t = minRect.size.width;
minRect.size.width = minRect.size.height;
minRect.size.height = t;
}
if ((minRect.size.width * 10 > minRect.size.height)
&& (minRect.size.width * 1 < minRect.size.height)
&& (abs(minRect.angle) < 30)) {
minRects.push_back(minRect);
}
for (int l = 0; l < 4; l++)
{
line(frame, vertex[l], vertex[(l + 1) % 4], Scalar(255, 0, 0), 2);
}
line(frame, Point(frame.cols / 2 - 15, frame.rows / 2),
Point(frame.cols / 2 + 15, frame.rows / 2), Scalar(0, 255, 255), 5);
line(frame, Point(frame.cols / 2, frame.rows / 2 - 15),
Point(frame.cols / 2, frame.rows / 2 + 15), Scalar(0, 255, 255), 5);
circle(frame, Point(frame.cols / 2, frame.rows / 2), 4, Scalar(0, 0, 255), -1);
}
}
Point2f ArmorDetection::GetArmorCenter() {
//遍历所有矩形,两两组合
RotatedRect leftRect, rightRect;
vector<int*> reliability;
double area[2], distance, height;
if (minRects.size() < 2) {
LostTarget();
return currentCenter;
}
for (int i = 0; i < minRects.size(); ++i) {
for (int j = i + 1; j < minRects.size(); ++j) {
int level = 0;
int temp[3];
leftRect = minRects[i];
rightRect = minRects[j];
//判断
if (leftRect.angle == rightRect.angle) {
level += 10;
}
else if (abs(leftRect.angle - rightRect.angle) < 5) {
level += 8;
}
else if (abs(leftRect.angle - rightRect.angle) < 10) {
level += 6;
}
else if (abs(leftRect.angle - rightRect.angle) < 30) {
level += 4;
}
else if (abs(leftRect.angle - rightRect.angle) < 90) {
level += 1;
}
else {
break;
}
area[0] = leftRect.size.width * leftRect.size.height;
area[1] = rightRect.size.width * rightRect.size.height;
if (area[0] == area[1]) {
level += 10;
}
else if (min(area[0], area[1]) * 1.5 > max(area[0], area[1])) {
level += 8;
}
else if (min(area[0], area[1]) * 2 > max(area[0], area[1])) {
level += 6;
}
else if (min(area[0], area[1]) * 3 > max(area[0], area[1])) {
level += 4;
}
else if (min(area[0], area[1]) * 4 > max(area[0], area[1])) {
level += 1;
}
else {
break;
}
double half_height = (leftRect.size.height + rightRect.size.height) / 4;
if (leftRect.center.y == rightRect.center.y) {
level += 10;
}
else if (abs(leftRect.center.y - rightRect.center.y) < 0.2 * half_height) {
level += 8;
}
else if (abs(leftRect.center.y - rightRect.center.y) < 0.4 * half_height) {
level += 6;
}
else if (abs(leftRect.center.y - rightRect.center.y) < 0.8 * half_height) {
level += 4;
}
else if (abs(leftRect.center.y - rightRect.center.y) < half_height) {
level += 1;
}
else {
break;
}
distance = Distance(leftRect.center, rightRect.center);
height = (leftRect.size.height + rightRect.size.height) / 2;
if (distance != 0 && distance > height) {
if (distance < 1.5 * height) {
level += 6;
}
else if (distance < 1.8 * height) {
level += 4;
}
else if (distance < 2.4 * height) {
level += 2;
}
else if (distance < 10 * height) {
level += 1;
}
else {
break;
}
}
temp[0] = i;
temp[1] = j;
temp[2] = level;
reliability.push_back(temp);
}
}
if (reliability.empty()) {
LostTarget();
return currentCenter;
}
else {
int maxLevel = 0, index = 0;
for (int k = 0; k < reliability.size(); ++k) {
if (reliability[k][2] > maxLevel) {
maxLevel = reliability[k][2];
index = k;
}
}
currentCenter.x = (minRects[reliability[index][0]].center.x + minRects[reliability[index][1]].center.x) / 2;
currentCenter.y = (minRects[reliability[index][0]].center.y + minRects[reliability[index][1]].center.y) / 2;
//与上一次的结果对比
if (lastCenter.x == 0 && lastCenter.y == 0) {
lastCenter = currentCenter;
lost = 0;
}
else {
double difference = Distance(currentCenter, lastCenter);
if (difference > 300) {
LostTarget();
return currentCenter;
}
}
line(frame, Point(currentCenter.x - 10, currentCenter.y - 10),
Point(currentCenter.x + 10, currentCenter.y + 10), Scalar(255, 255, 0), 5);
line(frame, Point(currentCenter.x + 10, currentCenter.y - 10),
Point(currentCenter.x - 10, currentCenter.y + 10), Scalar(255, 255, 0), 5);
circle(frame, currentCenter, 7.5, Scalar(0, 0, 255), 5);
imshow("frame", frame);
return currentCenter;
}
}
void ArmorDetection::LostTarget() {
lost++;
if (lost < 3) {
currentCenter = lastCenter;
}
else {
currentCenter = Point2f(0, 0);
lastCenter = Point2f(0, 0);
}
}
double ArmorDetection::Distance(Point2f a, Point2f b) {
return sqrt((a.x - b.x) * (a.x - b.x) +
(a.y - b.y) * (a.y - b.y));
}
double ArmorDetection::max(double first, double second) {
return first > second ? first : second;
}
double ArmorDetection::min(double first, double second) {
return first < second ? first : second;
}
#pragma once
#ifndef ARMORDETECTION_H
#define ARMORDETECTION_H
#include
#include
using namespace std;
using namespace cv;
class ArmorDetection {
private:
Mat frame, hsv, mask;
Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
Point2f currentCenter;
Point2f lastCenter;
vector<RotatedRect> minRects;
int lost;
public:
ArmorDetection();
explicit ArmorDetection(Mat& input);
void setInputImage(Mat input);
void Pretreatment();
Point2f GetArmorCenter();
int iLowH = 49;
int iHighH = 93;
int iLowS = 5;
int iHighS = 95;
int iLowV = 255;
int iHighV = 255;
private:
void LostTarget();
double Distance(Point2f, Point2f);
double max(double, double);
double min(double, double);
};
#endif
该程序存在很多瑕疵,仅供初学者参考:)
(小车儿挺帅~据说远处的1号更帅^v*)