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 }