// see https://github.com/fiji/Auto_Threshold/blob/master/src/main/java/fiji/threshold/Auto_Threshold.java // Zack, G. W., Rogers, W. E. and Latt, S. A., 1977, // Automatic Measurement of Sister Chromatid Exchange Frequency, // Journal of Histochemistry and Cytochemistry 25 (7), pp. 741-753 // // modified from Johannes Schindelin plugin /** * Return a threshold for a histogram using Triangle algorithm. * @param histogram - The image histogram. * @returns The threshold. */ export function triangle(histogram: Uint32Array): number { // find min and max let min = 0; let dmax = 0; let max = 0; let min2 = 0; for (let i = 0; i < histogram.length; i++) { if (histogram[i] > 0) { min = i; break; } } if (min > 0) { // line to the (p==0) point, not to histogram[min] min--; } // The Triangle algorithm cannot tell whether the data is skewed to one side or another. // This causes a problem as there are 2 possible thresholds between the max and the 2 extremes // of the histogram. // Here I propose to find out to which side of the max point the data is furthest, and use that as // the other extreme. for (let i = histogram.length - 1; i > 0; i--) { if (histogram[i] > 0) { min2 = i; break; } } if (min2 < histogram.length - 1) { // line to the (p==0) point, not to data[min] min2++; } for (let i = 0; i < histogram.length; i++) { if (histogram[i] > dmax) { max = i; dmax = histogram[i]; } } // find which is the furthest side let inverted = false; if (max - min < min2 - max) { // reverse the histogram inverted = true; let left = 0; // index of leftmost element let right = histogram.length - 1; // index of rightmost element while (left < right) { // exchange the left and right elements const temp = histogram[left]; histogram[left] = histogram[right]; histogram[right] = temp; // move the bounds toward the center left++; right--; } min = histogram.length - 1 - min2; max = histogram.length - 1 - max; } if (min === max) { return min; } // describe line by nx * x + ny * y - d = 0 let nx, ny, d; // nx is just the max frequency as the other point has freq=0 nx = histogram[max]; // -min; // data[min]; // lowest value bmin = (p=0)% in the image ny = min - max; d = Math.hypot(nx, ny); nx /= d; ny /= d; d = nx * min + ny * histogram[min]; // find split point let split = min; let splitDistance = 0; for (let i = min + 1; i <= max; i++) { const newDistance = nx * i + ny * histogram[i] - d; if (newDistance > splitDistance) { split = i; splitDistance = newDistance; } } split--; if (inverted) { // The histogram might be used for something else, so let's reverse it back let left = 0; let right = histogram.length - 1; while (left < right) { const temp = histogram[left]; histogram[left] = histogram[right]; histogram[right] = temp; left++; right--; } return histogram.length - 1 - split; } else { return split; } }