Difference between revisions of "Example Color Segmentation"

From BoofCV
(Created page with "<center> <gallery heights=150 widths=400 > File:Sunflowers.jpg| Input sunflow image. File:Example_color_segment_yellow.jpg|Image segmented using the color yellow. </gallery> <...")
 
m
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
<center>
 
<center>
 
<gallery heights=150 widths=400 >
 
<gallery heights=150 widths=400 >
File:Sunflowers.jpg| Input sunflow image.
+
File:Sunflowers.jpg| Input sunflower image.
 
File:Example_color_segment_yellow.jpg|Image segmented using the color yellow.
 
File:Example_color_segment_yellow.jpg|Image segmented using the color yellow.
 
</gallery>
 
</gallery>
Line 8: Line 8:
 
Demonstration for how an image can be segmented using color information.  First the image is converted into HSV color space to add robustness against changes in lighting.  Then the user selects a color and it selects pixels with a hue and saturation value and display the resulting image.
 
Demonstration for how an image can be segmented using color information.  First the image is converted into HSV color space to add robustness against changes in lighting.  Then the user selects a color and it selects pixels with a hue and saturation value and display the resulting image.
  
Example File: [https://github.com/lessthanoptimal/BoofCV/blob/v0.14/examples/src/boofcv/examples/ExampleSegmentColor.java ExampleSegmentColor.java]
+
Example File: [https://github.com/lessthanoptimal/BoofCV/blob/v0.37/examples/src/main/java/boofcv/examples/segmentation/ExampleSegmentColor.java ExampleSegmentColor.java]
  
 
Concepts:
 
Concepts:
Line 16: Line 16:
 
Related Examples:
 
Related Examples:
 
* [[Example_Color_Space| Color Space]]
 
* [[Example_Color_Space| Color Space]]
 +
* [[Example_Watershed_with_Seeds| Watershed with Seeds]]
 +
* [[Example_Image_Segmentation| Image Segmentation]]
  
 
= Example Code =
 
= Example Code =
Line 22: Line 24:
 
  * Example which demonstrates how color can be used to segment an image.  The color space is converted from RGB into
 
  * Example which demonstrates how color can be used to segment an image.  The color space is converted from RGB into
 
  * HSV.  HSV separates intensity from color and allows you to search for a specific color based on two values
 
  * HSV.  HSV separates intensity from color and allows you to search for a specific color based on two values
  * independent of lighting conditions.  Other color spaces are supported, such as YUV.
+
  * independent of lighting conditions.  Other color spaces are supported, such as YUV, XYZ, and LAB.
 
  *
 
  *
 
  * @author Peter Abeles
 
  * @author Peter Abeles
 
  */
 
  */
 
public class ExampleSegmentColor {
 
public class ExampleSegmentColor {
 
 
/**
 
/**
 
* Shows a color image and allows the user to select a pixel, convert it to HSV, print
 
* Shows a color image and allows the user to select a pixel, convert it to HSV, print
Line 39: Line 40:
 
float[] color = new float[3];
 
float[] color = new float[3];
 
int rgb = image.getRGB(e.getX(),e.getY());
 
int rgb = image.getRGB(e.getX(),e.getY());
ColorHsv.rgbToHsv((rgb >> 16) & 0xFF,(rgb >> 8) & 0xFF , rgb&0xFF,color);
+
ColorHsv.rgbToHsv((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, color);
System.out.println("h = " + color[0]);
+
System.out.println("H = " + color[0]+" S = "+color[1]+" V = "+color[2]);
System.out.println("s = "+color[1]);
 
System.out.println("v = "+color[2]);
 
  
showSelectedColor("Selected",image,(float)color[0],(float)color[1]);
+
showSelectedColor("Selected",image,color[0],color[1]);
 
}
 
}
 
});
 
});
 
 
ShowImages.showWindow(gui,"Color Selector");
 
ShowImages.showWindow(gui,"Color Selector");
 
}
 
}
Line 54: Line 52:
 
* Selectively displays only pixels which have a similar hue and saturation values to what is provided.
 
* Selectively displays only pixels which have a similar hue and saturation values to what is provided.
 
* This is intended to be a simple example of color based segmentation.  Color based segmentation can be done
 
* This is intended to be a simple example of color based segmentation.  Color based segmentation can be done
* in RGB color, but is more problematic.  More robust techniques can use Gaussian
+
* in RGB color, but is more problematic due to it not being intensity invariant.  More robust techniques
* models.
+
* can use Gaussian models instead of a uniform distribution, as is done below.
 
*/
 
*/
 
public static void showSelectedColor( String name , BufferedImage image , float hue , float saturation ) {
 
public static void showSelectedColor( String name , BufferedImage image , float hue , float saturation ) {
MultiSpectral<ImageFloat32> input = ConvertBufferedImage.convertFromMulti(image,null,ImageFloat32.class);
+
Planar<GrayF32> input = ConvertBufferedImage.convertFromPlanar(image,null,true,GrayF32.class);
MultiSpectral<ImageFloat32> hsv = new MultiSpectral<ImageFloat32>(ImageFloat32.class,input.width,input.height,3);
+
Planar<GrayF32> hsv = input.createSameShape();
 
 
// Ensure the the bands are in RGB order
 
ConvertBufferedImage.orderBandsIntoRGB(input,image);
 
  
 
// Convert into HSV
 
// Convert into HSV
ColorHsv.rgbToHsv_F32(input,hsv);
+
ColorHsv.rgbToHsv(input,hsv);
  
// Pixels which are more than this different from the selected color are set to black
+
// Euclidean distance squared threshold for deciding which pixels are members of the selected set
 
float maxDist2 = 0.4f*0.4f;
 
float maxDist2 = 0.4f*0.4f;
  
 
// Extract hue and saturation bands which are independent of intensity
 
// Extract hue and saturation bands which are independent of intensity
ImageFloat32 H = hsv.getBand(0);
+
GrayF32 H = hsv.getBand(0);
ImageFloat32 S = hsv.getBand(1);
+
GrayF32 S = hsv.getBand(1);
  
// Adjust the relative importance of Hue and Saturation
+
// Adjust the relative importance of Hue and Saturation.
 +
// Hue has a range of 0 to 2*PI and Saturation from 0 to 1.
 
float adjustUnits = (float)(Math.PI/2.0);
 
float adjustUnits = (float)(Math.PI/2.0);
  
Line 81: Line 77:
 
for( int y = 0; y < hsv.height; y++ ) {
 
for( int y = 0; y < hsv.height; y++ ) {
 
for( int x = 0; x < hsv.width; x++ ) {
 
for( int x = 0; x < hsv.width; x++ ) {
// remember Hue is an angle in radians, so simple subtraction doesn't work
+
// Hue is an angle in radians, so simple subtraction doesn't work
 
float dh = UtilAngle.dist(H.unsafe_get(x,y),hue);
 
float dh = UtilAngle.dist(H.unsafe_get(x,y),hue);
 
float ds = (S.unsafe_get(x,y)-saturation)*adjustUnits;
 
float ds = (S.unsafe_get(x,y)-saturation)*adjustUnits;
  
// this distance measure is a bit naive, but good enough for this demonstration
+
// this distance measure is a bit naive, but good enough for to demonstrate the concept
 
float dist2 = dh*dh + ds*ds;
 
float dist2 = dh*dh + ds*ds;
 
if( dist2 <= maxDist2 ) {
 
if( dist2 <= maxDist2 ) {
Line 96: Line 92:
 
}
 
}
  
public static void main( String args[] ) {
+
public static void main( String[] args ) {
BufferedImage image = UtilImageIO.loadImage("../data/applet/sunflowers.jpg");
+
BufferedImage image = UtilImageIO.loadImage(UtilIO.pathExample("sunflowers.jpg"));
  
 
// Let the user select a color
 
// Let the user select a color

Latest revision as of 19:37, 21 December 2020

Demonstration for how an image can be segmented using color information. First the image is converted into HSV color space to add robustness against changes in lighting. Then the user selects a color and it selects pixels with a hue and saturation value and display the resulting image.

Example File: ExampleSegmentColor.java

Concepts:

  • Color space
  • Image segmentation

Related Examples:

Example Code

/**
 * Example which demonstrates how color can be used to segment an image.  The color space is converted from RGB into
 * HSV.  HSV separates intensity from color and allows you to search for a specific color based on two values
 * independent of lighting conditions.  Other color spaces are supported, such as YUV, XYZ, and LAB.
 *
 * @author Peter Abeles
 */
public class ExampleSegmentColor {
	/**
	 * Shows a color image and allows the user to select a pixel, convert it to HSV, print
	 * the HSV values, and calls the function below to display similar pixels.
	 */
	public static void printClickedColor( final BufferedImage image ) {
		ImagePanel gui = new ImagePanel(image);
		gui.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				float[] color = new float[3];
				int rgb = image.getRGB(e.getX(),e.getY());
				ColorHsv.rgbToHsv((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, color);
				System.out.println("H = " + color[0]+" S = "+color[1]+" V = "+color[2]);

				showSelectedColor("Selected",image,color[0],color[1]);
			}
		});
		ShowImages.showWindow(gui,"Color Selector");
	}

	/**
	 * Selectively displays only pixels which have a similar hue and saturation values to what is provided.
	 * This is intended to be a simple example of color based segmentation.  Color based segmentation can be done
	 * in RGB color, but is more problematic due to it not being intensity invariant.  More robust techniques
	 * can use Gaussian models instead of a uniform distribution, as is done below.
	 */
	public static void showSelectedColor( String name , BufferedImage image , float hue , float saturation ) {
		Planar<GrayF32> input = ConvertBufferedImage.convertFromPlanar(image,null,true,GrayF32.class);
		Planar<GrayF32> hsv = input.createSameShape();

		// Convert into HSV
		ColorHsv.rgbToHsv(input,hsv);

		// Euclidean distance squared threshold for deciding which pixels are members of the selected set
		float maxDist2 = 0.4f*0.4f;

		// Extract hue and saturation bands which are independent of intensity
		GrayF32 H = hsv.getBand(0);
		GrayF32 S = hsv.getBand(1);

		// Adjust the relative importance of Hue and Saturation.
		// Hue has a range of 0 to 2*PI and Saturation from 0 to 1.
		float adjustUnits = (float)(Math.PI/2.0);

		// step through each pixel and mark how close it is to the selected color
		BufferedImage output = new BufferedImage(input.width,input.height,BufferedImage.TYPE_INT_RGB);
		for( int y = 0; y < hsv.height; y++ ) {
			for( int x = 0; x < hsv.width; x++ ) {
				// Hue is an angle in radians, so simple subtraction doesn't work
				float dh = UtilAngle.dist(H.unsafe_get(x,y),hue);
				float ds = (S.unsafe_get(x,y)-saturation)*adjustUnits;

				// this distance measure is a bit naive, but good enough for to demonstrate the concept
				float dist2 = dh*dh + ds*ds;
				if( dist2 <= maxDist2 ) {
					output.setRGB(x,y,image.getRGB(x,y));
				}
			}
		}

		ShowImages.showWindow(output,"Showing "+name);
	}

	public static void main( String[] args ) {
		BufferedImage image = UtilImageIO.loadImage(UtilIO.pathExample("sunflowers.jpg"));

		// Let the user select a color
		printClickedColor(image);
		// Display pre-selected colors
		showSelectedColor("Yellow",image,1f,1f);
		showSelectedColor("Green",image,1.5f,0.65f);
	}
}