Skip to content

Commit 2ac61cd

Browse files
authored
Merge pull request #4090 from troelsy:4.x
Fixed division zero and unintentional bias in Otsu's threshold (CUDA)
2 parents f2854f4 + f37829a commit 2ac61cd

File tree

1 file changed

+19
-15
lines changed

1 file changed

+19
-15
lines changed

modules/cudaarithm/src/cuda/threshold.cu

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ __global__ void otsu_sums(uint *histogram, uint *threshold_sums, unsigned long l
127127
}
128128

129129
__global__ void
130-
otsu_variance(float2 *variance, uint *histogram, uint *threshold_sums, unsigned long long *sums)
130+
otsu_variance(float2 *variance, uint *histogram, uint *threshold_sums, unsigned long long *sums, uint n_samples)
131131
{
132132
const uint n_bins = 256;
133133

@@ -137,7 +137,6 @@ otsu_variance(float2 *variance, uint *histogram, uint *threshold_sums, unsigned
137137
int bin_idx = threadIdx.x;
138138
int threshold = blockIdx.x;
139139

140-
uint n_samples = threshold_sums[0];
141140
uint n_samples_above = threshold_sums[threshold];
142141
uint n_samples_below = n_samples - n_samples_above;
143142

@@ -149,15 +148,21 @@ otsu_variance(float2 *variance, uint *histogram, uint *threshold_sums, unsigned
149148
float threshold_variance_below_f32 = 0;
150149
if (bin_idx > threshold)
151150
{
152-
float mean = (float) sum_above / n_samples_above;
153-
float sigma = bin_idx - mean;
154-
threshold_variance_above_f32 = sigma * sigma;
151+
if (n_samples_above > 0)
152+
{
153+
float mean = (float) sum_above / n_samples_above;
154+
float sigma = bin_idx - mean;
155+
threshold_variance_above_f32 = sigma * sigma;
156+
}
155157
}
156158
else
157159
{
158-
float mean = (float) sum_below / n_samples_below;
159-
float sigma = bin_idx - mean;
160-
threshold_variance_below_f32 = sigma * sigma;
160+
if (n_samples_below > 0)
161+
{
162+
float mean = (float) sum_below / n_samples_below;
163+
float sigma = bin_idx - mean;
164+
threshold_variance_below_f32 = sigma * sigma;
165+
}
161166
}
162167

163168
uint bin_count = histogram[bin_idx];
@@ -198,15 +203,14 @@ __device__ bool has_lowest_score(
198203
}
199204

200205
__global__ void
201-
otsu_score(uint *otsu_threshold, uint *threshold_sums, float2 *variance)
206+
otsu_score(uint *otsu_threshold, uint *threshold_sums, float2 *variance, uint n_samples)
202207
{
203208
const uint n_thresholds = 256;
204209

205210
__shared__ float shared_memory[n_thresholds];
206211

207212
int threshold = threadIdx.x;
208213

209-
uint n_samples = threshold_sums[0];
210214
uint n_samples_above = threshold_sums[threshold];
211215
uint n_samples_below = n_samples - n_samples_above;
212216

@@ -241,7 +245,7 @@ otsu_score(uint *otsu_threshold, uint *threshold_sums, float2 *variance)
241245
}
242246
}
243247

244-
void compute_otsu(uint *histogram, uint *otsu_threshold, Stream &stream)
248+
void compute_otsu(uint *histogram, uint *otsu_threshold, uint n_samples, Stream &stream)
245249
{
246250
const uint n_bins = 256;
247251
const uint n_thresholds = 256;
@@ -261,12 +265,12 @@ void compute_otsu(uint *histogram, uint *otsu_threshold, Stream &stream)
261265
otsu_sums<<<grid_all, block_all, 0, cuda_stream>>>(
262266
histogram, gpu_threshold_sums.ptr<uint>(), gpu_sums.ptr<unsigned long long>());
263267
otsu_variance<<<grid_all, block_all, 0, cuda_stream>>>(
264-
gpu_variances.ptr<float2>(), histogram, gpu_threshold_sums.ptr<uint>(), gpu_sums.ptr<unsigned long long>());
268+
gpu_variances.ptr<float2>(), histogram, gpu_threshold_sums.ptr<uint>(), gpu_sums.ptr<unsigned long long>(), n_samples);
265269
otsu_score<<<grid_score, block_score, 0, cuda_stream>>>(
266-
otsu_threshold, gpu_threshold_sums.ptr<uint>(), gpu_variances.ptr<float2>());
270+
otsu_threshold, gpu_threshold_sums.ptr<uint>(), gpu_variances.ptr<float2>(), n_samples);
267271
}
268272

269-
// TODO: Replace this is cv::cuda::calcHist
273+
// TODO: Replace this with cv::cuda::calcHist
270274
template <uint n_bins>
271275
__global__ void histogram_kernel(
272276
uint *histogram, const uint8_t *image, uint width,
@@ -334,7 +338,7 @@ double cv::cuda::threshold(InputArray _src, OutputArray _dst, double thresh, dou
334338
calcHist(src, gpu_histogram, stream);
335339

336340
GpuMat gpu_otsu_threshold(1, 1, CV_32SC1, pool.getAllocator());
337-
compute_otsu(gpu_histogram.ptr<uint>(), gpu_otsu_threshold.ptr<uint>(), stream);
341+
compute_otsu(gpu_histogram.ptr<uint>(), gpu_otsu_threshold.ptr<uint>(), src.rows * src.cols, stream);
338342

339343
cv::Mat mat_otsu_threshold;
340344
gpu_otsu_threshold.download(mat_otsu_threshold, stream);

0 commit comments

Comments
 (0)