OpenCV4入门教程069:颜色圆检测

索引地址:系列索引

首先,普通彩色图是RGB的,标准红色是(255,0,0),但是没有什么是遵照标准的,如果红色分量占主体,那么此颜色就显示偏红。对于代码开发来说不好定量控制。

HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间,也称六角锥体模型(Hexcone Model)。这个模型中颜色的参数分别是:

  • 色调H——用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
  • 饱和度S——饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和
  • 明度V——明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
    RGB和CMY颜色模型都是面向硬件的,而HSV(Hue Saturation Value)颜色模型是面向用户的。

HSV模型的三维表示从RGB立方体演化而来。设想从RGB沿立方体对角线的白色顶点向黑色顶点观察,就可以看到立方体的六边形外形。六边形边界表示色彩,水平轴表示纯度,明度沿垂直轴测量。

HSV颜色空间可以用一个圆锥空间模型来描述。圆锥的顶点处,V=0,H和S无定义,代表黑色。圆锥的顶面中心处V=max,S=0,H无定义,代表白色。

hsv

可以看到HSV模型中只有H控制颜色,这样就好控制了。饱和度和明度的最大值为100%,换成像素值为255。

红色大概在h>300h<25;红色大概在35<h<85;绿色大概在85<h<200
其次,圆检测就是上一篇的霍夫变换检测了。

测试代码1

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
// 功能:代码 5-28 颜色圆检测
// 作者:朱伟 zhu1988wei@163.com
// 来源:《OpenCV图像处理编程实例》
// 博客:http://blog.csdn.net/zhuwei1988
// 更新:2016-8-1
// 说明:版权所有,引用或摘录请联系作者,并按照上面格式注明出处,谢谢。//
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <string>
#include <vector>
int main()
{
cv::Mat srcImage = cv::imread("circles.jpg");
if (!srcImage.data)
return -1;
cv::imshow("srcImage", srcImage);
cv::Mat resultImage = srcImage.clone();
// 中值滤波
cv::medianBlur(srcImage, srcImage, 3);
// 转换成hsv颜色空间
cv::Mat hsvImage;
cv::cvtColor(srcImage, hsvImage, cv::COLOR_BGR2HSV);
cv::imshow("hsvImage", hsvImage);
// 颜色阈值化处理
cv::Mat lowTempMat;
cv::Mat upperTempMat;
// 低阈值限定
cv::inRange(hsvImage, cv::Scalar(0, 100, 100),
cv::Scalar(10, 255, 255), lowTempMat);
// 高阈值限定
cv::inRange(hsvImage, cv::Scalar(160, 100, 100),
cv::Scalar(179, 255, 255), upperTempMat);
cv::imshow("lowTempMat", lowTempMat);
cv::imshow("upperTempMat", upperTempMat);
// 颜色阈值限定合并
cv::Mat redTempMat;
cv::addWeighted(lowTempMat, 1.0, upperTempMat,
1.0, 0.0, redTempMat);
// 高斯平滑
cv::GaussianBlur(redTempMat, redTempMat, cv::Size(9, 9), 2, 2);
// 霍夫变换
std::vector<cv::Vec3f> circles;
cv::HoughCircles(redTempMat, circles, cv::HOUGH_GRADIENT,
1, redTempMat.rows / 8, 100, 20, 0, 0);
// 颜色圆检测结果判断
if (circles.size() == 0)
return 1;
for (int i = 0; i < circles.size(); ++i)
{
// 绘制检测到颜色圆
cv::Point center(round(circles[i][0]), round(circles[i][1]));
int radius = round(circles[i][2]);
cv::circle(resultImage, center, radius,
cv::Scalar(0, 255, 0), 5);
}
cv::imshow("resultImage", resultImage);
cv::waitKey(0);
return 0;
}

测试图片是从网上偷来的,测试效果:

result

测试2

这次我们动态调整参数观察效果

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
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
using namespace cv;

#include<iostream>
#include<string>
using namespace std;
//输入图像
Mat img;
//灰度值归一化
Mat bgr;
//HSV图像
Mat hsv;
//色相
int hmin = 0;
int hmin_Max = 360;
int hmax = 360;
int hmax_Max = 360;
//饱和度
int smin = 0;
int smin_Max = 255;
int smax = 255;
int smax_Max = 255;
//亮度
int vmin = 106;
int vmin_Max = 255;
int vmax = 250;
int vmax_Max = 255;
//显示原图的窗口
string windowName = "src";
//输出图像的显示窗口
string dstName = "dst";
//输出图像
Mat dst;
//回调函数
void callBack(int, void*)
{
//输出图像分配内存
dst = Mat::zeros(img.size(), CV_32FC3);
//掩码
Mat mask;
inRange(hsv, Scalar(hmin, smin / float(smin_Max), vmin / float(vmin_Max)), Scalar(hmax, smax / float(smax_Max), vmax / float(vmax_Max)), mask);
//只保留
for (int r = 0; r < bgr.rows; r++)
{
for (int c = 0; c < bgr.cols; c++)
{
if (mask.at<uchar>(r, c) == 255)
{
dst.at<Vec3f>(r, c) = bgr.at<Vec3f>(r, c);
}
}
}
//输出图像
imshow(dstName, dst);
//保存图像
dst.convertTo(dst, CV_8UC3, 255.0, 0);
imwrite("HSV_inRange.jpg", dst);
}
int main(int argc, char*argv[])
{
//输入图像
img = imread("circles.jpg", IMREAD_COLOR);
if (!img.data || img.channels() != 3)
return -1;
imshow(windowName, img);
//彩色图像的灰度值归一化
img.convertTo(bgr, CV_32FC3, 1.0 / 255, 0);
//颜色空间转换
cvtColor(bgr, hsv, COLOR_BGR2HSV);
//定义输出图像的显示窗口
namedWindow(dstName, WINDOW_GUI_EXPANDED);
//调节色相 H
createTrackbar("hmin", dstName, &hmin, hmin_Max, callBack);
createTrackbar("hmax", dstName, &hmax, hmax_Max, callBack);
//调节饱和度 S
createTrackbar("smin", dstName, &smin, smin_Max, callBack);
createTrackbar("smax", dstName, &smax, smax_Max, callBack);
//调节亮度 V
createTrackbar("vmin", dstName, &vmin, vmin_Max, callBack);
createTrackbar("vmax", dstName, &vmax, vmax_Max, callBack);
callBack(0, 0);
waitKey(0);
return 0;
}

result

可以自己调整参数观察效果


OpenCV4入门教程069:颜色圆检测
https://feater.top/opencv/opencv-detect-colorful-circle/
作者
JackeyLea
发布于
2020年11月10日
许可协议