Histogram equalization and histogram matching for image processing

1 Histogram equalization

  Histogram equalization is an image processing method that converts the gray distribution in the image into a uniform distribution, thereby enhancing the contrast of the image. Histogram equalization can convert the original white or black image into an image whose contrast conforms to human vision.

1.1 Principle

Continuous space image grayscale r ∈ [ 0 , L − 1 ]
  in continuous space , L represents the gray level r\in[0,L-1], L represents the gray levelr[0,L1 ] , L represents the gray level , the expected equalization conversion function is
s = T ( r ) , 0 ≤ r ≤ L − 1 s=T(r),0\le r\le L-1s=T(r),0rL1
  of whichTTT is the grayscale transformation function,sss is the transformed gray value, and the change function satisfies two conditions:

  • T ( r ) T(r) T ( r ) in the interval[ 0 , L − 1 ] [0, L-1][0,L1 ] is a strictly monotonically increasing function. Ensure that the conversion is one-to-one correspondence to avoid ambiguity;
  • 0 ≤ r ≤ L − 1 0 \le r\le L - 10rL1时,0 ≤ s ≤ L − 1 0 \le s\le L - 10sL1 . Ensure that the grayscale range of the input and output is the same.

  What we expect is to input the gray probability distribution p ( r ) p(r)p ( r ) is converted into the output gray probability distributionp ( s ) = 1 L − 1 p(s)=\frac{1}{L - 1}p(s)=L11. Here we choose the following transformation function to prove that this function is feasible:
s = T ( r ) = ( L − 1 ) ∫ 0 rpr ( w ) dw , w is the dummy variable s=T(r)=(L- 1)\int_{0}^{r}p_r(w)dw, w is the dummy variable of the integrals=T(r)=(L1)0rpr( w ) d w , w is the dummy variable of the integral
  First,∫ 0 rpr ( w ) dw \int_{0}^{r}p_r(w)dw0rpr( w ) The value range of d w is[ 0 , 1 ] [0,1][0,1 ] ThereforessThe value range of s is[ 0 , L − 1 ] [0,L-1][0,L1 ] ; In addition, this function is also strictly monotonically increasing. The basic conditions are met. Below we prove thatp ( s ) = 1 L − 1 p(s)=\frac{1}{L-1}p(s)=L11。因为
p ( s ) = p r ( r ) ∣ d r d s ∣ = p r ( r ) 1 d s d r = p r ( r ) 1 ( L − 1 ) d d r [ ∫ 0 r p r ( w ) d w ] = p r ( r ) 1 ( L − 1 ) p r ( r ) = 1 L − 1 \begin{equation} \begin{aligned} p(s)&=p_r(r)|\frac{dr}{ds}|\\ &=p_r(r)\frac{1}{\frac{ds}{dr}}\\ &=p_r(r)\frac{1}{(L-1)\frac{d}{dr}[\int_{0}^{r}p_r(w)dw]}\\ &=p_r(r)\frac{1}{(L-1)p_r(r)}\\ &=\frac{1}{L-1} \end{aligned} \end{equation} p(s)=pr(r)dsdr=pr(r)drds1=pr(r)(L1)drd[0rpr( w ) d w ]1=pr(r)(L1)pr(r)1=L11
  So s = T ( r ) = ( L − 1 ) ∫ 0 rpr ( w ) dws=T(r)=(L-1)\int_{0}^{r}p_r(w)dws=T(r)=(L1)0rpr( w ) d w can be used as an equalization transformation function.
Discrete space
  is always discrete space for image processing, the gray levelrk of discrete space, k is the gray level, k ∈ [ 0 , L − 1 ] r_k, k is the gray level, k\in [0,L-1 ]rk, k is the gray level, k[0,L1 ] the probability is approximately
pr ( rk ) = nk MN p_r(r_k)=\frac{n_k}{MN}pr(rk)=MNnk
  Where k is the gray level, k ∈ [ 0 , L − 1 ] k is the gray level, k\in [0,L-1]k is the gray level, k[0,L1] M M M andNNN is the width and height of the image,nk n_knkis the number of pixels in the current gray level. Then use the above transformation function to get sk s_ksk
s k = T ( r k ) = ( L − 1 ) ∑ j = 0 k p r ( r j ) = L − 1 M N ∑ j = 0 k n j s_k=T(r_k)=(L-1)\sum_{j=0}^{k}p_r(r_j)=\frac{L-1}{MN}\sum_{j=0}^{k}{n_j} sk=T(rk)=(L1)j=0kpr(rj)=MNL1j=0knj
  In addition, the gray value calculated by the above change function may be a decimal, so it needs to be rounded to the nearest integer. And for the RGB image, if the images of the R, G, and B channels are respectively transformed, there will be a hue problem, so the image needs to be converted into other color spaces such as YUV, and only the grayscale transformation of Y is performed.

1.2 Implementation

  The implementation is relatively simple. First, the number of each gray level is calculated pixel by pixel, and the probability of each gray level is calculated according to the number of changes. Finally, the final color mapping relationship is calculated using the above formula, and the original image will be converted to the original image according to the mapping relationship. Colors are mapped.

static vector<float> countGrayProp(const Mat &img) {
    
    
    assert(img.channels() == 1);
    double pixelProp = 1.0 / (img.rows * img.cols);
    vector<float> ret(GRAPH_GRAY_LAYER_NUM, 0.0);
    for (int i = 0; i < img.rows; i++) {
    
    
        for (int j = 0; j < img.cols; j++) {
    
    
            ret[static_cast<int>(img.at<uchar>(i, j))] += pixelProp;
        }
    }

    return ret;
}
/*
    * @brief 均衡化灰度图
    */
static Mat avgGrayHistogram(const Mat &img) {
    
    
    assert(img.channels() == 1);
    vector<float> props = countGrayProp(img);
    vector<float> propSum(GRAPH_GRAY_LAYER_NUM, 0.0);
    for (int i = 0; i < GRAPH_GRAY_LAYER_NUM;i ++) {
    
    
        if (i == 0) {
    
    
            propSum[i] = props[i];
        }
        else {
    
    
            propSum[i] = (props[i] + propSum[i - 1]);
        }

    }

    Mat ret(img.rows, img.cols, CV_8UC1);
    for (int i = 0; i < img.rows; i++) {
    
    
        for (int j = 0; j < img.cols; j++) {
    
    
            int value = static_cast<int>(img.at<uchar>(i, j));
            ret.at<uchar>(i, j) = int((GRAPH_GRAY_LAYER_NUM - 1) * propSum[value]);
        }
    }

    return ret;
}

Mat avgHistogram(const Mat &img) {
    
    
    if (img.channels() == 1) {
    
    
			return avgGrayHistogram(img);
		}
		else if (img.channels() == 3) {
    
    
			Mat yuvImg;
			cvtColor(img, yuvImg, COLOR_BGR2YUV);
			std::vector<Mat> yuvImgs;
			split(yuvImg, yuvImgs);
			yuvImgs[0] = avgGrayHistogram(yuvImgs[0]);

			Mat proYUV, ret;
			merge(yuvImgs, proYUV);
			cv::cvtColor(proYUV, ret, COLOR_YUV2BGR);
			return ret;
		}

		return img;
}

  The effect of the single-channel grayscale image is as follows, and it can be seen that the grayscale in the equalized grayscale histogram is more uniform:
insert image description here
insert image description here

  If you directly equalize the three channels of rgb, the following situation will appear (1, 2, 3, and 4 in the four pictures 1 and 3 are the pictures before processing, and 34 is the picture after processing)
insert image description here

  First, the image is converted to other color spaces such as YUV, and only the Y component is equalized so that there will be no obvious color difference and singularity.
insert image description here

2 Histogram matching

2.1 Principle

  Using histogram equalization to adjust the gray level of the image can quickly and efficiently adjust the image to meet the perception of the human eye. However, this method is too simple and crude, and the histogram of the target cannot be customized, which is not very effective for some scenarios. Histogram regulation or histogram matching is a method to solve the problem that histogram equalization cannot specify the histogram probability distribution of the output image. This method can map the probability distribution of the input image to the specified output histogram probability distribution.
Continuous space
  task target: the probability density distribution pr ( r ) p_r(r) of the input imagepr( r ) , the output image probability density distribution ispz ( z ) p_z(z)pz( z ) .
  In the histogram equalization task,sss andrrThe mapping relationship of r is s = T ( r ) = ( L − 1 ) ∫ 0 rpr ( w ) dws=T(r)=(L-1)\int_{0}^{r}p_r(w)dws=T(r)=(L1)0rpr( w ) d w . Similarly, forpz ( z ) p_z(z)pz( z ) for histogram equalization, thenG ( z ) = ( L − 1 ) ∫ 0 zpz ( w ) dw G(z)=(L-1)\int_{0}^{z}p_z(w)dwG(z)=(L1)0zpz( w ) d w,其中G ( z ) = T ( r ) G(z)=T(r)G(z)=T(r),即
T ( r ) = ( L − 1 ) ∫ 0 r p r ( w ) d w = G ( z ) = ( L − 1 ) ∫ 0 z p z ( t ) d t \begin{equation} \begin{aligned} T(r)=(L-1)\int_{0}^{r}p_r(w)dw=G(z)=(L-1)\int_{0}^{z}p_z(t)dt \end{aligned} \end{equation} T(r)=(L1)0rpr( w ) d w=G(z)=(L1)0zpz(t)dt
  则:
z = G − 1 ( T ( r ) ) z=G^{-1}(T(r)) z=G1 (T(r))
  Therefore, a probability density aspr ( r ) p_r(r)prThe image of ( r ) is specified aspz ( z ) p_z(z)pz( z ) steps are:

  1. Calculate the probability distribution pr ( r ) p_r(r) of each gray level of the input imagepr(r)
  2. Calculate the histogram equalization mapping function of the input image;
  3. According to the specified pz ( z ) p_z(z)pz( z ) Calculate the mapping functionG ( z ) G(z)G(z)
  4. G ( z ) G(z) The inverse transformation function of G ( z ) G − 1 ( T ( r ) ) G^{-1}(T(r))G1 (T(r)), process each pixel in the image to get the target grayscale image.

Discrete space
  In discrete space, pr ( r ) p_r(r)pr( r ) The output after histogram equalization issk = L − 1 MN ∑ j = 0 knj s_k=\frac{L-1}{MN}\sum_{j=0}^{k}{n_j}sk=MNL1j=0knj,而 G ( z ) = ( L − 1 ) ∑ i = 0 q p z ( z j ) G(z)=(L-1)\sum_{i=0}^{q}p_z(z_j) G(z)=(L1)i=0qpz(zj) . According to the inference of continuous space, the output value iszq = G − 1 ( sk ) z_q=G^{-1}(s_k)zq=G1(sk) .
  It can be seen from the above inference that we only need to find the inverse transformationG − 1 ( sk ) G^{-1}(s_k)G1(sk) is enough, but in fact, since the gray levels we use are limited, such as 256 gray levels, it is often only necessary to exhaustively enumerate.

  1. Calculate the probability distribution pr ( r ) p_r(r) of each gray level of the input imagepr(r)
  2. Perform histogram equalization on the input image to obtain r → skr\rightarrow s_k of the input imagerskthe mapping;
  3. Calculate the histogram equalization mapping relationship q → sqq\rightarrow s_q of the target probability density distributionqsq
  4. Find the closest G ( z ) G(z) in the mapping relationship in step 3G ( z ) , if there are multiple values, select the smallest one, that is, getsk → q s_k\rightarrow qskmap of q .

It is possible to find G ( z ) G(z)   in an implementationG ( z ) is not strictly monotonically increasing and does not meet the conditions mentioned in histogram equalization, but this is not a serious problem in discrete spaces.

2.2 Implementation

  The implementation is relatively simple, the main thing is to search for content.

	static Mat matchGrayHistogram(const cv::Mat &img, const std::vector<float>& targetProp) {
    
    
		assert(img.channels() == 1);
		vector<float> props = countGrayProp(img);
		vector<float> propSum(GRAPH_GRAY_LAYER_NUM, 0.0), targPropSum(GRAPH_GRAY_LAYER_NUM, 0.0);
		for (int i = 0; i < GRAPH_GRAY_LAYER_NUM; i++) {
    
    
			if (i == 0) {
    
    
				propSum[i] = props[i];
				targPropSum[i] = targetProp[i];
			}
			else {
    
    
				propSum[i] = (props[i] + propSum[i - 1]);
				targPropSum[i] = (targetProp[i] + targPropSum[i - 1]);
			}
		}

		//将输入和输出的标签映射整数化
		for (int i = 0; i < GRAPH_GRAY_LAYER_NUM; i++) {
    
    
			int layer = GRAPH_GRAY_LAYER_NUM - 1;
			propSum[i] = std::min<float>(GRAPH_GRAY_LAYER_NUM - 1, static_cast<int>(layer * propSum[i] + 0.5));
			targPropSum[i] = std::min<float>(GRAPH_GRAY_LAYER_NUM - 1, static_cast<int>(layer * targPropSum[i] + 0.5));
		}

		//映射关系搜索,propSum中存储r->sk,targPropSum中存储z->sk 目标搜索sk->z
		std::vector<int> skzMap(GRAPH_GRAY_LAYER_NUM, -1);
		for (int i = 0; i < GRAPH_GRAY_LAYER_NUM; i++) {
    
    
			int sk = propSum[i];
			if (skzMap[sk] == -1) {
    
    
				//使用二分查找法在targetPropSum中搜索sk
				int left = 0, right = targPropSum.size() - 1;
				int mid = 0;
				while (left < right) {
    
    
					mid = left + (right - left) / 2.0;
					if (targPropSum[mid] == sk) {
    
    
						while (mid > 1 && targPropSum[mid] == targPropSum[mid - 1]) {
    
     mid--; }
						skzMap[sk] = mid;
						break;
					}
					else if (targPropSum[mid] > sk) {
    
    
						right = mid - 1;
					}
					else {
    
    
						left = mid + 1;
					}
				}

				if (targPropSum[mid] != sk) {
    
    
					if (left != 0 && abs(sk - targPropSum[left - 1]) < abs(sk - targPropSum[left])) {
    
    
						skzMap[sk] = left - 1;
					}
					else {
    
    
						skzMap[sk] = left;
					}
				}
				else {
    
    
					printf("");
				}
			}
		}

		Mat ret(img.rows, img.cols, CV_8UC1);
		for (int i = 0; i < img.rows; i++) {
    
    
			for (int j = 0; j < img.cols; j++) {
    
    
				int value = static_cast<int>(img.at<uchar>(i, j));
				ret.at<uchar>(i, j) = skzMap[propSum[value]];
			}
		}

		return ret;
	}

	Mat GrayTransform::matchHistogram(const cv::Mat &img, const std::vector<float>& targetProp) {
    
    
		assert(targetProp.size() == 256);
		if (img.channels() == 1) {
    
    
			return matchGrayHistogram(img, targetProp);
		}
		else if (img.channels() == 3) {
    
    
			Mat yuvImg;
			cvtColor(img, yuvImg, COLOR_BGR2YUV);
			std::vector<Mat> yuvImgs;
			split(yuvImg, yuvImgs);
			yuvImgs[0] = matchGrayHistogram(yuvImgs[0], targetProp);

			Mat proYUV, ret;
			merge(yuvImgs, proYUV);
			cv::cvtColor(proYUV, ret, COLOR_YUV2BGR);
			return ret;
		}

		return img;
	}

insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/GrayOnDream/article/details/127021987