OpenCvSharp實戰:C#交通信號燈識別系統詳解
在智能交通系統領域,交通信號燈識別是一項基礎且關鍵的技術。借助OpenCvSharp庫,C#開發者可以快速構建高效準確的交通信號識別系統。本文將詳細介紹如何使用OpenCvSharp在C#環境下實現交通信號燈的自動識別,提供完整代碼示例和詳細注釋,助力開發者快速掌握這一技術。
OpenCvSharp簡介
OpenCvSharp是一個OpenCV的.NET封裝庫,它允許.NET開發者使用C#等語言調用OpenCV的強大功能。相比于其他封裝庫,OpenCvSharp具有以下優勢:
- 接口設計符合C#風格,使用更加自然
- 完整支持OpenCV的主要功能
- 性能損耗小,接近原生C++版本
- 文檔完善,社區活躍
環境搭建
安裝必要組件
首先,我們需要通過NuGet包管理器安裝OpenCvSharp:
// 在Visual Studio中,通過NuGet包管理器安裝以下包:
// OpenCvSharp4
// OpenCvSharp4.runtime.win
或者在項目文件中添加:
<PackageReference Include="OpenCvSharp4" Version="4.7.0.20230115" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.7.0.20230115" />
交通信號燈識別原理
交通信號燈識別主要分為以下幾個步驟:
- 圖像預處理:調整大小、降噪、增強對比度
- 顏色空間轉換:從BGR轉到HSV顏色空間,便于顏色識別
- 顏色閾值分割:提取紅、黃、綠三種顏色區域
- 形狀識別:識別圓形區域,確定信號燈位置
- 結果分析:根據顏色和位置判斷信號燈狀態
完整代碼實現
下面是一個完整的交通信號燈識別系統的實現:
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("無法讀取圖像!");
return;
}
// 顯示原始圖像
using (new Window("原始圖像", src))
{
// 調整圖像大小以加快處理速度
Mat resized = new Mat();
Cv2.Resize(src, resized, new Size(0, 0), 0.5, 0.5);
// 進行高斯模糊以減少噪聲
Mat blurred = new Mat();
Cv2.GaussianBlur(resized, blurred, new Size(5, 5), 0);
// 轉換到HSV顏色空間
Mat hsv = new Mat();
Cv2.CvtColor(blurred, hsv, ColorConversionCodes.BGR2HSV);
// 定義紅、黃、綠三種顏色的HSV范圍
// 注意:紅色在HSV中橫跨兩個區間,需要兩個范圍
// 紅色范圍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);
// 創建掩碼
Mat redMask1 = new Mat();
Mat redMask2 = new Mat();
Mat redMask = new Mat();
Mat yellowMask = new Mat();
Mat greenMask = new Mat();
// 應用閾值,提取各個顏色區域
Cv2.InRange(hsv, redLower1, redUpper1, redMask1);
Cv2.InRange(hsv, redLower2, redUpper2, redMask2);
Cv2.BitwiseOr(redMask1, redMask2, redMask); // 合并兩個紅色區間
Cv2.InRange(hsv, yellowLower, yellowUpper, yellowMask);
Cv2.InRange(hsv, greenLower, greenUpper, greenMask);
// 顯示各顏色掩碼
using (new Window("紅色掩碼", redMask))
using (new Window("黃色掩碼", yellowMask))
using (new Window("綠色掩碼", greenMask))
{
// 對每個掩碼應用形態學操作以去除噪聲
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);
// 創建結果圖像
Mat result = resized.Clone();
// 處理并繪制紅色信號
ProcessContours(result, redContours, "Red", new Scalar(0, 0, 255));
// 處理并繪制黃色信號
ProcessContours(result, yellowContours, "Yellow", new Scalar(0, 255, 255));
// 處理并繪制綠色信號
ProcessContours(result, greenContours, "Green", new Scalar(0, 255, 0));
// 顯示結果
using (new Window("識別結果", result))
{
Cv2.WaitKey(0);
}
}
}
}
}
/// <summary>
/// 處理輪廓并繪制識別結果
/// </summary>
/// <param name="image">要繪制的圖像</param>
/// <param name="contours">輪廓數組</param>
/// <param name="label">標簽文本</param>
/// <param name="color">繪制顏色</param>
static void ProcessContours(Mat image, Point[][] contours, string label, Scalar color)
{
foreach (var contour in contours)
{
// 計算輪廓面積
double area = Cv2.ContourArea(contour);
bool isValidArea = false;
isValidArea = area > 3000;
// 忽略小面積噪點
if (!isValidArea) continue;
// 獲取最小外接圓
Point2f center;
float radius;
Cv2.MinEnclosingCircle(contour, out center, out radius);
// 計算輪廓矩
Moments moments = Cv2.Moments(contour);
// 計算輪廓中心點
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) // 如果面積比超過60%,認為是圓形
{
// 繪制圓和中心點
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);
// 繪制標簽
Cv2.PutText(image, label, new Point(cx - 20, cy - 20),
HersheyFonts.HersheySimplex, 0.5, color, 2);
// 輸出信息
Console.WriteLine($"檢測到{label}: 位置({cx},{cy}), 半徑: {radius}, 面積: {area}");
}
}
}
}
}
總結
本文詳細介紹了如何使用OpenCvSharp在C#環境下實現交通信號燈識別系統。從基礎的環境搭建到完整的代碼實現,再到系統優化與常見問題解決方案,全面覆蓋了開發過程中的關鍵環節。通過這套系統,開發者可以快速構建出準確可靠的交通信號識別應用,為智能交通系統、自動駕駛等領域提供基礎支持。