0


【OpenCV】 红绿灯识别检测

一:红绿灯识别检测效果展示

使用到了OpenCV轮廓识别

如上图 轮廓识别 分别检测识别出红灯 绿灯 [检测出来的红灯轮廓和绿灯轮廓如下图所示]

在红绿灯都亮时,可以检测到数值

当红灯不亮 绿灯亮时,红灯没有数值 绿灯显示数值

当拍摄车辆通行,也就是红绿灯都不亮的时候,红灯绿灯都没有数值

二:红绿灯识别检测具体步骤

1.初始化设置,对亮度设置 视频路径 进行初始化设置

  1. int redCount = 0;
  2. int greenCount = 0;
  3. Mat frame;
  4. Mat img;
  5. Mat imgYCrCb;
  6. Mat imgGreen;
  7. Mat imgRed;
  8. // 亮度参数
  9. double a = 0.3;
  10. double b = (1 - a) * 125;
  11. VideoCapture capture("D:/00000000000003jieduanshipincailliao/123.mp4");//导入视频的路径
  12. if (!capture.isOpened())
  13. {
  14. cout << "Start device failed!\n" << endl;//启动设备失败!
  15. return -1;
  16. }

2.帧处理,调整视频亮度,分解YCrCb的三个成分,拆分红和绿,对这两种颜色进行特征提取

  1. // 帧处理
  2. while (1)
  3. {
  4. capture >> frame;
  5. //调整亮度
  6. frame.convertTo(img, img.type(), a, b);
  7. //转换为YCrCb颜色空间
  8. cvtColor(img, imgYCrCb, CV_BGR2YCrCb);
  9. imgRed.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);
  10. imgGreen.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);
  11. //分解YCrCb的三个成分
  12. vector<Mat> planes;
  13. split(imgYCrCb, planes);
  14. // 遍历以根据Cr分量拆分红色和绿色
  15. MatIterator_<uchar> it_Cr = planes[1].begin<uchar>(),
  16. it_Cr_end = planes[1].end<uchar>();
  17. MatIterator_<uchar> it_Red = imgRed.begin<uchar>();
  18. MatIterator_<uchar> it_Green = imgGreen.begin<uchar>();
  19. for (; it_Cr != it_Cr_end; ++it_Cr, ++it_Red, ++it_Green)
  20. {
  21. // RED, 145<Cr<470 红色
  22. if (*it_Cr > 145 && *it_Cr < 470)
  23. *it_Red = 255;
  24. else
  25. *it_Red = 0;
  26. // GREEN 95<Cr<110 绿色
  27. if (*it_Cr > 95 && *it_Cr < 110)
  28. *it_Green = 255;
  29. else
  30. *it_Green = 0;
  31. }

3.腐蚀膨胀处理,去除其他噪点,提高红绿灯提取特征

  1. //膨胀和腐蚀
  2. dilate(imgRed, imgRed, Mat(15, 15, CV_8UC1), Point(-1, -1));
  3. erode(imgRed, imgRed, Mat(1, 1, CV_8UC1), Point(-1, -1));
  4. dilate(imgGreen, imgGreen, Mat(15, 15, CV_8UC1), Point(-1, -1));
  5. erode(imgGreen, imgGreen, Mat(1, 1, CV_8UC1), Point(-1, -1));
  6. redCount = processImgR(imgRed);
  7. greenCount = processImgG(imgGreen);
  8. cout << "red:" << redCount << "; " << "green:" << greenCount << endl;

4.红绿灯识别检测,给出识别结果显示

  1. if(redCount == 0 && greenCount == 0)
  2. {
  3. cv::putText(frame, "lights out", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(255, 255, 255), 8, 8, 0);
  4. }else if(redCount > greenCount)
  5. {
  6. cv::putText(frame, "red light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 0, 255), 8, 8, 0);
  7. }else{
  8. cv::putText(frame, "green light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 255, 0), 8, 8, 0);
  9. }

5.对红灯和绿灯进行轮廓提取

  1. int processImgR(Mat src)
  2. {
  3. Mat tmp;
  4. vector<vector<Point>> contours;
  5. vector<Vec4i> hierarchy;
  6. vector<Point> hull;
  7. CvPoint2D32f tempNode;
  8. CvMemStorage* storage = cvCreateMemStorage();
  9. CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);
  10. Rect* trackBox;
  11. Rect* result;
  12. int resultNum = 0;
  13. int area = 0;
  14. src.copyTo(tmp);
  15. //提取轮廓
  16. findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
  17. if (contours.size() > 0)
  18. {
  19. trackBox = new Rect[contours.size()];
  20. result = new Rect[contours.size()];
  21. //确定要跟踪的区域
  22. for (int i = 0; i < contours.size(); i++)
  23. {
  24. cvClearSeq(pointSeq);
  25. // 获取凸包的点集
  26. convexHull(Mat(contours[i]), hull, true);
  27. int hullcount = (int)hull.size();
  28. // 凸包的保存点
  29. for (int j = 0; j < hullcount - 1; j++)
  30. {
  31. tempNode.x = hull[j].x;
  32. tempNode.y = hull[j].y;
  33. cvSeqPush(pointSeq, &tempNode);
  34. }
  35. trackBox[i] = cvBoundingRect(pointSeq);
  36. }
  37. if (isFirstDetectedR)
  38. {
  39. lastTrackBoxR = new Rect[contours.size()];
  40. for (int i = 0; i < contours.size(); i++)
  41. lastTrackBoxR[i] = trackBox[i];
  42. lastTrackNumR = contours.size();
  43. isFirstDetectedR = false;
  44. }
  45. else
  46. {
  47. for (int i = 0; i < contours.size(); i++)
  48. {
  49. for (int j = 0; j < lastTrackNumR; j++)
  50. {
  51. if (isIntersected(trackBox[i], lastTrackBoxR[j]))
  52. {
  53. result[resultNum] = trackBox[i];
  54. break;
  55. }
  56. }
  57. resultNum++;
  58. }
  59. delete[] lastTrackBoxR;
  60. lastTrackBoxR = new Rect[contours.size()];
  61. for (int i = 0; i < contours.size(); i++)
  62. {
  63. lastTrackBoxR[i] = trackBox[i];
  64. }
  65. lastTrackNumR = contours.size();
  66. }
  67. delete[] trackBox;
  68. }
  69. else
  70. {
  71. isFirstDetectedR = true;
  72. result = NULL;
  73. }
  74. cvReleaseMemStorage(&storage);
  75. if (result != NULL)
  76. {
  77. for (int i = 0; i < resultNum; i++)
  78. {
  79. area += result[i].area();
  80. }
  81. }
  82. delete[] result;
  83. return area;
  84. }
  85. int processImgG(Mat src)
  86. {
  87. Mat tmp;
  88. vector<vector<Point> > contours;
  89. vector<Vec4i> hierarchy;
  90. vector< Point > hull;
  91. CvPoint2D32f tempNode;
  92. CvMemStorage* storage = cvCreateMemStorage();
  93. CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);
  94. Rect* trackBox;
  95. Rect* result;
  96. int resultNum = 0;
  97. int area = 0;
  98. src.copyTo(tmp);
  99. //提取轮廓
  100. findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
  101. if (contours.size() > 0)
  102. {
  103. trackBox = new Rect[contours.size()];
  104. result = new Rect[contours.size()];
  105. // 确定要跟踪的区域
  106. for (int i = 0; i < contours.size(); i++)
  107. {
  108. cvClearSeq(pointSeq);
  109. // 获取凸包的点集
  110. convexHull(Mat(contours[i]), hull, true);
  111. int hullcount = (int)hull.size();
  112. // 保存凸包的点
  113. for (int j = 0; j < hullcount - 1; j++)
  114. {
  115. tempNode.x = hull[j].x;
  116. tempNode.y = hull[j].y;
  117. cvSeqPush(pointSeq, &tempNode);
  118. }
  119. trackBox[i] = cvBoundingRect(pointSeq);
  120. }
  121. if (isFirstDetectedG)
  122. {
  123. lastTrackBoxG = new Rect[contours.size()];
  124. for (int i = 0; i < contours.size(); i++)
  125. lastTrackBoxG[i] = trackBox[i];
  126. lastTrackNumG = contours.size();
  127. isFirstDetectedG = false;
  128. }
  129. else
  130. {
  131. for (int i = 0; i < contours.size(); i++)
  132. {
  133. for (int j = 0; j < lastTrackNumG; j++)
  134. {
  135. if (isIntersected(trackBox[i], lastTrackBoxG[j]))
  136. {
  137. result[resultNum] = trackBox[i];
  138. break;
  139. }
  140. }
  141. resultNum++;
  142. }
  143. delete[] lastTrackBoxG;
  144. lastTrackBoxG = new Rect[contours.size()];
  145. for (int i = 0; i < contours.size(); i++)
  146. {
  147. lastTrackBoxG[i] = trackBox[i];
  148. }
  149. lastTrackNumG = contours.size();
  150. }
  151. delete[] trackBox;
  152. }
  153. else
  154. {
  155. isFirstDetectedG = true;
  156. result = NULL;
  157. }
  158. cvReleaseMemStorage(&storage);
  159. if (result != NULL)
  160. {
  161. for (int i = 0; i < resultNum; i++)
  162. {
  163. area += result[i].area();
  164. }
  165. }
  166. delete[] result;
  167. return area;
  168. }

6.确定两个矩形区域是否相交

  1. //确定两个矩形区域是否相交
  2. bool isIntersected(Rect r1, Rect r2)
  3. {
  4. int minX = max(r1.x, r2.x);
  5. int minY = max(r1.y, r2.y);
  6. int maxX = min(r1.x + r1.width, r2.x + r2.width);
  7. int maxY = min(r1.y + r1.height, r2.y + r2.height);
  8. if (minX < maxX && minY < maxY)
  9. return true;
  10. else
  11. return false;
  12. }

三: 红绿灯识别检测源码分享

  1. #include "opencv2/opencv.hpp"
  2. #include "opencv2/imgproc.hpp"
  3. #include <windows.h>
  4. #include <iostream>
  5. using namespace std;
  6. using namespace cv;
  7. // Function headers
  8. int processImgR(Mat);
  9. int processImgG(Mat);
  10. bool isIntersected(Rect, Rect);
  11. // Global variables
  12. bool isFirstDetectedR = true;
  13. bool isFirstDetectedG = true;
  14. Rect* lastTrackBoxR;
  15. Rect* lastTrackBoxG;
  16. int lastTrackNumR;
  17. int lastTrackNumG;
  18. //主函数
  19. int main()
  20. {
  21. int redCount = 0;
  22. int greenCount = 0;
  23. Mat frame;
  24. Mat img;
  25. Mat imgYCrCb;
  26. Mat imgGreen;
  27. Mat imgRed;
  28. // 亮度参数
  29. double a = 0.3;
  30. double b = (1 - a) * 125;
  31. VideoCapture capture("D:/00000000000003jieduanshipincailliao/123.mp4");//导入视频的路径
  32. if (!capture.isOpened())
  33. {
  34. cout << "Start device failed!\n" << endl;//启动设备失败!
  35. return -1;
  36. }
  37. // 帧处理
  38. while (1)
  39. {
  40. capture >> frame;
  41. //调整亮度
  42. frame.convertTo(img, img.type(), a, b);
  43. //转换为YCrCb颜色空间
  44. cvtColor(img, imgYCrCb, CV_BGR2YCrCb);
  45. imgRed.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);
  46. imgGreen.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);
  47. //分解YCrCb的三个成分
  48. vector<Mat> planes;
  49. split(imgYCrCb, planes);
  50. // 遍历以根据Cr分量拆分红色和绿色
  51. MatIterator_<uchar> it_Cr = planes[1].begin<uchar>(),
  52. it_Cr_end = planes[1].end<uchar>();
  53. MatIterator_<uchar> it_Red = imgRed.begin<uchar>();
  54. MatIterator_<uchar> it_Green = imgGreen.begin<uchar>();
  55. for (; it_Cr != it_Cr_end; ++it_Cr, ++it_Red, ++it_Green)
  56. {
  57. // RED, 145<Cr<470 红色
  58. if (*it_Cr > 145 && *it_Cr < 470)
  59. *it_Red = 255;
  60. else
  61. *it_Red = 0;
  62. // GREEN 95<Cr<110 绿色
  63. if (*it_Cr > 95 && *it_Cr < 110)
  64. *it_Green = 255;
  65. else
  66. *it_Green = 0;
  67. }
  68. //膨胀和腐蚀
  69. dilate(imgRed, imgRed, Mat(15, 15, CV_8UC1), Point(-1, -1));
  70. erode(imgRed, imgRed, Mat(1, 1, CV_8UC1), Point(-1, -1));
  71. dilate(imgGreen, imgGreen, Mat(15, 15, CV_8UC1), Point(-1, -1));
  72. erode(imgGreen, imgGreen, Mat(1, 1, CV_8UC1), Point(-1, -1));
  73. redCount = processImgR(imgRed);
  74. greenCount = processImgG(imgGreen);
  75. cout << "red:" << redCount << "; " << "green:" << greenCount << endl;
  76. if(redCount == 0 && greenCount == 0)
  77. {
  78. cv::putText(frame, "lights out", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(255, 255, 255), 8, 8, 0);
  79. }else if(redCount > greenCount)
  80. {
  81. cv::putText(frame, "red light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 0, 255), 8, 8, 0);
  82. }else{
  83. cv::putText(frame, "green light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 255, 0), 8, 8, 0);
  84. }
  85. imshow("video", frame);
  86. imshow("Red", imgRed);
  87. imshow("Green", imgGreen);
  88. // Handle with the keyboard input
  89. if (cvWaitKey(20) == 'q')
  90. break;
  91. }
  92. return 0;
  93. }
  94. int processImgR(Mat src)
  95. {
  96. Mat tmp;
  97. vector<vector<Point>> contours;
  98. vector<Vec4i> hierarchy;
  99. vector<Point> hull;
  100. CvPoint2D32f tempNode;
  101. CvMemStorage* storage = cvCreateMemStorage();
  102. CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);
  103. Rect* trackBox;
  104. Rect* result;
  105. int resultNum = 0;
  106. int area = 0;
  107. src.copyTo(tmp);
  108. //提取轮廓
  109. findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
  110. if (contours.size() > 0)
  111. {
  112. trackBox = new Rect[contours.size()];
  113. result = new Rect[contours.size()];
  114. //确定要跟踪的区域
  115. for (int i = 0; i < contours.size(); i++)
  116. {
  117. cvClearSeq(pointSeq);
  118. // 获取凸包的点集
  119. convexHull(Mat(contours[i]), hull, true);
  120. int hullcount = (int)hull.size();
  121. // 凸包的保存点
  122. for (int j = 0; j < hullcount - 1; j++)
  123. {
  124. tempNode.x = hull[j].x;
  125. tempNode.y = hull[j].y;
  126. cvSeqPush(pointSeq, &tempNode);
  127. }
  128. trackBox[i] = cvBoundingRect(pointSeq);
  129. }
  130. if (isFirstDetectedR)
  131. {
  132. lastTrackBoxR = new Rect[contours.size()];
  133. for (int i = 0; i < contours.size(); i++)
  134. lastTrackBoxR[i] = trackBox[i];
  135. lastTrackNumR = contours.size();
  136. isFirstDetectedR = false;
  137. }
  138. else
  139. {
  140. for (int i = 0; i < contours.size(); i++)
  141. {
  142. for (int j = 0; j < lastTrackNumR; j++)
  143. {
  144. if (isIntersected(trackBox[i], lastTrackBoxR[j]))
  145. {
  146. result[resultNum] = trackBox[i];
  147. break;
  148. }
  149. }
  150. resultNum++;
  151. }
  152. delete[] lastTrackBoxR;
  153. lastTrackBoxR = new Rect[contours.size()];
  154. for (int i = 0; i < contours.size(); i++)
  155. {
  156. lastTrackBoxR[i] = trackBox[i];
  157. }
  158. lastTrackNumR = contours.size();
  159. }
  160. delete[] trackBox;
  161. }
  162. else
  163. {
  164. isFirstDetectedR = true;
  165. result = NULL;
  166. }
  167. cvReleaseMemStorage(&storage);
  168. if (result != NULL)
  169. {
  170. for (int i = 0; i < resultNum; i++)
  171. {
  172. area += result[i].area();
  173. }
  174. }
  175. delete[] result;
  176. return area;
  177. }
  178. int processImgG(Mat src)
  179. {
  180. Mat tmp;
  181. vector<vector<Point> > contours;
  182. vector<Vec4i> hierarchy;
  183. vector< Point > hull;
  184. CvPoint2D32f tempNode;
  185. CvMemStorage* storage = cvCreateMemStorage();
  186. CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);
  187. Rect* trackBox;
  188. Rect* result;
  189. int resultNum = 0;
  190. int area = 0;
  191. src.copyTo(tmp);
  192. //提取轮廓
  193. findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
  194. if (contours.size() > 0)
  195. {
  196. trackBox = new Rect[contours.size()];
  197. result = new Rect[contours.size()];
  198. // 确定要跟踪的区域
  199. for (int i = 0; i < contours.size(); i++)
  200. {
  201. cvClearSeq(pointSeq);
  202. // 获取凸包的点集
  203. convexHull(Mat(contours[i]), hull, true);
  204. int hullcount = (int)hull.size();
  205. // 保存凸包的点
  206. for (int j = 0; j < hullcount - 1; j++)
  207. {
  208. tempNode.x = hull[j].x;
  209. tempNode.y = hull[j].y;
  210. cvSeqPush(pointSeq, &tempNode);
  211. }
  212. trackBox[i] = cvBoundingRect(pointSeq);
  213. }
  214. if (isFirstDetectedG)
  215. {
  216. lastTrackBoxG = new Rect[contours.size()];
  217. for (int i = 0; i < contours.size(); i++)
  218. lastTrackBoxG[i] = trackBox[i];
  219. lastTrackNumG = contours.size();
  220. isFirstDetectedG = false;
  221. }
  222. else
  223. {
  224. for (int i = 0; i < contours.size(); i++)
  225. {
  226. for (int j = 0; j < lastTrackNumG; j++)
  227. {
  228. if (isIntersected(trackBox[i], lastTrackBoxG[j]))
  229. {
  230. result[resultNum] = trackBox[i];
  231. break;
  232. }
  233. }
  234. resultNum++;
  235. }
  236. delete[] lastTrackBoxG;
  237. lastTrackBoxG = new Rect[contours.size()];
  238. for (int i = 0; i < contours.size(); i++)
  239. {
  240. lastTrackBoxG[i] = trackBox[i];
  241. }
  242. lastTrackNumG = contours.size();
  243. }
  244. delete[] trackBox;
  245. }
  246. else
  247. {
  248. isFirstDetectedG = true;
  249. result = NULL;
  250. }
  251. cvReleaseMemStorage(&storage);
  252. if (result != NULL)
  253. {
  254. for (int i = 0; i < resultNum; i++)
  255. {
  256. area += result[i].area();
  257. }
  258. }
  259. delete[] result;
  260. return area;
  261. }
  262. //确定两个矩形区域是否相交
  263. bool isIntersected(Rect r1, Rect r2)
  264. {
  265. int minX = max(r1.x, r2.x);
  266. int minY = max(r1.y, r2.y);
  267. int maxX = min(r1.x + r1.width, r2.x + r2.width);
  268. int maxY = min(r1.y + r1.height, r2.y + r2.height);
  269. if (minX < maxX && minY < maxY)
  270. return true;
  271. else
  272. return false;
  273. }
标签: opencv 人工智能 c++

本文转载自: https://blog.csdn.net/m0_56051805/article/details/126286905
版权归原作者 顾城沐心 所有, 如有侵权,请联系我们删除。

“【OpenCV】 红绿灯识别检测”的评论:

还没有评论