Difference between revisions of "Example Thresholding"
From BoofCV
Jump to navigationJump to search (Created page with "<center> <gallery caption="Variable Lighting" heights=200 widths=600> File:VariableLight_Otsu_Square.jpg|Calibration grid. ''Left:'' original, ''Middle:'' Global Otsu, ''Right...") |
m |
||
(11 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
<center> | <center> | ||
<gallery caption="Variable Lighting" heights=200 widths=600> | <gallery caption="Variable Lighting" heights=200 widths=600> | ||
File:VariableLight_Otsu_Square.jpg|Calibration grid. ''Left:'' original, ''Middle:'' Global Otsu, ''Right:'' | File:VariableLight_Otsu_Square.jpg|Calibration grid. ''Left:'' original, ''Middle:'' Global Otsu, ''Right:'' Local Square | ||
</gallery> | </gallery> | ||
<gallery caption="Difficult Text Example" heights=200 widths=600> | <gallery caption="Difficult Text Example" heights=200 widths=600> | ||
File:Text_square_sauvola.jpg|''Left:'' Original, ''Middle:'' | File:Text_square_sauvola.jpg|''Left:'' Original, ''Middle:'' Local Square, ''Right:'' Sauvola | ||
</gallery> | </gallery> | ||
</center> | </center> | ||
Thresholding gray scale images is one of the most basic ways to segment an image. | Thresholding gray scale images is one of the most basic ways to segment an image. It is quick and effective in many situations. BoofCV provides several algorithms for computing both global and locally adaptive thresholds. | ||
Example Code: | Example Code: | ||
* [https://github.com/lessthanoptimal/BoofCV/blob/v0. | * [https://github.com/lessthanoptimal/BoofCV/blob/v0.40/examples/src/main/java/boofcv/examples/segmentation/ExampleThresholding.java ExampleThresholding.java] | ||
Concepts: | Concepts: | ||
* Segmentation | * Segmentation | ||
* Thresholding | * Thresholding | ||
Relevant Videos: | |||
* [https://youtu.be/TGg-xgTyaU8?t=525 New Algorithms in v0.28] | |||
Relevant Examples/Tutorials: | Relevant Examples/Tutorials: | ||
Line 27: | Line 30: | ||
<syntaxhighlight lang="java"> | <syntaxhighlight lang="java"> | ||
/** | /** | ||
* Demonstration of different techniques for automatic thresholding an image to create a binary image. | * Demonstration of different techniques for automatic thresholding an image to create a binary image. The binary | ||
* image can then be used for shape analysis and other applications. | * image can then be used for shape analysis and other applications. Global methods apply the same threshold | ||
* to the entire image. | * to the entire image. Local methods compute a local threshold around each pixel and can handle uneven | ||
* lighting, but produce noisy results in regions with uniform lighting. | * lighting, but produce noisy results in regions with uniform lighting. | ||
* | * | ||
* @author Peter Abeles | |||
* @see boofcv.examples.imageprocessing.ExampleBinaryOps | * @see boofcv.examples.imageprocessing.ExampleBinaryOps | ||
*/ | */ | ||
public class ExampleThresholding { | public class ExampleThresholding { | ||
public static void threshold( String imageName ) { | public static void threshold( String imageName ) { | ||
BufferedImage image = UtilImageIO. | BufferedImage image = UtilImageIO.loadImageNotNull(imageName); | ||
// convert into a usable format | // convert into a usable format | ||
GrayF32 input = ConvertBufferedImage.convertFromSingle(image, null, GrayF32.class); | |||
var binary = new GrayU8(input.width, input.height); | |||
// Display multiple images in the same window | // Display multiple images in the same window | ||
var gui = new ListDisplayPanel(); | |||
// Global Methods | // Global Methods | ||
GThresholdImageOps.threshold(input, binary, ImageStatistics.mean(input), true); | GThresholdImageOps.threshold(input, binary, ImageStatistics.mean(input), true); | ||
gui.addImage(VisualizeBinaryData.renderBinary(binary, null),"Global: Mean"); | gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Global: Mean"); | ||
GThresholdImageOps.threshold(input, binary, GThresholdImageOps.computeOtsu(input, 0, | GThresholdImageOps.threshold(input, binary, GThresholdImageOps.computeOtsu(input, 0, 255), true); | ||
gui.addImage(VisualizeBinaryData.renderBinary(binary, null),"Global: Otsu"); | gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Global: Otsu"); | ||
GThresholdImageOps.threshold(input, binary, GThresholdImageOps.computeEntropy(input, 0, | GThresholdImageOps.threshold(input, binary, GThresholdImageOps.computeEntropy(input, 0, 255), true); | ||
gui.addImage(VisualizeBinaryData.renderBinary(binary, null),"Global: Entropy"); | gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Global: Entropy"); | ||
// Local method | // Local method | ||
GThresholdImageOps. | GThresholdImageOps.localMean(input, binary, ConfigLength.fixed(57), 1.0, true, null, null, null); | ||
gui.addImage(VisualizeBinaryData.renderBinary(binary, null)," | gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Mean"); | ||
GThresholdImageOps. | GThresholdImageOps.localGaussian(input, binary, ConfigLength.fixed(85), 1.0, true, null, null); | ||
gui.addImage(VisualizeBinaryData.renderBinary(binary, null)," | gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Gaussian"); | ||
GThresholdImageOps. | GThresholdImageOps.localNiblack(input, binary, ConfigLength.fixed(11), 0.30f, true); | ||
gui.addImage(VisualizeBinaryData.renderBinary(binary, null)," | gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Niblack"); | ||
GThresholdImageOps.localSauvola(input, binary, ConfigLength.fixed(11), 0.30f, true); | |||
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Sauvola"); | |||
GThresholdImageOps.localWolf(input, binary, ConfigLength.fixed(11), 0.30f, true); | |||
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Wolf"); | |||
GThresholdImageOps.localNick(input, binary, ConfigLength.fixed(11), -0.2f, true); | |||
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: NICK"); | |||
GThresholdImageOps.blockMinMax(input, binary, ConfigLength.fixed(21), 1.0, true, 15); | |||
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Block: Min-Max"); | |||
GThresholdImageOps.blockMean(input, binary, ConfigLength.fixed(21), 1.0, true); | |||
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Block: Mean"); | |||
GThresholdImageOps.blockOtsu(input, binary, false, ConfigLength.fixed(21), 0.5, 1.0, true); | |||
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Block: Otsu"); | |||
// Sauvola is tuned for text image. | // Sauvola is tuned for text image. Change radius to make it run better in others. | ||
// Show the image image for reference | // Show the image image for reference | ||
gui.addImage(ConvertBufferedImage.convertTo(input,null),"Input Image"); | gui.addImage(ConvertBufferedImage.convertTo(input, null), "Input Image"); | ||
String fileName = | String fileName = imageName.substring(imageName.lastIndexOf('/') + 1); | ||
ShowImages.showWindow(gui,fileName); | ShowImages.showWindow(gui, fileName); | ||
} | } | ||
public static void main(String[] args) { | public static void main( String[] args ) { | ||
// example in which global thresholding works best | // example in which global thresholding works best | ||
threshold(" | threshold(UtilIO.pathExample("particles01.jpg")); | ||
// example in which adaptive/local thresholding works best | // example in which adaptive/local thresholding works best | ||
threshold(" | threshold(UtilIO.pathExample("segment/uneven_lighting_squares.jpg")); | ||
// hand written text with non-uniform stained background | // hand written text with non-uniform stained background | ||
threshold(" | threshold(UtilIO.pathExample("segment/stained_handwriting.jpg")); | ||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Latest revision as of 15:32, 17 January 2022
Thresholding gray scale images is one of the most basic ways to segment an image. It is quick and effective in many situations. BoofCV provides several algorithms for computing both global and locally adaptive thresholds.
Example Code:
Concepts:
- Segmentation
- Thresholding
Relevant Videos:
Relevant Examples/Tutorials:
Example Code
/**
* Demonstration of different techniques for automatic thresholding an image to create a binary image. The binary
* image can then be used for shape analysis and other applications. Global methods apply the same threshold
* to the entire image. Local methods compute a local threshold around each pixel and can handle uneven
* lighting, but produce noisy results in regions with uniform lighting.
*
* @author Peter Abeles
* @see boofcv.examples.imageprocessing.ExampleBinaryOps
*/
public class ExampleThresholding {
public static void threshold( String imageName ) {
BufferedImage image = UtilImageIO.loadImageNotNull(imageName);
// convert into a usable format
GrayF32 input = ConvertBufferedImage.convertFromSingle(image, null, GrayF32.class);
var binary = new GrayU8(input.width, input.height);
// Display multiple images in the same window
var gui = new ListDisplayPanel();
// Global Methods
GThresholdImageOps.threshold(input, binary, ImageStatistics.mean(input), true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Global: Mean");
GThresholdImageOps.threshold(input, binary, GThresholdImageOps.computeOtsu(input, 0, 255), true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Global: Otsu");
GThresholdImageOps.threshold(input, binary, GThresholdImageOps.computeEntropy(input, 0, 255), true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Global: Entropy");
// Local method
GThresholdImageOps.localMean(input, binary, ConfigLength.fixed(57), 1.0, true, null, null, null);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Mean");
GThresholdImageOps.localGaussian(input, binary, ConfigLength.fixed(85), 1.0, true, null, null);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Gaussian");
GThresholdImageOps.localNiblack(input, binary, ConfigLength.fixed(11), 0.30f, true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Niblack");
GThresholdImageOps.localSauvola(input, binary, ConfigLength.fixed(11), 0.30f, true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Sauvola");
GThresholdImageOps.localWolf(input, binary, ConfigLength.fixed(11), 0.30f, true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: Wolf");
GThresholdImageOps.localNick(input, binary, ConfigLength.fixed(11), -0.2f, true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Local: NICK");
GThresholdImageOps.blockMinMax(input, binary, ConfigLength.fixed(21), 1.0, true, 15);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Block: Min-Max");
GThresholdImageOps.blockMean(input, binary, ConfigLength.fixed(21), 1.0, true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Block: Mean");
GThresholdImageOps.blockOtsu(input, binary, false, ConfigLength.fixed(21), 0.5, 1.0, true);
gui.addImage(VisualizeBinaryData.renderBinary(binary, false, null), "Block: Otsu");
// Sauvola is tuned for text image. Change radius to make it run better in others.
// Show the image image for reference
gui.addImage(ConvertBufferedImage.convertTo(input, null), "Input Image");
String fileName = imageName.substring(imageName.lastIndexOf('/') + 1);
ShowImages.showWindow(gui, fileName);
}
public static void main( String[] args ) {
// example in which global thresholding works best
threshold(UtilIO.pathExample("particles01.jpg"));
// example in which adaptive/local thresholding works best
threshold(UtilIO.pathExample("segment/uneven_lighting_squares.jpg"));
// hand written text with non-uniform stained background
threshold(UtilIO.pathExample("segment/stained_handwriting.jpg"));
}
}