我是靠谱客的博主 老实荔枝,这篇文章主要介绍图像处理之直方图均衡化,现在分享给大家,希望可以做个参考。

直方图均衡化 Histogram Equalization

假如图像的灰度分布不均匀,其灰度分布集中在较窄的范围内,使图像的细节不够清晰,对比度较低。通常采用直方图均衡化直方图规定化两种变换,使图像的灰度范围拉开或使灰度均匀分布,从而增大反差,使图像细节清晰,以达到增强的目的。
直方图均衡化,对图像进行非线性拉伸,重新分配图像的灰度值,使一定范围内图像的灰度值大致相等。这样,原来直方图中间的峰值部分对比度得到增强,而两侧的谷底部分对比度降低,输出图像的直方图是一个较为平坦的直方图。

均衡化算法

直方图的均衡化实际也是一种灰度的变换过程,将当前的灰度分布通过一个变换函数,变换为范围更宽、灰度分布更均匀的图像。也就是将原图像的直方图修改为在整个灰度区间内大致均匀分布,因此扩大了图像的动态范围,增强图像的对比度。通常均衡化选择的变换函数是灰度的累积概率,直方图均衡化算法的步骤:

1、计算原图像的灰度直方图 P ( S k ) = n k n P(S_k)=n_kn P(Sk)=nkn,其中 n n n为像素总数, n k n_k nk为灰度级 S k S_k Sk的像素个数

2、计算原始图像的累积直方图
C D F ( S k ) = ∑ i = 0 k n i n = ∑ i = 0 k P s ( S i ) CDF(S_k)=sum_{i=0}^kn_in=sum_{i=0}^kPs(Si) CDF(Sk)=i=0knin=i=0kPs(Si)
D j = L ⋅ C D F ( S i ) D_j=L⋅CDF(S_i) Dj=LCDF(Si)
其中 D j D_j Dj是目的图像的像素, C D F ( S i ) CDF(S_i) CDF(Si)是源图像灰度为i的累积分布, L L L是图像中最大灰度级(灰度图为255)直接应用该方法得到图像的灰度直方图

3、将灰度直方图进行归一化,计算灰度的累积概率;
创建灰度变化的查找表
应用查找表,将原图像变换为灰度均衡的图像

均衡化过程中,必须要保证两个条件

1、像素无论怎么映射,一定要保证原来的大小关系不变,较亮的区域,依旧是较亮的,较暗依旧暗,只是对比度增大,绝对不能明暗颠倒;

2、如果是八位图像,那么像素映射函数的值域应在0和255之间的,不能越界。

综合以上两个条件,累积分布函数是个好的选择,因为累积分布函数单调增函数(控制大小关系),并且值域是0到1(控制越界问题),所以直方图均衡化中使用的是累积分布函数。

累积分布函数

累积分布函数具有一些好的性质,那么如何运用累积分布函数使得直方图均衡化?比较概率分布函数和累积分布函数,前者的二维图像是参差不齐的,后者是单调递增的。直方图均衡化过程中,映射方法是
S k = ∑ j = 0 k n j n . k = 0 , 1... , L − 1 S_k = sum_{j=0}^kfrac{n_j}{n} . k=0,1...,L-1 Sk=j=0knnj.k=0,1...,L1
n n n是图像素总和, n k n_k nk是当前灰度级的像素个数, L L L是图像中灰度级总数

操作步骤有:

直方图规定化

直方图规定化,就是对原始图像做变换,使得变换后的图像的直方图跟我们规定的一样。

具体步骤如下:

1、首先对原始图像做直方图均衡化,得到每个像素s和累积分布T(s);

2、根据需要的规定化直方图,求累积分布G(Z);

3、显然,如果累积直方图中有0值,那么是不会分配像素值的,因为0乘以255还是零。

4、对于每一个T(s)(假设其像素值为ss),找到在G(Z)中与其差值最小的那个G(z)值(假设对应的像素值为zz),那么规定化后就把ss变换为zz。

直方图规定化流程下图:

1、计算原图像的累积直方图

2、计算规定直方图的累积直方图

3、计算两累积直方图的差值的绝对值

4、根据累积直方图差值建立灰度级的映射

局部直方图处理&直方图统计

Opencv代码

灰度直方图均衡

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// HistogramGrayEqualizeHist.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <opencv2/core/core.hpp> //cvGetSize cvCreateImage #include <opencv2/highgui/highgui.hpp> #include <opencv2/opencv.hpp> //cvResize cvInitMatHeader cvGetMinMaxHistValue cvCvtColor #include <opencv2/imgproc/imgproc.hpp> #ifdef _DEBUG #pragma comment(lib, "opencv_core244d") #pragma comment(lib, "opencv_highgui244d") #pragma comment(lib, "opencv_imgproc244d") //cvResize #else #pragma comment(lib, "opencv_core244d") #pragma comment(lib, "opencv_highgui244d") #pragma comment(lib, "opencv_imgproc244d") //cvResize #endif #define cvQueryHistValue_1D(hist,idx0) ((float)cvGetReal1D( (hist)->bins, (idx0))) using namespace std; #pragma comment(linker, "/subsystem:"windows" /entry:"mainCRTStartup"") void FillWhite(IplImage *pImage) { cvRectangle(pImage, cvPoint(0, 0), cvPoint(pImage->width, pImage->height), CV_RGB(255, 255, 255), CV_FILLED); } // 创建灰度图像的直方图 CvHistogram* CreateGrayImageHist(IplImage **ppImage) { int nHistSize = 256; float fRange[] = {0, 255}; //灰度级的范围 float *pfRanges[] = {fRange}; CvHistogram *pcvHistogram = cvCreateHist(1, &nHistSize, CV_HIST_ARRAY, pfRanges); cvCalcHist(ppImage, pcvHistogram); return pcvHistogram; } // 根据直方图创建直方图图像 IplImage* CreateHisogramImage(int nImageWidth, int nScale, int nImageHeight, CvHistogram *pcvHistogram) { IplImage *pHistImage = cvCreateImage(cvSize(nImageWidth * nScale, nImageHeight), IPL_DEPTH_8U, 1); FillWhite(pHistImage); //统计直方图中的最大直方块 float fMaxHistValue = 0; cvGetMinMaxHistValue(pcvHistogram, NULL, &fMaxHistValue, NULL, NULL); //分别将每个直方块的值绘制到图中 int i; for(i = 0; i < nImageWidth; i++) { float fHistValue = cvQueryHistValue_1D(pcvHistogram, i); //像素为i的直方块大小 int nRealHeight = cvRound((fHistValue / fMaxHistValue) * nImageHeight); //要绘制的高度 cvRectangle(pHistImage, cvPoint(i * nScale, nImageHeight - 1), cvPoint((i + 1) * nScale - 1, nImageHeight - nRealHeight), cvScalar(i, 0, 0, 0), CV_FILLED ); } return pHistImage; } int main( int argc, char** argv ) { const char *pstrWindowsSrcTitle = "原图"; const char *pstrWindowsGrayTitle = "灰度图"; const char *pstrWindowsHistTitle = "直方图"; const char *pstrWindowsGrayEqualizeTitle = "灰度图-均衡化后"; const char *pstrWindowsHistEqualizeTitle = "直方图-均衡化后"; // 从文件中加载原图 // IplImage *pSrcImage = cvLoadImage("./images/yangmi.jpg", CV_LOAD_IMAGE_UNCHANGED); IplImage *pSrcImage = cvLoadImage("./images/beauty.png", CV_LOAD_IMAGE_UNCHANGED); IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); IplImage *pGrayEqualizeImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); // 灰度图 cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); // 直方图图像数据 int nHistImageWidth = 255; int nHistImageHeight = 150; int nScale = 2; // 灰度直方图及直方图图像 CvHistogram *pcvHistogram = CreateGrayImageHist(&pGrayImage); IplImage *pHistImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogram); // 均衡化 //函数功能:直方图均衡化,该函数能归一化图像亮度和增强对比度 //第一个参数表示输入图像,必须为灰度图(8位,单通道图) //第二个参数表示输出图像 //该函数采用如下法则对输入图像进行直方图均衡化: //1:计算输入图像的直方图H。 //2:直方图归一化,因此直方块和为255。 //3:计算直方图积分,H'(i) = Sum(H(j)) (0<=j<=i)。 //4:采用H'作为查询表:dst(x, y) = H'(src(x, y))进行图像变换。 cvEqualizeHist(pGrayImage, pGrayEqualizeImage); // 均衡化后的灰度直方图及直方图图像 CvHistogram *pcvHistogramEqualize = CreateGrayImageHist(&pGrayEqualizeImage); IplImage *pHistEqualizeImage = CreateHisogramImage(nHistImageWidth, nScale, nHistImageHeight, pcvHistogramEqualize); // 显示 cvNamedWindow(pstrWindowsSrcTitle); cvNamedWindow(pstrWindowsGrayTitle); cvNamedWindow(pstrWindowsGrayEqualizeTitle); cvNamedWindow(pstrWindowsHistTitle); cvNamedWindow(pstrWindowsHistEqualizeTitle); cvShowImage(pstrWindowsSrcTitle,pSrcImage); cvShowImage(pstrWindowsGrayTitle,pGrayImage); cvShowImage(pstrWindowsGrayEqualizeTitle,pGrayEqualizeImage); cvShowImage(pstrWindowsHistTitle,pHistImage); cvShowImage(pstrWindowsHistEqualizeTitle,pHistEqualizeImage); cvWaitKey(0); //回收资源代码… cvDestroyWindow(pstrWindowsSrcTitle); cvDestroyWindow(pstrWindowsGrayTitle); cvDestroyWindow(pstrWindowsGrayEqualizeTitle); cvDestroyWindow(pstrWindowsHistTitle); cvDestroyWindow(pstrWindowsHistEqualizeTitle); cvReleaseImage(&pSrcImage); cvReleaseImage(&pGrayImage); cvReleaseImage(&pGrayEqualizeImage); cvReleaseImage(&pHistImage); cvReleaseImage(&pHistEqualizeImage); return 0; }

直方图规定化

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void hist_specify(const Mat &src, const Mat &dst,Mat &result) { Histogram1D hist1D; MatND src_hist = hist1D.getHistogram(src); MatND dst_hist = hist1D.getHistogram(dst); float src_cdf[256] = { 0 }; float dst_cdf[256] = { 0 }; // 源图像和目标图像的大小不一样,要将得到的直方图进行归一化处理 src_hist /= (src.rows * src.cols); dst_hist /= (dst.rows * dst.cols); // 计算原始直方图和规定直方图的累积概率 for (int i = 0; i < 256; i++) { if (i == 0) { src_cdf[i] = src_hist.at<float>(i); dst_cdf[i] = dst_hist.at<float>(i); } else { src_cdf[i] = src_cdf[i - 1] + src_hist.at<float>(i); dst_cdf[i] = dst_cdf[i - 1] + dst_hist.at<float>(i); } } // 累积概率的差值 float diff_cdf[256][256]; for (int i = 0; i < 256; i++) for (int j = 0; j < 256; j++) diff_cdf[i][j] = fabs(src_cdf[i] - dst_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 = 1; j < 256; j++) { if (min > diff_cdf[i][j]) { min = diff_cdf[i][j]; index = j; } } lut.at<uchar>(i) = static_cast<uchar>(index); } // 应用查找表,做直方图规定化 LUT(src, lut, result); }

最后

以上就是老实荔枝最近收集整理的关于图像处理之直方图均衡化的全部内容,更多相关图像处理之直方图均衡化内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(140)

评论列表共有 0 条评论

立即
投稿
返回
顶部