先说一下BGR颜色空间,bgr三原色,人眼中有四种感光细胞,分别是三种红、绿、蓝锥形的刚光细胞,以及感知黑白的杆状细胞,模型如下:
分别代表的是色调、饱和度、亮度。HSV是一种类似于BGR的颜色空间,H:表示的是颜色的类型,S:表示的是从不饱和到饱和,V:表示的是亮度。模型如下:
那为啥还要有一个HSV模型?假如说我想提取红色,但是你用BGR颜色模型的提取可以有几百万中可能都是红的的,所以这个BGR模型是有缺陷的,因此提出了HSV模型。下图是从文库中找到的不同颜色的阈值范围:
H(色度)=[0,360],0==red, 120==green, 240==blue
S(饱和度) 色饱和度参数是色环上的从圆点到彩色点的半径
我们再说一下除了HSV模型,还有一个HSI模型,两者类似,不同在于:I代表亮度,V代表明度。
亮度和明度的区别是:
一种纯色的明度等于白色的明度,而纯色的亮度等于中度灰的亮度。换句话说就是明度是相对于100%而言的,而亮度是相对于50%而言的,模型如下:
由于HSV空间中只有一个通道是颜色通道,所以我们一般使用HSV空间来彩色分割。因此我们现需要将一个图像从BGR颜色空间转换到HSV颜色空间,cvCvtColor算子,然后在利用inRange根据HSV设置的范围检测目标。
设 (r, g, b)分别是一个颜色的红、绿和蓝坐标,它们的值是在0到1之间的实数。设max等价于r, g和b中的最大者。设min等于这些值中的最小者。要找到在HSL空间中的 (h, s, l)值,这里的h ∈ [0, 360)度是角度的色相角,而s, l ∈ [0,1]是饱和度和亮度,计算为
h的值通常规范化到位于0到360°之间。而h = 0用于max = min的(定义为灰色)时候而不是留下h未定义。
HSL和HSV有同样的色相定义,但是其他分量不同。HSV颜色的s和v的值定义如下:
void inRange(
InputArray src, //输入要处理的图像,可以为单通道或多通道
InputArray lowerb,// 包含下边界的数组或标量(HSV的最小值)
InputArray upperb,//包含上边界数组或标量(HSV的最大值)
OutputArray dst);//输出图像,与输入图像src 尺寸相同且为CV_8U 类型
#if 1 // 图像分割 --彩色分割
Mat img; //输入图像:
Mat bgr;// 灰度值归一化
Mat hsv;//hsv 图像
// 色相
int hmin = 0;
int hmin_max = 360;
int hmax = 180;
int hmax_max = 180;
//色饱和度
int smin = 0;
int smin_max = 255;
int smax = 255;
int smax_max = 255;
// 亮度
int vmin = 106;
int vmin_max = 255;
int vmax = 255;
int vmax_max = 255;
string windowname = "src";
string dstname = "dst";
Mat dst;
void callback_hsv(int, void*);
int main() {
img = imread("C:\\Users\\19473\\Desktop\\opencv_images\\528.jpg");
if (!img.data)
{
printf("could not load image....\n");
}
imshow(windowname,img);
bgr = img.clone();
namedWindow(dstname, CV_WINDOW_AUTOSIZE);
// 将bgr 颜色空间转换为HSV
cvtColor(bgr,hsv,CV_BGR2HSV);
createTrackbar("hmin:", dstname,&hmin, hmin_max, callback_hsv);
createTrackbar("hmax:", dstname, &hmax, hmax_max, callback_hsv);
createTrackbar("smin:", dstname, &smin, smin_max, callback_hsv);
createTrackbar("smax:", dstname, &smax, smax_max, callback_hsv);
createTrackbar("vmin:", dstname, &vmin, vmin_max, callback_hsv);
createTrackbar("vmax:", dstname, &vmax, vmax_max, callback_hsv);
callback_hsv(0,0);
waitKey(0);
return 0;
}
void callback_hsv(int, void*) {
dst = Mat::zeros(img.size(), img.type());
Mat mask;//掩码
inRange(hsv, Scalar(hmin, smin, vmin), Scalar(hmin_max, smin_max, vmin_max), mask); //掩码得到原图的转换
for (int r = 0; r < bgr.rows; r++)
{
for (int c = 0; c < bgr.cols; c++)
{
if (mask.at(r, c) == 255)
{
dst.at(r, c) = bgr.at(r, c);
}
}
}
imshow(dstname, dst);
}
#endif