2025-11-17
C#
00

目录

1. 引言
2. 应用场景
3. 环境准备
4. 基本实现流程
4.1 基础代码框架
5. 红色苹果计数示例
6. 实时视频处理
7. 常见问题与解决方案
9. 总结

1. 引言

基于颜色的对象检测和计数在工业、农业、医疗等领域有着广泛的应用。借助OpenCvSharp,我们可以快速实现这类功能。本文将详细介绍如何使用C#和OpenCvSharp来实现基于颜色的对象检测和计数。

2. 应用场景

  • 工业生产线上的产品计数(如不同颜色的瓶盖)
  • 农业领域的水果分选计数
  • 医疗领域的细胞计数
  • 质量控制中的缺陷检测
  • 交通监控中的车辆计数
  • 零售业中的商品库存统计

3. 环境准备

C#
// 安装必要的NuGet包 // Install-Package OpenCvSharp4 // Install-Package OpenCvSharp4.runtime.win using OpenCvSharp; using System;

4. 基本实现流程

4.1 基础代码框架

C#
public class ColorObjectCounter { private Scalar lowerBound; private Scalar upperBound; public ColorObjectCounter(Scalar lower, Scalar upper) { lowerBound = lower; upperBound = upper; } public int CountObjects(string imagePath) { using (var src = Cv2.ImRead(imagePath)) { return CountObjects(src); } } public int CountObjects(Mat image) { if (image == null) throw new ArgumentNullException(nameof(image)); // 1. 转换颜色空间 using var hsvImage = new Mat(); Cv2.CvtColor(image, hsvImage, ColorConversionCodes.BGR2HSV); // 2. 创建掩码 using var mask = new Mat(); Cv2.InRange(hsvImage, lowerBound, upperBound, mask); // 3. 形态学操作 using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(5, 5)); using var processedMask = new Mat(); Cv2.MorphologyEx(mask, processedMask, MorphTypes.Open, kernel); // 4. 查找轮廓 Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours( processedMask, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple); // 5. 过滤和计数 return FilterAndCountContours(contours); } private int FilterAndCountContours(Point[][] contours) { int count = 0; foreach (var contour in contours) { double area = Cv2.ContourArea(contour); if (area > 100) // 面积阈值,需要根据实际情况调整 { count++; } } return count; } }
C#
static void Main(string[] args) { // 调整HSV范围以更好地检测红色缝线 Scalar lowerRed1 = new Scalar(0, 50, 50); // 降低饱和度和亮度的最小值 Scalar upperRed1 = new Scalar(10, 255, 255); // 创建检测器实例 ColorObjectCounter counter1 = new ColorObjectCounter(lowerRed1, upperRed1); string imagePath = "output_cropped2.jpg"; // 调用检测方法 int redObjects = counter1.CountObjects(imagePath); Console.WriteLine($"检测到 {redObjects} 条红色线"); }

image.png

5. 红色苹果计数示例

C#
static void Main(string[] args) { string imagePath = "apple.jpg"; VisualizeDetection(imagePath,"apple1.jpg"); Console.ReadKey(); } public static void VisualizeDetection(string imagePath, string outputPath) { using (var image = Cv2.ImRead(imagePath)) { using (var hsv = new Mat()) { Cv2.CvtColor(image, hsv, ColorConversionCodes.BGR2HSV); // 创建红色掩码,调整HSV范围使其更严格 using (var mask = new Mat()) { // 创建两个掩码来处理红色在HSV空间中的两个范围 using (var mask1 = new Mat()) using (var mask2 = new Mat()) { // 第一个红色范围 (0-10) Cv2.InRange(hsv, new Scalar(0, 120, 120), // 提高最小饱和度和亮度 new Scalar(10, 255, 255), mask1); // 第二个红色范围 (160-180) Cv2.InRange(hsv, new Scalar(160, 120, 120), // 提高最小饱和度和亮度 new Scalar(180, 255, 255), mask2); // 合并两个掩码 Cv2.BitwiseOr(mask1, mask2, mask); // 形态学操作 var kernelSize = new Size(3, 3); var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, kernelSize); Cv2.Erode(mask, mask, kernel, iterations: 2); Cv2.Dilate(mask, mask, kernel, iterations: 2); // 找到轮廓 Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours( mask, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple); // 绘制轮廓和标记 int count = 0; foreach (var contour in contours) { double area = Cv2.ContourArea(contour); double perimeter = Cv2.ArcLength(contour, true); // 调整面积阈值和添加圆形度阈值 if (area > 500 && area < 100000 ) // 调整这些阈值以适应您的图片 { count++; var rect = Cv2.BoundingRect(contour); Cv2.Rectangle(image, rect, new Scalar(0, 255, 0), 2); Cv2.PutText(image, count.ToString(), new Point(rect.X, rect.Y - 10), HersheyFonts.HersheySimplex, 0.9, new Scalar(0, 255, 0), 2); } } // 在图像上显示总计数 Cv2.PutText(image, $"Total Apples: {count}", new Point(10, 30), HersheyFonts.HersheySimplex, 1.0, new Scalar(0, 255, 0), 2); // 保存结果 Cv2.ImWrite(outputPath, image); // 显示结果窗口 Cv2.ImShow("Apple Detection Result", image); Cv2.WaitKey(0); Cv2.DestroyAllWindows(); } } } } }

image.png

6. 实时视频处理

C#
public class RealTimeColorDetector { private ColorObjectCounter counter; private VideoCapture capture; public RealTimeColorDetector(int cameraIndex = 0) { capture = new VideoCapture(cameraIndex); counter = new ColorObjectCounter( new Scalar(0, 100, 100), new Scalar(10, 255, 255) ); } public void StartDetection() { using (var window = new Window("实时检测")) using (var frame = new Mat()) { while (true) { capture.Read(frame); if (frame.Empty()) break; int count = counter.CountObjects(frame); // 显示计数结果 Cv2.PutText(frame, $"Count: {count}", new Point(10, 30), HersheyFonts.HersheySimplex, 1.0, new Scalar(0, 255, 0), 2); window.ShowImage(frame); if (Cv2.WaitKey(1) == 27) // ESC键退出 break; } } } public void Dispose() { capture?.Dispose(); } }

image.png

这个例子只算是一个抛转了,哈哈。

7. 常见问题与解决方案

光照变化处理

C#
public void AdjustBrightness(Mat image, double alpha = 1.0, double beta = 0) { Cv2.ConvertScaleAbs(image, image, alpha, beta); }

误检处理

C#
private bool IsValidObject(Point[] contour) { double area = Cv2.ContourArea(contour); double perimeter = Cv2.ArcLength(contour, true); double circularity = 4 * Math.PI * area / (perimeter * perimeter); return area > 100 && circularity > 0.7; // 添加形状判断 }

9. 总结

基于颜色的对象检测和计数是计算机视觉中的一个重要应用。通过C#和OpenCvSharp,我们可以快速实现这类功能,并应用到各种实际场景中。关键步骤包括:

  1. 颜色空间转换(BGR到HSV)
  2. 颜色阈值分割
  3. 图像形态学处理
  4. 轮廓检测和过滤
  5. 对象计数和可视化

根据具体应用场景,可以进行相应的优化和调整,如添加形状判断、处理光照变化等。同时,通过并行处理等方式可以提高处理效率。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!