C#如何检测图像颜色,获取图片中不同血滴的色值或颜色名

C# 多血滴颜色检测实现方案
实现思路
整体分为三个核心步骤:
- 图像分割:从背景中提取出每一个独立的血滴区域
- 主色提取:计算单个血滴区域的平均色值作为该血滴的代表色
- 颜色映射:将RGB色值转换为十六进制代码,匹配对应的标准颜色名称
依赖安装
首先安装所需NuGet包:
Emgu.CV:OpenCV的C#封装,用于图像分割、轮廓检测Emgu.CV.runtime.windows:Windows平台运行时(如果是Linux/macOS可安装对应平台的运行时包)System.Drawing.Common:用于颜色处理(.NET Core/.NET 5+需要单独安装)
如果需要纯跨平台实现,可将Emgu CV替换为SixLabors.ImageSharp,逻辑一致。
完整代码实现
using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using System.Drawing; using System.Collections.Generic; using System.Linq; using System; // 血滴检测结果结构 public struct BloodDropResult { /// <summary> /// 血滴在图片中的外接矩形位置 /// </summary> public Rectangle BoundingBox { get; set; } /// <summary> /// 十六进制颜色代码 /// </summary> public string HexColor { get; set; } /// <summary> /// 匹配的颜色名称 /// </summary> public string ColorName { get; set; } } public class BloodDropColorDetector { // 预定义颜色映射表,可根据实际需求扩展颜色项 private static readonly Dictionary<string, Color> PredefinedColors = new Dictionary<string, Color> { {"红色", Color.Red}, {"深红色", Color.DarkRed}, {"浅红色", Color.LightCoral}, {"粉红色", Color.Pink}, {"橙色", Color.Orange}, {"黄色", Color.Yellow}, {"绿色", Color.Green}, {"深绿色", Color.DarkGreen}, {"蓝色", Color.Blue}, {"浅蓝色", Color.LightBlue}, {"紫色", Color.Purple}, {"棕色", Color.Brown}, {"黑色", Color.Black}, {"灰色", Color.Gray} }; /// <summary> /// 检测图片中所有血滴的颜色 /// </summary> /// <param name="imagePath">本地图片路径</param> /// <returns>所有血滴的检测结果列表</returns> public List<BloodDropResult> DetectBloodDropColors(string imagePath) { var results = new List<BloodDropResult>(); using var originalImg = CvInvoke.Imread(imagePath, ImreadModes.Color); if (originalImg.IsEmpty) throw new ArgumentException("图片读取失败,请检查路径是否正确"); // 转HSV色彩空间做阈值分割,更容易分离彩色前景和白色背景 using var hsvImg = new Mat(); CvInvoke.CvtColor(originalImg, hsvImg, ColorConversion.Bgr2Hsv); // 阈值参数可根据实际图片的背景、血滴颜色调整 var lowerHsv = new ScalarArray(new Hsv(0, 30, 30).MCvScalar); var upperHsv = new ScalarArray(new Hsv(179, 255, 255).MCvScalar); using var mask = new Mat(); CvInvoke.InRange(hsvImg, lowerHsv, upperHsv, mask); // 形态学开运算去除小噪点 using var kernel = CvInvoke.GetStructuringElement(ElementShape.Ellipse, new Size(5, 5), new Point(-1, -1)); CvInvoke.MorphologyEx(mask, mask, MorphOp.Open, kernel, new Point(-1, -1), 1, BorderType.Default, new MCvScalar(0)); // 查找所有血滴的外轮廓 var contours = new VectorOfVectorOfPoint(); CvInvoke.FindContours(mask, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { var contour = contours[i]; // 过滤面积过小的噪点区域 if (CvInvoke.ContourArea(contour) < 80) continue; // 获取血滴的外接矩形区域 var dropRect = CvInvoke.BoundingRectangle(contour); // 提取血滴区域的平均色值作为主色 using var roi = new Mat(originalImg, dropRect); var meanColor = CvInvoke.Mean(roi); // OpenCV默认BGR顺序,转换为RGB var dominantColor = Color.FromArgb((int)meanColor.V2, (int)meanColor.V1, (int)meanColor.V0); results.Add(new BloodDropResult { BoundingBox = dropRect, HexColor = $"#{dominantColor.R:X2}{dominantColor.G:X2}{dominantColor.B:X2}", ColorName = GetNearestColorName(dominantColor) }); } return results; } // 计算欧式距离匹配最接近的预定义颜色 private string GetNearestColorName(Color targetColor) { return PredefinedColors .OrderBy(c => Math.Pow(c.Value.R - targetColor.R, 2) + Math.Pow(c.Value.G - targetColor.G, 2) + Math.Pow(c.Value.B - targetColor.B, 2)) .First().Key; } }
调用示例
// 初始化检测器 var detector = new BloodDropColorDetector(); // 传入本地图片路径检测 var dropResults = detector.DetectBloodDropColors(@"C:\Users\XXX\Desktop\blood-drops.jpg"); // 输出结果 foreach (var result in dropResults) { Console.WriteLine($"血滴位置:X={result.BoundingBox.X}, Y={result.BoundingBox.Y} | 颜色代码:{result.HexColor} | 颜色名称:{result.ColorName}"); }
注意事项
- 阈值参数需要根据你实际使用的图片背景、血滴颜色调整,避免出现漏检或者误检
- 预定义颜色映射表可以自行扩展更多颜色项,提升颜色名称匹配的准确率
- 如果是.NET 6+非Windows平台使用System.Drawing.Common需要添加运行时配置,或者直接使用跨平台的ImageSharp库替换实现
内容的提问来源于stack exchange,提问作者محمد حسین مظفری
相关产品推荐
相关产品推荐

