package edu.berkeley.cs.nlp.ocular.image; import edu.berkeley.cs.nlp.ocular.image.ImageUtils.PixelType; import java.awt.Color; import java.awt.image.BufferedImage; import java.util.Arrays; import java.util.List; import edu.berkeley.cs.nlp.ocular.preprocessing.VerticalProfile.VerticalSegmentation; /** * @author Taylor Berg-Kirkpatrick (tberg@eecs.berkeley.edu) */ public class Visualizer { public static BufferedImage renderObservationsAndSegmentation(PixelType[][][] observations, List<Integer>[] boundaries) { int[][][] rgbImage = convertToThresholdedRgb(observations, Color.BLACK.getRGB(), Color.RED.getRGB(), Color.WHITE.getRGB()); overlaySegmentationBoundaries(rgbImage, boundaries); return ImageUtils.makeRgbImage(combineLinesRGB(rgbImage)); } public static BufferedImage renderBlackProbs(double[][][] blackProbs) { return ImageUtils.makeRgbImage(combineLinesRGB(convertBlackProbsToRgb(blackProbs))); } public static BufferedImage renderObservations(PixelType[][][] observations) { int[][][] rgbImage = convertToThresholdedRgb(observations, Color.BLACK.getRGB(), Color.RED.getRGB(), Color.WHITE.getRGB()); return ImageUtils.makeRgbImage(combineLinesRGB(rgbImage)); } public static BufferedImage renderBlackProbsAndSegmentation(double[][][] blackProbs, List<Integer>[] boundaries) { int[][][] rgbImage = convertBlackProbsToRgb(blackProbs); overlaySegmentationBoundaries(rgbImage, boundaries); return ImageUtils.makeRgbImage(combineLinesRGB(rgbImage)); } public static BufferedImage renderOverlay(PixelType[][][] observations, double[][][] blackProbs, List<Integer>[] boundaries) { int[][][] rgbImage = convertToThresholdedRgb(observations, Color.BLUE.getRGB(), Color.RED.getRGB(), Color.BLACK.getRGB()); overlayBlackProbabilities(rgbImage, blackProbs); overlaySegmentationBoundaries(rgbImage, boundaries); return ImageUtils.makeRgbImage(combineLinesRGB(rgbImage)); } public static BufferedImage renderLineExtraction(PixelType[][][] observations) { int maxWidth = 0; for (PixelType[][] line : observations) { maxWidth = Math.max(maxWidth, line.length); } int[][] rgbSpace = new int[maxWidth][observations[0][0].length]; for (int w=0; w<maxWidth; ++w) Arrays.fill(rgbSpace[w], Color.LIGHT_GRAY.getRGB()); int[][][] rgbLines = convertToThresholdedRgb(observations, Color.BLACK.getRGB(), Color.GRAY.getRGB(), Color.WHITE.getRGB()); int[][][] rgbSpacedLines = new int[rgbLines.length*2][maxWidth][10]; for (int line=0; line<rgbLines.length; ++line) { rgbSpacedLines[2*line] = rgbLines[line]; rgbSpacedLines[2*line+1] = rgbSpace; } return ImageUtils.makeRgbImage(combineLinesRGB(rgbSpacedLines)); } public static BufferedImage renderLineExtraction(PixelType[][] line) { int[][] rgbLine = convertToThresholdedRgb(new PixelType[][][]{ line }, Color.BLACK.getRGB(), Color.GRAY.getRGB(), Color.WHITE.getRGB())[0]; return ImageUtils.makeRgbImage(rgbLine); } public static BufferedImage renderLineExtraction(double[][] levels, VerticalSegmentation segmentation) { int[][] rgbImage = new int[levels.length][levels[0].length]; for (int i = 0; i < levels.length; i++) { for (int j = 0; j < levels[i].length; j++) { if (ImageUtils.getPixelType(levels[i][j]) == PixelType.BLACK) { switch (segmentation.getType(j)) { case ASCENDER: rgbImage[i][j] = Color.BLUE.getRGB(); break; case BASE: rgbImage[i][j] = Color.BLACK.getRGB(); break; case DESCENDER: rgbImage[i][j] = Color.RED.getRGB(); break; default: throw new RuntimeException("Unrecognized type: " + segmentation.getType(j)); } } else { switch (segmentation.getType(j)) { case ASCENDER: rgbImage[i][j] = Color.WHITE.getRGB(); break; case BASE: rgbImage[i][j] = Color.WHITE.getRGB(); break; case DESCENDER: rgbImage[i][j] = Color.LIGHT_GRAY.getRGB(); break; default: throw new RuntimeException("Unrecognized type: " + segmentation.getType(j)); } } } } return ImageUtils.makeRgbImage(rgbImage); } private static int[][][] convertToThresholdedRgb(PixelType[][][] observations, int blackColorRgb, int unobservedColorRgb, int whiteColorRgb) { int[][][] rgbImage = new int[observations.length][][]; for (int i=0; i<observations.length; ++i) { rgbImage[i] = new int[observations[i].length][]; for (int j=0; j<observations[i].length; ++j) { rgbImage[i][j] = new int[observations[i][j].length]; for (int k=0; k<observations[i][j].length; ++k) { if (observations[i][j][k] == PixelType.BLACK) { rgbImage[i][j][k] = blackColorRgb; } else if (observations[i][j][k] == PixelType.WHITE) { rgbImage[i][j][k] = whiteColorRgb; } else { rgbImage[i][j][k] = unobservedColorRgb; } } } } return rgbImage; } private static int[][][] convertBlackProbsToRgb(double[][][] probs) { int[][][] newImage = new int[probs.length][][]; for (int i=0; i<probs.length; ++i) { newImage[i] = new int[probs[i].length][]; for (int j=0; j<probs[i].length; ++j) { newImage[i][j] = new int[probs[i][j].length]; for (int k=0; k<probs[i][j].length; ++k) { int val = (int) (255 * (1.0 - probs[i][j][k])); newImage[i][j][k] = (new Color(val, val, val)).getRGB(); } } } return newImage; } private static void overlaySegmentationBoundaries(int[][][] image, List<Integer>[] boundaries) { for (int d=0; d<image.length; ++d) { List<Integer> boundariesThisLine = boundaries[d]; for (int i=0; i<boundariesThisLine.size(); ++i) { int boundary = boundariesThisLine.get(i); for (int h=0; h<image[d][0].length; ++h) { Color cur = new Color(image[d][boundary][h]); image[d][boundary][h] = (new Color((int) (Math.min(255, (cur.getRed()+50))*0.5), (int) Math.min(255, cur.getGreen()+50), (int) (Math.min(255, (cur.getBlue()+50))*0.5))).getRGB(); } } } } private static void overlayBlackProbabilities(int[][][] image, double[][][] blackProbs) { for (int i=0; i<image.length; ++i) { for (int j=0; j<image[i].length; ++j) { for (int k=0; k<image[i][j].length; ++k) { // Swap out the redness component of the image with a redness component // proportional to the amount of black in the image int redness = (int)(blackProbs[i][j][k] * ImageUtils.MAX_LEVEL); image[i][j][k] = (image[i][j][k] & 0xFF00FFFF) | (redness << 16); } } } } private static int[][] combineLinesRGB(int[][][] imageByLine) { int lineHeight = imageByLine[0][0].length; int linesHeight = imageByLine.length * lineHeight; int longestLineLength = 0; for (int d=0; d<imageByLine.length; ++d) { longestLineLength = Math.max(longestLineLength, imageByLine[d].length); } int[][] combinedLines = new int[longestLineLength][linesHeight]; for (int d=0; d<imageByLine.length; ++d) { for (int w=0; w<combinedLines.length; ++w) { int verticalOffset = d * lineHeight; for (int h=0; h<lineHeight; ++h) { // If we're still writing the line if (w<imageByLine[d].length) { combinedLines[w][h+verticalOffset] = imageByLine[d][w][h]; } else { combinedLines[w][h+verticalOffset] = Color.LIGHT_GRAY.getRGB(); } } } } return combinedLines; } }