車輛顏色識別基本原理:
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;
}