RM装甲板中心识别

简易的装甲板识别程序.

Armor1.pro:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += \
        main.cpp

INCLUDEPATH += /usr/local/include \
               /usr/local/include/opencv4

LIBS += /usr/local/lib/*.so \

1、首先是头文件和一些开始的处理:

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
#include<vector>
#include <time.h>
using namespace cv;
using namespace std;

const int ANGLE_TO_UP = 1;
const int WIDTH_GREATER_THAN_HEIGHT = 0;

2、为了防止有其他装甲板的干扰,加入限幅滤波:

#define DELAT_MAX 30//定义限幅滤波误差最大值
typedef	int filter_type;//定义限幅滤波数据类型
filter_type filter(filter_type effective_value, filter_type new_value, filter_type delat_max);
filter_type filter(filter_type effective_value, filter_type new_value, filter_type delat_max)
{
    if ( ( new_value - effective_value > delat_max ) || ( effective_value - new_value > delat_max ))
    {
        new_value=effective_value;
        return effective_value;
    }
    else
    {
        new_value=effective_value;
        return new_value;
    }
}

3、为了辅助筛选装甲板,提高算法运行速度,做一次筛选预处理

// 为辅助筛选装甲板,提高算法运行速度,做一次筛选预处理
RotatedRect& adjustRec(cv::RotatedRect& rec, const int mode)
   {
       using std::swap;

       float& width = rec.size.width;
       float& height = rec.size.height;
       float& angle = rec.angle;

       if (mode == WIDTH_GREATER_THAN_HEIGHT)
       {
           if (width < height)
           {
               swap(width, height);
               angle += 90.0;
           }
       }

       while (angle >= 90.0) angle -= 180.0;
       while (angle < -90.0) angle += 180.0;

       if (mode == ANGLE_TO_UP)
       {
           if (angle >= 45.0)
           {
               swap(width, height);
               angle -= 90.0;
           }
           else if (angle < -45.0)
           {
               swap(width, height);
               angle += 90.0;
           }
       }
   return rec;
}//由于灯条是竖着的,借此纠正不是竖着的轮廓,方便算法查找

4、接下来是主函数

4.1 为了获取随机颜色的轮廓,设置随机种子(可省略)

//植入随机种子
    srand(time(NULL));

4.2 导入图像

 //第一步,导入图像
    Mat imgOriginal;
    imgOriginal = imread("/home/dahazi/Desktop/a.png", IMREAD_COLOR);
    if (imgOriginal.empty())
    {
        cout << "Could not open or find the image" << std::endl;
        return -1;
    }

4.3 转HSV图像,重新合并两通道

//第二步,转HSV图像,重新合并两通道,为了方便后面寻找图像中所有的轮廓
    Mat imgHSV;
    vector<Mat> hsvSplit;
    cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV);//将RGB转换为HSV,便于识别
    split(imgHSV, hsvSplit);
    equalizeHist(hsvSplit[2], hsvSplit[2]);
    merge(hsvSplit, imgHSV);//重新合并

4.4 图像二值化处理,摒弃环境光干扰

//第三步,图像二值化处理,摒弃环境光干扰
    Mat thresHold;
    threshold(hsvSplit[2],thresHold,240,245,THRESH_BINARY);

4.5 模糊/膨胀处理

//第四步,模糊/膨胀处理,让图像变得圆润
    blur(thresHold, thresHold, Size(3,3));
    Mat element = getStructuringElement(MORPH_ELLIPSE,Size(3,3));//膨胀
    dilate(thresHold, element, element);

4.6 开始寻找轮廓

//第五步,开始寻找轮廓
    vector<RotatedRect> vc;
    vector<RotatedRect> vRec;
    vector<vector<Point>> Light_Contour;// 发现的轮廓
    findContours(element.clone(),Light_Contour, RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);

4.7 从面积上选轮廓

//第六步,从面积上选轮廓
    for (int i = 0;i < Light_Contour.size();i++)
    {
        //求轮廓面积
        float Light_Contour_Area = contourArea(Light_Contour[i]);
        //去除较小轮廓fitllipse的限制条件
        if (Light_Contour_Area < 15 || Light_Contour[i].size() <= 10)
            continue;
        // 用椭圆拟合区域得到外接矩形
        RotatedRect Light_Rec = fitEllipse(Light_Contour[i]);
        Light_Rec = adjustRec(Light_Rec, ANGLE_TO_UP);

        if (Light_Rec.angle > 10 )
            continue;
        // 长宽比和轮廓面积比限制
        if (Light_Rec.size.width / Light_Rec.size.height > 1.5
                || Light_Contour_Area / Light_Rec.size.area() < 0.5)
            continue;
        // 扩大灯柱的面积
        Light_Rec. size.height *= 1.1;
        Light_Rec.size.width *= 1.1;
        vc.push_back(Light_Rec);
    }

4.8 从灯条长宽比上来筛选轮廓并标记中心

//第七步,从灯条长宽比上来筛选轮廓
    for (size_t i = 0; i < vc.size(); i++)
    {
        for (size_t j = i + 1; (j < vc.size()); j++)
        {
            //判断是否为相同灯条
            float Contour_angle = abs(vc[i].angle - vc[j].angle); //角度差
            if (Contour_angle >= 7)
                continue;
            //长度差比率
            float Contour_Len1 = abs(vc[i].size.height - vc[j].size.height) / max(vc[i].size.height, vc[j].size.height);
            //宽度差比率
            float Contour_Len2 = abs(vc[i].size.width - vc[j].size.width) / max(vc[i].size.width, vc[j].size.width);
            if (Contour_Len1 > 0.25 || Contour_Len2 > 0.25)
                continue;


            RotatedRect ARMOR;
            ARMOR.center.x = (vc[i].center.x + vc[j].center.x) / 2.; //x坐标
            ARMOR.center.y = (vc[i].center.y + vc[j].center.y) / 2.; //y坐标
            ARMOR.angle = (vc[i].angle + vc[j].angle) / 2.; //角度
            float nh, nw, yDiff, xDiff;
            nh = (vc[i].size.height + vc[j].size.height) / 2; //高度
            // 宽度
            nw = sqrt((vc[i].center.x - vc[j].center.x) * (vc[i].center.x - vc[j].center.x) + (vc[i].center.y - vc[j].center.y) * (vc[i].center.y - vc[j].center.y));
            float ratio = nw / nh; //匹配到的装甲板的长宽比
            xDiff = abs(vc[i].center.x - vc[j].center.x) / nh; //x差比率
            yDiff = abs(vc[i].center.y - vc[j].center.y) / nh; //y差比率
            if (ratio < 1.0 || ratio > 5.0 || xDiff < 0.5 || yDiff > 2.0)
                continue;
            ARMOR.size.height = nh;
            ARMOR.size.width = nw;
            vRec.push_back(ARMOR);
            Point2f point1;
            Point2f point2;
            point1.x=vc[i].center.x;point1.y=vc[i].center.y+20;
            point2.x=vc[j].center.x;point2.y=vc[j].center.y-20;
            int xmidnum = (point1.x+point2.x)/2;
            int ymidnum = (point1.y+point2.y)/2;
            //此时轮廓已筛选完毕,为了方便输出,我们将得到的数据就此输出处理
            ARMOR.center.x = filter(ARMOR.center.x,xmidnum, DELAT_MAX);
            ARMOR.center.y = filter(ARMOR.center.y,ymidnum, DELAT_MAX);
            //随机颜色拟合线
            Scalar color(rand() & 255, rand() & 255, rand() & 255);
            rectangle(imgOriginal, point1,point2, color, 2);//将装甲板框起来
            circle(imgOriginal,ARMOR.center,10,color);//在装甲板中心画一个圆

        }
    }

4.9 展示

imshow("Armor", imgOriginal);

5 效果图

希望对你有所帮助。

  • 6
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值