Robomaster2023 能量机关识别demo

该代码实现了一个基于OpenCV的视频处理Demo,用于识别Robomaster比赛中的能量机关。通过检测和分析图像中的轮廓,找到最小外接矩形,对目标进行定位和跟踪。在无干扰的仿真视频中,检测效果良好,但实际应用时需考虑更多环境因素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Robomaster2023 能量机关识别demo

在这里插入图片描述

效果视频
https://www.bilibili.com/video/BV1zT411C7PY/?vd_source=15a7e7c79fb0c7348fc5147c131dd6af

/*
 * @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 = "/home/idriver/tjk/project/rm/buff_demo/blue.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;
                }
                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;    
                        }
                    } 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);
                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;
            }    
        }
        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;
}

注:

  • 只是一个demo!!!
  • 使用的仿真视频做检测,没有环境干扰,实际使用时需要很多的处理。
  • 检测思路和之前的风车检测差不多,现在使用的分离式灯带感觉更容易检测了。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FlyDremever

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值