這是數字圖像處理課的大作業,完成于 2013/06/17,需要調用 openCV 庫,完整源碼和報告如下:
?
1
#include <cv.h>
2
#include <highgui.h>
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <math.h>
6
#include <assert.h>
7
#include <
string
>
8
9
/*
灰度級結點
*/
10
typedef
struct
{
11
int
pixels;
//
灰度級對應像素個數
12
float
rate;
//
像素比例
13
float
accuRate;
//
累計像素比例
14
int
map;
//
到均衡化后的灰度級的映射
15
} levNode;
16
17
void
histeqGray(IplImage* pGray,
int
levels,
int
argc);
18
IplImage* histImage(IplImage* pSrc,
int
histWidth,
int
histHeight,
int
nScale);
19
20
int
main(
int
argc,
char
*
argv[])
21
{
22
int
levels;
23
std::
string
imgName, inTmp;
24
if
(argc ==
3
) {
25
levels = atoi(argv[
1
]);
26
imgName = argv[
2
];
27
}
28
else
if
(argc ==
2
)
29
imgName = argv[
1
];
30
else
{
31
printf(
"
usage: histeq [levels] image_name \n
"
);
32
return
-
1
;
33
}
34
35
IplImage* pSrc =
cvLoadImage(imgName.c_str(), CV_LOAD_IMAGE_UNCHANGED);
36
int
channel = pSrc->
nChannels;
37
38
IplImage* pChnl[
4
] =
{ NULL };
39
40
for
(
int
i =
0
; i < channel; ++
i)
41
pChnl[i] = cvCreateImage(cvGetSize(pSrc), pSrc->depth,
1
);
42
43
cvSplit(pSrc, pChnl[
0
], pChnl[
1
], pChnl[
2
], pChnl[
3
]);
44
45
for
(
int
i =
0
; i < channel; ++
i)
46
histeqGray(pChnl[i], levels, argc);
47
48
IplImage* pEql = cvCreateImage(cvGetSize(pSrc), pChnl[
0
]->depth, pSrc->
nChannels);
49
50
cvMerge(pChnl[
0
], pChnl[
1
], pChnl[
2
], pChnl[
3
], pEql);
51
52
inTmp = imgName +
"
_Eql.jpg
"
;
53
cvSaveImage(inTmp.c_str(), pEql);
54
55
//
cvNamedWindow(imgName.c_str(), CV_WINDOW_AUTOSIZE);
56
cvShowImage(imgName.c_str(), pSrc);
57
//
cvNamedWindow(inTmp.c_str(), CV_WINDOW_AUTOSIZE);
58
cvShowImage(inTmp.c_str(), pEql);
59
60
IplImage* pSrcGray = cvCreateImage(cvGetSize(pSrc), IPL_DEPTH_8U,
1
);
61
if
(pSrc->nChannels ==
3
)
62
cvCvtColor(pSrc, pSrcGray, CV_BGR2GRAY);
63
else
64
cvCopyImage(pSrc, pSrcGray);
65
IplImage* pEqlGray = cvCreateImage(cvGetSize(pEql), IPL_DEPTH_8U,
1
);
66
if
(pSrc->nChannels ==
3
)
67
cvCvtColor(pEql, pEqlGray, CV_BGR2GRAY);
68
else
69
cvCopyImage(pEql, pEqlGray);
70
imgName +=
"
_Hist.jpg
"
;
71
inTmp +=
"
_Hist.jpg
"
;
72
int
nScale =
2
;
73
int
histWidth =
/*
pSrc->width * nScale
*/
256
*
nScale;
74
int
histHeight =
/*
pSrc->height
*/
128
;
75
IplImage* pSrcGrayHist =
histImage(pSrcGray, histWidth, histHeight, nScale);
76
IplImage* pEqlGrayHist =
histImage(pEqlGray, histWidth, histHeight, nScale);
77
cvSaveImage(imgName.c_str(), pSrcGrayHist);
78
cvSaveImage(inTmp.c_str(), pEqlGrayHist);
79
cvShowImage(imgName.c_str(), pSrcGrayHist);
80
cvShowImage(inTmp.c_str(), pEqlGrayHist);
81
82
cvWaitKey();
83
84
cvReleaseImage(&
pEql);
85
cvReleaseImage(&
pEqlGray);
86
for
(
int
i =
0
; i < channel; ++
i)
87
cvReleaseImage(&
pChnl[i]);
88
cvReleaseImage(&
pSrc);
89
cvReleaseImage(&
pSrcGray);
90
91
return
0
;
92
}
93
94
/*
95
* 直方圖均衡化函數
96
* pGray為輸入的灰度圖
97
* levels為均衡化的灰度級
98
*/
99
void
histeqGray(IplImage* pGray,
int
levels,
int
argc)
100
{
101
int
depth = pGray->
depth;
102
printf(
"
%d \n
"
, depth);
103
int
width = pGray->
width;
104
int
height = pGray->
height;
105
int
sumPixels = width * height;
//
總像素數
106
printf(
"
%d \n
"
, sumPixels);
107
int
values = static_cast<
int
>(pow((
float
)
2
, depth));
//
根據圖像深度計算像素取值范圍
108
if
(argc ==
2
) levels =
values;
109
printf(
"
%d \n
"
, levels);
110
111
int
outDepth;
112
/*
if (levels <= 2)
113
outDepth = 1;
114
else
*/
if
(levels <=
256
)
115
outDepth =
8
;
116
else
if
(levels <=
65536
)
117
outDepth =
16
;
118
119
assert(levels <=
values);
120
int
intervals = values / levels;
//
根據像素取值范圍和灰度級求每個灰度級的像素間隔
121
levNode* levNodes = (levNode*)calloc(levels,
sizeof
(levNode));
//
生成灰度結點
122
//
for (int lev = 0; lev < levels; ++lev) printf("%d \n", levNodes[lev].pixels);
123
//
char* pValues = pGray->imageData;
124
125
/*
統計每個灰度級的像素個數
*/
126
for
(
int
y =
0
; y < height; ++
y)
127
for
(
int
x =
0
; x < width; ++
x) {
128
CvScalar scal =
cvGet2D(pGray, y, x);
129
int
val = (
int
)scal.val[
0
];
130
//
printf("%d \n", val);
131
for
(
int
lev =
0
; lev < levels; ++
lev) {
132
if
( val >= intervals*lev && val < intervals*(lev+
1
)) {
133
++levNodes[lev].pixels;
break
;
134
}
135
}
136
}
137
138
int
sum =
0
;
139
for
(
int
lev =
0
; lev < levels; ++
lev)
140
sum +=
levNodes[lev].pixels;
141
printf(
"
%d \n
"
, sum);
142
143
/*
計算每個灰度級像素比例和累計比例
*/
144
levNodes[
0
].accuRate = levNodes[
0
].rate = levNodes[
0
].pixels / (
float
)sumPixels;
145
levNodes[
0
].map = (
int
)(levNodes[
0
].accuRate * (levels -
1
) +
0.5
);
146
printf(
"
%d \n
"
, levNodes[
0
].pixels);
147
for
(
int
lev =
1
; lev < levels; ++
lev) {
148
levNodes[lev].rate = levNodes[lev].pixels / (
float
)sumPixels;
149
levNodes[lev].accuRate = levNodes[lev-
1
].accuRate +
levNodes[lev].rate;
150
levNodes[lev].map = (
int
)(levNodes[lev].accuRate * (levels -
1
) +
0.5
);
151
}
152
printf(
"
%f \n
"
, levNodes[levels-
1
].accuRate);
153
154
/*
生成均衡化后的圖像
*/
155
for
(
int
y =
0
; y < height; ++
y)
156
for
(
int
x =
0
; x < width; ++
x) {
157
CvScalar scal =
cvGet2D(pGray, y, x);
158
int
val = (
int
)scal.val[
0
];
159
//
printf("%d \n", val);
160
for
(
int
lev =
0
; lev < levels; ++
lev) {
161
if
(val >= intervals*lev && val < intervals*(lev+
1
)) {
162
scal.val[
0
] =
levNodes[lev].map;
163
//
printf("%f \n", scal.val[0]);
164
cvSet2D(pGray, y, x, scal);
165
break
;
166
}
167
}
168
}
169
pGray->depth =
outDepth;
170
171
free(levNodes);
172
}
173
174
/*
175
* 繪制直方圖函數
176
*/
177
IplImage* histImage(IplImage* pSrc,
int
histWidth,
int
histHeight,
int
nScale)
178
{
179
int
histSize = static_cast<
int
>(pow((
float
)
2
, pSrc->
depth));
180
CvHistogram* pHist = cvCreateHist(
/*
pSrc->nChannels
*/
1
, &
histSize, CV_HIST_ARRAY);
181
cvCalcHist(&
pSrc, pHist);
182
183
IplImage* pHistImg = cvCreateImage(cvSize(histWidth, histHeight), IPL_DEPTH_8U,
1
);
184
cvRectangle(pHistImg, cvPoint(
0
,
0
), cvPoint(pHistImg->width,pHistImg->height), CV_RGB(
255
,
255
,
255
), CV_FILLED);
185
186
float
histMaxVal =
0
;
187
cvGetMinMaxHistValue(pHist,
0
, &
histMaxVal);
188
189
for
(
int
i =
0
; i < histSize; i++
)
190
{
191
float
histValue= cvQueryHistValue_1D(pHist, i);
//
像素為i的直方塊大小
192
int
nRealHeight = cvRound((histValue / histMaxVal) * histHeight);
//
要繪制的高度
193
cvRectangle(pHistImg,
194
cvPoint(i*nScale, histHeight -
1
),
195
cvPoint((i +
1
)*nScale -
1
, histHeight -
nRealHeight),
196
cvScalar(i),
197
CV_FILLED
198
);
199
}
200
//
cvFillConvexPoly
201
202
cvReleaseHist(&
pHist);
203
return
pHistImg;
204
}
?
一、直方圖均衡化概述
直方圖均衡化是一種圖像增強方法,其基本思想是把給定圖像的直方圖分布改造成均勻分布的直方圖,從而增加象素灰度值的動態范圍,達到增強圖像整體對比度的效果。由信息學的理論來解釋,具有最大熵(信息量)的圖像為均衡化圖像。
直方圖均衡化可表示為:
,t為某個象素變換后的灰度級,s為該象素變換前的灰度級。
該灰度變換函數應滿足如下兩個條件:
條件1:保證原圖各灰度級在變換后仍保持從黑到白(或從白到黑)的排列順序;
條件2:保證變換前后灰度值動態范圍的一致性。
可以證明累積分布函數(cumulative distribution function CDF)滿足上述兩個條件并能將s的分布轉換為t的均勻分布。
事實上,s的CDF就是原始圖的累積直方圖,即:
根據這個公式,可以直接算出直方圖均衡化后各象素的灰度值。
需要取整,以滿足數字圖象的要求。
?
二、算法步驟
|
步驟 |
運算 |
|
1 |
|
|
2 |
|
|
3 |
計算原始直方圖(像素比例) |
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
計算新的直方圖 |
三、算法測試
1、灰度圖
2、彩色圖
?
四、結果分析
(1)對于灰度圖和彩色圖,算法結果都不錯,直方圖顯示像素分布很廣、很平均。
(2)直方圖均衡化的優點:自動增強整個圖像的對比度。
(3)直方圖均衡化的不足:具體增強效果不易控制,處理的結果總是得到全局均衡化的直方圖。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

