/*
* Copyright (c) 2011-2016, 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.struct.image.GrayS32;
import boofcv.struct.image.GrayU8;
import georegression.struct.point.Point2D_I32;
import sun.awt.image.ByteInterleavedRaster;
import sun.awt.image.IntegerInterleavedRaster;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Random;
/**
* @author Peter Abeles
*/
public class VisualizeBinaryData {
public static BufferedImage renderContours( List<EdgeContour> edges , int colors[] ,
int width , int height , 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<Contour> contours , int colorExternal, int colorInternal ,
int width , int height , 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<Point2D_I32> 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<Contour> contours , int colorExternal[], int colorInternal ,
int width , int height , 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<Point2D_I32> 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 List of contours
* @param colors List of RGB colors for each element in contours. If null then random colors will be used.
* @param out (Optional) Storage for output
*/
public static void render(List<Contour> contours , int colors[] , BufferedImage out) {
colors = checkColors(colors,contours.size());
for( Contour c : contours ) {
int color = colors[c.id-1];
for(Point2D_I32 p : c.external ) {
out.setRGB(p.x,p.y,color);
}
}
}
public static int[] checkColors( 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<Contour> 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<Contour> contours , Color internal , Color external , 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) scale)));
for( Contour c : contours ) {
if( external != null) {
g2.setColor(external);
renderContour(scale, g2, l, c.external);
}
if( internal != null) {
g2.setColor(internal);
for (List<Point2D_I32> inner : c.internal) {
renderContour(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 ) {
renderContour(scale, g2, l, c.external);
}
if( internal != null) {
for (List<Point2D_I32> inner : c.internal) {
renderContour(scale, g2, l, inner);
}
}
}
g2.setColor(before);
}
}
private static void renderContour(double scale, Graphics2D g2, Line2D.Double l, List<Point2D_I32> 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);
}
}
public static BufferedImage renderLabeled(GrayS32 labelImage, int colors[], BufferedImage out) {
if( out == null ) {
out = new BufferedImage(labelImage.getWidth(),labelImage.getHeight(),BufferedImage.TYPE_INT_RGB);
}
try {
if( out.getRaster() instanceof IntegerInterleavedRaster) {
renderLabeled(labelImage, colors, (IntegerInterleavedRaster)out.getRaster());
} 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, 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, 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, IntegerInterleavedRaster raster) {
int rasterIndex = 0;
int data[] = raster.getDataStorage();
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, BufferedImage out) {
if( out == null ) {
out = new BufferedImage(binaryImage.getWidth(),binaryImage.getHeight(),BufferedImage.TYPE_BYTE_GRAY);
}
try {
if( out.getRaster() instanceof ByteInterleavedRaster ) {
renderBinary(binaryImage, invert, (ByteInterleavedRaster) out.getRaster());
} else if( out.getRaster() instanceof IntegerInterleavedRaster ) {
renderBinary(binaryImage, invert, (IntegerInterleavedRaster) out.getRaster());
} 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, ByteInterleavedRaster raster) {
int rasterIndex = 0;
byte data[] = raster.getDataStorage();
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) ((1 - binaryImage.data[indexSrc++]) * 255);
}
}
} 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++] * 255);
}
}
}
} else {
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) ((1 - binaryImage.data[indexSrc++]) * 255);
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++] * 255);
for (int i = 0; i < numBands; i++) {
data[rasterIndex++] = val;
}
}
}
}
}
}
private static void renderBinary(GrayU8 binaryImage, boolean invert, IntegerInterleavedRaster raster) {
int rasterIndex = 0;
int data[] = raster.getDataStorage();
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;
}
}
}
}
}