84 #include <visp3/core/vpImageConvert.h> 85 #include <visp3/imgproc/vpImgproc.h> 89 int fastRound(
const float value) {
return (
int)(value + 0.5f); }
91 void clipHistogram(
const std::vector<int> &hist, std::vector<int> &clippedHist,
const int limit)
94 int clippedEntries = 0, clippedEntriesBefore = 0;
95 int histlength = (int)hist.size();
98 clippedEntriesBefore = clippedEntries;
100 for (
int i = 0; i < histlength; i++) {
101 int d = clippedHist[i] - limit;
104 clippedHist[i] = limit;
108 int d = clippedEntries / (histlength);
109 int m = clippedEntries % (histlength);
110 for (
int i = 0; i < histlength; i++) {
115 int s = (histlength - 1) / m;
116 for (
int i = s / 2; i < histlength; i += s) {
120 }
while (clippedEntries != clippedEntriesBefore);
123 void createHistogram(
const int blockRadius,
const int bins,
const int blockXCenter,
const int blockYCenter,
126 std::fill(hist.begin(), hist.end(), 0);
128 int xMin = std::max(0, blockXCenter - blockRadius);
129 int yMin = std::max(0, blockYCenter - blockRadius);
130 int xMax = std::min((
int)I.
getWidth(), blockXCenter + blockRadius + 1);
131 int yMax = std::min((
int)I.
getHeight(), blockYCenter + blockRadius + 1);
133 for (
int y = yMin; y < yMax; ++y) {
134 for (
int x = xMin; x < xMax; ++x) {
135 ++hist[fastRound(I[y][x] / 255.0f * bins)];
140 std::vector<float> createTransfer(
const std::vector<int> &hist,
const int limit, std::vector<int> &cdfs)
142 clipHistogram(hist, cdfs, limit);
143 int hMin = (int)hist.size() - 1;
145 for (
int i = 0; i < hMin; ++i) {
151 for (
int i = hMin; i < (int)hist.size(); ++i) {
156 int cdfMin = cdfs[hMin];
157 int cdfMax = cdfs[hist.size() - 1];
159 std::vector<float> transfer(hist.size());
160 for (
int i = 0; i < (int)transfer.size(); ++i) {
161 transfer[i] = (cdfs[i] - cdfMin) / (
float)(cdfMax - cdfMin);
167 float transferValue(
const int v, std::vector<int> &clippedHist)
169 int clippedHistLength = (int)clippedHist.size();
170 int hMin = clippedHistLength - 1;
171 for (
int i = 0; i < hMin; i++) {
172 if (clippedHist[i] != 0) {
178 for (
int i = hMin; i <= v; i++) {
179 cdf += clippedHist[i];
183 for (
int i = v + 1; i < clippedHistLength; ++i) {
184 cdfMax += clippedHist[i];
187 int cdfMin = clippedHist[hMin];
188 return (cdf - cdfMin) / (float)(cdfMax - cdfMin);
191 float transferValue(
const int v,
const std::vector<int> &hist, std::vector<int> &clippedHist,
const int limit)
193 clipHistogram(hist, clippedHist, limit);
195 return transferValue(v, clippedHist);
225 const float slope,
const bool fast)
227 if (blockRadius < 0) {
228 std::cerr <<
"Error: blockRadius < 0!" << std::endl;
232 if (bins < 0 || bins > 256) {
233 std::cerr <<
"Error: (bins < 0 || bins > 256)!" << std::endl;
237 if ((
unsigned int)(2 * blockRadius + 1) > I1.
getWidth() || (
unsigned int)(2 * blockRadius + 1) > I1.
getHeight()) {
238 std::cerr <<
"Error: (unsigned int) (2*blockRadius+1) > I1.getWidth() || " 239 "(unsigned int) (2*blockRadius+1) > I1.getHeight()!" 247 int blockSize = 2 * blockRadius + 1;
248 int limit = (int)(slope * blockSize * blockSize / bins + 0.5);
255 int cm = I1.
getWidth() - nc * blockSize;
261 for (
int i = 0; i < nc; ++i) {
262 cs[i] = i * blockSize + blockRadius + 1;
268 for (
int i = 0; i < nc; ++i) {
269 cs[i] = i * blockSize + blockRadius + 1;
271 cs[nc] = I1.
getWidth() - blockRadius - 1;
276 cs[0] = blockRadius + 1;
277 for (
int i = 0; i < nc; ++i) {
278 cs[i + 1] = i * blockSize + blockRadius + 1 + cm / 2;
280 cs[nc + 1] = I1.
getWidth() - blockRadius - 1;
283 int rm = I1.
getHeight() - nr * blockSize;
288 rs.resize((
size_t)nr);
289 for (
int i = 0; i < nr; ++i) {
290 rs[i] = i * blockSize + blockRadius + 1;
295 rs.resize((
size_t)(nr + 1));
296 for (
int i = 0; i < nr; ++i) {
297 rs[i] = i * blockSize + blockRadius + 1;
299 rs[nr] = I1.
getHeight() - blockRadius - 1;
303 rs.resize((
size_t)(nr + 2));
304 rs[0] = blockRadius + 1;
305 for (
int i = 0; i < nr; ++i) {
306 rs[i + 1] = i * blockSize + blockRadius + 1 + rm / 2;
308 rs[nr + 1] = I1.
getHeight() - blockRadius - 1;
311 std::vector<int> hist((
size_t)(bins + 1));
312 std::vector<int> cdfs((
size_t)(bins + 1));
313 std::vector<float> tl;
314 std::vector<float> tr;
315 std::vector<float> br;
316 std::vector<float> bl;
318 for (
int r = 0; r <= (int)rs.size(); ++r) {
319 int r0 = std::max(0, r - 1);
320 int r1 = std::min((
int)rs.size() - 1, r);
321 int dr = rs[r1] - rs[r0];
323 createHistogram(blockRadius, bins, cs[0], rs[r0], I1, hist);
324 tr = createTransfer(hist, limit, cdfs);
328 createHistogram(blockRadius, bins, cs[0], rs[r1], I1, hist);
329 br = createTransfer(hist, limit, cdfs);
332 int yMin = (r == 0 ? 0 : rs[r0]);
333 int yMax = (r < (int)rs.size() ? rs[r1] : I1.
getHeight());
335 for (
int c = 0; c <= (int)cs.size(); ++c) {
336 int c0 = std::max(0, c - 1);
337 int c1 = std::min((
int)cs.size() - 1, c);
338 int dc = cs[c1] - cs[c0];
344 createHistogram(blockRadius, bins, cs[c1], rs[r0], I1, hist);
345 tr = createTransfer(hist, limit, cdfs);
349 createHistogram(blockRadius, bins, cs[c1], rs[r1], I1, hist);
350 br = createTransfer(hist, limit, cdfs);
354 int xMin = (c == 0 ? 0 : cs[c0]);
355 int xMax = (c < (int)cs.size() ? cs[c1] : I1.
getWidth());
356 for (
int y = yMin; y < yMax; ++y) {
357 float wy = (float)(rs[r1] - y) / dr;
359 for (
int x = xMin; x < xMax; ++x) {
360 float wx = (float)(cs[c1] - x) / dc;
361 int v = fastRound(I1[y][x] / 255.0f * bins);
366 float t0 = 0.0f, t1 = 0.0f;
372 t0 = wx * t00 + (1.0f - wx) * t01;
373 t1 = wx * t10 + (1.0f - wx) * t11;
376 float t = (r0 == r1) ? t0 : wy * t0 + (1.0f - wy) * t1;
377 I2[y][x] = std::max(0, std::min(255, fastRound(t * 255.0f)));
383 std::vector<int> hist(bins + 1), prev_hist(bins + 1);
384 std::vector<int> clippedHist(bins + 1);
388 int xMax0 = std::min((
int)I1.
getWidth(), blockRadius);
390 for (
int y = 0; y < (int)I1.
getHeight(); y++) {
391 int yMin = std::max(0, y - (
int)blockRadius);
392 int yMax = std::min((
int)I1.
getHeight(), y + blockRadius + 1);
396 std::fill(hist.begin(), hist.end(), 0);
398 for (
int yi = yMin; yi < yMax; yi++) {
399 for (
int xi = xMin0; xi < xMax0; xi++) {
400 ++hist[fastRound(I1[yi][xi] / 255.0f * bins)];
407 for (
int yi = yMin; yi < yMax; yi++) {
408 for (
int xi = xMin0; xi < xMax0; xi++) {
409 ++hist[fastRound(I1[yi][xi] / 255.0f * bins)];
416 int yMin1 = yMin - 1;
418 for (
int xi = xMin0; xi < xMax0; xi++) {
419 --hist[fastRound(I1[yMin1][xi] / 255.0f * bins)];
423 if (y + blockRadius < (
int)I1.
getHeight()) {
424 int yMax1 = yMax - 1;
426 for (
int xi = xMin0; xi < xMax0; xi++) {
427 ++hist[fastRound(I1[yMax1][xi] / 255.0f * bins)];
434 for (
int x = 0; x < (int)I1.
getWidth(); x++) {
435 int xMin = std::max(0, x - (
int)blockRadius);
436 int xMax = x + blockRadius + 1;
439 int xMin1 = xMin - 1;
441 for (
int yi = yMin; yi < yMax; yi++) {
442 --hist[fastRound(I1[yi][xMin1] / 255.0f * bins)];
447 int xMax1 = xMax - 1;
449 for (
int yi = yMin; yi < yMax; yi++) {
450 ++hist[fastRound(I1[yi][xMax1] / 255.0f * bins)];
454 int v = fastRound(I1[y][x] / 255.0f * bins);
455 int w = std::min((
int)I1.
getWidth(), xMax) - xMin;
457 int limit = (int)(slope * n / bins + 0.5f);
458 I2[y][x] = fastRound(transferValue(v, hist, clippedHist, limit) * 255.0f);
502 clahe(pR, resR, blockRadius, bins, slope, fast);
503 clahe(pG, resG, blockRadius, bins, slope, fast);
504 clahe(pB, resB, blockRadius, bins, slope, fast);
508 unsigned char *ptrStart = (
unsigned char *)I2.
bitmap;
509 unsigned char *ptrEnd = ptrStart + size * 4;
510 unsigned char *ptrCurrent = ptrStart;
512 unsigned int cpt = 0;
513 while (ptrCurrent != ptrEnd) {
514 *ptrCurrent = resR.
bitmap[cpt];
517 *ptrCurrent = resG.
bitmap[cpt];
520 *ptrCurrent = resB.
bitmap[cpt];
523 *ptrCurrent = pa.bitmap[cpt];
Type * bitmap
points toward the bitmap
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=NULL)
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
VISP_EXPORT void clahe(const vpImage< unsigned char > &I1, vpImage< unsigned char > &I2, const int blockRadius=150, const int bins=256, const float slope=3.0f, const bool fast=true)
unsigned int getHeight() const
unsigned int getWidth() const