简介
颜色的提取在HSV空间效果更好,然而我们的图像格式一般都是RGB格式的。因此我们首先需要用到将RGB图像格式转换为HSV格式。简单介绍一下HSV,H表示色彩、色调,S表示纯度,V表示色彩的明亮程度。值得一提的是,HSV各数据的取值范围根据各自的计算方法都没统一。
公式:
设 (r, g, b) 分别是一个颜色的红、绿和蓝坐标,它们的值是在 0 到 1 之间的实数
设 max 等于 r, g, b 中的最大者
设 min 等于 r, g, b 中的最小者
代码(BGR转HSV):
我们采用的方法,H取值范围[0,360],S取值范围[0,1],V取值范围[0,1]
struct BGR // 定义BGR结构体
{
uchar b;
uchar g;
uchar r;
};
struct HSV // 定义HSV结构体
{
int h;
double s;
double v;
};
bool IsEquals(double val1, double val2)
{
return fabs(val1 - val2) < 0.001;
}
// 将RGB格式转换为HSV格式
void BGR2HSV(BGR &bgr, HSV &hsv)
{
double b, g, r;
double h, s, v;
double min, max;
double delta;
b = bgr.b / 255.0;
g = bgr.g / 255.0;
r = bgr.r / 255.0;
if (r > g)
{
max = MAX(r, b);
min = MIN(g, b);
}
else
{
max = MAX(g, b);
min = MIN(r, b);
}
v = max;
delta = max - min;
if (IsEquals(max, 0))
s = 0.0;
else
s = delta / max;
if (max == min)
h = 0.0;
else
{
if (IsEquals(r, max) && g >= b)
{
h = 60 * (g - b) / delta + 0;
}
else if (IsEquals(r, max) && g < b)
{
h = 60 * (g - b) / delta + 360;
}
else if (IsEquals(g, max))
{
h = 60 * (b - r) / delta + 120;
}
else if (IsEquals(b, max))
{
h = 60 * (r - g) / delta + 240;
}
}
hsv.h = (int)(h + 0.5);
hsv.h = (hsv.h > 359) ? (hsv.h - 360) : hsv.h;
hsv.h = (hsv.h < 0) ? (hsv.h + 360) : hsv.h;
hsv.s = s;
hsv.v = v;
}
// 调用
int main()
{
''''''
// 载入检测图片
Mat srcImg = imread("./src/3.jpg");
int width = srcImg.cols;//图像宽度
int height = srcImg.rows;//图像高度
Mat matRgb = Mat::zeros(srcImg.size(), CV_8UC1);
int x, y; //循环
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
// 获取BGR值
BGR bgr;
bgr.b = srcImg.at<Vec3b>(y, x)[0];
bgr.g = srcImg.at<Vec3b>(y, x)[1];
bgr.r = srcImg.at<Vec3b>(y, x)[2];
HSV hsv;
BGR2HSV(bgr, hsv); // bgr转hsv
}
根据hsv分量模型,各种颜色范围分布如下:
注:该表的数值范围:H[0,180],S[0,255],v[0,255]
而之前代码获取的数值范围:H[0,360],S[0,1],v[0,1]
因此需要进行一个转换.
代码(提取红色区域)
// 第一步:分割红色颜色色块
Mat matRgb = Mat::zeros(srcImg.size(), CV_8UC1);
int x, y; //循环
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
{
// 获取BGR值
BGR bgr;
bgr.b = srcImg.at<Vec3b>(y, x)[0];
bgr.g = srcImg.at<Vec3b>(y, x)[1];
bgr.r = srcImg.at<Vec3b>(y, x)[2];
HSV hsv;
BGR2HSV(bgr, hsv); // bgr转hsv
//红色范围
if ((hsv.h >= 156* 2 && hsv.h <= 180 * 2 || hsv.h >= 0 && hsv.h <= 10 * 2)
&& hsv.s * 255 >= 43&& hsv.s * 255 <= 255
&& hsv.v * 255 >= 46 && hsv.v * 255 <= 255)
{
matRgb.at<uchar>(y, x) = 255;
}// if
}// for
参考博客:
https://blog.csdn.net/greenapple_shan/article/details/40214719
https://blog.csdn.net/weixin_39128119/article/details/88669521
https://www.cnblogs.com/wangyblzu/p/5710715.html
https://blog.csdn.net/lly_3485390095/article/details/104570885