图像直方图由于其计算代价较小,且具有图像平移、旋转、缩放不变性等众多优点,广泛地应用于图像处理的各个领域,特别是灰度图像的阈值分割、基于颜色的图像检索以及图像分类。
图像分割
图像分割是图像识别的基础,对图像进行图像分割,将目标从背景区域中分离出,可以避免图像识别时在图像上进行盲目的搜索,大大提高图像识别的效率以及识别准确率。基于灰度直方图的阈值分割计算简单,适用于目标与背景分布于不同灰度范围的灰度图像,特别是遥感图像。
图像检索
图像检索是指快速有效地从大规模图像数据库中检索出所需的图像,是目前一个非常重要又富有的挑战性的研究课题。颜色特征由于其直观性、计算代价较小等优点,在图像检索中扮演着重要角色,早期的图像检索算法也主要利用颜色特征,特别是颜色直方图。
图像分类
图像分类任务主要是对一组图进行一系列自在这里插入图片描述
动处理,最终确定图形所属的类别。图像分类具有广泛的应用前景,是计算机视觉的难点问题。针对图像分类的算法众多,其中以基于bag-words模型的方法最为经典有效。该方法首先利用提取的颜色、形状等特征构建视觉词典,然后在图像上统计视觉词的直方图,最后利用视觉词直方图作为特征运用分类器进行分类决策。
void calcHist( const Mat* images, int nimages,
const int* channels, InputArray mask,
OutputArray hist, int dims, const int* histSize,
const float** ranges, bool uniform=true, bool accumulate=false );
参数解释:
/*
* 1. 读取原图像并转化为灰度图
*/
cv::Mat srcImg, grayImg;
srcImg = cv::imread("./img/dog.jpg");
if (!srcImg.data){
/*文件读取错误*/
return -1;
}
cv::cvtColor(srcImg, grayImg, cv::CV_BGR2GRAY);//转换为灰度图像
/*
* 2. calcHist 来获取颜色分布强度数据
*/
const int channels[] = { 0 };
cv::Mat hist;
int dims = 1;//设置直方图维度,灰度直方图为1通道
const int histSize[] = { 256 };//直方图每一个维度划分的柱条的数目
//每一个维度取值范围
float pranges[] = { 0, 255 };//取值区间
const float* ranges[] = { pranges };
cv::calcHist(&grayImg, 1, channels, cv::Mat(), hist, dims, histSize, ranges, true, false);//计算直方图
/*
* 3. 通过calcHist的数据来绘制灰度直方图
*/
int scale = 2;
int hist_height = 256;
cv::Mat hist_img = cv::Mat::zeros(hist_height, 256 * scale, CV_8UC3); //创建一个黑底的8位的3通道图像,高256,宽256*2
double minval,maxval;
cv::minMaxLoc(hist, &minval, &maxval);//定义矩阵中最小值,最大值的位置
int scale = 2;
int hist_height = 256;
cv::Mat hist_ing = cv::Mat::zeros(hist_height, scale * bins, CV_8UC3);
for (int i = 0; i < bins; i++)
{
float bin_val = hist.at(i);//图像的灰度频率表
int inten = cvRound(bin_val * hist_height / maxval);//绘制高度
rectangle(hist_ing, cv::Point(scale * i, hist_height - 1), cv::Point((i + 1) * scale - 1, hist_height - inten), CV_RGB(255, 255, 255));
}
cv::imshow("gray hist", hist_ing);
cv::waitKey(0);
绘制各个通道的直方图方法和绘制灰度直方图方法一样,通过cv::split 分离出各个通道数据,再分别绘制
int histSize = 256;
float range[] = { 0,255 };
const float* Ranges = { range };
cv::Mat src = cv::imread(m_strImgPath);
std::vectorbgr_planes;
cv::split(src, bgr_planes);
cv::Mat b_hist, g_hist, r_hist;
cv::calcHist(&bgr_planes[0], 1, 0, cv::Mat(), b_hist, 1, &histSize, &Ranges, true, false);
cv::calcHist(&bgr_planes[1], 1, 0, cv::Mat(), g_hist, 1, &histSize, &Ranges, true, false);
cv::calcHist(&bgr_planes[2], 1, 0, cv::Mat(), r_hist, 1, &histSize, &Ranges, true, false);
//归一化
int hist_w = 500;//直方图的图像的宽
int hist_h = 300; //直方图的图像的高
int nHistSize = 256;
int bin_w = cvRound((double)hist_w / nHistSize); //区间
cv::Mat histImage(hist_h, hist_w, CV_8UC3, cv::Scalar(0, 0, 0));//绘制直方图显示的图像
cv::normalize(b_hist, b_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());//归一化
cv::normalize(g_hist, g_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
cv::normalize(r_hist, r_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
for (int i = 1; i < nHistSize; i++)
{
//绘制蓝色分量直方图
cv::line(histImage, cv::Point((i - 1) * bin_w, hist_h - cvRound(b_hist.at(i - 1))),
cv::Point((i)*bin_w, hist_h - cvRound(b_hist.at(i))), cv::Scalar(255, 0, 0), 2);
//绘制绿色分量直方图
cv::line(histImage, cv::Point((i - 1) * bin_w, hist_h - cvRound(g_hist.at(i - 1))),
cv::Point((i)*bin_w, hist_h - cvRound(g_hist.at(i))), cv::Scalar(0, 255, 0), 2);
//绘制红色分量直方图
cv::line(histImage, cv::Point((i - 1) * bin_w, hist_h - cvRound(r_hist.at(i - 1))),
cv::Point((i)*bin_w, hist_h - cvRound(r_hist.at(i))), cv::Scalar(0, 0, 255), 2);
}
同理可以绘制HSV等颜色空间的各个通道直方图