颜色识别
视频讲解如下:
在本章节中给大家演示如何进行颜色识别,主要函数:inRange。当前代码并非毛星云的代码,而是博主自行整理的,毛星云的教程中好像没有颜色识别这一讲。
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
HSV颜色空间介绍
参考网址:https://blog.csdn.net/Solomon1558/article/details/43772147
系统的颜色识别采用的是SHV(HSI)颜色空间。
HSI(Hue,Saturation andIntensity)颜色空间是从人的视觉系统出发,用色调(Hue)、色饱和度(Saturation或Chroma)和亮度(Intensity或Brightness)来描述颜色。HSI颜色空间可以用一个圆锥空间模型来描述,如下图。

用这种描述HIS颜色空间的圆锥模型相当复杂,但确能把色调、亮度和色饱和度的变化情形表现得很清楚。其中:
(A)HSI圆锥空间模型
(B)线条示意图:圆锥上亮度、色度和饱和度的关系。
(C)纵轴表示亮度:亮度值是沿着圆锥的轴线度量的,沿着圆锥轴线上的点表示完全不饱和的颜色,按照不同的灰度等级,最亮点为纯白色、最暗点为纯黑色。
(D)圆锥纵切面:描述了同一色调的不同亮度和饱和度关系。
(E)圆锥横切面:色调H为绕着圆锥截面度量的色环,圆周上的颜色为完全饱和的纯色,色饱和度为穿过中心的半径横轴。
HSV颜色空间设置方法
参考网址:https://blog.csdn.net/taily_duan/article/details/51506776
在描述设置方法之前,我们先假定我们需要设置的系统识别颜色为黄色,而我们需要设置的颜色HSV的值,其中:
H值的范围:0~180
S值的范围:0~255
V值的范围:0~255
网上给出了一张HSV范围的参考表,当然了,该表只能作为参考,因为表中部分红色被归为紫色,实际取值范围还得根据实际情况进行调整,参考表如下图:

实际的黄色HSV值取值范围确定方法如下:
步骤1:
首先在网上找一张黄色图片,图片如下:

步骤2:
将图片用Photoshop打开,因为使用Photoshop我们能够很直接的获取到图片中颜色的HSV值,图片打开如下

通过设置颜色属性,我们可以看到有一个“HSB滑块”的选项,然后通过吸管工具不断的提取图片中黄色区域的颜色,我们可以发现颜色属性中HSB的值是在变化的,并且H的变化范围为0~360,S的变化范围为0~100,B的变化范围为0~100,。其中HSB和HSV的对应关系如下:
Photoshop | OpenCV | 比例关系 |
---|
H | H | 2:1 |
S | S | 百分比关系 |
B | V | 百分比关系 |
通过吸管工具的提取效果显示,在Photoshop中色调H的大致范围为41~58,饱和度S的范围为83%~100%,亮度B的范围为60%~100%,但是为了能够让系统更能准确的识别出黄色,我们还得借助Photoshop的另一个工具拾色器。如下:

我们都知道,黄色的RGB颜色为:(255,255,0),通过拾色器设置RGB颜色,我们可以发现,黄色的色调H的最大值为60,饱和度S和亮度B的最大值为100%,也就是说在Photoshop中黄色的HSB值范围如下:
色调H范围:41~60
饱和度S范围:83%~100%
亮度B范围:60%~100%
我们知道,Photoshop中的HSB和OpenCV中的HSV是存在比例关系的,所以在OpenCV中HSV的取值范围为:
色调H最小值:41/2≈20
色调H最大值:60/2 = 30
饱和度S最小值:255*83%≈212
饱和度S最大值:255*100%=255
亮度V最小值:255*60%=153
亮度V最大值:255*100%=255
步骤3
通过前一步的HSV范围提取,到了这一步我们就可以直接使用函数inRange()进行图像颜色空间的识别了,实现代码如下:
int iLowH = 20;
int iHighH = 30;
int iLowS = 0.83 * 255;
int iHighS = 255;
int iLowV = 0.60 * 255;
int iHighV = 255;
cvtColor(inImg, imgHSV, COLOR_BGR2HSV);//转为HSV
Mat imgThresholded;
inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded);
将原始图像转换成HSV图像后的效果如下:

经过颜色识别后的图像如下:

通过以上识别,我们可以发现,系统已经能够将图像中的黄色区域给扣取出来,为了能够更好的说明,系统颜色识别的准确性,我准备了这样一张图片,如下:

系统识别结果如下:
将原始图像转换成HSV图像后的效果如下:

经过颜色识别后的图像如下:

到了这一步,系统的颜色识别功能就完成了。
项目工程演示
前面讲解了如何提取HSV颜色空间区间,下面我们来演示一下我们的C#、C++、Python三个版本的颜色识别demo。
首先了,我们准备一张测试用的图片:

运行效果如下(C#):

C#版本代码如下:
using OpenCvSharp;
namespace demo
{
internal class Program
{
/// <summary>
/// 颜色识别(除红色外的其他单色)
/// </summary>
/// <param name="srcImage"></param>
/// <returns></returns>
static Mat ColorFindContours(Mat srcImage,
int iLowH, int iHighH,
int iLowS, int iHighS,
int iLowV, int iHighV)
{
Mat bufImg = new Mat();
Mat imgHSV = new Mat();
//转为HSV
Cv2.CvtColor(srcImage, imgHSV, ColorConversionCodes.BGR2HSV);
Cv2.InRange(imgHSV, new Scalar(iLowH, iLowS, iLowV), new Scalar(iHighH, iHighS, iHighV), bufImg);
return bufImg;
}
/// <summary>
/// 颜色识别(红色)
/// </summary>
/// <param name="srcImage"></param>
/// <returns></returns>
static Mat ColorFindContours2(Mat srcImage)
{
Mat des1 = ColorFindContours(srcImage,
350 / 2, 360 / 2, // 色调最小值~最大值
(int)(255 * 0.70), 255, // 饱和度最小值~最大值
(int)(255 * 0.60), 255); // 亮度最小值~最大值
Mat des2 = ColorFindContours(srcImage,
0, 16 / 2, // 色调最小值~最大值
(int)(255 * 0.70), 255, // 饱和度最小值~最大值
(int)(255 * 0.60), 255); // 亮度最小值~最大值
return des1 + des2;
}
/// <summary>
/// 黄色识别
/// </summary>
static void demo1()
{
Mat g_srcImage = Cv2.ImRead("../../../images/color.jpg");
Cv2.ImShow("原始图1", g_srcImage);
Mat des = ColorFindContours(g_srcImage,
45 / 2, 60 / 2, // 色调最小值~最大值
(int)(255 * 0.60), 255, // 饱和度最小值~最大值
(int)(255 * 0.90), 255); // 亮度最小值~最大值
Cv2.ImShow("demo1", des);
}
/// <summary>
/// 红色识别
/// </summary>
static void demo2()
{
Mat g_srcImage = Cv2.ImRead("../../../images/color.jpg");
Cv2.ImShow("原始图2", g_srcImage);
Mat des = ColorFindContours2(g_srcImage);
Cv2.ImShow("demo2", des);
}
static void Main(string[] args)
{
demo1();
demo2();
Cv2.WaitKey();
}
}
}
C++版本代码如下:
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
// 颜色识别(除红色外的其他单色)
Mat ColorFindContours(Mat srcImage,
int iLowH, int iHighH,
int iLowS, int iHighS,
int iLowV, int iHighV)
{
Mat bufImg;
Mat imgHSV;
//转为HSV
cvtColor(srcImage, imgHSV, COLOR_BGR2HSV);
inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), bufImg);
return bufImg;
}
// 颜色识别(红色)
Mat ColorFindContours2(Mat srcImage)
{
Mat des1 = ColorFindContours(srcImage,
350 / 2, 360 / 2, // 色调最小值~最大值
(int)(255 * 0.70), 255, // 饱和度最小值~最大值
(int)(255 * 0.60), 255); // 亮度最小值~最大值
Mat des2 = ColorFindContours(srcImage,
0, 16 / 2, // 色调最小值~最大值
(int)(255 * 0.70), 255, // 饱和度最小值~最大值
(int)(255 * 0.60), 255); // 亮度最小值~最大值
return des1 + des2;
}
int main()
{
//载入色卡
Mat srcImage = imread("../images/color.jpg");
imshow("原始图", srcImage);
// 黄色识别
Mat des = ColorFindContours(srcImage,
45 / 2, 60 / 2, // 色调最小值~最大值
(int)(255 * 0.60), 255, // 饱和度最小值~最大值
(int)(255 * 0.90), 255); // 亮度最小值~最大值
imshow("des1", des);
// 红色识别
des = ColorFindContours2(srcImage);
imshow("des2", des);
waitKey(0);
return 0;
}
Python版本代码如下:
import cv2
import numpy as np
def ColorFindContours(srcImage, iLowH, iHighH, iLowS, iHighS, iLowV, iHighV):
# 转为HSV
imgHSV = cv2.cvtColor(srcImage, cv2.COLOR_BGR2HSV)
bufImg = cv2.inRange(imgHSV, np.array((iLowH, iLowS, iLowV)), np.array((iHighH, iHighS, iHighV)))
return bufImg
def ColorFindContours2(srcImage):
des1 = ColorFindContours(srcImage,
350 / 2, 360 / 2, # 色调最小值~最大值
int(255 * 0.70), 255, # 饱和度最小值~最大值
int(255 * 0.60), 255) # 亮度最小值~最大值
des2 = ColorFindContours(srcImage,
0, int(16 / 2), # 色调最小值~最大值
int(255 * 0.70), 255, # 饱和度最小值~最大值
int(255 * 0.60), 255) # 亮度最小值~最大值
return des1 + des2
# 载入色卡
srcImage = cv2.imread("../images/color.jpg")
# 显示原图
cv2.imshow("srcImage", srcImage)
des = ColorFindContours(srcImage,
45 / 2, 60 / 2, # 色调最小值~最大值
int(255 * 0.60), 255, # 饱和度最小值~最大值
int(255 * 0.90), 255) # 亮度最小值~最大值
cv2.imshow("des1", des)
des = ColorFindContours2(srcImage)
cv2.imshow("des2", des)
cv2.waitKey(0)
cv2.destroyAllWindows()