最近要完成装甲板灯条识别的任务,但我本身对于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; |
| 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); |
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]); |
| |
| 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; |
| 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); |
| |
| 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]); |
| |
| 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; |
| } |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!