OpenCvSharp實(shí)戰(zhàn):C#交通信號(hào)燈識(shí)別系統(tǒng)詳解
在智能交通系統(tǒng)領(lǐng)域,交通信號(hào)燈識(shí)別是一項(xiàng)基礎(chǔ)且關(guān)鍵的技術(shù)。借助OpenCvSharp庫(kù),C#開(kāi)發(fā)者可以快速構(gòu)建高效準(zhǔn)確的交通信號(hào)識(shí)別系統(tǒng)。本文將詳細(xì)介紹如何使用OpenCvSharp在C#環(huán)境下實(shí)現(xiàn)交通信號(hào)燈的自動(dòng)識(shí)別,提供完整代碼示例和詳細(xì)注釋?zhuān)﹂_(kāi)發(fā)者快速掌握這一技術(shù)。
OpenCvSharp簡(jiǎn)介
OpenCvSharp是一個(gè)OpenCV的.NET封裝庫(kù),它允許.NET開(kāi)發(fā)者使用C#等語(yǔ)言調(diào)用OpenCV的強(qiáng)大功能。相比于其他封裝庫(kù),OpenCvSharp具有以下優(yōu)勢(shì):
- 接口設(shè)計(jì)符合C#風(fēng)格,使用更加自然
- 完整支持OpenCV的主要功能
- 性能損耗小,接近原生C++版本
- 文檔完善,社區(qū)活躍
環(huán)境搭建
安裝必要組件
首先,我們需要通過(guò)NuGet包管理器安裝OpenCvSharp:
// 在Visual Studio中,通過(guò)NuGet包管理器安裝以下包:
// OpenCvSharp4
// OpenCvSharp4.runtime.win
或者在項(xiàng)目文件中添加:
<PackageReference Include="OpenCvSharp4" Version="4.7.0.20230115" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.7.0.20230115" />
交通信號(hào)燈識(shí)別原理
交通信號(hào)燈識(shí)別主要分為以下幾個(gè)步驟:
- 圖像預(yù)處理:調(diào)整大小、降噪、增強(qiáng)對(duì)比度
- 顏色空間轉(zhuǎn)換:從BGR轉(zhuǎn)到HSV顏色空間,便于顏色識(shí)別
- 顏色閾值分割:提取紅、黃、綠三種顏色區(qū)域
- 形狀識(shí)別:識(shí)別圓形區(qū)域,確定信號(hào)燈位置
- 結(jié)果分析:根據(jù)顏色和位置判斷信號(hào)燈狀態(tài)
完整代碼實(shí)現(xiàn)
下面是一個(gè)完整的交通信號(hào)燈識(shí)別系統(tǒng)的實(shí)現(xiàn):
using OpenCvSharp;
namespace AppTrafficLight
{
internal class Program
{
static void Main(string[] args)
{
// 圖像路徑
string imagePath = "traffic_light.jpg";
// 讀取圖像
using (Mat src = Cv2.ImRead(imagePath))
{
if (src.Empty())
{
Console.WriteLine("無(wú)法讀取圖像!");
return;
}
// 顯示原始圖像
using (new Window("原始圖像", src))
{
// 調(diào)整圖像大小以加快處理速度
Mat resized = new Mat();
Cv2.Resize(src, resized, new Size(0, 0), 0.5, 0.5);
// 進(jìn)行高斯模糊以減少噪聲
Mat blurred = new Mat();
Cv2.GaussianBlur(resized, blurred, new Size(5, 5), 0);
// 轉(zhuǎn)換到HSV顏色空間
Mat hsv = new Mat();
Cv2.CvtColor(blurred, hsv, ColorConversionCodes.BGR2HSV);
// 定義紅、黃、綠三種顏色的HSV范圍
// 注意:紅色在HSV中橫跨兩個(gè)區(qū)間,需要兩個(gè)范圍
// 紅色范圍1(0-10)
Scalar redLower1 = new Scalar(0, 100, 100);
Scalar redUpper1 = new Scalar(10, 255, 255);
// 紅色范圍2(160-180)
Scalar redLower2 = new Scalar(160, 100, 100);
Scalar redUpper2 = new Scalar(180, 255, 255);
// 黃色范圍
Scalar yellowLower = new Scalar(15, 100, 100);
Scalar yellowUpper = new Scalar(30, 255, 255);
// 綠色范圍
Scalar greenLower = new Scalar(75, 50, 50);
Scalar greenUpper = new Scalar(95, 255, 255);
// 創(chuàng)建掩碼
Mat redMask1 = new Mat();
Mat redMask2 = new Mat();
Mat redMask = new Mat();
Mat yellowMask = new Mat();
Mat greenMask = new Mat();
// 應(yīng)用閾值,提取各個(gè)顏色區(qū)域
Cv2.InRange(hsv, redLower1, redUpper1, redMask1);
Cv2.InRange(hsv, redLower2, redUpper2, redMask2);
Cv2.BitwiseOr(redMask1, redMask2, redMask); // 合并兩個(gè)紅色區(qū)間
Cv2.InRange(hsv, yellowLower, yellowUpper, yellowMask);
Cv2.InRange(hsv, greenLower, greenUpper, greenMask);
// 顯示各顏色掩碼
using (new Window("紅色掩碼", redMask))
using (new Window("黃色掩碼", yellowMask))
using (new Window("綠色掩碼", greenMask))
{
// 對(duì)每個(gè)掩碼應(yīng)用形態(tài)學(xué)操作以去除噪聲
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(5, 5));
Cv2.MorphologyEx(redMask, redMask, MorphTypes.Open, kernel);
Cv2.MorphologyEx(yellowMask, yellowMask, MorphTypes.Open, kernel);
Cv2.MorphologyEx(greenMask, greenMask, MorphTypes.Open, kernel);
// 尋找輪廓
Point[][] redContours, yellowContours, greenContours;
HierarchyIndex[] redHierarchy, yellowHierarchy, greenHierarchy;
Cv2.FindContours(redMask, out redContours, out redHierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
Cv2.FindContours(yellowMask, out yellowContours, out yellowHierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
Cv2.FindContours(greenMask, out greenContours, out greenHierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
// 創(chuàng)建結(jié)果圖像
Mat result = resized.Clone();
// 處理并繪制紅色信號(hào)
ProcessContours(result, redContours, "Red", new Scalar(0, 0, 255));
// 處理并繪制黃色信號(hào)
ProcessContours(result, yellowContours, "Yellow", new Scalar(0, 255, 255));
// 處理并繪制綠色信號(hào)
ProcessContours(result, greenContours, "Green", new Scalar(0, 255, 0));
// 顯示結(jié)果
using (new Window("識(shí)別結(jié)果", result))
{
Cv2.WaitKey(0);
}
}
}
}
}
/// <summary>
/// 處理輪廓并繪制識(shí)別結(jié)果
/// </summary>
/// <param name="image">要繪制的圖像</param>
/// <param name="contours">輪廓數(shù)組</param>
/// <param name="label">標(biāo)簽文本</param>
/// <param name="color">繪制顏色</param>
static void ProcessContours(Mat image, Point[][] contours, string label, Scalar color)
{
foreach (var contour in contours)
{
// 計(jì)算輪廓面積
double area = Cv2.ContourArea(contour);
bool isValidArea = false;
isValidArea = area > 3000;
// 忽略小面積噪點(diǎn)
if (!isValidArea) continue;
// 獲取最小外接圓
Point2f center;
float radius;
Cv2.MinEnclosingCircle(contour, out center, out radius);
// 計(jì)算輪廓矩
Moments moments = Cv2.Moments(contour);
// 計(jì)算輪廓中心點(diǎn)
int cx = (int)(moments.M10 / moments.M00);
int cy = (int)(moments.M01 / moments.M00);
// 如果輪廓接近圓形
double circleArea = Math.PI * radius * radius;
double areaRatio = area / circleArea;
if (areaRatio > 0.6) // 如果面積比超過(guò)60%,認(rèn)為是圓形
{
// 繪制圓和中心點(diǎn)
Cv2.Circle(image, (int)center.X, (int)center.Y, (int)radius, color, 2);
Cv2.Circle(image, cx, cy, 5, new Scalar(255, 255, 255), -1);
// 繪制標(biāo)簽
Cv2.PutText(image, label, new Point(cx - 20, cy - 20),
HersheyFonts.HersheySimplex, 0.5, color, 2);
// 輸出信息
Console.WriteLine($"檢測(cè)到{label}: 位置({cx},{cy}), 半徑: {radius}, 面積: {area}");
}
}
}
}
}
總結(jié)
本文詳細(xì)介紹了如何使用OpenCvSharp在C#環(huán)境下實(shí)現(xiàn)交通信號(hào)燈識(shí)別系統(tǒng)。從基礎(chǔ)的環(huán)境搭建到完整的代碼實(shí)現(xiàn),再到系統(tǒng)優(yōu)化與常見(jiàn)問(wèn)題解決方案,全面覆蓋了開(kāi)發(fā)過(guò)程中的關(guān)鍵環(huán)節(jié)。通過(guò)這套系統(tǒng),開(kāi)發(fā)者可以快速構(gòu)建出準(zhǔn)確可靠的交通信號(hào)識(shí)別應(yīng)用,為智能交通系統(tǒng)、自動(dòng)駕駛等領(lǐng)域提供基礎(chǔ)支持。