All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.gui.binary.VisualizeBinaryData Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

There is a newer version: 1.1.7
Show newest version
/*
 * Copyright (c) 2022, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.gui.binary;

import boofcv.alg.feature.detect.edge.EdgeContour;
import boofcv.alg.feature.detect.edge.EdgeSegment;
import boofcv.alg.filter.binary.Contour;
import boofcv.gui.BoofSwingUtil;
import boofcv.struct.image.GrayS32;
import boofcv.struct.image.GrayU8;
import georegression.struct.point.Point2D_I32;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.image.*;
import java.util.List;
import java.util.Random;

/**
 * Operations for visualizing binary images and related data structures.
 *
 * @author Peter Abeles
 */
public class VisualizeBinaryData {
	public static BufferedImage renderContours( List edges,
												@Nullable int[] colors,
												int width, int height,
												@Nullable BufferedImage out ) {
		if (out == null) {
			out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		} else {
			Graphics2D g2 = out.createGraphics();
			g2.setColor(Color.BLACK);
			g2.fillRect(0, 0, width, height);
		}

		colors = checkColors(colors, edges.size());

		for (int i = 0; i < edges.size(); i++) {
			EdgeContour e = edges.get(i);
			int color = colors[i];

			for (EdgeSegment s : e.segments) {
				for (Point2D_I32 p : s.points) {
					out.setRGB(p.x, p.y, color);
				}
			}
		}

		return out;
	}

	/**
	 * Draws contours. Internal and external contours are different user specified colors.
	 *
	 * @param contours List of contours
	 * @param colorExternal RGB color
	 * @param colorInternal RGB color
	 * @param width Image width
	 * @param height Image height
	 * @param out (Optional) storage for output image
	 * @return Rendered contours
	 */
	public static BufferedImage renderContours( List contours, int colorExternal, int colorInternal,
												int width, int height, @Nullable BufferedImage out ) {
		if (out == null) {
			out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		} else {
			Graphics2D g2 = out.createGraphics();
			g2.setColor(Color.BLACK);
			g2.fillRect(0, 0, width, height);
		}

		for (Contour c : contours) {
			for (Point2D_I32 p : c.external) {
				out.setRGB(p.x, p.y, colorExternal);
			}
			for (List l : c.internal) {
				for (Point2D_I32 p : l) {
					out.setRGB(p.x, p.y, colorInternal);
				}
			}
		}

		return out;
	}

	/**
	 * Draws contours. Internal and external contours are different user specified colors.
	 *
	 * @param contours List of contours
	 * @param colorExternal (Optional) Array of RGB colors for each external contour
	 * @param colorInternal RGB color
	 * @param width Image width
	 * @param height Image height
	 * @param out (Optional) storage for output image
	 * @return Rendered contours
	 */
	public static BufferedImage renderContours( List contours,
												@Nullable int[] colorExternal, int colorInternal,
												int width, int height, @Nullable BufferedImage out ) {
		if (out == null) {
			out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		} else {
			Graphics2D g2 = out.createGraphics();
			g2.setColor(Color.BLACK);
			g2.fillRect(0, 0, width, height);
		}

		colorExternal = checkColors(colorExternal, contours.size());

		int index = 0;
		for (Contour c : contours) {
			int color = colorExternal[index++];
			for (Point2D_I32 p : c.external) {
				out.setRGB(p.x, p.y, color);
			}
			for (List l : c.internal) {
				for (Point2D_I32 p : l) {
					out.setRGB(p.x, p.y, colorInternal);
				}
			}
		}

		return out;
	}

	/**
	 * Renders only the external contours. Each contour is individually colored as specified by 'colors'
	 *
	 * @param contours (Input) List of contours
	 * @param colors (Input) List of RGB colors for each element in contours. If null then random colors will be used.
	 * @param out (Output) Where the contours are rendered.
	 */
	public static void render( List contours, int[] colors, BufferedImage out ) {
		colors = checkColors(colors, contours.size());

		for (int i = 0; i < contours.size(); i++) {
			Contour c = contours.get(i);
			int color = colors[i];

			for (Point2D_I32 p : c.external) {
				out.setRGB(p.x, p.y, color);
			}
		}
	}

	public static int[] checkColors( @Nullable int[] colors, int size ) {
		if (colors == null) {
			colors = new int[size];
			Random rand = new Random(123);
			for (int i = 0; i < size; i++) {
				colors[i] = rand.nextInt();
			}
		}
		return colors;
	}

	public static BufferedImage render( List contours, Color color, BufferedImage out ) {
		for (Contour c : contours) {
			for (Point2D_I32 p : c.external) {
				out.setRGB(p.x, p.y, color.getRGB());
			}
		}

		return out;
	}

	public static void render( List> contours, boolean loops,
							   Color color, double stroke, double scale, Graphics2D g2 ) {
		BoofSwingUtil.antialiasing(g2);

		Line2D.Double l = new Line2D.Double();

		g2.setStroke(new BasicStroke(Math.max(1, (float)(stroke*scale))));
		g2.setColor(color);
		for (List c : contours) {
			if (loops)
				renderLoop(scale, g2, l, c);
			else
				renderLine(scale, g2, l, c);
		}

		if (scale > 4) {
			Color before = g2.getColor();
			g2.setStroke(new BasicStroke(1));
			g2.setColor(Color.LIGHT_GRAY);

			for (List c : contours) {
				if (loops)
					renderLoop(scale, g2, l, c);
				else
					renderLine(scale, g2, l, c);
			}

			g2.setColor(before);
		}
	}

	public static void render( List contours, @Nullable Color internal, @Nullable Color external,
							   double stroke, double scale, Graphics2D g2 ) {
		g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

		Line2D.Double l = new Line2D.Double();

		g2.setStroke(new BasicStroke(Math.max(1, (float)(stroke*scale))));
		for (Contour c : contours) {

			if (external != null) {
				g2.setColor(external);
				renderLoop(scale, g2, l, c.external);
			}

			if (internal != null) {
				g2.setColor(internal);
				for (List inner : c.internal) {
					renderLoop(scale, g2, l, inner);
				}
			}
		}

		if (scale > 4) {
			Color before = g2.getColor();
			g2.setStroke(new BasicStroke(1));
			g2.setColor(Color.LIGHT_GRAY);

			for (Contour c : contours) {
				if (external != null) {
					renderLoop(scale, g2, l, c.external);
				}

				if (internal != null) {
					for (List inner : c.internal) {
						renderLoop(scale, g2, l, inner);
					}
				}
			}
			g2.setColor(before);
		}
	}

	private static void renderLoop( double scale, Graphics2D g2, Line2D.Double l, List list ) {
		for (int i = 0, j = list.size() - 1; i < list.size(); j = i, i++) {
			Point2D_I32 p0 = list.get(i);
			Point2D_I32 p1 = list.get(j);

			// draw it in the middle
			l.setLine((p0.x + 0.5)*scale, (p0.y + 0.5)*scale, (p1.x + 0.5)*scale, (p1.y + 0.5)*scale);
			g2.draw(l);
		}
	}

	private static void renderLine( double scale, Graphics2D g2, Line2D.Double l, List list ) {
		for (int i = 1, j = 0; i < list.size(); j = i, i++) {
			Point2D_I32 p0 = list.get(i);
			Point2D_I32 p1 = list.get(j);

			// draw it in the middle
			l.setLine((p0.x + 0.5)*scale, (p0.y + 0.5)*scale, (p1.x + 0.5)*scale, (p1.y + 0.5)*scale);
			g2.draw(l);
		}
	}

	public static BufferedImage renderLabeled( GrayS32 labelImage, int[] colors, @Nullable BufferedImage out ) {

		if (out == null) {
			out = new BufferedImage(labelImage.getWidth(), labelImage.getHeight(), BufferedImage.TYPE_INT_RGB);
		}

		WritableRaster raster = out.getRaster();
		DataBuffer buffer = raster.getDataBuffer();
		try {

			if (buffer.getDataType() == DataBuffer.TYPE_INT) {
				renderLabeled(labelImage, colors, (DataBufferInt)buffer);
			} else {
				_renderLabeled(labelImage, out, colors);
			}
			// hack so that it knows the image has been modified
			out.setRGB(0, 0, out.getRGB(0, 0));
		} catch (SecurityException e) {
			_renderLabeled(labelImage, out, colors);
		}
		return out;
	}

	/**
	 * Renders a labeled image where label=0 is assumed to be the background and is always set to black. All
	 * other labels are assigned a random color.
	 *
	 * @param labelImage Labeled image with background having a value of 0
	 * @param numRegions Number of labeled in the image, excluding the background.
	 * @param out Output image. If null a new image is declared
	 * @return Colorized labeled image
	 */
	public static BufferedImage renderLabeledBG( GrayS32 labelImage, int numRegions, @Nullable BufferedImage out ) {

		int[] colors = new int[numRegions + 1];

		Random rand = new Random(123);
		for (int i = 0; i < colors.length; i++) {
			colors[i] = rand.nextInt();
		}
		colors[0] = 0;

		return renderLabeled(labelImage, colors, out);
	}

	/**
	 * Renders a labeled where each region is assigned a random color.
	 *
	 * @param labelImage Labeled image with labels from 0 to numRegions-1
	 * @param numRegions Number of labeled in the image
	 * @param out Output image. If null a new image is declared
	 * @return Colorized labeled image
	 */
	public static BufferedImage renderLabeled( GrayS32 labelImage, int numRegions, @Nullable BufferedImage out ) {

		int[] colors = new int[numRegions];

		Random rand = new Random(123);
		for (int i = 0; i < colors.length; i++) {
			colors[i] = rand.nextInt();
		}

		return renderLabeled(labelImage, colors, out);
	}

	private static void _renderLabeled( GrayS32 labelImage, BufferedImage out, int[] colors ) {
		int w = labelImage.getWidth();
		int h = labelImage.getHeight();

		for (int y = 0; y < h; y++) {
			int indexSrc = labelImage.startIndex + y*labelImage.stride;
			for (int x = 0; x < w; x++) {
				int rgb = colors[labelImage.data[indexSrc++]];
				out.setRGB(x, y, rgb);
			}
		}
	}

	private static void renderLabeled( GrayS32 labelImage, int[] colors, DataBufferInt buffer ) {
		int rasterIndex = 0;
		int[] data = buffer.getData();

		int w = labelImage.getWidth();
		int h = labelImage.getHeight();

		for (int y = 0; y < h; y++) {
			int indexSrc = labelImage.startIndex + y*labelImage.stride;
			for (int x = 0; x < w; x++) {
				data[rasterIndex++] = colors[labelImage.data[indexSrc++]];
			}
		}
	}

	/**
	 * Renders a binary image. 0 = black and 1 = white.
	 *
	 * @param binaryImage (Input) Input binary image.
	 * @param invert (Input) if true it will invert the image on output
	 * @param out (Output) optional storage for output image
	 * @return Output rendered binary image
	 */
	public static BufferedImage renderBinary( GrayU8 binaryImage, boolean invert, @Nullable BufferedImage out ) {

		if (out == null || (out.getWidth() != binaryImage.width || out.getHeight() != binaryImage.height)) {
			out = new BufferedImage(binaryImage.getWidth(), binaryImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
		}

		try {
			WritableRaster raster = out.getRaster();
			DataBuffer buffer = raster.getDataBuffer();
			if (buffer.getDataType() == DataBuffer.TYPE_BYTE) {
				_renderBinary(binaryImage, invert, (DataBufferByte)buffer, raster);
			} else if (buffer.getDataType() == DataBuffer.TYPE_INT) {
				_renderBinary(binaryImage, invert, (DataBufferInt)buffer);
			} else {
				_renderBinary(binaryImage, invert, out);
			}
		} catch (SecurityException e) {
			_renderBinary(binaryImage, invert, out);
		}
		// hack so that it knows the buffer has been modified
		out.setRGB(0, 0, out.getRGB(0, 0));
		return out;
	}

	private static void _renderBinary( GrayU8 binaryImage, boolean invert, BufferedImage out ) {
		int w = binaryImage.getWidth();
		int h = binaryImage.getHeight();

		if (invert) {
			for (int y = 0; y < h; y++) {
				int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
				for (int x = 0; x < w; x++) {
					int rgb = binaryImage.data[indexSrc++] != 0 ? 0 : 0x00FFFFFF;
					out.setRGB(x, y, rgb);
				}
			}
		} else {
			for (int y = 0; y < h; y++) {
				int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
				for (int x = 0; x < w; x++) {
					int rgb = binaryImage.data[indexSrc++] != 0 ? 0x00FFFFFF : 0;
					out.setRGB(x, y, rgb);
				}
			}
		}
	}

	private static void _renderBinary( GrayU8 binaryImage, boolean invert,
									   DataBufferByte buffer, WritableRaster raster ) {
		int rasterIndex = 0;
		byte[] data = buffer.getData();

		int w = binaryImage.getWidth();
		int h = binaryImage.getHeight();

		int numBands = raster.getNumBands();
		if (numBands == 1) {
			if (invert) {
				for (int y = 0; y < h; y++) {
					int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
					for (int x = 0; x < w; x++) {
						data[rasterIndex++] = (byte)(binaryImage.data[indexSrc++] == 0 ? 255 : 0);
					}
				}
			} else {
				for (int y = 0; y < h; y++) {
					int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
					for (int x = 0; x < w; x++) {
						data[rasterIndex++] = (byte)(binaryImage.data[indexSrc++] == 0 ? 0 : 255);
					}
				}
			}
		} else if (numBands == 3) {
			if (invert) {
				for (int y = 0; y < h; y++) {
					int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
					for (int x = 0; x < w; x++) {
						byte val = (byte)(binaryImage.data[indexSrc++] == 0 ? 255 : 0);
						for (int i = 0; i < numBands; i++) {
							data[rasterIndex++] = val;
						}
					}
				}
			} else {
				for (int y = 0; y < h; y++) {
					int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
					for (int x = 0; x < w; x++) {
						byte val = (byte)(binaryImage.data[indexSrc++] == 0 ? 0 : 255);
						for (int i = 0; i < numBands; i++) {
							data[rasterIndex++] = val;
						}
					}
				}
			}
		} else if (numBands == 4) {
			if (invert) {
				for (int y = 0; y < h; y++) {
					int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
					for (int x = 0; x < w; x++) {
						byte val = (byte)(binaryImage.data[indexSrc++] == 0 ? 255 : 0);
						data[rasterIndex++] = (byte)0xFF;
						for (int i = 1; i < 4; i++) {
							data[rasterIndex++] = val;
						}
					}
				}
			} else {
				for (int y = 0; y < h; y++) {
					int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
					for (int x = 0; x < w; x++) {
						byte val = (byte)(binaryImage.data[indexSrc++] == 0 ? 0 : 255);
						data[rasterIndex++] = (byte)0xFF;
						for (int i = 1; i < 4; i++) {
							data[rasterIndex++] = val;
						}
					}
				}
			}
		}
	}

	private static void _renderBinary( GrayU8 binaryImage, boolean invert, DataBufferInt buffer ) {
		int rasterIndex = 0;
		int[] data = buffer.getData();

		int w = binaryImage.getWidth();
		int h = binaryImage.getHeight();

		if (invert) {
			for (int y = 0; y < h; y++) {
				int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
				for (int x = 0; x < w; x++) {
					data[rasterIndex++] = binaryImage.data[indexSrc++] != 0 ? 0 : 0xFFFFFFFF;
				}
			}
		} else {
			for (int y = 0; y < h; y++) {
				int indexSrc = binaryImage.startIndex + y*binaryImage.stride;
				for (int x = 0; x < w; x++) {
					data[rasterIndex++] = binaryImage.data[indexSrc++] != 0 ? 0xFFFFFFFF : 0;
				}
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy