demo/2023816/test.cpp

205 lines
7.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Descripttion:
* @version:
* @Author: tjk
* @Date: 2023-01-31 17:01:02
* @LastEditors: Please set LastEditors
* @LastEditTime: 2023-02-01 17:04:12
*/
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;
//定义击打板点中心、距离
typedef struct armor_point {
cv::Point point;
double dis;
}armor_point;
//画出旋转矩形
void drawRotatedRect(cv::Mat& img, const cv::RotatedRect& rect, const cv::Scalar& color, int thickness)
{
cv::Point2f Vertex[4];
rect.points(Vertex);
for (int i = 0; i < 4; i++)
{
cv::line(img, Vertex[i], Vertex[(i + 1) % 4], color, thickness);
}
}
double distance(cv::Point a, cv::Point b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int main()
{
//读取视频资源
string video_path ="./vedio/blue2.mp4";
cv::VideoCapture cap;
cap.open(video_path);
// cv::VideoWriter writer;
// int coder = cv::VideoWriter::fourcc('M','J','P','G');//选择编码格式
// double fps=25.0;//设置视频帧率
// string filename="live.avi";//保存的视频文件名称
// writer.open(filename,coder,fps,cv::Size(1350,1080),true);//创建保存视频文件的视频流
// if(!writer.isOpened()){
// cout<<"打开视频文件失败,请确认是否为合法输入"<<endl;
// return -1;
// }
while (true) {
cv::Mat src_frame;
cap >> src_frame;
cv::resize(src_frame, src_frame, cv::Size(640, 480));
//读取视频、重新规定窗口大小
vector<cv::Mat> bgr_images;
cv::split(src_frame, bgr_images);
cv::Mat b_src_img = bgr_images[0];
//分离颜色通道、取蓝色通道进行图像模糊
cv::blur(b_src_img, b_src_img, cv::Size(3, 3));
//二值化
cv::Mat threshold_img;
cv::threshold(b_src_img, threshold_img, 130, 255, cv::THRESH_BINARY);
//寻找轮廓
vector<vector<cv::Point>> contours;
cv::findContours(threshold_img, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
cv::drawContours(src_frame,contours,-1,cv::Scalar(0,0,255));
cv::Point r_center; // R 的中心点
vector<cv::RotatedRect> contours_min_rects;//所有轮廓的最小外接矩形
vector<cv::RotatedRect> armor_min_rects;
vector<cv::RotatedRect> target_min_rects;
vector<cv::RotatedRect> r_min_rects; //R
int r_index = -1;
// int cnt = 0;
for (unsigned int contour_index = 0; contour_index < contours.size(); contour_index++) {
// //寻找最小旋转矩形,放进容器,顺便将面积过大的剔除,长宽比悬殊的剔除
cv::RotatedRect minrect = minAreaRect(contours[contour_index]);
cv::Rect rect = boundingRect(contours[contour_index]);
//找到旋转矩形
if (minrect.size.area() <= 6000.0 && minrect.size.area() > 150) {
float width;
float height;
//判断长宽比 宽长高短
if (minrect.size.width > minrect.size.height) {
width = minrect.size.width;
height = minrect.size.height;
}
else {
width = minrect.size.height;
height = minrect.size.width;
}
//如果宽高比小于5 再判断是不是中心R标 如果宽高比小于1.17 那么则是中心R标 注意此处中心R标的限定条件有中心的位置
if (width / height < 5) {
contours_min_rects.push_back(minrect);
if (minrect.size.area() > 200 && minrect.size.area() < 350 && minrect.center.y > 100) { // find R
if (height / width > 0.85) {
// R_minRects.push_back(minrect);
r_center = minrect.center;
cv::circle(src_frame, minrect.center, 15, cv::Scalar(5, 255, 100));
r_index = contour_index;
// std::cout<<cnt++<<std::endl;
}
}
//如果面积不满足要求并且宽高比小于1.42 那么为最小旋转矩形
else {
if (minrect.size.area() > 300 && minrect.size.area() < 4350 && (height / width) < 0.7) {
armor_min_rects.push_back(minrect);
}
}
}
}
}
bool find_ok = false;
//计算两个最小旋转矩形之间的距离
for (int i = 0; i < armor_min_rects.size() - 1; i++) {
for (int j = i + 1; j < armor_min_rects.size(); j++) {
double dis = distance(armor_min_rects[i].center, armor_min_rects[j].center);
//如果距离小于100 那么将其视为可能的击打板
if (dis < 100) {
target_min_rects.push_back(armor_min_rects[i]);
target_min_rects.push_back(armor_min_rects[j]);
find_ok = true;
break;
}
// std::cout<<dis<<std::endl;
}
if (find_ok) {
break;
}
}
//如果没有找到两个对应的最小矩形 那么重新进入while循环
if (target_min_rects.size() != 2) {
continue;
}
else {
//找到两个最小矩形对应的点 由此找到中心点
cv::RotatedRect rrect_in; //= target_minRects[0];
cv::RotatedRect rrect_out;// = target_minRects[1];
double dis1 = distance(r_center, target_min_rects[0].center);
double dis2 = distance(r_center, target_min_rects[1].center);
if (dis1 > dis2) {
rrect_in = target_min_rects[1];
rrect_out = target_min_rects[0];
}
else {
rrect_in = target_min_rects[0];
rrect_out = target_min_rects[1];
}
drawRotatedRect(src_frame, rrect_in, cv::Scalar(0, 250, 0), 1);
drawRotatedRect(src_frame, rrect_out, cv::Scalar(0, 0, 255), 1);
cv::Point target_center = cv::Point((int)((rrect_in.center.x + rrect_out.center.x) / 2), (int)((rrect_in.center.y + rrect_out.center.y) / 2));
cv::circle(src_frame, target_center, 5, cv::Scalar(0, 0, 255), -1);
cv::Point2f in_vet_points[4];
cv::Point2f out_vet_points[4];
//找到内外两个矩形的所有点 计算出所有点与中心的距离
rrect_in.points(in_vet_points);
rrect_out.points(out_vet_points);
vector<armor_point> armor_points;
for (int i = 0; i < 4; i++) {
armor_point point;
point.point = in_vet_points[i];
point.dis = distance(target_center, in_vet_points[i]);
armor_points.push_back(point);
}
for (int i = 0; i < 4; i++) {
armor_point point;
point.point = out_vet_points[i];
point.dis = distance(target_center, out_vet_points[i]);
armor_points.push_back(point);
}
//找到所有点与中心距离最近的四个点
sort(armor_points.begin(), armor_points.end(), [](armor_point a, armor_point b) {return a.dis < b.dis; });
for (int i = 0; i < 4; i++)
{
cv::circle(src_frame, armor_points[i].point, 3, cv::Scalar(255, 0, 255), -1);
}
int buff_run_radius = (int)distance(r_center, target_center);
cv::circle(src_frame, r_center, buff_run_radius, cv::Scalar(55, 110, 255), 1);
}
// cv::resize(src_frame,src_frame,cv::Size(1350,1080));
// writer.write(src_frame);//把图像写入视频流
cv::imshow("src_img", src_frame);
cv::imshow("threshold_img",threshold_img);
if (cv::waitKey(0) == 'q') {
break;
}
}
// writer.release();
cap.release();
return 0;
}