下面是一个例子
这样就可以直观的看到直方图的变换了,可以理解为一个非线性的分段的平移拉伸
/*
* 画数组直方图,画在一个Mat上
*/
void show_lzb(int arr[], int size, string title)
{
Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
int _max = 0;
for (int i = 0; i < size; i++)
{
if (arr[i] > _max)
{
_max = arr[i];//找到数组中的最大值,后面需要归一化
}
}
for (int i = 0; i < 256; i++)
{
int current_value = (int)(double(arr[i]) / double(_max) * 256);//每次都要将数组的值根据最大值归一化到0-255之间
line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - current_value), Scalar(255, 0, 255));
}
imshow(title, drawImage);
}
void show_lzb(double arr[], int size, string title)
{
Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
double _max = 0;
for (int i = 0; i < size; i++)
{
if (arr[i] > _max)
{
_max = arr[i];//找到数组中的最大值,后面需要归一化
}
}
for (int i = 0; i < 256; i++)
{
int current_value = (int)(double(arr[i]) / double(_max) * 256);//每次都要将数组的值根据最大值归一化到0-255之间
line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - current_value), Scalar(255, 0, 255));
}
imshow(title, drawImage);
}
/*
* 均衡化JHH
*/
void JHH(Mat& img)
{
Mat dst = img.clone();
int row = img.rows;
int col = img.cols;
int N = row * col;
//计算直方图
int arr_1[256] = { 0 };
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
uchar value = img.at<uchar>(i, j);
arr_1[value]++;
}
}
show_lzb(arr_1, 256, "arr_1");
//计算概率
double arr_2[256] = { 0 };
for (int i = 0; i < 256; i++)
{
arr_2[i] = (double)arr_1[i] / N;
}
show_lzb(arr_2, 256, "arr_2");
//计算概率密度
double arr_3[256] = { 0 };
arr_3[0] = arr_2[0];
for (int i = 1; i < 256; i++)
{
arr_3[i] = arr_3[i - 1] + arr_2[i];
}
show_lzb(arr_3, 256, "arr_3");
//概率密度归一化到255
int arr_4[256] = { 0 };
for (int i = 0; i < 256; i++)
{
arr_4[i] = (int)(arr_3[i] * 255);
}
show_lzb(arr_4, 256, "arr_4");
//灰度变换
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
uchar value = dst.at<uchar>(i, j);
dst.at<uchar>(i, j) = arr_4[value];
}
}
imshow("dst", dst);
}
int main()
{
Mat src = imread("123.jpg", 0);
imshow("src", src);
JHH(src);
waitKey(0);
}