All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
otsuthr.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: otsuthr.cpp
3  * Description: Simple Otsu thresholding for binarizing images.
4  * Author: Ray Smith
5  * Created: Fri Mar 07 12:31:01 PST 2008
6  *
7  * (C) Copyright 2008, Google Inc.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include "otsuthr.h"
21 
22 #include <string.h>
23 #include "allheaders.h"
24 #include "helpers.h"
25 #include "openclwrapper.h"
26 
27 
28 namespace tesseract {
29 
30 // Computes the Otsu threshold(s) for the given image rectangle, making one
31 // for each channel. Each channel is always one byte per pixel.
32 // Returns an array of threshold values and an array of hi_values, such
33 // that a pixel value >threshold[channel] is considered foreground if
34 // hi_values[channel] is 0 or background if 1. A hi_value of -1 indicates
35 // that there is no apparent foreground. At least one hi_value will not be -1.
36 // Delete thresholds and hi_values with delete [] after use.
37 // The return value is the number of channels in the input image, being
38 // the size of the output thresholds and hi_values arrays.
39 int OtsuThreshold(Pix* src_pix, int left, int top, int width, int height,
40  int** thresholds, int** hi_values) {
41  int num_channels = pixGetDepth(src_pix) / 8;
42  // Of all channels with no good hi_value, keep the best so we can always
43  // produce at least one answer.
44  PERF_COUNT_START("OtsuThreshold")
45  int best_hi_value = 1;
46  int best_hi_index = 0;
47  bool any_good_hivalue = false;
48  double best_hi_dist = 0.0;
49  *thresholds = new int[num_channels];
50  *hi_values = new int[num_channels];
51  // all of channel 0 then all of channel 1...
52  int *histogramAllChannels = new int[kHistogramSize * num_channels];
53 
54  // only use opencl if compiled w/ OpenCL and selected device is opencl
55 #ifdef USE_OPENCL
56  // Calculate Histogram on GPU
57  OpenclDevice od;
58  if (od.selectedDeviceIsOpenCL() &&
59  (num_channels == 1 || num_channels == 4) && top == 0 && left == 0 ) {
60  od.HistogramRectOCL(
61  (const unsigned char*)pixGetData(src_pix),
62  num_channels,
63  pixGetWpl(src_pix) * 4,
64  left,
65  top,
66  width,
67  height,
69  histogramAllChannels);
70 
71  // Calculate Threshold from Histogram on cpu
72  for (int ch = 0; ch < num_channels; ++ch) {
73  (*thresholds)[ch] = -1;
74  (*hi_values)[ch] = -1;
75  int *histogram = &histogramAllChannels[kHistogramSize * ch];
76  int H;
77  int best_omega_0;
78  int best_t = OtsuStats(histogram, &H, &best_omega_0);
79  if (best_omega_0 == 0 || best_omega_0 == H) {
80  // This channel is empty.
81  continue;
82  }
83  // To be a convincing foreground we must have a small fraction of H
84  // or to be a convincing background we must have a large fraction of H.
85  // In between we assume this channel contains no thresholding information.
86  int hi_value = best_omega_0 < H * 0.5;
87  (*thresholds)[ch] = best_t;
88  if (best_omega_0 > H * 0.75) {
89  any_good_hivalue = true;
90  (*hi_values)[ch] = 0;
91  } else if (best_omega_0 < H * 0.25) {
92  any_good_hivalue = true;
93  (*hi_values)[ch] = 1;
94  } else {
95  // In case all channels are like this, keep the best of the bad lot.
96  double hi_dist = hi_value ? (H - best_omega_0) : best_omega_0;
97  if (hi_dist > best_hi_dist) {
98  best_hi_dist = hi_dist;
99  best_hi_value = hi_value;
100  best_hi_index = ch;
101  }
102  }
103  }
104  } else {
105 #endif
106  for (int ch = 0; ch < num_channels; ++ch) {
107  (*thresholds)[ch] = -1;
108  (*hi_values)[ch] = -1;
109  // Compute the histogram of the image rectangle.
110  int histogram[kHistogramSize];
111  HistogramRect(src_pix, ch, left, top, width, height, histogram);
112  int H;
113  int best_omega_0;
114  int best_t = OtsuStats(histogram, &H, &best_omega_0);
115  if (best_omega_0 == 0 || best_omega_0 == H) {
116  // This channel is empty.
117  continue;
118  }
119  // To be a convincing foreground we must have a small fraction of H
120  // or to be a convincing background we must have a large fraction of H.
121  // In between we assume this channel contains no thresholding information.
122  int hi_value = best_omega_0 < H * 0.5;
123  (*thresholds)[ch] = best_t;
124  if (best_omega_0 > H * 0.75) {
125  any_good_hivalue = true;
126  (*hi_values)[ch] = 0;
127  } else if (best_omega_0 < H * 0.25) {
128  any_good_hivalue = true;
129  (*hi_values)[ch] = 1;
130  } else {
131  // In case all channels are like this, keep the best of the bad lot.
132  double hi_dist = hi_value ? (H - best_omega_0) : best_omega_0;
133  if (hi_dist > best_hi_dist) {
134  best_hi_dist = hi_dist;
135  best_hi_value = hi_value;
136  best_hi_index = ch;
137  }
138  }
139  }
140 #ifdef USE_OPENCL
141  }
142 #endif // USE_OPENCL
143  delete[] histogramAllChannels;
144 
145  if (!any_good_hivalue) {
146  // Use the best of the ones that were not good enough.
147  (*hi_values)[best_hi_index] = best_hi_value;
148  }
150  return num_channels;
151 }
152 
153 // Computes the histogram for the given image rectangle, and the given
154 // single channel. Each channel is always one byte per pixel.
155 // Histogram is always a kHistogramSize(256) element array to count
156 // occurrences of each pixel value.
157 void HistogramRect(Pix* src_pix, int channel,
158  int left, int top, int width, int height,
159  int* histogram) {
160  PERF_COUNT_START("HistogramRect")
161  int num_channels = pixGetDepth(src_pix) / 8;
162  channel = ClipToRange(channel, 0, num_channels - 1);
163  int bottom = top + height;
164  memset(histogram, 0, sizeof(*histogram) * kHistogramSize);
165  int src_wpl = pixGetWpl(src_pix);
166  l_uint32* srcdata = pixGetData(src_pix);
167  for (int y = top; y < bottom; ++y) {
168  const l_uint32* linedata = srcdata + y * src_wpl;
169  for (int x = 0; x < width; ++x) {
170  int pixel = GET_DATA_BYTE(const_cast<void*>(
171  reinterpret_cast<const void *>(linedata)),
172  (x + left) * num_channels + channel);
173  ++histogram[pixel];
174  }
175  }
177 }
178 
179 // Computes the Otsu threshold(s) for the given histogram.
180 // Also returns H = total count in histogram, and
181 // omega0 = count of histogram below threshold.
182 int OtsuStats(const int* histogram, int* H_out, int* omega0_out) {
183  int H = 0;
184  double mu_T = 0.0;
185  for (int i = 0; i < kHistogramSize; ++i) {
186  H += histogram[i];
187  mu_T += static_cast<double>(i) * histogram[i];
188  }
189 
190  // Now maximize sig_sq_B over t.
191  // http://www.ctie.monash.edu.au/hargreave/Cornall_Terry_328.pdf
192  int best_t = -1;
193  int omega_0, omega_1;
194  int best_omega_0 = 0;
195  double best_sig_sq_B = 0.0;
196  double mu_0, mu_1, mu_t;
197  omega_0 = 0;
198  mu_t = 0.0;
199  for (int t = 0; t < kHistogramSize - 1; ++t) {
200  omega_0 += histogram[t];
201  mu_t += t * static_cast<double>(histogram[t]);
202  if (omega_0 == 0)
203  continue;
204  omega_1 = H - omega_0;
205  if (omega_1 == 0)
206  break;
207  mu_0 = mu_t / omega_0;
208  mu_1 = (mu_T - mu_t) / omega_1;
209  double sig_sq_B = mu_1 - mu_0;
210  sig_sq_B *= sig_sq_B * omega_0 * omega_1;
211  if (best_t < 0 || sig_sq_B > best_sig_sq_B) {
212  best_sig_sq_B = sig_sq_B;
213  best_t = t;
214  best_omega_0 = omega_0;
215  }
216  }
217  if (H_out != NULL) *H_out = H;
218  if (omega0_out != NULL) *omega0_out = best_omega_0;
219  return best_t;
220 }
221 
222 } // namespace tesseract.
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:115
#define PERF_COUNT_START(FUNCT_NAME)
#define PERF_COUNT_END
int OtsuStats(const int *histogram, int *H_out, int *omega0_out)
Definition: otsuthr.cpp:182
const int kHistogramSize
Definition: otsuthr.h:27
#define NULL
Definition: host.h:144
int OtsuThreshold(Pix *src_pix, int left, int top, int width, int height, int **thresholds, int **hi_values)
Definition: otsuthr.cpp:39
void HistogramRect(Pix *src_pix, int channel, int left, int top, int width, int height, int *histogram)
Definition: otsuthr.cpp:157