2

What I'm trying to do is to compute 2D DCT of an image in Java and then save the result back to file.

Read file:

coverImage = readImg(coverPath);
private BufferedImage readImg(String path) {

        BufferedImage destination = null;

        try {

            destination = ImageIO.read(new File(path));

        } catch (IOException e) {

            e.printStackTrace();

        }

        return destination;

    }

Convert to float array:

cover = convertToFloatArray(coverImage);
private float[] convertToFloatArray(BufferedImage source) {

        securedImage = (WritableRaster) source.getData();

        float[] floatArray = new float[source.getHeight() * source.getWidth()];
        floatArray = securedImage.getPixels(0, 0, source.getWidth(), source.getHeight(), floatArray);

        return floatArray;

    }

Run the DCT:

runDCT(cover, coverImage.getHeight(), coverImage.getWidth());
private void runDCT(float[] floatArray, int rows, int cols) {

        dct = new FloatDCT_2D(rows, cols);

        dct.forward(floatArray, false);

        securedImage.setPixels(0, 0, cols, rows, floatArray); 

    }

And then save it as image:

convertDctToImage(securedImage, coverImage.getHeight(), coverImage.getWidth());
private void convertDctToImage(WritableRaster secured, int rows, int cols) {

        coverImage.setData(secured);

        File file = new File(securedPath);
        try {
            ImageIO.write(coverImage, "png", file);
        } catch (IOException ex) {
            Logger.getLogger(DCT2D.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

But what I get is: http://kyle.pl/up/2012/05/29/dct_stack.png

Can anyone tell me what I'm doing wrong? Or maybe I don't understand something here?

Filburt
  • 17,626
  • 12
  • 64
  • 115
Kyle
  • 184
  • 2
  • 13

1 Answers1

0

This is a piece of code, that works for me:

//reading image
BufferedImage image = javax.imageio.ImageIO.read(new File(filename));

//width * 2, because DoubleFFT_2D needs 2x more space - for Real and Imaginary parts of complex numbers
double[][] brightness = new double[img.getHeight()][img.getWidth() * 2];

//convert colored image to grayscale (brightness of each pixel)
for ( int y = 0; y < image.getHeight(); y++ ) {
    raster.getDataElements( 0, y, image.getWidth(), 1, dataElements );
    for ( int x = 0; x < image.getWidth(); x++ ) {
        //notice x and y swapped - it's JTransforms format of arrays
        brightness[y][x] = brightnessRGB(dataElements[x]);
    }
}

//do FT (not FFT, because FFT is only* for images with width and height being 2**N)
//DoubleFFT_2D writes data to the same array - to brightness
new DoubleFFT_2D(img.getHeight(), img.getWidth()).realForwardFull(brightness);

//visualising frequency domain
BufferedImage fd = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
outRaster = fd.getRaster();
for ( int y = 0; y < img.getHeight(); y++ ) {
    for ( int x = 0; x < img.getWidth(); x++ ) {
        //we calculate complex number vector length (sqrt(Re**2 + Im**2)). But these lengths are to big to
        //fit in 0 - 255 scale of colors. So I divide it on 223. Instead of "223", you may want to choose
        //another factor, wich would make you frequency domain look best
        int power = (int) (Math.sqrt(Math.pow(brightness[y][2 * x], 2) + Math.pow(brightness[y][2 * x + 1], 2)) / 223);
        power = power > 255 ? 255 : power;
        //draw a grayscale color on image "fd"
        fd.setRGB(x, y, new Color(c, c, c).getRGB());
    }
}

draw(fd);

Resulting image should look like big black space in the middle and white spots in all four corners. Usually people visualise FD so, that zero frequency appears in the center of the image. So, if you need classical FD (one, that looks like star for reallife images), you need to upgrade "fd.setRGB(x, y..." a bit:

int w2 = img.getWidth() / 2;
int h2 = img.getHeight() / 2;
int newX = x + w2 >= img.getWidth() ? x - w2  : x + w2;
int newY = y + h2 >= img.getHeight() ? y - h2  : y + h2;

fd.setRGB(newX, newY, new Color(power, power, power).getRGB());

brightnessRGB and draw methods for the lazy:

public static int brightnessRGB(int rgb) {
    int r = (rgb >> 16) & 0xff;
    int g = (rgb >> 8) & 0xff;
    int b = rgb & 0xff;
    return (r+g+b)/3;
}
private static void draw(BufferedImage img) {
    JLabel picLabel = new JLabel(new ImageIcon(img));
    JPanel jPanelMain = new JPanel();
    jPanelMain.add(picLabel);
    JFrame jFrame = new JFrame();
    jFrame.add(jPanelMain);
    jFrame.pack();
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jFrame.setVisible(true);
}

I know, I'm a bit late, but I just did all that for my program. So, let it be here for those, who'll get here from googling.

Oroboros102
  • 2,214
  • 1
  • 27
  • 41