Skip to content

Instantly share code, notes, and snippets.

@Brixomatic
Forked from heidisu/App.java
Last active July 24, 2018 20:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Brixomatic/e0961c41219a82aeed3a175c1385f9df to your computer and use it in GitHub Desktop.
Save Brixomatic/e0961c41219a82aeed3a175c1385f9df to your computer and use it in GitHub Desktop.
Haar transform
package haar;
import java.awt.*;
import java.awt.image.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import haar.RGBChannelFilter.Channel;
public class App {
public static void main(final String[] args) {
try {
final HaarTransform haarTransform = new HaarTransform();
final BufferedImage image = ImageIO.read(App.class.getResourceAsStream("Geisha-by-Luca-Tarlazzi-513x640.jpg"));
System.out.println(new Dimension(image.getWidth(), image.getHeight()));
final Image grayScale = convertToGrayScale(image);
final BufferedImage bufferedImage = toBufferedImage(grayScale);
displayImage(bufferedImage);
final double[][] result = haarTransform.transform(imageToMatrix(bufferedImage));
final BufferedImage updated = toImage(result);
displayImage(updated);
} catch (final IOException e) {
e.printStackTrace();
}
}
private static void displayImage(final Image image) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
final JLabel lblimage = new JLabel(new ImageIcon(image));
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(lblimage, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
final JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(lblimage);
frame.add(mainPanel);
frame.setVisible(true);
}
});
}
private static Image convertToGrayScale(final BufferedImage colorImage) {
final ImageFilter filter = new RGBChannelFilter(Channel.Red);
final ImageProducer producer = new FilteredImageSource(colorImage.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(producer);
}
private static BufferedImage toBufferedImage(final Image img) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
}
final BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
final Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
return bimage;
}
private static double[][] imageToMatrix(final BufferedImage image) {
final Dimension dim = new Dimension(image.getWidth() / 2 * 2, image.getHeight() / 2 * 2); // dimension must be even
final double[][] matrix = new double[dim.width][dim.height];
for (int y = 0; y < dim.height; y++) { // height must be even
for (int x = 0; x < dim.width; x++) { // width must be even
matrix[x][y] = getPixel(image, x, y);
}
}
return matrix;
}
private static int getPixel(final BufferedImage image, final int x, final int y) {
final int clr = image.getRGB(x, y);
return clr & 0x000000ff;
}
private static BufferedImage toImage(final double[][] transform) {
final Dimension dim = new Dimension(transform.length, transform[0].length); // dimension must be even
final BufferedImage image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < dim.height; ++y) {
for (int x = 0; x < dim.width; ++x) {
int value = (int) transform[x][y];
value = value < 0 ? 255 + value : value;
final Color color = new Color(value, value, value);
image.setRGB(x, y, color.getRGB());
}
}
return image;
}
}
package haar;
public class HaarTransform {
public double[][] transform(final double[][] input) {
return transformRows(transformColumns(input));
}
private static double[][] transformColumns(final double[][] input) {
final int width = input.length;
final int height = input[0].length;
final double[][] result = new double[width][height];
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width / 2; ++x) {
result[x][y] = (input[2 * x][y] + input[2 * x + 1][y]) / 2.0;
result[width / 2 + x][y] = (input[2 * x][y] - input[2 * x + 1][y]) / 2.0;
}
}
return result;
}
private static double[][] transformRows(final double[][] input) {
final int width = input.length;
final int height = input[0].length;
final double[][] result = new double[width][height];
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height / 2; ++y) {
result[x][y] = (input[x][2 * y] + input[x][2 * y + 1]) / 2.0;
result[x][height / 2 + y] = (input[x][2 * y] - input[x][2 * y + 1]) / 2.0;
}
}
return result;
}
}
package haar;
import java.awt.Color;
import java.awt.image.RGBImageFilter;
/**
* @author Wanja Gayk
*/
public class RGBChannelFilter extends RGBImageFilter {
private final Channel channel;
public static enum Channel {
Alpha {
@Override
int extract(final int rgb) {
return rgb >> 24 & 0xFF;
}
},
Red {
@Override
int extract(final int rgb) {
return rgb >> 16 & 0xFF;
}
},
Green {
@Override
int extract(final int rgb) {
return rgb >> 8 & 0xFF;
}
},
Blue {
@Override
int extract(final int rgb) {
return rgb & 0xFF;
}
};
abstract int extract(final int rgb);
};
public RGBChannelFilter(final Channel channel) {
// canFilterIndexColorModel indicates whether or not it is acceptable
// to apply the color filtering of the filterRGB method to the color
// table entries of an IndexColorModel object in lieu of pixel by pixel
// filtering.
canFilterIndexColorModel = true;
this.channel = channel;
}
@SuppressWarnings("unused")
@Override
public int filterRGB(final int x, final int y, final int rgb) {
final int channelValue = channel.extract(rgb);
return new Color(channelValue, channelValue, channelValue).getRGB();
}
}
@Brixomatic
Copy link
Author

Changes:

  • fixed flaw that images had to be square and of even width and height - now rectangular shapes of uneven size work (one pixel column/row gets truncated if necessary).
  • instead of gray-scaling with pixel boost, create a gray scale image from one channel (red, green, blue or alpha).
  • fixed bug that closing window didn't stop application
  • fixed bug that Swing components were not created in the Event Dispatching Thread
  • made the code easier to read by using "x" , "y", "width" and "height", instead of indexes "i" and "j".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment