79 #include <visp3/core/vpImageConvert.h>
80 #include <visp3/imgproc/vpImgproc.h>
85 int fastRound(
float value) {
return static_cast<int>(value + 0.5f); }
87 void clipHistogram(
const std::vector<int> &hist, std::vector<int> &clippedHist,
int limit)
90 int clippedEntries = 0, clippedEntriesBefore = 0;
91 int histlength =
static_cast<int>(hist.size());
94 clippedEntriesBefore = clippedEntries;
96 for (
int i = 0; i < histlength; ++i) {
97 int d = clippedHist[i] - limit;
100 clippedHist[i] = limit;
104 int d = clippedEntries / histlength;
105 int m = clippedEntries % histlength;
106 for (
int i = 0; i < histlength; ++i) {
111 int s = (histlength - 1) / m;
112 for (
int i = s / 2; i < histlength; i += s) {
116 }
while (clippedEntries != clippedEntriesBefore);
120 std::vector<int> &hist)
122 std::fill(hist.begin(), hist.end(), 0);
124 int xMin = std::max<int>(0, blockXCenter - blockRadius);
125 int yMin = std::max<int>(0, blockYCenter - blockRadius);
126 int xMax = std::min<int>(
static_cast<int>(I.
getWidth()), blockXCenter + blockRadius + 1);
127 int yMax = std::min<int>(
static_cast<int>(I.
getHeight()), blockYCenter + blockRadius + 1);
129 for (
int y = yMin; y < yMax; ++y) {
130 for (
int x = xMin; x < xMax; ++x) {
131 ++hist[
fastRound((I[y][x] / 255.0f) * bins)];
136 std::vector<float>
createTransfer(
const std::vector<int> &hist,
int limit, std::vector<int> &cdfs)
139 int hMin =
static_cast<int>(hist.size()) - 1;
142 bool hasNotFoundFirstNotZero =
true;
144 while ((i < stopIdx) && hasNotFoundFirstNotZero) {
147 hasNotFoundFirstNotZero =
false;
152 int hist_size =
static_cast<int>(hist.size());
153 for (
int i = hMin; i < hist_size; ++i) {
158 int cdfMin = cdfs[hMin];
159 int cdfMax = cdfs[hist.size() - 1];
161 std::vector<float> transfer(hist.size());
162 int transfer_size =
static_cast<int>(transfer.size());
163 for (
int i = 0; i < transfer_size; ++i) {
164 transfer[i] = (cdfs[i] - cdfMin) /
static_cast<float>(cdfMax - cdfMin);
172 int clippedHistLength =
static_cast<int>(clippedHist.size());
173 int hMin = clippedHistLength - 1;
176 bool hasNotFoundFirstNotZero =
true;
177 while ((i<idxStop) && hasNotFoundFirstNotZero) {
178 if (clippedHist[i] != 0) {
180 hasNotFoundFirstNotZero =
false;
186 for (
int i = hMin; i <= v; ++i) {
187 cdf += clippedHist[i];
191 for (
int i = v + 1; i < clippedHistLength; ++i) {
192 cdfMax += clippedHist[i];
195 int cdfMin = clippedHist[hMin];
196 return (cdf - cdfMin) /
static_cast<float>(cdfMax - cdfMin);
199 float transferValue(
int v,
const std::vector<int> &hist, std::vector<int> &clippedHist,
int limit)
206 bool checkClaheInputs(
const int &blockRadius,
const int &bins,
const unsigned int &width,
const unsigned int &height)
208 if (blockRadius < 0) {
209 std::cerr <<
"Error: blockRadius < 0!" << std::endl;
213 const int maxBins = 256;
214 if ((bins < 0) || (bins > maxBins)) {
215 std::cerr <<
"Error: (bins < 0 || bins > " << maxBins <<
")!" << std::endl;
220 if ((
static_cast<unsigned int>((twice * blockRadius) + 1) > width) || (
static_cast<unsigned int>((twice * blockRadius) + 1) > height)) {
221 std::cerr <<
"Error: (unsigned int) (2*blockRadius+1) > I1.getWidth() || "
222 "(unsigned int) (2*blockRadius+1) > I1.getHeight()!"
236 int blockSize = (val_2 * blockRadius) + 1;
237 int limit =
static_cast<int>(((slope * blockSize * blockSize) / bins) + 0.5);
242 int cm = I1.
getWidth() - (nc * blockSize);
247 for (
int i = 0; i < nc; ++i) {
248 cs[i] = (i * blockSize) + blockRadius + 1;
253 for (
int i = 0; i < nc; ++i) {
254 cs[i] = (i * blockSize) + blockRadius + 1;
256 cs[nc] = I1.
getWidth() - blockRadius - 1;
259 cs.resize(nc + val_2);
260 cs[0] = blockRadius + 1;
261 for (
int i = 0; i < nc; ++i) {
262 cs[i + 1] = (i * blockSize) + blockRadius + 1 + (cm / val_2);
264 cs[nc + 1] = I1.
getWidth() - blockRadius - 1;
267 int rm = I1.
getHeight() - (nr * blockSize);
271 rs.resize(
static_cast<size_t>(nr));
272 for (
int i = 0; i < nr; ++i) {
273 rs[i] = (i * blockSize) + blockRadius + 1;
277 rs.resize(
static_cast<size_t>(nr + 1));
278 for (
int i = 0; i < nr; ++i) {
279 rs[i] = (i * blockSize) + blockRadius + 1;
281 rs[nr] = I1.
getHeight() - blockRadius - 1;
284 rs.resize(
static_cast<size_t>(nr + val_2));
285 rs[0] = blockRadius + 1;
286 for (
int i = 0; i < nr; ++i) {
287 rs[i + 1] = (i * blockSize) + blockRadius + 1 + (rm / val_2);
289 rs[nr + 1] = I1.
getHeight() - blockRadius - 1;
292 std::vector<int> hist(
static_cast<size_t>(bins + 1)), cdfs(
static_cast<size_t>(bins + 1));
293 std::vector<float> tl, tr, br, bl;
294 int rs_size =
static_cast<int>(rs.size());
295 for (
int r = 0; r <= rs_size; ++r) {
296 int r0 = std::max<int>(0, r - 1);
297 int r1 = std::min<int>(
static_cast<int>(rs.size()) - 1, r);
298 int dr = rs[r1] - rs[r0];
309 int yMin = (r == 0 ? 0 : rs[r0]);
310 int yMax = (r < static_cast<int>(rs.size()) ? rs[r1] : I1.
getHeight());
311 int cs_size =
static_cast<int>(cs.size());
312 for (
int c = 0; c <= cs_size; ++c) {
313 int c0 = std::max<int>(0, c - 1);
314 int c1 = std::min<int>(
static_cast<int>(cs.size()) - 1, c);
315 int dc = cs[c1] - cs[c0];
330 int xMin = (c == 0 ? 0 : cs[c0]);
331 int xMax = (c < static_cast<int>(cs.size()) ? cs[c1] : I1.
getWidth());
332 for (
int y = yMin; y < yMax; ++y) {
333 float wy =
static_cast<float>(rs[r1] - y) / dr;
334 for (
int x = xMin; x < xMax; ++x) {
335 float wx =
static_cast<float>(cs[c1] - x) / dc;
336 int v =
fastRound((I1[y][x] / 255.0f) * bins);
341 float t0 = (c0 == c1) ? t00 : ((wx * t00) + ((1.0f - wx) * t01));
342 float t1 = (c0 == c1) ? t10 : ((wx * t10) + ((1.0f - wx) * t11));
343 float t = (r0 == r1) ? t0 : ((wy * t0) + ((1.0f - wy) * t1));
344 const int maxPixelIntensity = 255;
345 I2[y][x] = std::max<unsigned char>(0, std::min<unsigned char>(maxPixelIntensity,
fastRound(t * 255.0f)));
352 std::vector<int> hist(bins + 1), prev_hist(bins + 1), clippedHist(bins + 1);
355 int xMax0 = std::min<int>(
static_cast<int>(I1.
getWidth()), blockRadius);
356 int i1_height =
static_cast<int>(I1.
getHeight());
357 for (
int y = 0; y < i1_height; ++y) {
358 int yMin = std::max<int>(0, y -
static_cast<int>(blockRadius));
359 int yMax = std::min<int>(
static_cast<int>(I1.
getHeight()), y + blockRadius + 1);
365 for (
int yi = yMin; yi < yMax; ++yi) {
366 for (
int xi = xMin0; xi < xMax0; ++xi) {
367 ++hist[
fastRound((I1[yi][xi] / 255.0f) * bins)];
375 int yMin1 = yMin - 1;
377 for (
int xi = xMin0; xi < xMax0; ++xi) {
378 --hist[
fastRound((I1[yMin1][xi] / 255.0f) * bins)];
382 if ((y + blockRadius) <
static_cast<int>(I1.
getHeight())) {
383 int yMax1 = yMax - 1;
385 for (
int xi = xMin0; xi < xMax0; ++xi) {
386 ++hist[
fastRound((I1[yMax1][xi] / 255.0f) * bins)];
392 int i1_width =
static_cast<int>(I1.
getWidth());
393 for (
int x = 0; x < i1_width; ++x) {
394 int xMin = std::max<int>(0, x -
static_cast<int>(blockRadius));
395 int xMax = x + blockRadius + 1;
398 int xMin1 = xMin - 1;
400 for (
int yi = yMin; yi < yMax; ++yi) {
401 --hist[
fastRound((I1[yi][xMin1] / 255.0f) * bins)];
405 if (xMax <=
static_cast<int>(I1.
getWidth())) {
406 int xMax1 = xMax - 1;
408 for (
int yi = yMin; yi < yMax; ++yi) {
409 ++hist[
fastRound((I1[yi][xMax1] / 255.0f) * bins)];
413 int v =
fastRound((I1[y][x] / 255.0f) * bins);
414 int w = std::min<int>(
static_cast<int>(I1.
getWidth()), xMax) - xMin;
416 int limit =
static_cast<int>(((slope * n) / bins) + 0.5f);
435 clahe(pR, resR, blockRadius, bins, slope, fast);
436 clahe(pG, resG, blockRadius, bins, slope, fast);
437 clahe(pB, resB, blockRadius, bins, slope, fast);
439 const unsigned int sizeRGBa = 4;
442 unsigned char *ptrStart =
reinterpret_cast<unsigned char *
>(I2.
bitmap);
443 unsigned char *ptrEnd = ptrStart + (size * sizeRGBa);
444 unsigned char *ptrCurrent = ptrStart;
446 unsigned int cpt = 0;
447 while (ptrCurrent != ptrEnd) {
448 *ptrCurrent = resR.
bitmap[cpt];
451 *ptrCurrent = resG.
bitmap[cpt];
454 *ptrCurrent = resB.
bitmap[cpt];
457 *ptrCurrent = pa.
bitmap[cpt];
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=nullptr)
unsigned int getWidth() const
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
VISP_EXPORT void clahe(const VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I1, VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I2, int blockRadius=150, int bins=256, float slope=3.0f, bool fast=true)
bool checkClaheInputs(const int &blockRadius, const int &bins, const unsigned int &width, const unsigned int &height)
void createHistogram(int blockRadius, int bins, int blockXCenter, int blockYCenter, const vpImage< unsigned char > &I, std::vector< int > &hist)
std::vector< float > createTransfer(const std::vector< int > &hist, int limit, std::vector< int > &cdfs)
float transferValue(int v, std::vector< int > &clippedHist)
int fastRound(float value)
void clipHistogram(const std::vector< int > &hist, std::vector< int > &clippedHist, int limit)