装甲板识别
装甲板识别是一个老项目了,很多人的入门项目也是它,接下来我来分享一下我的代码(写代码过程中也参考了很多网络上的博客和很多RM强队的代码),目前我的还只是初创,全供大家入门时观赏。
第一步,先是进行图像读取,利用videocapture capture来读取视频,然后用循环读取每一帧
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{VideoCapture capture("C:/Users/qq117/Desktop/ood_red.mp4");Mat frame;while (true){capture.read(frame);if (frame.empty()){break;}int c = waitKey(30);if (c == 27)break;}waitKey(0);return 0;}
第二步,对图像进行预处理,我是采用颜色作为特征,分离通道,将所要颜色部分表露出来,同时由于装甲板灯光的特性,我采用了先高斯滤波模糊,后膨胀、闭运算,使我所要的轮廓更加准确,然后再findcontours
vector<Mat>channels;split(frame, channels);Mat red = channels.at(2);inRange(red, Scalar(156, 43, 46), Scalar(180, 255, 255), red);Canny(red, red, 0, 30, 3);GaussianBlur(red, red, Size(3, 3), 0);Mat element = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));dilate(red, red, element);morphologyEx(red, red, MORPH_CLOSE, 0);vector<vector<Point>>contours;vector<Vec4i>hierachy;findContours(red, contours, hierachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
第三部分就是拟合部分,但由于我才疏学浅,暂时还不能详细解释,只好先将代码放这,之后再来改,望见谅。
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 > 5)continue;// 扩大灯柱的面积Light_Rec.size.height *= 1.1;Light_Rec.size.width *= 1.1;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 angleDiff_ = abs(leftLight.angle - rightLight.angle);//长度差比率float LenDiff_ratio = abs(leftLight.length - rightLight.length) / max(leftLight.length, rightLight.length);//筛选if (angleDiff_ > 10 || LenDiff_ratio > 0.8) {continue;}//左右灯条相距距离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 lendiff = abs(leftLight.length - rightLight.length) / meanLen;//左右灯条中心点y的差值float yDiff = abs(leftLight.center.y - rightLight.center.y);//y差比率float yDiff_ratio = yDiff / meanLen;//左右灯条中心点x的差值float xDiff = abs(leftLight.center.x - rightLight.center.x);//x差比率float xDiff_ratio = xDiff / meanLen;//相距距离与灯条长度比值float ratio = dis / meanLen;//筛选if (lendiff > 0.5 ||yDiff_ratio > 1.2 ||xDiff_ratio > 2 ||xDiff_ratio < 0.6 ||ratio > 3.5 ||ratio < 0.5) {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);}}}
接下来,我就放出我的完整代码(C++)
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
class LightDescriptor
{
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();}const LightDescriptor& operator =(const LightDescriptor& ld){this->width = ld.width;this->length = ld.length;this->center = ld.center;this->angle = ld.angle;this->area = ld.area;return *this;}
public:float width;float length;cv::Point2f center;float angle;float area;
};int main(int argc, char** argv)
{VideoCapture capture("C:/Users/qq117/Desktop/ood_red.mp4");Mat frame;while (true){capture.read(frame);if (frame.empty()){break;}vector<Mat>channels;split(frame, channels);Mat red = channels.at(2);inRange(red, Scalar(156, 43, 46), Scalar(180, 255, 255), red);Canny(red, red, 0, 30, 3);GaussianBlur(red, red, Size(3, 3), 0);Mat element = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));dilate(red, red, element);morphologyEx(red, red, MORPH_CLOSE, 0);vector<vector<Point>>contours;vector<Vec4i>hierachy;findContours(red, contours, hierachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);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 > 5)continue;// 扩大灯柱的面积Light_Rec.size.height *= 1.1;Light_Rec.size.width *= 1.1;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 angleDiff_ = abs(leftLight.angle - rightLight.angle);//长度差比率float LenDiff_ratio = abs(leftLight.length - rightLight.length) / max(leftLight.length, rightLight.length);//筛选if (angleDiff_ > 10 || LenDiff_ratio > 0.8) {continue;}//左右灯条相距距离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 lendiff = abs(leftLight.length - rightLight.length) / meanLen;//左右灯条中心点y的差值float yDiff = abs(leftLight.center.y - rightLight.center.y);//y差比率float yDiff_ratio = yDiff / meanLen;//左右灯条中心点x的差值float xDiff = abs(leftLight.center.x - rightLight.center.x);//x差比率float xDiff_ratio = xDiff / meanLen;//相距距离与灯条长度比值float ratio = dis / meanLen;//筛选if (lendiff > 0.5 ||yDiff_ratio > 1.2 ||xDiff_ratio > 2 ||xDiff_ratio < 0.6 ||ratio > 3.5 ||ratio < 0.5) {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);}}}imshow("装甲板识别1", red);imshow("装甲板识别", frame);int c = waitKey(30);if (c == 27)break;}waitKey(0);return 0;}