Computes the Otsu threshold(s) for the given image rectangle, making one for each channel. Each channel is always one byte per pixel. Returns an array of threshold values and an array of hi_values, such that a pixel value >threshold[channel] is considered foreground if hi_values[channel] is 0 or background if 1. A hi_value of -1 indicates that there is no apparent foreground. At least one hi_value
| 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 | |
| 52 | // only use opencl if compiled w/ OpenCL and selected device is opencl |
| 53 | #ifdef USE_OPENCL |
| 54 | // all of channel 0 then all of channel 1... |
| 55 | int* histogramAllChannels = new int[kHistogramSize * num_channels]; |
| 56 | |
| 57 | // Calculate Histogram on GPU |
| 58 | OpenclDevice od; |
| 59 | if (od.selectedDeviceIsOpenCL() && (num_channels == 1 || num_channels == 4) && |
| 60 | top == 0 && left == 0) { |
| 61 | od.HistogramRectOCL((unsigned char*)pixGetData(src_pix), num_channels, |
| 62 | pixGetWpl(src_pix) * 4, left, top, width, height, |
| 63 | kHistogramSize, histogramAllChannels); |
| 64 | |
| 65 | // Calculate Threshold from Histogram on cpu |
| 66 | for (int ch = 0; ch < num_channels; ++ch) { |
| 67 | (*thresholds)[ch] = -1; |
| 68 | (*hi_values)[ch] = -1; |
| 69 | int *histogram = &histogramAllChannels[kHistogramSize * ch]; |
| 70 | int H; |
| 71 | int best_omega_0; |
| 72 | int best_t = OtsuStats(histogram, &H, &best_omega_0); |
| 73 | if (best_omega_0 == 0 || best_omega_0 == H) { |
| 74 | // This channel is empty. |
| 75 | continue; |
| 76 | } |
| 77 | // To be a convincing foreground we must have a small fraction of H |
| 78 | // or to be a convincing background we must have a large fraction of H. |
| 79 | // In between we assume this channel contains no thresholding information. |
| 80 | int hi_value = best_omega_0 < H * 0.5; |
| 81 | (*thresholds)[ch] = best_t; |
| 82 | if (best_omega_0 > H * 0.75) { |
| 83 | any_good_hivalue = true; |
| 84 | (*hi_values)[ch] = 0; |
| 85 | } else if (best_omega_0 < H * 0.25) { |
| 86 | any_good_hivalue = true; |
| 87 | (*hi_values)[ch] = 1; |
| 88 | } else { |
| 89 | // In case all channels are like this, keep the best of the bad lot. |
| 90 | double hi_dist = hi_value ? (H - best_omega_0) : best_omega_0; |
| 91 | if (hi_dist > best_hi_dist) { |
| 92 | best_hi_dist = hi_dist; |
| 93 | best_hi_value = hi_value; |
| 94 | best_hi_index = ch; |
| 95 | } |
| 96 | } |
no test coverage detected