• 【OpenCV】 红绿灯识别检测


    目录

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

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

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

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

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

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

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

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

    三: 红绿灯识别检测完整代码


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

    使用到了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 planes;
    13. split(imgYCrCb, planes);
    14. // 遍历以根据Cr分量拆分红色和绿色
    15. MatIterator_ it_Cr = planes[1].begin(),
    16. it_Cr_end = planes[1].end();
    17. MatIterator_ it_Red = imgRed.begin();
    18. MatIterator_ it_Green = imgGreen.begin();
    19. for (; it_Cr != it_Cr_end; ++it_Cr, ++it_Red, ++it_Green)
    20. {
    21. // RED, 145
    22. if (*it_Cr > 145 && *it_Cr < 470)
    23. *it_Red = 255;
    24. else
    25. *it_Red = 0;
    26. // GREEN 95
    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> contours;
    5. vector hierarchy;
    6. vector 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 > contours;
    89. vector 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
    4. #include
    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 planes;
    49. split(imgYCrCb, planes);
    50. // 遍历以根据Cr分量拆分红色和绿色
    51. MatIterator_ it_Cr = planes[1].begin(),
    52. it_Cr_end = planes[1].end();
    53. MatIterator_ it_Red = imgRed.begin();
    54. MatIterator_ it_Green = imgGreen.begin();
    55. for (; it_Cr != it_Cr_end; ++it_Cr, ++it_Red, ++it_Green)
    56. {
    57. // RED, 145
    58. if (*it_Cr > 145 && *it_Cr < 470)
    59. *it_Red = 255;
    60. else
    61. *it_Red = 0;
    62. // GREEN 95
    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> contours;
    98. vector hierarchy;
    99. vector 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 > contours;
    182. vector 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. }
  • 相关阅读:
    基于Python的智能视频分析之人数统计的多种实现
    PostgreSQL数据库
    【析】一类动态车辆路径问题模型和两阶段算法
    Vue项目 -- 解决Eslint导致的console报错问题
    共享内存区
    Linux安装MySQL【Ubuntu20.04】
    mysql8.0 服务器和服务器启动程序 客户端程序
    Java生成二维码
    面试题:项目中是如何使用ES(elasticsearch)的?如何优化的?数据量多少?
    面试官:vue的这些原理你了解吗?
  • 原文地址:https://blog.csdn.net/m0_56051805/article/details/126286905