色彩直方图是统计不同色彩在图像中的像素个数。例如,下图的猫咪在RGB色彩空间中每通道的灰度直方图(线条的颜色与其通道相对应)。
将图像转为HSV色彩空间(Hue:色调;Saturation:饱和度;Value:亮度),我们可以更稳定地提取特定的颜色。本示例采用HSV色彩空间的H、S通道来进行颜色提取。H、S通道下的色彩直方图二维的展现形式如下(竖列为Hue通道,横行为Saturation通道,图像中的像素亮度越高,表明该色彩在原始图像中出现的频次越高):
程序执行过程:
#include
#include
#include
#include
#include
void calcBackProject_demo() {
int num_srcs = 6;
vector<Mat> hsv_rscs;
for (int i=1; i<num_srcs+1; i++) {
Mat src = imread("./skin_"+ to_string(i) +".jpg");
if (src.empty()) {
cout << "Failed to load src image ..." << endl;
}
if (src.rows > 500 || src.cols > 500) {
pyrDown(src, src);
}
Mat hsv_src;
cvtColor(src, hsv_src, COLOR_BGR2HSV);
hsv_rscs.push_back(hsv_src);
}
Mat dest = imread("./skin_test.png");
if (dest.empty()) {
cout << "Failed to load dest image ..." << endl;
}
Mat hsv_dest, hist;
cvtColor(dest, hsv_dest, COLOR_BGR2HSV);
int bin_w = 10;
const int channels[] = {0,1};
const int histSize[] = {static_cast<int>(ceil(180/bin_w)),static_cast<int>(ceil(256/bin_w))};
float h_range[] = {0,180};
float s_range[] = {0,256};
const float* ranges[] = {h_range, s_range};
hist.create(histSize[0], histSize[1], CV_32F);
Mat hist_tmp;
for (int i=0; i<num_srcs; i++) {
calcHist(&hsv_rscs[i], 1, channels, Mat(), hist_tmp, 2, histSize, ranges);
add(hist, hist_tmp, hist);
}
Mat histImg = Mat::zeros(histSize[0]*bin_w, histSize[1]*bin_w, CV_8UC1);
normalize(hist, hist, 0, 255, NORM_MINMAX);
double max, min;
minMaxLoc(hist, &min, &max);
cout << "rows: " << hist.rows << "\t" << "cols: " << hist.cols << "\t" << "max: " << max << "\t" << "min: " << min << endl << endl;
// cout << hist << endl << endl;
for (int i=1; i<=histSize[0]; i++) {
for (int j=1; j<=histSize[1]; j++) {
rectangle(histImg, Point((j-1)*bin_w, (i-1)*bin_w), Point(j*bin_w, i*bin_w), saturate_cast<int>(hist.at<float>(i-1,j-1)), -1);
}
}
imshow("histImg", histImg);
Mat backProj;
calcBackProject(&hsv_dest, 1, channels, hist, backProj, ranges);
imshow("backProj", backProj);
waitKey(0);
destroyAllWindows();
}
int main(int argc, char** argv){
calcBackProject_demo();
return 0;
}