HSV颜色模型
如果我们想找出一副图像中的蓝色部分,我们需要检查rgb分量中的blue分量就可以了。一般blue分量是0-255的值,即便蓝色分量255了,由于另外两个分量的影响,需要考虑各个分量的配比问题,rgb作为颜色判断很难实现,就有了hsv模型hsv,photoshop中hsb
HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)。
色调H
用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
饱和度S
饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
亮度V
亮度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
在OpenCV中hsv 数据为8UC则取值分别为 0-180 0-255 0-255 ,即蓝色240对应的应该是120
1, 预处理
//src目前是BGR颜色空间,转换成HSV
Mat hsv;
cvtColor(src, hsv, COLOR_BGR2HSV);
//imshow("hsv", hsv);
效果
2找蓝色像素:h(100-124),s(43-255),v(46-255)
遍历
获取通道数
int channels = hsv.channels();
int height = hsv.rows;
//如下图,宽度变成了列数乘以3
int width = hsv.cols * channels;
//如果是连续存储,按照1行来处理,如下图,内存地址从0到8为第一行,将下一行看作为一行。
if (hsv.isContinuous()) {
width *= height;
height = 1;
}
uchar* p;
for (int i = 0; i < height; i++)
{
//取第i行的数据
p = hsv.ptr<uchar>(i);
//每次处理channels个数据,这里j步长为channels,每次都取3个。
for (int j = 0; j < width; j += channels) {
//获取 h s v 分量
int h = p[j];
int s = p[j + 1];
int v = p[j + 2];
//h(100-124),s(43-255),v(46-255)
bool isBlue = false;
if (h >= 100 && h <= 124 &&
s >= 43 && s <= 255 &&
v >= 46 && v <= 255
) {
isBlue = true;
}
if (isBlue)
{
//凸显蓝色(v分量最大255)
p[j] = 0;//h
p[j + 1] = 0;//s
p[j + 2] = 255;//v
}
else {
//变黑(v分量为0)
p[j] = 0;//h
p[j + 1] = 0;//s
p[j + 2] = 0;//v
}
}
}// end for
//imshow("凸显蓝色", hsv);
处理完之后如图:
如果是蓝色的车,可能就识别不了了。
vector<Mat> hsv_split;
split(hsv, hsv_split);//对图像按通道进行分离 , merge()合并
//imshow("分离v分量", hsv_split[2]);//v分离
https://blog.csdn.net/u012819339/article/details/82222008
分离 之后如图:
分离分量之后,和sobel一样,进行二值化,闭操作,找轮廓。。。
注意:
之前的是蓝色的,还有一种是黄色的。
//蓝色车牌:字符浅背景深,正二值化
//黄色车牌:字符深背景浅,反二值化
//二值化
Mat shold;
//THRESH_OTSU 大律法 自适应阈值
//THRESH_BINARY 正二值化
//THRESH_BINARY_INV 反二值化
//蓝色车牌:字符浅背景深,正二值化
//黄色车牌:字符深背景浅,反二值化
threshold(hsv_split[2], shold, 0, 255, THRESH_OTSU + THRESH_BINARY);
//imshow("color二值化", shold);
//闭操作
Mat close;
Mat element = getStructuringElement(MORPH_RECT, Size(17, 3));
morphologyEx(shold, close, MORPH_CLOSE, element);
//imshow("color闭操作", close);
//找轮廓
vector<vector<Point>> contours;
findContours(close, //输入图像
contours, //输出轮廓
RETR_EXTERNAL, //外轮廓
CHAIN_APPROX_NONE //轮廓上所有像素点
);
RotatedRect rotatedRect;
vector<RotatedRect> vec_color_rects;
//遍历并判断矩形尺寸
Mat src_clone = src.clone();
for each (vector<Point> points in contours)
{
rotatedRect = minAreaRect(points);//带角度的矩形
rectangle(src_clone, rotatedRect.boundingRect(), Scalar(0, 0, 255));
if (verifySizes(rotatedRect)) {
vec_color_rects.push_back(rotatedRect);
}
}
for each (RotatedRect rect in vec_color_rects)
{
rectangle(src_clone, rect.boundingRect(), Scalar(0, 255, 0));
}
//imshow("color找轮廓", src_clone);
//矩形矫正(角度判断,旋转矩形,调整大小)
tortuosity(src, vec_color_rects, dst_plates);
/*for each (Mat m in dst_plates)
{
//imshow("color定位候选车牌", m);
//waitKey();
}*/
color二值化:
sobel二值化
sobel闭操作(左)和color闭操作(右边)图对比
显然,color闭操作要好一点。