基于颜色的对象检测和计数在工业、农业、医疗等领域有着广泛的应用。借助OpenCvSharp,我们可以快速实现这类功能。本文将详细介绍如何使用C#和OpenCvSharp来实现基于颜色的对象检测和计数。
C#// 安装必要的NuGet包
// Install-Package OpenCvSharp4
// Install-Package OpenCvSharp4.runtime.win
using OpenCvSharp;
using System;
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} 条红色线");
}

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();
}
}
}
}
}

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();
}
}

这个例子只算是一个抛转了,哈哈。
光照变化处理
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; // 添加形状判断
}
基于颜色的对象检测和计数是计算机视觉中的一个重要应用。通过C#和OpenCvSharp,我们可以快速实现这类功能,并应用到各种实际场景中。关键步骤包括:
根据具体应用场景,可以进行相应的优化和调整,如添加形状判断、处理光照变化等。同时,通过并行处理等方式可以提高处理效率。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!