1 Mat ImageAHE(Mat img, int block)
2 {
3 Mat AHE_GO = img.clone();
4
5 int width = img.cols;
6 int height = img.rows;
7 int width_block = width / block; //每个小格子的长和宽
8 int height_block = height / block;
9 //存储各个直方图
10
11
12 int tmp2[16 * 16][256] = { 0 };//10要和block保持一致
13 float C2[16 * 16][256] = { 0.0 };
14 //分块
15 int total = width_block * height_block;//分割的总的块儿数
16 for (int i = 0; i < block; i++)
17 {
18 for (int j = 0; j < block; j++)
19 {
20 int start_x = i * width_block;
21 int end_x = start_x + width_block;
22 int start_y = j * height_block;
23 int end_y = start_y + height_block;
24
25 int num = i + block * j;
26 //遍历小块,计算直方图
27 for (int ii = start_x; ii < end_x; ii++)
28 {
29 for (int jj = start_y; jj < end_y; jj++)
30 {
31 int index = img.at<uchar>(jj, ii);
32 tmp2[num][index]++;
33 }
34 }
35 //计算累积分布直方图
36 for (int k = 0; k < 256; k++)
37 {
38 if (k == 0)
39 C2[num][k] = 1.0f * tmp2[num][k] / total;
40 else
41 C2[num][k] = C2[num][k - 1] + 1.0f * tmp2[num][k] / total;
42 }
43 }
44 }
45 //将统计结果写入
46 for (int i = 0; i < block; i++)
47 {
48 for (int j = 0; j < block; j++)
49 {
50 int start_x = i * width_block;
51 int end_x = start_x + width_block;
52 int start_y = j * height_block;
53 int end_y = start_y + height_block;
54 int num = i + block * j;
55 //遍历小块,计算直方图
56 for (int ii = start_x; ii < end_x; ii++)
57 {
58 for (int jj = start_y; jj < end_y; jj++)
59 {
60 int index = img.at<uchar>(jj, ii);
61 //结果直接写入AHE_GO中去
62 AHE_GO.at<uchar>(jj, ii) = C2[num][index] * 255;
63 }
64 }
65 }
66 }
67 return AHE_GO;
68 }
69
70 Mat ImageEqaualize(Mat img)
71 {
72 int width = img.cols;
73 int height = img.rows;
74 Mat HT_GO = img.clone();
75 int tmp[256] = { 0 };
76 float C[256] = { 0.0 };
77 int total = width * height;
78 for (int i = 0; i < img.rows; i++)
79 {
80 for (int j = 0; j < img.cols; j++)
81 {
82 int index = img.at<uchar>(i, j);
83 tmp[index] ++;
84 }
85 }
86 //计算累积函数
87 for (int i = 0; i < 256; i++) {
88 if (i == 0)
89 C[i] = 1.0f * tmp[i] / total;
90 else
91 C[i] = C[i - 1] + 1.0f * tmp[i] / total;
92 }
93 //这里的累积函数分配的方法非常直观高效
94 for (int i = 0; i < img.rows; i++) {
95 for (int j = 0; j < img.cols; j++) {
96 int index = img.at<uchar>(i, j);
97 HT_GO.at<uchar>(i, j) = C[index] * 255;
98 }
99 }
100 return HT_GO;
101 }
102
103 Mat ImageClHe(Mat img, int block)
104 {
105 int width = img.cols/ block;
106 int height = img.rows/ block;
107 Mat CLHE_GO = img.clone();
108 int tmp[256] = { 0 };
109 float C[256] = { 0.0 };
110 int total = width * height;
111 for (int i = 0; i < img.rows; i++)
112 {
113 for (int j = 0; j < img.cols; j++)
114 {
115 int index = img.at<uchar>(i, j);
116 tmp[index] ++;
117 }
118 }
119 /////////////////////////限制对比度计算部分,注意这个地方average的计算不一定科学
120 int average = width * height / 255 /64;
121 int LIMIT = 4 * average;
122 int steal = 0;
123 for (int k = 0; k < 256; k++)
124 {
125 if (tmp[k] > LIMIT) {
126 steal += tmp[k] - LIMIT;
127 tmp[k] = LIMIT;
128 }
129 }
130 int bonus = steal / 256;
131 //hand out the steals averagely
132 for (int k = 0; k < 256; k++)
133 {
134 tmp[k] += bonus;
135 }
136 ///////////////////////////////////////////
137 //计算累积函数
138 for (int i = 0; i < 256; i++) {
139 if (i == 0)
140 C[i] = 1.0f * tmp[i] / total;
141 else
142 C[i] = C[i - 1] + 1.0f * tmp[i] / total;
143 }
144 //这里的累积函数分配的方法非常直观高效
145 for (int i = 0; i < img.rows; i++) {
146 for (int j = 0; j < img.cols; j++) {
147 int index = img.at<uchar>(i, j);
148 CLHE_GO.at<uchar>(i, j) = C[index] * 255;
149 }
150 }
151 return CLHE_GO;
152 }
153
154 Mat ImageClHeNoInter(Mat img, int block)
155 {
156 Mat CLAHE_GO = img.clone();
157
158 int width = img.cols;
159 int height = img.rows;
160 int width_block = width / block; //每个小格子的长和宽
161 int height_block = height / block;
162 //存储各个直方图
163 int tmp2[8 * 8][256] = { 0 };
164 float C2[8 * 8][256] = { 0.0 };
165 //分块
166 int total = width_block * height_block;
167 for (int i = 0; i < block; i++)
168 {
169 for (int j = 0; j < block; j++)
170 {
171 int start_x = i * width_block;
172 int end_x = start_x + width_block;
173 int start_y = j * height_block;
174 int end_y = start_y + height_block;
175 int num = i + block * j;
176 //遍历小块,计算直方图
177 for (int ii = start_x; ii < end_x; ii++)
178 {
179 for (int jj = start_y; jj < end_y; jj++)
180 {
181 int index = img.at<uchar>(jj, ii);
182 tmp2[num][index]++;
183 }
184 }
185 //裁剪和增加操作,也就是clahe中的cl部分
186 //这里的参数 对应《Gem》上面 fCliplimit = 4 , uiNrBins = 255
187 int average = width_block * height_block / 255;
188 int LIMIT = 4 * average;
189 int steal = 0;
190 for (int k = 0; k < 256; k++)
191 {
192 if (tmp2[num][k] > LIMIT) {
193 steal += tmp2[num][k] - LIMIT;
194 tmp2[num][k] = LIMIT;
195 }
196 }
197 int bonus = steal / 256;
198 //hand out the steals averagely
199 for (int k = 0; k < 256; k++)
200 {
201 tmp2[num][k] += bonus;
202 }
203 //计算累积分布直方图
204 for (int k = 0; k < 256; k++)
205 {
206 if (k == 0)
207 C2[num][k] = 1.0f * tmp2[num][k] / total;
208 else
209 C2[num][k] = C2[num][k - 1] + 1.0f * tmp2[num][k] / total;
210 }
211 }
212 }
213 //计算变换后的像素值
214 //将统计结果写入
215 for (int i = 0; i < block; i++)
216 {
217 for (int j = 0; j < block; j++)
218 {
219 int start_x = i * width_block;
220 int end_x = start_x + width_block;
221 int start_y = j * height_block;
222 int end_y = start_y + height_block;
223 int num = i + block * j;
224 //遍历小块,计算直方图
225 for (int ii = start_x; ii < end_x; ii++)
226 {
227 for (int jj = start_y; jj < end_y; jj++)
228 {
229 int index = img.at<uchar>(jj, ii);
230 //结果直接写入AHE_GO中去
231 CLAHE_GO.at<uchar>(jj, ii) = C2[num][index] * 255;
232 }
233 }
234 }
235
236 }
237 return CLAHE_GO;
238 }
239
240 Mat ImageClahe(Mat img, int block)
241 {
242 Mat CLAHE_GO = img.clone();
243 //int block = _step;//pblock
244 int width = img.cols;
245 int height = img.rows;
246 int width_block = width / block; //每个小格子的长和宽
247 int height_block = height / block;
248 //存储各个直方图
249 int tmp2[8 * 8][256] = { 0 };
250 float C2[8 * 8][256] = { 0.0 };
251 //分块
252 int total = width_block * height_block;
253 for (int i = 0; i < block; i++)
254 {
255 for (int j = 0; j < block; j++)
256 {
257 int start_x = i * width_block;
258 int end_x = start_x + width_block;
259 int start_y = j * height_block;
260 int end_y = start_y + height_block;
261 int num = i + block * j;
262 //遍历小块,计算直方图
263 for (int ii = start_x; ii < end_x; ii++)
264 {
265 for (int jj = start_y; jj < end_y; jj++)
266 {
267 int index = img.at<uchar>(jj, ii);
268 tmp2[num][index]++;
269 }
270 }
271 //裁剪和增加操作,也就是clahe中的cl部分
272 //这里的参数 对应《Gem》上面 fCliplimit = 4 , uiNrBins = 255
273 int average = width_block * height_block / 255;
274 //关于参数如何选择,需要进行讨论。不同的结果进行讨论
275 //关于全局的时候,这里的这个cl如何算,需要进行讨论
276 int LIMIT = 40 * average;
277 int steal = 0;
278 for (int k = 0; k < 256; k++)
279 {
280 if (tmp2[num][k] > LIMIT) {
281 steal += tmp2[num][k] - LIMIT;
282 tmp2[num][k] = LIMIT;
283 }
284 }
285 int bonus = steal / 256;
286 //hand out the steals averagely
287 for (int k = 0; k < 256; k++)
288 {
289 tmp2[num][k] += bonus;
290 }
291 //计算累积分布直方图
292 for (int k = 0; k < 256; k++)
293 {
294 if (k == 0)
295 C2[num][k] = 1.0f * tmp2[num][k] / total;
296 else
297 C2[num][k] = C2[num][k - 1] + 1.0f * tmp2[num][k] / total;
298 }
299 }
300 }
301 //计算变换后的像素值
302 //根据像素点的位置,选择不同的计算方法
303 for (int i = 0; i < width; i++)
304 {
305 for (int j = 0; j < height; j++)
306 {
307 //four coners
308 if (i <= width_block / 2 && j <= height_block / 2)
309 {
310 int num = 0;
311 CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
312 }
313 else if (i <= width_block / 2 && j >= ((block - 1)*height_block + height_block / 2)) {
314 int num = block * (block - 1);
315 CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
316 }
317 else if (i >= ((block - 1)*width_block + width_block / 2) && j <= height_block / 2) {
318 int num = block - 1;
319 CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
320 }
321 else if (i >= ((block - 1)*width_block + width_block / 2) && j >= ((block - 1)*height_block + height_block / 2)) {
322 int num = block * block - 1;
323 CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
324 }
325 //four edges except coners
326 else if (i <= width_block / 2)
327 {
328 //线性插值
329 int num_i = 0;
330 int num_j = (j - height_block / 2) / height_block;
331 int num1 = num_j * block + num_i;
332 int num2 = num1 + block;
333 float p = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
334 float q = 1 - p;
335 CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
336 }
337 else if (i >= ((block - 1)*width_block + width_block / 2)) {
338 //线性插值
339 int num_i = block - 1;
340 int num_j = (j - height_block / 2) / height_block;
341 int num1 = num_j * block + num_i;
342 int num2 = num1 + block;
343 float p = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
344 float q = 1 - p;
345 CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
346 }
347 else if (j <= height_block / 2) {
348 //线性插值
349 int num_i = (i - width_block / 2) / width_block;
350 int num_j = 0;
351 int num1 = num_j * block + num_i;
352 int num2 = num1 + 1;
353 float p = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
354 float q = 1 - p;
355 CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
356 }
357 else if (j >= ((block - 1)*height_block + height_block / 2)) {
358 //线性插值
359 int num_i = (i - width_block / 2) / width_block;
360 int num_j = block - 1;
361 int num1 = num_j * block + num_i;
362 int num2 = num1 + 1;
363 float p = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
364 float q = 1 - p;
365 CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
366 }
367 //双线性插值
368 else {
369 int num_i = (i - width_block / 2) / width_block;
370 int num_j = (j - height_block / 2) / height_block;
371 int num1 = num_j * block + num_i;
372 int num2 = num1 + 1;
373 int num3 = num1 + block;
374 int num4 = num2 + block;
375 float u = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
376 float v = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
377 CLAHE_GO.at<uchar>(j, i) = (int)((u*v*C2[num4][CLAHE_GO.at<uchar>(j, i)] +
378 (1 - v)*(1 - u)*C2[num1][CLAHE_GO.at<uchar>(j, i)] +
379 u * (1 - v)*C2[num2][CLAHE_GO.at<uchar>(j, i)] +
380 v * (1 - u)*C2[num3][CLAHE_GO.at<uchar>(j, i)]) * 255);
381 }
382 //最后这步,类似高斯平滑
383 CLAHE_GO.at<uchar>(j, i) = CLAHE_GO.at<uchar>(j, i) + (CLAHE_GO.at<uchar>(j, i) << 8) + (CLAHE_GO.at<uchar>(j, i) << 16);
384 }
385 }
386 return CLAHE_GO;
387 }