Histogram equalization and histogram matching

1. Histogram Equalization

Usually, images with a more uniform histogram look more in line with the visual effects of the human eye. If you need to adjust the histogram with darker, brighter or more concentrated grayscale in the image into a histogram with uniform grayscale distribution, you need to use a histogram equalization algorithm.

Insert image description here

Histogram equalization is essentially to equalize the distribution of the number of gray levels in the image, that is, the number of gray levels is not concentrated on some gray levels. When the histogram of the image is completely evenly distributed, at this time The entropy of the image is the largest (that is, the probability distribution of each gray level is balanced), and the contrast of the image is also the largest, thereby enhancing the observability of the image.
Histogram equalization is a method of enhancing image contrast. Its main idea is to transform the histogram distribution of an image into an approximately uniform distribution through the cumulative distribution function , thereby enhancing the contrast of the image. The ideal effect is as follows:
Insert image description here
The actual processing effect is as follows:
Insert image description here
From the above figure, you can see that after histogram equalization, the distribution of the histogram is less concentrated and the contrast of the image is also improved.

The implementation steps of histogram equalization
(1) count the number of gray levels in the image
(2) calculate the cumulative distribution probability of the gray level
(3) obtain the probability density of the transformed gray level through the transformation function
(4) spread the original Figure, modify the original image
code as follows:

# include <iostream>
#include <opencv.hpp>

using namespace cv;
using namespace std;
void GetHistogram(const Mat& srcImage, int* histogram);

int main() {
    
    
	Mat srcImage; //存放读取的原图
	Mat dstImage; //直方均衡的图像
	srcImage = imread("d://1.jpg", 0); //1RGB 0灰色

	if (!srcImage.data) 
		cout << "图片加载失败,请检查文件是否存在!" << endl;
	else
		cout << "图片加载成功!" << endl;
	CV_Assert(srcImage.type() == CV_8UC1); //判断图像是否为灰度图片,非灰色报错
	dstImage.create(srcImage.size(), srcImage.type()); //设置目标图与原图大小和类型相同

	// 计算直方图,即为每个灰度级在图像中的数目
	int histogram[256]; //存放为每一个灰度级在图像中的数目
	GetHistogram(srcImage, histogram);

	//计算累积分布函数,变换函数
	int pixelSrcImage = srcImage.cols * srcImage.rows;
	int Lut[256]; //分布函数
	Lut[0] = (1.0 * histogram[0] / pixelSrcImage) * 255;
	int sum = histogram[0];
	for (int i = 1; i < 256; ++i) {
    
    
		sum += histogram[i];
		Lut[i] = (1.0 * sum / pixelSrcImage) * 255;
	}

	//灰度变换
	uchar* srcImageDate = srcImage.data;
	uchar* dstImageDate = dstImage.data;
	for (int i = 0; i < pixelSrcImage; ++i) {
    
    
		dstImageDate[i] = Lut[srcImageDate[i]];
	}
	imshow("原始图像", srcImage);
	imshow("直方图均衡后图像", dstImage);
	//保持等待状态
	waitKey(0);//括号里可以填任意正整数,意味着,图像显示的毫秒时间

	return 0;
}
void GetHistogram(const Mat& srcImage, int* histogram) {
    
    
	memset(histogram, 0, 256 * sizeof(int)); //设置histogram数组初始全为0

	//建立直方图, 统计图像中每一灰度级数
	int pixelCount = srcImage.cols * srcImage.rows;
	uchar *srcImageDate = srcImage.data;
	for (int i = 0; i < pixelCount; ++i) {
    
    
		int grayDate = srcImageDate[i];
		histogram[grayDate]++;
	}
}

HE is a method to adjust the global image of the image and cannot effectively improve the local contrast. For some images, some details cannot be displayed after using histogram equalization, which leads to (adaptive) local histogram equalization. change.

2. Adaptive histogram equalization

Its principle is the same as histogram equalization, except that the cumulative distribution function of the local area of ​​the image is selected during mapping. Also, consider that if there is noise , the noise will be amplified. To avoid this situation use contrast limiting. For each small block, if the bin in the histogram exceeds the upper limit of contrast, the pixels are evenly dispersed into other bins, and then the histogram is equalized.
Insert image description here
Contrast Limited Adaptive Histogram Equalization (CLAHE, Contrast Limited Adaptive Histogram Equalization) algorithm, although it was originally proposed as an image enhancement algorithm, is now used in image defogging, low-light image enhancement, underwater It has applications in image effect adjustment and digital photo improvement.
It is implemented through the createCLAHE function in OpenCV, and the code called by C++ is as follows ( note: the input image should be an 8bit image ):

Mat adaptiveEqualizeHist(Mat src)
{
    
    
	src.convertTo(src, CV_8UC1);
	Mat temp, clahe_img;
	temp = src.clone();

	cv::Ptr<cv::CLAHE> clahe = createCLAHE();
	clahe->setClipLimit(4.);    // (int)(4.*(8*8)/256)
	clahe->setTilesGridSize(Size(8, 8)); // 将图像分为8*8块
	clahe->apply(temp, clahe_img);
	temp.release();
	clahe_img.copyTo(temp);
	return temp;
}

The python call is as follows:

import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
 
src = cv.imread("pic.png", 0)  # 直接以灰度图方式读入
img = src.copy()
 
# 创建一个自适应均衡化的对象,并应用于图像
clahe = cv.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
dst = clahe.apply(img)
 
# 显示图像
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img, cmap=plt.cm.gray)
axes[0].set_title("原图")
axes[1].imshow(dst, cmap=plt.cm.gray)
axes[1].set_title("自适应均衡化后的图像")
plt.show()

3. Histogram matching

Through the above introduction, we already know that histogram equalization is essentially a transformation function mapped through the cumulative distribution function, which can be achieved through the lookup table LUT.
Histogram equalization is to boost the image within the entire grayscale range; but sometimes, this boosting across the entire range may not be the best, and we may need it to follow a certain grayscale distribution. To pull up, it is necessary to use histogram matching (standardization).
Histogram matching, also called histogram specification, is an operation to transform the grayscale distribution of an image according to a specific pattern.
The principle is implemented on the basis of histogram equalization. The implementation steps are as follows:
Insert image description here

Code implementation steps

  1. Calculate the cumulative histogram of the source image;
  2. Calculate the cumulative histogram of the specified image;
  3. Calculate the absolute value of the difference between each gray level of the cumulative histogram of the source image and each gray level of the cumulative histogram of the specified image;
  4. Find the minimum value corresponding to the absolute value in each level in step 3. The gray level corresponding to the minimum value is the mapped value.
#include<iostream>
#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
    
    
	Mat image1, image1_gray, hist1, image2, image2_gray, hist2, image_enhanced;   //定义修改图像,灰度修改图像, 修改直方图,目标图像,灰度目标图像,目标直方图, 规定化增强图像
	image1 = imread("lena.png");  //读取图像;
	if (image1.empty())
	{
    
    
		cout << "读取错误" << endl;
		return -1;
	}

	cvtColor(image1, image1_gray, COLOR_BGR2GRAY);  //灰度化
	imshow(" image1_gray", image1_gray);   //显示灰度图像

	image2 = imread("1043.jpg");  //读取图像;
	if (image2.empty())
	{
    
    
		cout << "读取错误" << endl;
		return -1;
	}

	cvtColor(image2, image2_gray, COLOR_BGR2GRAY);  //灰度化
	imshow(" image2_gray", image2_gray);   //显示灰度图像

	//均衡化处理
	equalizeHist(image1_gray, image1_gray);
	equalizeHist(image2_gray, image2_gray);


	//获取两个均衡化图像的直方图
	int histsize = 256;
	float ranges[] = {
    
     0,256 };
	const float* histRanges = {
    
     ranges };
	calcHist(&image1_gray, 1, 0, Mat(), hist1, 1, &histsize, &histRanges, true, false);
	calcHist(&image2_gray, 1, 0, Mat(), hist2, 1, &histsize, &histRanges, true, false);

	//计算两个均衡化图像直方图的累积概率
	float hist1_cdf[256] = {
    
     hist1.at<float>(0) };
	float hist2_cdf[256] = {
    
     hist2.at<float>(0) };
	for (int i = 1; i < 256; i++)
	{
    
    
		hist1_cdf[i] = (hist1_cdf[i - 1] + hist1.at<float>(i));
		hist2_cdf[i] = (hist2_cdf[i - 1] + hist2.at<float>(i));
	}

	for (int i = 0; i < 256; i++)
	{
    
    
		hist1_cdf[i] = hist1_cdf[i] / (image1_gray.rows * image1_gray.cols);
		hist2_cdf[i] = hist2_cdf[i] / (image2_gray.rows * image2_gray.cols);
	}

	// 两个累计概率之间的差值,用于找到最接近的点
	float diff_cdf[256][256];
	for (int i = 0; i < 256; i++) {
    
    
		for (int j = 0; j < 256; j++)
		{
    
    
			diff_cdf[i][j] = fabs(hist1_cdf[i] - hist2_cdf[j]);
		}
	}

	Mat lut(1, 256, CV_8U);
	for (int i = 0; i < 256; i++)
	{
    
    
		//查找源灰度级为i的映射灰度和i的累积概率差最小(灰度接近)的规定化灰度
		float min = diff_cdf[i][0];
		int index = 0;
		for (int j = 0; j < 256; j++) {
    
    
			if (min > diff_cdf[i][j]) {
    
    
				min = diff_cdf[i][j];
				index = j;
			}
		}
		lut.at<uchar>(i) = index;
	}
	LUT(image1_gray, lut, image_enhanced);  //图像中进行映射
	imshow("image_enhanced", image_enhanced);
	waitKey(0);  //暂停,保持图像显示,等待按键结束
	return 0;
}

References
[1] Principle and implementation of histogram equalization
[2] Spatial domain enhancement of images - Principle and implementation of histogram equalization algorithm
[3] https://www.cnblogs.com/yanshw/p/15429887 .html
[4] https://blog.csdn.net/mmmmmk_/article/details/82927411
[5] https://zhuanlan.zhihu.com/p/618170011

Guess you like

Origin blog.csdn.net/qq_44924694/article/details/132480400