Visual Servoing Platform
version 3.7.0
Toggle main menu visibility
Loading...
Searching...
No Matches
vpThreshold.cpp
1
/*
2
* ViSP, open source Visual Servoing Platform software.
3
* Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4
*
5
* This software is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
9
* See the file LICENSE.txt at the root directory of this source
10
* distribution for additional information about the GNU GPL.
11
*
12
* For using ViSP with software that can not be combined with the GNU
13
* GPL, please contact Inria about acquiring a ViSP Professional
14
* Edition License.
15
*
16
* See https://visp.inria.fr for more information.
17
*
18
* This software was developed at:
19
* Inria Rennes - Bretagne Atlantique
20
* Campus Universitaire de Beaulieu
21
* 35042 Rennes Cedex
22
* France
23
*
24
* If you have questions regarding the use of this file, please contact
25
* Inria at visp@inria.fr
26
*
27
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29
*
30
* Description:
31
* Automatic thresholding functions.
32
*/
33
38
39
#include <visp3/core/vpHistogram.h>
40
#include <visp3/core/vpImageTools.h>
41
#include <visp3/imgproc/vpImgproc.h>
42
43
namespace
VISP_NAMESPACE_NAME
44
{
45
46
bool
isBimodal
(
const
std::vector<float> &hist_float)
47
{
48
int
modes = 0;
49
const
int
bimodalVal = 2;
50
size_t
hist_float_size_m_1 = hist_float.size() - 1;
51
for
(
size_t
cpt = 1; cpt < hist_float_size_m_1; ++cpt) {
52
if
((hist_float[cpt - 1] < hist_float[cpt]) && (hist_float[cpt] > hist_float[cpt + 1])) {
53
++modes;
54
}
55
56
if
(modes > bimodalVal) {
57
return
false
;
58
}
59
}
60
61
return
(modes == bimodalVal);
62
}
63
64
int
computeThresholdHuang
(
const
vpHistogram
&hist)
65
{
66
// Code ported from the AutoThreshold ImageJ plugin:
67
// Implements Huang's fuzzy thresholding method
68
// Uses Shannon's entropy function (one can also use Yager's entropy
69
// function) Huang L.-K. and Wang M.-J.J. (1995) "Image Thresholding by
70
// Minimizing the Measures of Fuzziness" Pattern Recognition, 28(1): 41-51
71
// Reimplemented (to handle 16-bit efficiently) by Johannes Schindelin Jan
72
// 31, 2011
73
74
// Find first and last non-empty bin
75
size_t
first, last;
76
size_t
hist_size = hist.
getSize
();
77
for
(first = 0; (first < hist_size) && (hist[static_cast<unsigned char>(first)] == 0); ++first) {
78
// do nothing
79
}
80
81
for
(last = (hist_size - 1); (last > first) && (hist[
static_cast<
unsigned
char
>
(last)] == 0); --last) {
82
// do nothing
83
}
84
85
if
(first == last) {
86
return
0;
87
}
88
89
// Calculate the cumulative density and the weighted cumulative density
90
std::vector<float> S(last + 1);
91
std::vector<float> W(last + 1);
92
93
S[0] =
static_cast<
float
>
(hist[0]);
94
W[0] = 0.0f;
95
for
(
size_t
i = std::max<size_t>(
static_cast<
size_t
>
(1), first); i <= last; ++i) {
96
S[i] = S[i - 1] + hist[
static_cast<
unsigned
char
>
(i)];
97
W[i] = W[i - 1] + (i *
static_cast<
float
>
(hist[
static_cast<
unsigned
char
>
(i)]));
98
}
99
100
// Precalculate the summands of the entropy given the absolute difference x
101
// - mu (integral)
102
float
C =
static_cast<
float
>
(last - first);
103
std::vector<float> Smu((last + 1) - first);
104
105
size_t
smu_size = Smu.size();
106
for
(
size_t
i = 1; i < smu_size; ++i) {
107
float
mu = 1 / (1 + (i / C));
108
Smu[i] = (-mu * std::log(mu)) - ((1 - mu) * std::log(1 - mu));
109
}
110
111
// Calculate the threshold
112
int
bestThreshold = 0;
113
float
bestEntropy = std::numeric_limits<float>::max();
114
115
for
(
size_t
threshold = first; threshold <= last; ++threshold) {
116
float
entropy = 0;
117
int
mu =
vpMath::round
(W[threshold] / S[threshold]);
118
for
(
size_t
i = first; i <= threshold; ++i) {
119
entropy += Smu[
static_cast<
size_t
>
(std::abs(
static_cast<
int
>
(i) - mu))] * hist[
static_cast<
unsigned
char
>
(i)];
120
}
121
122
mu =
vpMath::round
((W[last] - W[threshold]) / (S[last] - S[threshold]));
123
for
(
size_t
i = threshold + 1; i <= last; ++i) {
124
entropy += Smu[
static_cast<
size_t
>
(std::abs(
static_cast<
int
>
(i) - mu))] * hist[
static_cast<
unsigned
char
>
(i)];
125
}
126
127
if
(bestEntropy > entropy) {
128
bestEntropy = entropy;
129
bestThreshold =
static_cast<
int
>
(threshold);
130
}
131
}
132
133
return
bestThreshold;
134
}
135
136
int
computeThresholdIntermodes
(
const
vpHistogram
&hist)
137
{
138
const
unsigned
int
minSize = 3;
139
if
(hist.
getSize
() < minSize) {
140
return
-1;
141
}
142
143
// Code based on the AutoThreshold ImageJ plugin:
144
// J. M. S. Prewitt and M. L. Mendelsohn, "The analysis of cell images," in
145
// Annals of the New York Academy of Sciences, vol. 128, pp. 1035-1053,
146
// 1966. ported to ImageJ plugin by G.Landini from Antti Niemisto's Matlab
147
// code (GPL) Original Matlab code Copyright (C) 2004 Antti Niemisto See
148
// http://www.cs.tut.fi/~ant/histthresh/ for an excellent slide presentation
149
// and the original Matlab code.
150
//
151
// Assumes a bimodal histogram. The histogram needs is smoothed (using a
152
// running average of size 3, iteratively) until there are only two local
153
// maxima. j and k Threshold t is (j+k)/2. Images with histograms having
154
// extremely unequal peaks or a broad and flat valley are unsuitable for this
155
// method.
156
157
std::vector<float> hist_float(hist.
getSize
());
158
unsigned
int
hist_size = hist.
getSize
();
159
for
(
unsigned
int
cpt = 0; cpt < hist_size; ++cpt) {
160
hist_float[cpt] =
static_cast<
float
>
(hist[cpt]);
161
}
162
163
int
iter = 0;
164
const
float
nbPtsAverage = 3.;
165
const
int
maxIter = 10000;
166
while
(!
isBimodal
(hist_float)) {
167
// Smooth with a 3 point running mean filter
168
size_t
hist_float_size_m_1 = hist_float.size() - 1;
169
for
(
size_t
cpt = 1; cpt < hist_float_size_m_1; ++cpt) {
170
hist_float[cpt] = (hist_float[cpt - 1] + hist_float[cpt] + hist_float[cpt + 1]) / nbPtsAverage;
171
}
172
173
// First value
174
hist_float[0] = (hist_float[0] + hist_float[1]) / 2.0f;
175
176
// Last value
177
const
size_t
var2 = 2;
178
hist_float[hist_float.size() - 1] = (((hist_float.size() - var2) + hist_float.size()) - 1) / 2.0f;
179
180
++iter;
181
182
if
(iter > maxIter) {
183
std::cerr <<
"Intermodes Threshold not found after "
<< maxIter <<
" iterations!"
<< std::endl;
184
return
-1;
185
}
186
}
187
188
// The threshold is the mean between the two peaks.
189
int
tt = 0;
190
size_t
hist_float_size_m_1 = hist_float.size() - 1;
191
for
(
size_t
cpt = 1; cpt < hist_float_size_m_1; ++cpt) {
192
if
((hist_float[cpt - 1] < hist_float[cpt]) && (hist_float[cpt] > hist_float[cpt + 1])) {
193
// Mode
194
tt +=
static_cast<
int
>
(cpt);
195
}
196
}
197
198
return
static_cast<
int
>
(std::floor(tt / 2.0));
// vpMath round of tt div 2.0
199
}
200
201
int
computeThresholdIsoData
(
const
vpHistogram
&hist,
unsigned
int
imageSize)
202
{
203
int
threshold = 0;
204
205
// Code based on BSD Matlab isodata implementation by zephyr
206
// STEP 1: Compute mean intensity of image from histogram, set T=mean(I)
207
std::vector<float> cumsum(hist.
getSize
(), 0.0f);
208
std::vector<float> sum_ip(hist.
getSize
(), 0.0f);
209
cumsum[0] =
static_cast<
float
>
(hist[0]);
210
211
unsigned
int
hist_size = hist.
getSize
();
212
for
(
unsigned
int
cpt = 1; cpt < hist_size; ++cpt) {
213
sum_ip[cpt] = (cpt *
static_cast<
float
>
(hist[cpt])) + sum_ip[cpt - 1];
214
cumsum[cpt] =
static_cast<
float
>
(hist[cpt]) + cumsum[cpt - 1];
215
}
216
217
int
T =
vpMath::round
(sum_ip[255] / imageSize);
218
219
// STEP 2: compute Mean above T (MAT) and Mean below T (MBT) using T from
220
float
MBT = sum_ip[
static_cast<
size_t
>
(T - 2)] / cumsum[
static_cast<
size_t
>
(T - 2)];
221
float
MAT = (sum_ip.back() - sum_ip[
static_cast<
size_t
>
(T - 1)]) / (cumsum.back() - cumsum[
static_cast<
size_t
>
(T - 1)]);
222
223
int
T2 =
vpMath::round
((MAT + MBT) / 2.0f);
224
225
//% STEP 3 to n: repeat step 2 if T(i)~=T(i-1)
226
while
(std::abs(T2 - T) >= 1) {
227
const
int
val_2 = 2;
228
MBT = sum_ip[
static_cast<
size_t
>
(T2 - val_2)] / cumsum[
static_cast<
size_t
>
(T2 - val_2)];
229
MAT = (sum_ip.back() - sum_ip[
static_cast<
size_t
>
(T2 - 1)]) / (cumsum.back() - cumsum[
static_cast<
size_t
>
(T2 - 1)]);
230
231
T = T2;
232
T2 =
vpMath::round
((MAT + MBT) / 2.0f);
233
threshold = T2;
234
}
235
236
return
threshold;
237
}
238
239
int
computeThresholdMean
(
const
vpHistogram
&hist,
unsigned
int
imageSize)
240
{
241
// C. A. Glasbey, "An analysis of histogram-based thresholding algorithms,"
242
// CVGIP: Graphical Models and Image Processing, vol. 55, pp. 532-537, 1993.
243
// The threshold is the mean of the greyscale data
244
float
sum_ip = 0.0f;
245
unsigned
int
hist_size = hist.
getSize
();
246
for
(
unsigned
int
cpt = 0; cpt < hist_size; ++cpt) {
247
sum_ip += cpt *
static_cast<
float
>
(hist[cpt]);
248
}
249
250
return
static_cast<
int
>
(std::floor(sum_ip / imageSize));
251
}
252
253
int
computeThresholdOtsu
(
const
vpHistogram
&hist,
unsigned
int
imageSize)
254
{
255
// Otsu, N (1979), "A threshold selection method from gray-level
256
// histograms", IEEE Trans. Sys., Man., Cyber. 9: 62-66,
257
// doi:10.1109/TSMC.1979.4310076
258
259
float
mu_T = 0.0f;
260
float
sum_ip_all[256];
261
int
hist_size =
static_cast<
int
>
(hist.
getSize
());
262
for
(
int
cpt = 0; cpt < hist_size; ++cpt) {
263
mu_T += cpt *
static_cast<
float
>
(hist[cpt]);
264
sum_ip_all[cpt] = mu_T;
265
}
266
267
// Weight Background / Foreground
268
float
w_B = 0.0f, w_F = 0.0f;
269
270
float
max_sigma_b = 0.0f;
271
int
threshold = 0;
272
273
bool
w_f_eq_nul =
false
;
274
int
cpt = 0;
275
const
int
maxCpt = 256;
276
while
((cpt < maxCpt) && (!w_f_eq_nul)) {
277
w_B += hist[cpt];
278
bool
w_b_eq_nul =
vpMath::nul
(w_B, std::numeric_limits<float>::epsilon());
279
if
(!w_b_eq_nul) {
280
281
w_F =
static_cast<
int
>
(imageSize) - w_B;
282
w_f_eq_nul =
vpMath::nul
(w_F, std::numeric_limits<float>::epsilon());
283
if
(!w_f_eq_nul) {
284
285
// Mean Background / Foreground
286
float
mu_B = sum_ip_all[cpt] /
static_cast<
float
>
(w_B);
287
float
mu_F = (mu_T - sum_ip_all[cpt]) /
static_cast<
float
>
(w_F);
288
// If there is a case where (w_B * w_F) exceed FLT_MAX, normalize
289
// histogram
290
float
sigma_b_sqr = w_B * w_F * (mu_B - mu_F) * (mu_B - mu_F);
291
292
if
(sigma_b_sqr >= max_sigma_b) {
293
threshold = cpt;
294
max_sigma_b = sigma_b_sqr;
295
}
296
}
297
// else exit the loop
298
}
299
++cpt;
300
}
301
302
return
threshold;
303
}
304
305
int
computeThresholdTriangle
(
vpHistogram
&hist)
306
{
307
int
threshold = 0;
308
309
// Zack, G. W., Rogers, W. E. and Latt, S. A., 1977,
310
// Automatic Measurement of Sister Chromatid Exchange Frequency,
311
// Journal of Histochemistry and Cytochemistry 25 (7), pp. 741-753
312
313
int
left_bound = -1, right_bound = -1, max_idx = -1, max_value = 0;
314
// Find max value index and left / right most index
315
int
hist_size =
static_cast<
int
>
(hist.
getSize
());
316
for
(
int
cpt = 0; cpt < hist_size; ++cpt) {
317
if
((left_bound == -1) && (hist[cpt] > 0)) {
318
left_bound =
static_cast<
int
>
(cpt);
319
}
320
321
if
((right_bound == -1) && (hist[
static_cast<
int
>
(hist.
getSize
()) - 1 - cpt] > 0)) {
322
right_bound =
static_cast<
int
>
(hist.
getSize
()) - 1 - cpt;
323
}
324
325
if
(
static_cast<
int
>
(hist[cpt]) > max_value) {
326
max_value =
static_cast<
int
>
(hist[cpt]);
327
max_idx = cpt;
328
}
329
}
330
331
// First / last index when hist(cpt) == 0
332
left_bound = left_bound > 0 ? (left_bound - 1) : left_bound;
333
right_bound = right_bound < (static_cast<int>(hist.
getSize
()) - 1) ? (right_bound + 1) : right_bound;
334
335
// Use the largest bound
336
bool
flip =
false
;
337
if
((max_idx - left_bound) < (right_bound - max_idx)) {
338
// Flip histogram to get the largest bound to the left
339
flip =
true
;
340
341
int
cpt_left = 0;
342
int
cpt_right =
static_cast<
int
>
(hist.
getSize
()) - 1;
343
for
(; cpt_left < cpt_right; ++cpt_left, --cpt_right) {
344
unsigned
int
temp = hist[cpt_left];
345
hist.
set
(cpt_left, hist[cpt_right]);
346
hist.
set
(cpt_right, temp);
347
}
348
349
left_bound =
static_cast<
int
>
(hist.
getSize
()) - 1 - right_bound;
350
max_idx =
static_cast<
int
>
(hist.
getSize
()) - 1 - max_idx;
351
}
352
353
// Distance from a point to a line defined by two points:
354
//\textbf{distance} \left ( P_1, P_2, \left ( x_0,y_0 \right ) \right )
355
// = \frac{ \left | \left ( y_2-y_1 \right ) x_0 - \left ( x_2-x_1 \right )
356
// y_0 + x_2 y_1 - y_2 x_1 \right | }
357
// { \sqrt{ \left ( y_2 - y_1 \right )^{2} + \left ( x_2 - x_1 \right
358
// )^{2} } }
359
// Constants are ignored
360
float
a =
static_cast<
float
>
(max_value);
// y_2 - y_1
361
float
b =
static_cast<
float
>
(left_bound - max_idx);
//-(x_2 - x_1)
362
float
max_dist = 0.0f;
363
364
for
(
int
cpt = left_bound + 1; cpt <= max_idx; ++cpt) {
365
float
dist = (a * cpt) + (b * hist[cpt]);
366
367
if
(dist > max_dist) {
368
max_dist = dist;
369
threshold = cpt;
370
}
371
}
372
--threshold;
373
374
if
(flip) {
375
threshold =
static_cast<
int
>
(hist.
getSize
()) - 1 - threshold;
376
}
377
378
return
threshold;
379
}
380
381
unsigned
char
autoThreshold
(
vpImage<unsigned char>
&I,
const
vpAutoThresholdMethod
&method,
382
const
unsigned
char
backgroundValue,
const
unsigned
char
foregroundValue)
383
{
384
if
(I.getSize() == 0) {
385
return
0;
386
}
387
388
// Compute image histogram
389
vpHistogram
histogram(I);
390
int
threshold = -1;
391
392
switch
(method) {
393
case
AUTO_THRESHOLD_HUANG
:
394
threshold =
computeThresholdHuang
(histogram);
395
break
;
396
397
case
AUTO_THRESHOLD_INTERMODES
:
398
threshold =
computeThresholdIntermodes
(histogram);
399
break
;
400
401
case
AUTO_THRESHOLD_ISODATA
:
402
threshold =
computeThresholdIsoData
(histogram, I.
getSize
());
403
break
;
404
405
case
AUTO_THRESHOLD_MEAN
:
406
threshold =
computeThresholdMean
(histogram, I.
getSize
());
407
break
;
408
409
case
AUTO_THRESHOLD_OTSU
:
410
threshold =
computeThresholdOtsu
(histogram, I.
getSize
());
411
break
;
412
413
case
AUTO_THRESHOLD_TRIANGLE
:
414
threshold =
computeThresholdTriangle
(histogram);
415
break
;
416
417
default
:
418
break
;
419
}
420
421
const
unsigned
char
threshold2 = 255;
422
if
(threshold != -1) {
423
// Threshold
424
vpImageTools::binarise
(I,
static_cast<
unsigned
char
>
(threshold), threshold2, backgroundValue, foregroundValue,
425
foregroundValue);
426
}
427
428
return
threshold;
429
}
430
431
}
// namespace
vpHistogram
Class to compute a gray level image histogram.
Definition
vpHistogram.h:109
vpHistogram::getSize
unsigned getSize() const
Definition
vpHistogram.h:388
vpHistogram::set
void set(const unsigned char level, unsigned int value)
Definition
vpHistogram.h:227
vpImageTools::binarise
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, bool useLUT=true)
Definition
vpImageTools.h:763
vpImage
Definition of the vpImage class member functions.
Definition
vpImage.h:131
vpMath::nul
static bool nul(double x, double threshold=0.001)
Definition
vpMath.h:453
vpMath::round
static int round(double x)
Definition
vpMath.h:413
VISP_NAMESPACE_NAME::autoThreshold
VISP_EXPORT unsigned char autoThreshold(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, const vpAutoThresholdMethod &method, const unsigned char backgroundValue=0, const unsigned char foregroundValue=255)
VISP_NAMESPACE_NAME
Definition
vpEigenConversion.h:44
VISP_NAMESPACE_NAME::isBimodal
bool isBimodal(const std::vector< float > &hist_float)
Definition
vpThreshold.cpp:46
VISP_NAMESPACE_NAME::computeThresholdIntermodes
int computeThresholdIntermodes(const vpHistogram &hist)
Definition
vpThreshold.cpp:136
VISP_NAMESPACE_NAME::computeThresholdIsoData
int computeThresholdIsoData(const vpHistogram &hist, unsigned int imageSize)
Definition
vpThreshold.cpp:201
VISP_NAMESPACE_NAME::computeThresholdMean
int computeThresholdMean(const vpHistogram &hist, unsigned int imageSize)
Definition
vpThreshold.cpp:239
VISP_NAMESPACE_NAME::computeThresholdOtsu
int computeThresholdOtsu(const vpHistogram &hist, unsigned int imageSize)
Definition
vpThreshold.cpp:253
VISP_NAMESPACE_NAME::computeThresholdTriangle
int computeThresholdTriangle(vpHistogram &hist)
Definition
vpThreshold.cpp:305
VISP_NAMESPACE_NAME::vpAutoThresholdMethod
vpAutoThresholdMethod
Definition
vpImgproc.h:66
VISP_NAMESPACE_NAME::AUTO_THRESHOLD_HUANG
@ AUTO_THRESHOLD_HUANG
Definition
vpImgproc.h:67
VISP_NAMESPACE_NAME::AUTO_THRESHOLD_MEAN
@ AUTO_THRESHOLD_MEAN
Definition
vpImgproc.h:79
VISP_NAMESPACE_NAME::AUTO_THRESHOLD_OTSU
@ AUTO_THRESHOLD_OTSU
Definition
vpImgproc.h:83
VISP_NAMESPACE_NAME::AUTO_THRESHOLD_INTERMODES
@ AUTO_THRESHOLD_INTERMODES
Definition
vpImgproc.h:71
VISP_NAMESPACE_NAME::AUTO_THRESHOLD_ISODATA
@ AUTO_THRESHOLD_ISODATA
Definition
vpImgproc.h:75
VISP_NAMESPACE_NAME::AUTO_THRESHOLD_TRIANGLE
@ AUTO_THRESHOLD_TRIANGLE
Definition
vpImgproc.h:87
VISP_NAMESPACE_NAME::computeThresholdHuang
int computeThresholdHuang(const vpHistogram &hist)
Definition
vpThreshold.cpp:64
modules
imgproc
src
vpThreshold.cpp
Generated by
1.17.0