车辆颜色识别基本原理:
1、将图像格式转为HSV
2、统计HSV各个通道的分布情况
3、将分布于颜色区间对应起来,统计各个颜色的数量
4、颜色数量最多的为车辆颜色
一般对颜色空间的图像进行有效处理都是在HSV空间进行的,然后对于基本色中对应的HSV分量需要给定一个严格的范围,下面是通过实验计算的模糊范围
H: 0 — 180
S: 0 — 255
V: 0 — 255
具体实现:
/* 输入(cv::Mat): 车辆颜色图片;
输出(std::string): 车辆名*/
std::string recognizeVehicleColor1(const cv::Mat& img)
{
cv::Size imgSize = img.size();
cv::Mat preImg = img(cv::Rect(imgSize.width*0.15, imgSize.height*0.15, imgSize.width*(1 - 0.3), imgSize.height*(1 - 0.3)));
// HSV 三通道操作
imshow("preImg", preImg);
cv::waitKey();
cv::Mat hsvImg;
cv::cvtColor(preImg, hsvImg, CV_BGR2HSV);
std::vector<cv::Mat> hsv_planes;
cv::split(hsvImg, hsv_planes); // 分离HSV通道
cv::Mat hMask, sMask, vMask;
cv::threshold(hsv_planes[1], sMask, 43, 255, cv::THRESH_BINARY); // 以43为阈值将S通道进行二值化 43来自 HSV基本颜色分量范围
//cv::multiply(sMask, bgrMask / 255, hMask); // 与背景 Mask 合成为一个 Mask
cv::threshold(hsv_planes[2], vMask, 46, 255, cv::THRESH_BINARY); // 以46为阈值将V通道进行二值化 46来自 HSV基本颜色分量范围
cv::multiply(vMask, sMask / 255, hMask); // 与背景 Mask 合成为一个 Mask 用于H通道
cv::threshold(hsv_planes[1], vMask, 43, 255, cv::THRESH_BINARY_INV);// 以43为阈值将S通道进行二值化 用于V通道
// 利用二值图 Mask 将 HSV 通道中的背景部分设为 0.
hsv_planes[1] = hsv_planes[2].clone();
cv::multiply(hsv_planes[0], hMask / 255, hsv_planes[0]);
cv::multiply(hsv_planes[2], vMask / 255, hsv_planes[2]);
// 分别计算三个通道的颜色直方图
int histSize = 180; // 将色调量化到180个级别 对应 H 取值范围 [0:180]
float ranges[] = { 0, 180 };
const float* hRanges = { ranges };
cv::Mat hsv_hist, sv_hist, v_hist;
//计算直方图
calcHist(&hsv_planes[0], 1, 0, cv::Mat(), hsv_hist, 1, &histSize, &hRanges, true, false);
histSize = 256;
ranges[1] = 256;
const float* Ranges = { ranges };
calcHist(&hsv_planes[2], 1, 0, cv::Mat(), sv_hist, 1, &histSize, &Ranges, true, false);
calcHist(&hsv_planes[1], 1, 0, cv::Mat(), v_hist, 1, &histSize, &Ranges, true, false);
std::map<std::string, float> color; // 定义颜色映射, 对每个颜色对应的HSV区间内进行统计
color["red"] = 0;
color["orange"] = 0;
color["yellow"] = 0;
color["green"] = 0;
color["cyan"] = 0;
color["blue"] = 0;
color["violet"] = 0;
color["black"] = 0;
color["grey"] = 0;
color["white"] = 0;
for (int r = 0; r < hsv_hist.rows; r++) {
float binVal = hsv_hist.at<float>(r);
if ((r <= 10 && r > 0) || (r >= 160)) // 红色区间 H [0,10]
{
color["red"] += binVal;
}
else if (r >= 11 && r <= 25) // 橙色区间 H [11,25]
{
color["orange"] += binVal;
}
else if (r >= 26 && r <= 34) // 黄色区间 H [26,34]
{
color["yellow"] += binVal;
}
else if (r >= 35 && r <= 77) // 绿色区间 H [35,77]
{
color["green"] += binVal;
}
else if (r >= 78 && r <= 99) // 青色区间 H [78,99]
{
color["cyan"] += binVal;
}
else if (r >= 100 && r <= 124) // 蓝色区间 H [100,124]
{
color["blue"] += binVal;
}
else if (r >= 125 && r <= 159) // 紫色区间 H [125,155]
{
color["violet"] += binVal;
}
}
for (int r = 1; r < sv_hist.rows; r++) {
float sv_binVal = sv_hist.at<float>(r);
if (r > 200)
{
color["white"] += sv_binVal; // 白色区间 H [200,255]
}
}
for (int r = 1; r < v_hist.rows; r++) {
float v_binVal = v_hist.at<float>(r);
if (r > 0 && r <= 46)
{
color["black"] += v_binVal; // 黑色区间 H [0,40]
}
}
float maxVal = 0;
std::string result = "";
std::map<std::string, float> ::const_iterator it = color.begin(); //找出对应颜色区间统计数最多的颜色
for (it; it != color.end(); it++)
{
if (it->second > maxVal)
{
maxVal = it->second;
result = it->first;
}
}
return result;
}