首页 > 其他分享 >RM-对装甲板灯条进行识别代码分析

RM-对装甲板灯条进行识别代码分析

时间:2023-04-07 14:34:52浏览次数:42  
标签:leftLight ratio center rightLight float 灯条 板灯条 RM 识别

最近要完成装甲板灯条识别的任务,但我本身对于OpenCV的了解还是甚微,所以只能是借鉴他人的代码并加以自身的理解。这里我借鉴的是https://blog.csdn.net/weixin_64054906/article/details/126674493
这里我逐段加以自己的分析。

1.引用头文件

#include "stdio.h"
#include<iostream> 
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;

这个我就不多赘述了,所有代码都要有的一块。

2.创建灯条类

由于在本次的代码中主要是根据灯条来进行对装甲板的识别,后续代码也要多次用到灯条相关的性质,所以先创建一个灯条类。

class LightDescriptor
{
public:float width, length, angle, area;  //创建灯条的属性变量,包括宽度,长度,角度,面积
      cv::Point2f center;  //创建灯条中心坐标的变量
public:
    LightDescriptor() {};  //声明灯条的函数,本函数作用实际上就是为主函数中使用灯条主函数的属性变量提供一种简便写法。
    LightDescriptor(const cv::RotatedRect& light) //创建灯条函数
    {
        width = light.size.width;
        length = light.size.height;
        center = light.center;
        angle = light.angle;
        area = light.size.area();
    }
};

3.集中定义变量(从这里开始进入主函数)

    VideoCapture video; //VC类对象化
    video.open("1234567.mp4"); //打开准备好的视频
    //变量集中定义
    Mat frame, channels[3], binary, Gaussian, dilatee; //frame对应录像的每一帧,用于后续读取录像;channels[3]定义图像的RGB通道;binary,Gaussian,dilatee都是定义一张图像
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5)); //创建一个矩形,大小为5*5的卷积核
    Rect boundRect; //这个变量后面没用过,y1s1,我真不知道在这里有啥用
    RotatedRect box; //这个同上
    vector<vector<Point>> contours;//与下一个变量作为轮廓检测函数的参数
    vector<Vec4i> hierarchy;
    vector<Point2f> boxPts(4);

4.图像预处理

        Rect point_array[20]; //未知
        video >> frame;  //读取每帧
        if (frame.empty()) {
            break;   //如果找不到录像,就跳出程序
        }
        split(frame, channels); //通道分离
        threshold(channels[0], binary, 220, 255, 0);//二值化
        GaussianBlur(binary, Gaussian, Size(5, 5), 0);//滤波
        dilate(Gaussian, dilatee, element); //对灯条进行膨胀
        findContours(dilatee, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);//轮廓检测
        vector<LightDescriptor> lightInfos;//创建一个灯条类的动态数组

5.筛选灯条

for (int i = 0; i < contours.size(); i++) {
            // 求轮廓面积
            double area = contourArea(contours[i]);
            // 去除较小轮廓&fitEllipse的限制条件
            if (area < 5 || contours[i].size() <= 1)
                continue;//相当于就是把这段轮廓去除掉
            // 用椭圆拟合区域得到外接矩形(特殊的处理方式:因为灯条是椭圆型的,所以用椭圆去拟合轮廓,再直接获取旋转外接矩形即可)
            RotatedRect Light_Rec = fitEllipse(contours[i]);
 
            // 长宽比和轮廓面积比限制(由于要考虑灯条的远近都被识别到,所以只需要看比例即可)
            if (Light_Rec.size.width / Light_Rec.size.height > 4)
                continue;
            lightInfos.push_back(LightDescriptor(Light_Rec));
        }

6.二重循环多条件匹配灯条

        for (size_t i = 0; i < lightInfos.size(); i++) {
            for (size_t j = i + 1; (j < lightInfos.size()); j++) {
                LightDescriptor& leftLight = lightInfos[i]; //左灯条特征
                LightDescriptor& rightLight = lightInfos[j]; //右灯条特征
                float angleGap_ = abs(leftLight.angle - rightLight.angle); //获取左右灯条的角度差
                //由于灯条长度会因为远近而受到影响,所以按照比值去匹配灯条,以下就是根据灯条的形态学特征逐条筛选符合条件的灯条
                float LenGap_ratio = abs(leftLight.length - rightLight.length) / max(leftLight.length, rightLight.length);
                float dis = pow(pow((leftLight.center.x - rightLight.center.x), 2) + pow((leftLight.center.y - rightLight.center.y), 2), 0.5);
                //均长
                float meanLen = (leftLight.length + rightLight.length) / 2;
                float lengap_ratio = abs(leftLight.length - rightLight.length) / meanLen;
                float yGap = abs(leftLight.center.y - rightLight.center.y);
                float yGap_ratio = yGap / meanLen;
                float xGap = abs(leftLight.center.x - rightLight.center.x);
                float xGap_ratio = xGap / meanLen;
                float ratio = dis / meanLen;
                //匹配不通过的条件
                if (angleGap_ > 15 ||
                    LenGap_ratio > 1.0 ||
                    lengap_ratio > 0.8 ||
                    yGap_ratio > 1.5 ||
                    xGap_ratio > 2.2 ||
                    xGap_ratio < 0.8 ||
                    ratio > 3 ||
                    ratio < 0.8) {
                    continue;
                }

7.绘制矩形

Point center = Point((leftLight.center.x + rightLight.center.x) / 2, (leftLight.center.y + rightLight.center.y) / 2); //获取两灯条的中心坐标
                RotatedRect rect = RotatedRect(center, Size(dis, meanLen), (leftLight.angle + rightLight.angle) / 2);
                Point2f vertices[4];
                rect.points(vertices);
                for (int i = 0; i < 4; i++) {
                    line(frame, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 255), 2.2);
                }

最后附上完整代码

#include "stdio.h"
#include<iostream> 
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "task2.h"
using namespace std;
using namespace cv;
//由于在识别中的核心物体以及相关的物理特性是灯条,所以建一个灯条类
class LightDescriptor
{	    //在识别以及匹配到灯条的功能中需要用到旋转矩形的长宽偏转角面积中心点坐标等
public:float width, length, angle, area;
      cv::Point2f center;
public:
    LightDescriptor() {};
    //让得到的灯条套上一个旋转矩形,以方便之后对角度这个特殊因素作为匹配标准
    LightDescriptor(const cv::RotatedRect& light)
    {
        width = light.size.width;
        length = light.size.height;
        center = light.center;
        angle = light.angle;
        area = light.size.area();
    }
};
int main()
{
    getMarix();
    VideoCapture video; //VC类对象化
    video.open("1234567.mp4");
    //变量集中定义
    Mat frame, channels[3], binary, Gaussian, dilatee;
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
    Rect boundRect;
    RotatedRect box;
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    vector<Point2f> boxPts(4);
    //图像预处理
    for (;;) {
        Rect point_array[20];
        video >> frame;  //读取每帧
        if (frame.empty()) {
            break;
        }
        split(frame, channels); //通道分离
        threshold(channels[0], binary, 220, 255, 0);//二值化
        GaussianBlur(binary, Gaussian, Size(5, 5), 0);//滤波
        dilate(Gaussian, dilatee, element);
        // dilate(Gaussian, dilate, element, Point(-1, -1));//膨胀,把滤波得到的细灯条变宽
        findContours(dilatee, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);//轮廓检测
        vector<LightDescriptor> lightInfos;//创建一个灯条类的动态数组
    //筛选灯条
        for (int i = 0; i < contours.size(); i++) {
            // 求轮廓面积
            double area = contourArea(contours[i]);
            // 去除较小轮廓&fitEllipse的限制条件
            if (area < 5 || contours[i].size() <= 1)
                continue;//相当于就是把这段轮廓去除掉
            // 用椭圆拟合区域得到外接矩形(特殊的处理方式:因为灯条是椭圆型的,所以用椭圆去拟合轮廓,再直接获取旋转外接矩形即可)
            RotatedRect Light_Rec = fitEllipse(contours[i]);
 
            // 长宽比和轮廓面积比限制(由于要考虑灯条的远近都被识别到,所以只需要看比例即可)
            if (Light_Rec.size.width / Light_Rec.size.height > 4)
                continue;
            lightInfos.push_back(LightDescriptor(Light_Rec));
        }
        //二重循环多条件匹配灯条
        for (size_t i = 0; i < lightInfos.size(); i++) {
            for (size_t j = i + 1; (j < lightInfos.size()); j++) {
                LightDescriptor& leftLight = lightInfos[i];
                LightDescriptor& rightLight = lightInfos[j];
                float angleGap_ = abs(leftLight.angle - rightLight.angle);
                //由于灯条长度会因为远近而受到影响,所以按照比值去匹配灯条
                float LenGap_ratio = abs(leftLight.length - rightLight.length) / max(leftLight.length, rightLight.length);
                float dis = pow(pow((leftLight.center.x - rightLight.center.x), 2) + pow((leftLight.center.y - rightLight.center.y), 2), 0.5);
                //均长
                float meanLen = (leftLight.length + rightLight.length) / 2;
                float lengap_ratio = abs(leftLight.length - rightLight.length) / meanLen;
                float yGap = abs(leftLight.center.y - rightLight.center.y);
                float yGap_ratio = yGap / meanLen;
                float xGap = abs(leftLight.center.x - rightLight.center.x);
                float xGap_ratio = xGap / meanLen;
                float ratio = dis / meanLen;
                //匹配不通过的条件
                if (angleGap_ > 15 ||
                    LenGap_ratio > 1.0 ||
                    lengap_ratio > 0.8 ||
                    yGap_ratio > 1.5 ||
                    xGap_ratio > 2.2 ||
                    xGap_ratio < 0.8 ||
                    ratio > 3 ||
                    ratio < 0.8) {
                    continue;
                }
                //绘制矩形
                Point center = Point((leftLight.center.x + rightLight.center.x) / 2, (leftLight.center.y + rightLight.center.y) / 2);
                RotatedRect rect = RotatedRect(center, Size(dis, meanLen), (leftLight.angle + rightLight.angle) / 2);
                Point2f vertices[4];
                rect.points(vertices);
                for (int i = 0; i < 4; i++) {
                    line(frame, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 255), 2.2);
                }
            }
        }
 
        namedWindow("video", WINDOW_FREERATIO);
        imshow("video", frame);
        waitKey(5);
    }
    video.release();
    cv::destroyAllWindows();
    return 0;
}

标签:leftLight,ratio,center,rightLight,float,灯条,板灯条,RM,识别
From: https://www.cnblogs.com/nobodyx/p/17273905.html

相关文章

  • Keil Arm中使用malloc函数的方法
    出处 http://blog.sina.com.cn/s/blog_a189aca10102vabo.htmlKeilArm中使用malloc函数的方法:1、需要使用微库:如果不选用微库的话会报错,例如:.\Output\SaiWu.axf:Error:L6915E:Libraryreportserror:__use_no_semihostingwasrequested,but_ttywrchwasreferenced2......
  • pycharm上安装pip
    网上的答案太花里胡哨了,简单一两个命令弄得长篇大论 查看是否安装pip,终端输入:pip--version如果显示:ModuleNotFoundError:Nomodulenamed'pip' 那就没有安装好 安装pip命令:python-mensurepip--default-pip然后再输入:pip--version 检查一下是否能显示版本号,能......
  • ORM相关学习记录
    1.orm项目1.1安装ormpipinstallmysqlclient如果windows安装报错后,使用whl安装下载地址:https://pypi.org/project/mysqlclient/#files找到对应python版本的wheel包,然后进行安装,可把包放到scripts目录中执行:pip3.7installmysqlclient-2.1.0-cp37-cp37m-win_amd64.whl1.2......
  • 基于simulink的车辆坡度与质量识别模型,扩展卡尔曼滤波,估计曲线与实际误差合理
    基于simulink的车辆坡度与质量识别模型,扩展卡尔曼滤波,估计曲线与实际误差合理YID:8572645488015821......
  • flask_day04:请求上下文分析 wtforms
    目录回顾请求上下文分析(源码:request原理)导出项目的依赖pipreqs函数和方法threading.local对象本质原理:偏函数flask整个生命执行流程(1.1.4版本为例)wtforms(了解)补充回顾1.蓝图 第一步:导入第二步:实例化的得到的对象,可以指定static和templates第三步:app中注册蓝图,注册......
  • flask请求上下文分析,源码request原理,wtforms,精确导出依赖,函数和方法,threading.locl对
    内容回顾蓝图第一步:导入第二步:实例化得到对象,可以指定static和templates第三步:app中注册蓝图,注册蓝图时,可以指定前缀第四步:使用蓝图,注册路由,注册请求扩展g对象当次请求的全局对象,在当次请求中可以放值和取值跟session的区别是session可以在多次请求中使用,g对象只在当次请......
  • java.nio.charset.MalformedInputException: Input length = 1
    将nacos作为配置中心时,发现加载nacos内容时报错:java.nio.charset.MalformedInputException:Inputlength=1后来发现,将项目统一为utf-8后,正常启动。 ......
  • pycharm中配置MongoDB数据库出现未找到驱动程序类 'com.dbschema.MongoJdbcDriver' (v
      之前重新装了一下pycharm,发现MongoDB数据库连接时发生了错误。具体错误:未找到驱动程序类'com.dbschema.MongoJdbcDriver'(view)。这怎么解决呢?其实很简单,在驱动程序中选一个版本进行下载就好了。步骤如下:1、找到驱动程序,点击MongoDB,再点击+号。2、找到最新版本,点击下载......
  • flask之请求上下文分析之导出项目依赖-函数和方法的区别-threading.local对象-偏函数-
    目录flask之请求上下文分析之导出项目依赖-函数和方法的区别-threading.local对象-偏函数-flask整个生命执行流程--wtforms今日内容详细1请求上下文分析(源码:request原理)1.1导出项目的依赖1.2函数和方法1.3threading.local对象1.4偏函数1.5flask整个生命执行流程(1.1.4版本......
  • Python ORM Pony SQLite数据库 常用操作
    Pony是一个高级的对象关系映射器ORM框架。Pony它能够使用Python生成器表达式和lambdas向数据库编写查询。Pony分析表达式的抽象语法树,并将其转换为SQL查询。支持SQLite,MySQL,PostgreSQL和Oracle等数据库,本文主要介绍PythonORMPony中SQLite数据库常用操作,及数据增加、删除、修......