欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++?OpenCV紅綠燈檢測(cè)Demo實(shí)現(xiàn)詳解

 更新時(shí)間:2022年11月15日 12:05:51   作者:Frank學(xué)習(xí)路上  
OpenCV(Open Source Computer Vision Library)是開(kāi)源的計(jì)算機(jī)視覺(jué)和機(jī)器學(xué)習(xí)庫(kù),提供了C++、 C、 Python、 Java接口,并支持Windows、 Linux、 Android、 Mac OS平臺(tái),下面這篇文章主要給大家介紹了關(guān)于C++?OpenCV紅綠燈檢測(cè)Demo實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下

很久以來(lái)一直想實(shí)現(xiàn)紅綠燈檢測(cè),今天它來(lái)了。

原理

OpenCV好強(qiáng),能夠提取紅綠燈的輪廓,并根據(jù)顏色空間判斷紅綠,不依賴深度學(xué)習(xí)算法也能做到可用的效果/demo。

紅綠燈檢測(cè)的基本步驟如下:

  • 輪廓檢測(cè)、計(jì)數(shù)
  • red、green和light_out三種狀態(tài)
  • 提取顏色空間,紅和綠
  • 膨脹和腐蝕,去除噪點(diǎn)
  • 判斷3種狀態(tài)

代碼實(shí)現(xiàn)

基于網(wǎng)絡(luò)上的代碼做復(fù)現(xiàn)的時(shí)候,遇到了opencv不同版本所出現(xiàn)的標(biāo)識(shí)符未聲明問(wèn)題,我這里是基于opencv4.5.4實(shí)現(xiàn)的,4.x的應(yīng)該都可以運(yùn)行。

創(chuàng)建trafficlight.h頭文件,將一些引用和全局變量放進(jìn)來(lái):

#pragma once

#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include <opencv2/imgproc/types_c.h>	//opencv3-4
#include <opencv2/imgproc/imgproc_c.h>	//出現(xiàn)很多未聲明標(biāo)識(shí)符的問(wèn)題
#include <windows.h>
#include <iostream>

using namespace std;
using namespace cv;

// 函數(shù)聲明
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;

然后創(chuàng)建main.cpp,將主函數(shù)和功能函數(shù)加進(jìn)來(lái):

//下一步:如何調(diào)整視頻檢測(cè)框,防止誤檢
#include "trafficlight.h"

/*
1.輪廓檢測(cè)、計(jì)數(shù)
2.red、green和light_out三種狀態(tài)
3.提取顏色空間,紅和綠
4.膨脹和腐蝕,去除噪點(diǎn)
5.判斷3種狀態(tài)
*/

//主函數(shù)

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

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

	// 亮度參數(shù)
	double a = 0.3;
	double b = (1 - a) * 125;

	VideoCapture capture("traffic.mkv");//導(dǎo)入視頻的路徑/攝像頭 0
	if (!capture.isOpened())
	{
		cout << "Start device failed!\n" << endl;//啟動(dòng)設(shè)備失敗!
		return -1;
	}

	// 幀處理
	while (1)
	{
		capture >> frame;
		//調(diào)整亮度
		frame.convertTo(img, img.type(), a, b);

		//轉(zhuǎn)換為YCrCb顏色空間
		cvtColor(img, imgYCrCb, CV_BGR2YCrCb);

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

		//分解YCrCb的三個(gè)成分
		vector<Mat> planes;
		split(imgYCrCb, planes);
		// 遍歷以根據(jù)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;
}

//輪廓處理函數(shù):紅
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()];

		//確定要跟蹤的區(qū)域
		for (int i = 0; i < contours.size(); i++)
		{
			cvClearSeq(pointSeq);
			// 獲取凸包的點(diǎn)集
			convexHull(Mat(contours[i]), hull, true);
			int hullcount = (int)hull.size();
			// 凸包的保存點(diǎn)
			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;
}

//輪廓處理函數(shù):綠
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()];

		// 確定要跟蹤的區(qū)域
		for (int i = 0; i < contours.size(); i++)
		{
			cvClearSeq(pointSeq);
			// 獲取凸包的點(diǎn)集
			convexHull(Mat(contours[i]), hull, true);
			int hullcount = (int)hull.size();
			// 保存凸包的點(diǎn)
			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;
}

//確定兩個(gè)矩形區(qū)域是否相交
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;
}

運(yùn)行結(jié)果如下(b站視頻):

打包程序?yàn)閑xe

首先在VS的擴(kuò)展和更新中安裝Installer的擴(kuò)展:

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

添加項(xiàng)目輸出:

在主輸出這里創(chuàng)建快捷方式,然后移動(dòng)到User’s Desktop文件夾下:

然后添加工程所需文件,把工程所需的數(shù)據(jù)文件和依賴庫(kù)都添加進(jìn)來(lái):

找依賴庫(kù)的方式可以用這個(gè)命令,然后搜索并添加進(jìn)來(lái):

最后,點(diǎn)擊生成,生成完成后,就可以安裝了:

安裝文件如下:

這樣打包出來(lái)的安裝程序在開(kāi)發(fā)電腦上可以正常運(yùn)行,但分發(fā)出去后其他電腦運(yùn)行會(huì)閃退,我已經(jīng)把所需的dll(opencv)都添加進(jìn)來(lái)了,有大佬解釋一下嗎。

以上。

總結(jié)

到此這篇關(guān)于C++ OpenCV紅綠燈檢測(cè)Demo實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++ OpenCV紅綠燈檢測(cè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于c++ ege圖形庫(kù)實(shí)現(xiàn)五子棋游戲

    基于c++ ege圖形庫(kù)實(shí)現(xiàn)五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了基于c++ ege圖形庫(kù)實(shí)現(xiàn)五子棋游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • C與C++動(dòng)態(tài)分配二維數(shù)組的實(shí)現(xiàn)方法

    C與C++動(dòng)態(tài)分配二維數(shù)組的實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇C與C++動(dòng)態(tài)分配二維數(shù)組的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12
  • C++解決輸出鏈表中倒數(shù)k個(gè)結(jié)點(diǎn)的問(wèn)題

    C++解決輸出鏈表中倒數(shù)k個(gè)結(jié)點(diǎn)的問(wèn)題

    這篇文章主要給大家介紹了關(guān)于如何利用C++解決輸出鏈表中倒數(shù)k個(gè)結(jié)點(diǎn)的問(wèn)題,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-12-12
  • C語(yǔ)言之格式化屏幕輸出詳解

    C語(yǔ)言之格式化屏幕輸出詳解

    這篇文章主要介紹了C語(yǔ)言之格式化屏幕輸出的相關(guān)資料,需要的朋友可以參考下,小編覺(jué)得這篇文章寫的還不錯(cuò),希望能夠給你帶來(lái)幫助
    2021-11-11
  • C++使用ADO實(shí)現(xiàn)存取圖片的方法

    C++使用ADO實(shí)現(xiàn)存取圖片的方法

    這篇文章主要介紹了C++使用ADO實(shí)現(xiàn)存取圖片的方法,需要的朋友可以參考下
    2014-07-07
  • 詳解C 語(yǔ)言項(xiàng)目中.h文件和.c文件的關(guān)系

    詳解C 語(yǔ)言項(xiàng)目中.h文件和.c文件的關(guān)系

    這篇文章主要介紹了詳解C 語(yǔ)言項(xiàng)目中.h文件和.c文件的關(guān)系的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • C語(yǔ)言實(shí)現(xiàn)桶排序的方法示例

    C語(yǔ)言實(shí)現(xiàn)桶排序的方法示例

    這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)桶排序的方法,簡(jiǎn)單描述了桶排序的概念、原理并結(jié)合實(shí)例形式分析了C語(yǔ)言實(shí)現(xiàn)桶排序算法的具體操作技巧,需要的朋友可以參考下
    2018-01-01
  • C語(yǔ)言小程序 楊輝三角示例代碼

    C語(yǔ)言小程序 楊輝三角示例代碼

    輸入要顯示的楊輝三角的行數(shù),會(huì)打印出金字塔型的楊輝三角,不過(guò)行數(shù)太多的話,效果不太好,可以再調(diào)整一下格式控制
    2013-07-07
  • C語(yǔ)言實(shí)現(xiàn)三子棋小游戲

    C語(yǔ)言實(shí)現(xiàn)三子棋小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)三子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++?中IO流詳解

    C++?中IO流詳解

    這篇文章主要介紹了C++?IO流的相關(guān)知識(shí)點(diǎn),文中有詳細(xì)的代碼,希望可以幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2023-05-05

最新評(píng)論