79 #include <visp3/core/vpImageConvert.h>
80 #include <visp3/imgproc/vpImgproc.h>
84 int fastRound(
float value) {
return static_cast<int>(value + 0.5f); }
86 void clipHistogram(
const std::vector<int> &hist, std::vector<int> &clippedHist,
int limit)
89 int clippedEntries = 0, clippedEntriesBefore = 0;
90 int histlength =
static_cast<int>(hist.size());
93 clippedEntriesBefore = clippedEntries;
95 for (
int i = 0; i < histlength; ++i) {
96 int d = clippedHist[i] - limit;
99 clippedHist[i] = limit;
103 int d = clippedEntries / histlength;
104 int m = clippedEntries % histlength;
105 for (
int i = 0; i < histlength; ++i) {
110 int s = (histlength - 1) / m;
111 for (
int i = s / 2; i < histlength; i += s) {
115 }
while (clippedEntries != clippedEntriesBefore);
118 void createHistogram(
int blockRadius,
int bins,
int blockXCenter,
int blockYCenter,
const vpImage<unsigned char> &I,
119 std::vector<int> &hist)
121 std::fill(hist.begin(), hist.end(), 0);
123 int xMin = std::max<int>(0, blockXCenter - blockRadius);
124 int yMin = std::max<int>(0, blockYCenter - blockRadius);
125 int xMax = std::min<int>(
static_cast<int>(I.
getWidth()), blockXCenter + blockRadius + 1);
126 int yMax = std::min<int>(
static_cast<int>(I.
getHeight()), blockYCenter + blockRadius + 1);
128 for (
int y = yMin; y < yMax; ++y) {
129 for (
int x = xMin; x < xMax; ++x) {
130 ++hist[fastRound((I[y][x] / 255.0f) * bins)];
135 std::vector<float> createTransfer(
const std::vector<int> &hist,
int limit, std::vector<int> &cdfs)
137 clipHistogram(hist, cdfs, limit);
138 int hMin =
static_cast<int>(hist.size()) - 1;
140 for (
int i = 0; i < hMin; ++i) {
146 int hist_size =
static_cast<int>(hist.size());
147 for (
int i = hMin; i < hist_size; ++i) {
152 int cdfMin = cdfs[hMin];
153 int cdfMax = cdfs[hist.size() - 1];
155 std::vector<float> transfer(hist.size());
156 int transfer_size =
static_cast<int>(transfer.size());
157 for (
int i = 0; i < transfer_size; ++i) {
158 transfer[i] = (cdfs[i] - cdfMin) /
static_cast<float>(cdfMax - cdfMin);
164 float transferValue(
int v, std::vector<int> &clippedHist)
166 int clippedHistLength =
static_cast<int>(clippedHist.size());
167 int hMin = clippedHistLength - 1;
168 for (
int i = 0; i < hMin; ++i) {
169 if (clippedHist[i] != 0) {
175 for (
int i = hMin; i <= v; ++i) {
176 cdf += clippedHist[i];
180 for (
int i = v + 1; i < clippedHistLength; ++i) {
181 cdfMax += clippedHist[i];
184 int cdfMin = clippedHist[hMin];
185 return (cdf - cdfMin) /
static_cast<float>(cdfMax - cdfMin);
188 float transferValue(
int v,
const std::vector<int> &hist, std::vector<int> &clippedHist,
int limit)
190 clipHistogram(hist, clippedHist, limit);
192 return transferValue(v, clippedHist);
200 if (blockRadius < 0) {
201 std::cerr <<
"Error: blockRadius < 0!" << std::endl;
205 if ((bins < 0) || (bins > 256)) {
206 std::cerr <<
"Error: (bins < 0 || bins > 256)!" << std::endl;
210 if ((
static_cast<unsigned int>((2 * blockRadius) + 1) > I1.
getWidth()) || (
static_cast<unsigned int>((2 * blockRadius) + 1) > I1.
getHeight())) {
211 std::cerr <<
"Error: (unsigned int) (2*blockRadius+1) > I1.getWidth() || "
212 "(unsigned int) (2*blockRadius+1) > I1.getHeight()!"
220 int blockSize = (2 * blockRadius) + 1;
221 int limit =
static_cast<int>(((slope * blockSize * blockSize) / bins) + 0.5);
228 int cm = I1.
getWidth() - (nc * blockSize);
234 for (
int i = 0; i < nc; ++i) {
235 cs[i] = (i * blockSize) + blockRadius + 1;
241 for (
int i = 0; i < nc; ++i) {
242 cs[i] = (i * blockSize) + blockRadius + 1;
244 cs[nc] = I1.
getWidth() - blockRadius - 1;
249 cs[0] = blockRadius + 1;
250 for (
int i = 0; i < nc; ++i) {
251 cs[i + 1] = (i * blockSize) + blockRadius + 1 + (cm / 2);
253 cs[nc + 1] = I1.
getWidth() - blockRadius - 1;
256 int rm = I1.
getHeight() - (nr * blockSize);
261 rs.resize(
static_cast<size_t>(nr));
262 for (
int i = 0; i < nr; ++i) {
263 rs[i] = (i * blockSize) + blockRadius + 1;
268 rs.resize(
static_cast<size_t>(nr + 1));
269 for (
int i = 0; i < nr; ++i) {
270 rs[i] = (i * blockSize) + blockRadius + 1;
272 rs[nr] = I1.
getHeight() - blockRadius - 1;
276 rs.resize(
static_cast<size_t>(nr + 2));
277 rs[0] = blockRadius + 1;
278 for (
int i = 0; i < nr; ++i) {
279 rs[i + 1] = (i * blockSize) + blockRadius + 1 + (rm / 2);
281 rs[nr + 1] = I1.
getHeight() - blockRadius - 1;
284 std::vector<int> hist(
static_cast<size_t>(bins + 1));
285 std::vector<int> cdfs(
static_cast<size_t>(bins + 1));
286 std::vector<float> tl;
287 std::vector<float> tr;
288 std::vector<float> br;
289 std::vector<float> bl;
291 int rs_size =
static_cast<int>(rs.size());
292 for (
int r = 0; r <= rs_size; ++r) {
293 int r0 = std::max<int>(0, r - 1);
294 int r1 = std::min<int>(
static_cast<int>(rs.size()) - 1, r);
295 int dr = rs[r1] - rs[r0];
297 createHistogram(blockRadius, bins, cs[0], rs[r0], I1, hist);
298 tr = createTransfer(hist, limit, cdfs);
303 createHistogram(blockRadius, bins, cs[0], rs[r1], I1, hist);
304 br = createTransfer(hist, limit, cdfs);
307 int yMin = (r == 0 ? 0 : rs[r0]);
308 int yMax = (r < static_cast<int>(rs.size()) ? rs[r1] : I1.
getHeight());
310 int cs_size =
static_cast<int>(cs.size());
311 for (
int c = 0; c <= cs_size; ++c) {
312 int c0 = std::max<int>(0, c - 1);
313 int c1 = std::min<int>(
static_cast<int>(cs.size()) - 1, c);
314 int dc = cs[c1] - cs[c0];
320 createHistogram(blockRadius, bins, cs[c1], rs[r0], I1, hist);
321 tr = createTransfer(hist, limit, cdfs);
326 createHistogram(blockRadius, bins, cs[c1], rs[r1], I1, hist);
327 br = createTransfer(hist, limit, cdfs);
331 int xMin = (c == 0 ? 0 : cs[c0]);
332 int xMax = (c < static_cast<int>(cs.size()) ? cs[c1] : I1.
getWidth());
333 for (
int y = yMin; y < yMax; ++y) {
334 float wy =
static_cast<float>(rs[r1] - y) / dr;
336 for (
int x = xMin; x < xMax; ++x) {
337 float wx =
static_cast<float>(cs[c1] - x) / dc;
338 int v = fastRound((I1[y][x] / 255.0f) * bins);
343 float t0 = 0.0f, t1 = 0.0f;
350 t0 = (wx * t00) + ((1.0f - wx) * t01);
351 t1 = (wx * t10) + ((1.0f - wx) * t11);
354 float t = (r0 == r1) ? t0 : (wy * t0) + ((1.0f - wy) * t1);
355 I2[y][x] = std::max<unsigned char>(0, std::min<unsigned char>(255, fastRound(t * 255.0f)));
362 std::vector<int> hist(bins + 1), prev_hist(bins + 1);
363 std::vector<int> clippedHist(bins + 1);
367 int xMax0 = std::min<int>(
static_cast<int>(I1.
getWidth()), blockRadius);
369 int i1_height =
static_cast<int>(I1.
getHeight());
370 for (
int y = 0; y < i1_height; ++y) {
371 int yMin = std::max<int>(0, y -
static_cast<int>(blockRadius));
372 int yMax = std::min<int>(
static_cast<int>(I1.
getHeight()), y + blockRadius + 1);
376 std::fill(hist.begin(), hist.end(), 0);
378 for (
int yi = yMin; yi < yMax; ++yi) {
379 for (
int xi = xMin0; xi < xMax0; ++xi) {
380 ++hist[fastRound(I1[yi][xi] / 255.0f * bins)];
387 for (
int yi = yMin; yi < yMax; ++yi) {
388 for (
int xi = xMin0; xi < xMax0; ++xi) {
389 ++hist[fastRound((I1[yi][xi] / 255.0f) * bins)];
397 int yMin1 = yMin - 1;
399 for (
int xi = xMin0; xi < xMax0; ++xi) {
400 --hist[fastRound((I1[yMin1][xi] / 255.0f) * bins)];
404 if ((y + blockRadius) <
static_cast<int>(I1.
getHeight())) {
405 int yMax1 = yMax - 1;
407 for (
int xi = xMin0; xi < xMax0; ++xi) {
408 ++hist[fastRound((I1[yMax1][xi] / 255.0f) * bins)];
414 int i1_width =
static_cast<int>(I1.
getWidth());
415 for (
int x = 0; x < i1_width; ++x) {
416 int xMin = std::max<int>(0, x -
static_cast<int>(blockRadius));
417 int xMax = x + blockRadius + 1;
420 int xMin1 = xMin - 1;
422 for (
int yi = yMin; yi < yMax; ++yi) {
423 --hist[fastRound((I1[yi][xMin1] / 255.0f) * bins)];
427 if (xMax <=
static_cast<int>(I1.
getWidth())) {
428 int xMax1 = xMax - 1;
430 for (
int yi = yMin; yi < yMax; ++yi) {
431 ++hist[fastRound((I1[yi][xMax1] / 255.0f) * bins)];
435 int v = fastRound((I1[y][x] / 255.0f) * bins);
436 int w = std::min<int>(
static_cast<int>(I1.
getWidth()), xMax) - xMin;
438 int limit =
static_cast<int>((slope * n) / bins + 0.5f);
439 I2[y][x] = fastRound(transferValue(v, hist, clippedHist, limit) * 255.0f);
457 clahe(pR, resR, blockRadius, bins, slope, fast);
458 clahe(pG, resG, blockRadius, bins, slope, fast);
459 clahe(pB, resB, blockRadius, bins, slope, fast);
463 unsigned char *ptrStart = (
unsigned char *)(I2.
bitmap);
464 unsigned char *ptrEnd = ptrStart + (size * 4);
465 unsigned char *ptrCurrent = ptrStart;
467 unsigned int cpt = 0;
468 while (ptrCurrent != ptrEnd) {
469 *ptrCurrent = resR.
bitmap[cpt];
472 *ptrCurrent = resG.
bitmap[cpt];
475 *ptrCurrent = resB.
bitmap[cpt];
478 *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 vpImage< unsigned char > &I1, vpImage< unsigned char > &I2, int blockRadius=150, int bins=256, float slope=3.0f, bool fast=true)