Skip to content

Instantly share code, notes, and snippets.

@Brixomatic Brixomatic/App.java forked from heidisu/App.java
Last active Jul 24, 2018

Embed
What would you like to do?
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

This comment has been minimized.

Copy link
Owner Author

commented Jul 24, 2018

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
You can’t perform that action at this time.