1灰度直方图
1.1 概念
灰度直方图是关于灰度级分布的函数,是对图像中灰度级分布的统计。
灰度直方图是将数字图像中的所有像素,按照灰度值的大小,统计其出现的频率。
灰度直方图是灰度级的函数,它表示图像中具有某种灰度级的像素的个数,反映了图像中某种灰度出现的频率。如果将图像总像素亮度(灰度级别)看成是一个随机变量,则其分布情况就反映了图像的统计特性,这可用probability density function (PDF)来刻画和描述,表现为灰度直方图。
其中C++的函数原型如下:
void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false );
参数解释:
arrays:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U or CV_32F)。同时一副图像可以有多个channes。
narrays:输入的图像的个数。
channels:用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。
mask:掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。
hist:计算出来的直方图
dims:计算出来的直方图的维数。
histSize:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
ranges:用来进行统计的范围。比如 float rang1[] = {0, 20}; float rang2[] = {30, 40}; const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
uniform:每一个竖条的宽度是否相等。
accumulate: 是否累加。如果为true,在下次计算的时候不会首先清空hist。
2 直方图均衡化
1.1 概念
直方图均衡化就是一种能仅靠输入图像直方图信息自动达到这种效果的变换函数。
它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。
直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。
直方图均衡化的基本思想是把原始图的直方图变换为均匀分布的形式,这样就增加了像素灰度值的动态范围从而可达到增强图像整体对比度的效果。
2.2 opencv表示
cv::equalizeHist(img_gray,equalize_Hist)
3.例程
int img_Hist(Mat& image)
{
if(!image.data)
{
cout << "fail to load image" << endl;
return 0;
}
Mat img_gray;
//GRAY
if(image.channels()==3)
{
cvtColor(image, img_gray, CV_BGR2GRAY);
}
else
{
image.copyTo(img_gray);
}
cv::imwrite("img_gray.jpg",img_gray);
MatND hist; // 在cv中用CvHistogram *hist = cvCreateHist
int dims = 1;
float hranges[] = {0, 255};
const float *ranges[] = {hranges}; // 这里需要为const类型
int size = 256;
int channels = 0;
// 计算图像的直方图
calcHist(&img_gray, 1, &channels, Mat(), hist, dims, &size, ranges); // cv 中是cvCalcHist
int scale = 1;
Mat imageShow(size * scale, size, CV_8U, Scalar(0));
// 获取最大值和最小值
double minVal = 0;
double maxVal = 0;
minMaxLoc(hist,&minVal, &maxVal, 0, 0); // cv中用的是cvGetMinMaxHistValue
//显示直方图的图像
int hpt = saturate_cast<int>(0.9 * size);
for(int i = 0; i < 256; i++)
{
float value = hist.at<float>(i); // 注意hist中是float类型 cv中用cvQueryHistValue_1D
int realValue = saturate_cast<int>(value * hpt/maxVal);
rectangle(imageShow,Point(i*scale, size - 1), Point((i+1)*scale - 1, size - realValue), Scalar(255));
}
namedWindow("Hist");
imshow("Hist", imageShow);
cv::imwrite("hist.jpg",imageShow);
Mat equalize_Hist;
cv::equalizeHist(img_gray,equalize_Hist);
namedWindow("equalize_Hist");
imshow("equalize_Hist", equalize_Hist);
cv::imwrite("equalize_Hist.jpg",equalize_Hist);
// 计算图像的直方图
calcHist(&equalize_Hist, 1, &channels, Mat(), hist, dims, &size, ranges); // cv 中是cvCalcHist
Mat imageShow_equal(size * scale, size, CV_8U, Scalar(0));
// 获取最大值和最小值
minMaxLoc(hist,&minVal, &maxVal, 0, 0); // cv中用的是cvGetMinMaxHistValue
//显示直方图的图像
hpt = saturate_cast<int>(0.9 * size);
for(int i = 0; i < 256; i++)
{
float value = hist.at<float>(i); // 注意hist中是float类型 cv中用cvQueryHistValue_1D
int realValue = saturate_cast<int>(value * hpt/maxVal);
rectangle(imageShow_equal,Point(i*scale, size - 1), Point((i+1)*scale - 1, size - realValue), Scalar(255));
}
namedWindow("Hist_equalize");
imshow("Hist_equalize", imageShow_equal);
cv::imwrite("Hist_equalize.jpg",imageShow_equal);
waitKey(0);
return 0;
}
int main (int args, char** argv)
{
Mat image = imread("/home/odroid/TEST/111.jpg", 1); // 这里也可以是BGR 但是想想提取轮廓 效果是一样的
imshow("original", image);
img_Hist(image);
waitKey();
return 0;
}
原始图 灰度图
灰度直方图 均衡化后的灰度直方图
直方图均衡化后的灰度图