C++ OpenCV红绿灯检测Demo实现详解

   2023-02-09 学习力0
核心提示:目录原理代码实现打包程序为exe总结很久以来一直想实现红绿灯检测,今天它来了。原理OpenCV好强,能够提取红绿灯的轮廓,并根据颜色空间判断红绿,不依赖深度学习算法也能做到可用的效果/demo。红绿灯检测的基本步骤如下:轮廓检测、计数red、green和light_ou

很久以来一直想实现红绿灯检测,今天它来了。

原理

OpenCV好强,能够提取红绿灯的轮廓,并根据颜色空间判断红绿,不依赖深度学习算法也能做到可用的效果/demo。

红绿灯检测的基本步骤如下:

  • 轮廓检测、计数
  • red、green和light_out三种状态
  • 提取颜色空间,红和绿
  • 膨胀和腐蚀,去除噪点
  • 判断3种状态

代码实现

基于网络上的代码做复现的时候,遇到了opencv不同版本所出现的标识符未声明问题,我这里是基于opencv4.5.4实现的,4.x的应该都可以运行。

创建trafficlight.h头文件,将一些引用和全局变量放进来:

#pragma once

#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include <opencv2/imgproc/types_c.h>	//opencv3-4
#include <opencv2/imgproc/imgproc_c.h>	//出现很多未声明标识符的问题
#include <windows.h>
#include <iostream>

using namespace std;
using namespace cv;

// 函数声明
int processImgR(Mat);
int processImgG(Mat);
bool isIntersected(Rect, Rect);
void detect(Mat& frame);

// 全局变量
bool isFirstDetectedR = true;
bool isFirstDetectedG = true;
Rect* lastTrackBoxR;
Rect* lastTrackBoxG;
int lastTrackNumR;
int lastTrackNumG;

然后创建main.cpp,将主函数和功能函数加进来:

//下一步:如何调整视频检测框,防止误检
#include "trafficlight.h"

/*
1.轮廓检测、计数
2.red、green和light_out三种状态
3.提取颜色空间,红和绿
4.膨胀和腐蚀,去除噪点
5.判断3种状态
*/

//主函数

int main()
{
	int redCount = 0;
	int greenCount = 0;

	Mat frame;
	Mat img;
	Mat imgYCrCb;
	Mat imgGreen;
	Mat imgRed;

	// 亮度参数
	double a = 0.3;
	double b = (1 - a) * 125;

	VideoCapture capture("traffic.mkv");//导入视频的路径/摄像头 0
	if (!capture.isOpened())
	{
		cout << "Start device failed!\n" << endl;//启动设备失败!
		return -1;
	}

	// 帧处理
	while (1)
	{
		capture >> frame;
		//调整亮度
		frame.convertTo(img, img.type(), a, b);

		//转换为YCrCb颜色空间
		cvtColor(img, imgYCrCb, CV_BGR2YCrCb);

		imgRed.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);
		imgGreen.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);

		//分解YCrCb的三个成分
		vector<Mat> planes;
		split(imgYCrCb, planes);
		// 遍历以根据Cr分量拆分红色和绿色
		MatIterator_<uchar> it_Cr = planes[1].begin<uchar>(),
			it_Cr_end = planes[1].end<uchar>();
		MatIterator_<uchar> it_Red = imgRed.begin<uchar>();
		MatIterator_<uchar> it_Green = imgGreen.begin<uchar>();

		for (; it_Cr != it_Cr_end; ++it_Cr, ++it_Red, ++it_Green)
		{
			// RED, 145<Cr<470 红色
			if (*it_Cr > 145 && *it_Cr < 470)
				*it_Red = 255;
			else
				*it_Red = 0;

			// GREEN 95<Cr<110 绿色
			if (*it_Cr > 95 && *it_Cr < 110)
				*it_Green = 255;
			else
				*it_Green = 0;
		}

		//膨胀和腐蚀
		dilate(imgRed, imgRed, Mat(15, 15, CV_8UC1), Point(-1, -1));
		erode(imgRed, imgRed, Mat(1, 1, CV_8UC1), Point(-1, -1));
		dilate(imgGreen, imgGreen, Mat(15, 15, CV_8UC1), Point(-1, -1));
		erode(imgGreen, imgGreen, Mat(1, 1, CV_8UC1), Point(-1, -1));

		redCount = processImgR(imgRed);
		greenCount = processImgG(imgGreen);
		cout << "red:" << redCount << ";  " << "green:" << greenCount << endl;

		//条件判断
		if (redCount == 0 && greenCount == 0)
		{
			cv::putText(frame, "lights out", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(255, 255, 255), 8, 8, 0);
		}
		else if (redCount > greenCount)
		{
			cv::putText(frame, "red light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 0, 255), 8, 8, 0);
		}
		else {
			cv::putText(frame, "green light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 255, 0), 8, 8, 0);
		}

		imshow("video", frame);
		//imshow("Red", imgRed);
		//imshow("Green", imgGreen);

		// Handle with the keyboard input
		if (waitKey(20) == 'q')
			break;
	}

	return 0;
}

//轮廓处理函数:红
int processImgR(Mat src)
{
	Mat tmp;

	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	vector<Point> hull;

	CvPoint2D32f tempNode;
	CvMemStorage* storage = cvCreateMemStorage();
	CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);

	Rect* trackBox;
	Rect* result;
	int resultNum = 0;

	int area = 0;
	src.copyTo(tmp);

	//提取轮廓
	findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

	if (contours.size() > 0)
	{
		trackBox = new Rect[contours.size()];
		result = new Rect[contours.size()];

		//确定要跟踪的区域
		for (int i = 0; i < contours.size(); i++)
		{
			cvClearSeq(pointSeq);
			// 获取凸包的点集
			convexHull(Mat(contours[i]), hull, true);
			int hullcount = (int)hull.size();
			// 凸包的保存点
			for (int j = 0; j < hullcount - 1; j++)
			{
				tempNode.x = hull[j].x;
				tempNode.y = hull[j].y;
				cvSeqPush(pointSeq, &tempNode);
			}

			trackBox[i] = cvBoundingRect(pointSeq);
		}

		if (isFirstDetectedR)
		{
			lastTrackBoxR = new Rect[contours.size()];
			for (int i = 0; i < contours.size(); i++)
				lastTrackBoxR[i] = trackBox[i];
			lastTrackNumR = contours.size();
			isFirstDetectedR = false;
		}
		else
		{
			for (int i = 0; i < contours.size(); i++)
			{
				for (int j = 0; j < lastTrackNumR; j++)
				{
					if (isIntersected(trackBox[i], lastTrackBoxR[j]))
					{
						result[resultNum] = trackBox[i];
						break;
					}
				}
				resultNum++;
			}
			delete[] lastTrackBoxR;
			lastTrackBoxR = new Rect[contours.size()];
			for (int i = 0; i < contours.size(); i++)
			{
				lastTrackBoxR[i] = trackBox[i];
			}
			lastTrackNumR = contours.size();
		}

		delete[] trackBox;
	}
	else
	{
		isFirstDetectedR = true;
		result = NULL;
	}
	cvReleaseMemStorage(&storage);

	if (result != NULL)
	{
		for (int i = 0; i < resultNum; i++)
		{
			area += result[i].area();
		}
	}
	delete[] result;

	return area;
}

//轮廓处理函数:绿
int processImgG(Mat src)
{
	Mat tmp;

	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	vector< Point > hull;

	CvPoint2D32f tempNode;
	CvMemStorage* storage = cvCreateMemStorage();
	CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);

	Rect* trackBox;
	Rect* result;
	int resultNum = 0;

	int area = 0;

	src.copyTo(tmp);
	//提取轮廓
	findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

	if (contours.size() > 0)
	{
		trackBox = new Rect[contours.size()];
		result = new Rect[contours.size()];

		// 确定要跟踪的区域
		for (int i = 0; i < contours.size(); i++)
		{
			cvClearSeq(pointSeq);
			// 获取凸包的点集
			convexHull(Mat(contours[i]), hull, true);
			int hullcount = (int)hull.size();
			// 保存凸包的点
			for (int j = 0; j < hullcount - 1; j++)
			{
				tempNode.x = hull[j].x;
				tempNode.y = hull[j].y;
				cvSeqPush(pointSeq, &tempNode);
			}

			trackBox[i] = cvBoundingRect(pointSeq);
		}

		if (isFirstDetectedG)
		{
			lastTrackBoxG = new Rect[contours.size()];
			for (int i = 0; i < contours.size(); i++)
				lastTrackBoxG[i] = trackBox[i];
			lastTrackNumG = contours.size();
			isFirstDetectedG = false;
		}
		else
		{
			for (int i = 0; i < contours.size(); i++)
			{
				for (int j = 0; j < lastTrackNumG; j++)
				{
					if (isIntersected(trackBox[i], lastTrackBoxG[j]))
					{
						result[resultNum] = trackBox[i];
						break;
					}
				}
				resultNum++;
			}
			delete[] lastTrackBoxG;
			lastTrackBoxG = new Rect[contours.size()];
			for (int i = 0; i < contours.size(); i++)
			{
				lastTrackBoxG[i] = trackBox[i];
			}
			lastTrackNumG = contours.size();
		}

		delete[] trackBox;
	}
	else
	{
		isFirstDetectedG = true;
		result = NULL;
	}
	cvReleaseMemStorage(&storage);

	if (result != NULL)
	{
		for (int i = 0; i < resultNum; i++)
		{
			area += result[i].area();
		}
	}
	delete[] result;

	return area;
}

//确定两个矩形区域是否相交
bool isIntersected(Rect r1, Rect r2)
{
	int minX = max(r1.x, r2.x);
	int minY = max(r1.y, r2.y);
	int maxX = min(r1.x + r1.width, r2.x + r2.width);
	int maxY = min(r1.y + r1.height, r2.y + r2.height);

	//判断是否相交
	if (minX < maxX && minY < maxY)
		return true;
	else
		return false;
}

运行结果如下(b站视频):

C++ OpenCV红绿灯检测Demo实现详解

打包程序为exe

首先在VS的扩展和更新中安装Installer的扩展:

C++ OpenCV红绿灯检测Demo实现详解

然后在解决方案下新建setup工程:

C++ OpenCV红绿灯检测Demo实现详解

添加项目输出:

C++ OpenCV红绿灯检测Demo实现详解

在主输出这里创建快捷方式,然后移动到User’s Desktop文件夹下:

C++ OpenCV红绿灯检测Demo实现详解

然后添加工程所需文件,把工程所需的数据文件和依赖库都添加进来:

C++ OpenCV红绿灯检测Demo实现详解

找依赖库的方式可以用这个命令,然后搜索并添加进来:

C++ OpenCV红绿灯检测Demo实现详解

最后,点击生成,生成完成后,就可以安装了:

C++ OpenCV红绿灯检测Demo实现详解

安装文件如下:

C++ OpenCV红绿灯检测Demo实现详解

这样打包出来的安装程序在开发电脑上可以正常运行,但分发出去后其他电脑运行会闪退,我已经把所需的dll(opencv)都添加进来了,有大佬解释一下吗。

以上。

总结

原文地址:https://blog.csdn.net/qq_40344790/article/details/127653557
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • matlab下mex 调用opencv库
    1. 首先写好待编译的.cpp文件,使用混合编程,以人脸检测为例#include "mex.h" // Required for the use of MEX files// Required for OpenCV #include "cv.h"static CvMemStorage* storage = 0;static CvHaarClassifierCascade* cascade = 0;/** This is a t
    02-09
  • 在Objective-C中使用OpenCV(含源码)
          申明:本博文内容来自于互联网,如因本文内容而发生的一切纠纷,均与本文章的翻译者无关。翻译质量因本人水平,有所限制。欢迎批评指正。本文章仅供参考、学习、交流之用,禁止用于任何商业用途。转载时请保留原文出处与保留本申明,多谢合作! 
    02-09
  • Python+OpenCV手势检测与识别Mediapipe基础篇
    Python+OpenCV手势检测与识别Mediapipe基础篇
    目录前言项目效果图认识Mediapipe项目环境代码核心代码视频帧率计算完整代码项目输出结语前言本篇文章适合刚入门OpenCV的同学们。文章将介绍如何使用Python利用OpenCV图像捕捉,配合强大的Mediapipe库来实现手势检测与识别;本系列后续还会继续更新Mediapipe
  • openCV-Python笔记之解读图像的读取、显示和保
    目录一、读入图像二、显示图像三、保存图像四、图片操作总结使用cv2.imread(),cv2.imshow(),cv2.imwrite()读取、显示和保存图像一、读入图像使用函数cv2.imread(filepath,flags)读入一副图片filepath:要读入图片的完整路径flags:读入图片的标志cv2.IMREAD
  • Python利用OpenCV和skimage实现图像边缘检测
    Python利用OpenCV和skimage实现图像边缘检测
    目录一、简介二、opencv 实践三、skimage 实践一、简介提取图片的边缘信息是底层数字图像处理的基本任务之一。边缘信息对进一步提取高层语义信息有很大的影响。大部分边缘检测算法都是上个世纪的了,OpenCV 的使用的算法是 Canny 边缘检测算法,大概是在 1986
  • Python基于OpenCV的视频图像处理详解
    Python基于OpenCV的视频图像处理详解
    目录初识OpenCV视频读写处理运动轨迹标记运动检测运动方向检测初识OpenCVOpenCV是一个开源的,跨平台的计算机视觉库,它采用优化的C/C++代码编写,能够充分利用多核处理器的优势,提供了Python,Ruby,MATPLOAB以及其他高级语言接口。OpenCV的设计目标是执行
  • C# OpenCV实现形状匹配的方法详解
    C# OpenCV实现形状匹配的方法详解
    1. 多角度模板匹配测试效果如下图:图1-1 图1-2图1-3正负角度均可正常识别,识别角度偏差1°2. 下面分享一下开发过程:a). ROI区域的生成,基于GDI+完成图形绘制,如图绘制模板设置区域,用来生成需要的模板特征。ROI区域绘制代码如下:/// summary/// 区域绘
  • 【CV】虹膜识别源代码下载,分别基于MATLAB、C+
    ###Date: 2018.3.28================================================================转载自:https://blog.csdn.net/ss910/article/details/738390351.Libor Masek的MATLAB虹膜识别论文和源代码下载,2003年http://www.peterkovesi.com/studentprojects/li
    02-08
  • opencv的resize和matlab的imresize函数的计算
    opencv的resize和matlab的imresize函数的计算
    在用c++代码复现matlab代码时,遇到两者resize函数的结果不相同的问题。opencv:resize(image1, reTmp, Size(50, 50), 0, 0, cv::INTER_LINEAR);matlab:tmp=imresize(img,[50 50],'bilinear','AntiAliasing',false);以一张500×396的彩色图片为例,resize到(50
    02-08
  • using Opencv Objective-C code
    In this post I'll use GLImageProcessing sample demo from Apple. Also you will need precompiled OpenCV for iPhone. How to make it read here.I've copied all OpenCV stuff to "opencv" folder into the GLImageProcessing. Here is project dire
    02-07
点击排行