OpenCvSharp实战:C#交通信号灯识别系统详解

开发 前端
本文详细介绍了如何使用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
  • 1.
  • 2.
  • 3.

或者在项目文件中添加:

<PackageReference Include="OpenCvSharp4" Version="4.7.0.20230115" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.7.0.20230115" />
  • 1.
  • 2.

交通信号灯识别原理

交通信号灯识别主要分为以下几个步骤:

  1. 图像预处理:调整大小、降噪、增强对比度
  2. 颜色空间转换:从BGR转到HSV颜色空间,便于颜色识别
  3. 颜色阈值分割:提取红、黄、绿三种颜色区域
  4. 形状识别:识别圆形区域,确定信号灯位置
  5. 结果分析:根据颜色和位置判断信号灯状态

完整代码实现

下面是一个完整的交通信号灯识别系统的实现:

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}");
                }
            }
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.

总结

本文详细介绍了如何使用OpenCvSharp在C#环境下实现交通信号灯识别系统。从基础的环境搭建到完整的代码实现,再到系统优化与常见问题解决方案,全面覆盖了开发过程中的关键环节。通过这套系统,开发者可以快速构建出准确可靠的交通信号识别应用,为智能交通系统、自动驾驶等领域提供基础支持。

责任编辑:武晓燕 来源: 技术老小子
相关推荐

2017-04-12 13:31:58

智能红绿灯迈阿密交通

2021-06-01 09:39:58

智能交通物联网IOT

2020-06-10 07:59:44

漏洞攻击黑客

2020-07-08 15:15:03

AndoridGoogle交通信号灯

2021-10-09 13:55:24

谷歌交通信号灯人工智能

2020-12-24 10:09:19

人工智能AI智能交通

2021-04-09 10:50:22

人工智能AI智能交通

2021-03-23 15:01:09

鸿蒙HarmonyOS应用开发

2014-06-10 10:47:37

2023-09-11 12:36:56

研究数据

2023-06-29 14:43:32

2017-09-11 20:15:28

智慧交通视频监控云平台

2024-03-18 09:54:32

开源AI模型

2009-01-18 09:31:00

网络故障网卡信号灯

2023-08-15 14:31:46

2009-08-25 17:24:55

C#串口通信程序

2018-06-26 10:12:41

华为

2022-09-18 21:39:42

自动驾驶识别
点赞
收藏

51CTO技术栈公众号