-1

Hey im trying to create a program which uses Floyd-Steinberg's dithering algorithm to produce a dithered version of a image.

the code for my program is below.

but I believe I am getting an error with with the rounding in the "calculateErr" multiplication with the diviser. the image I am using to test is this cat one: Cat Image

and for some reason it ends up looking like this Dithered cat image

any solutions to what I am doing wrong would be greatly appreciated.

import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class Dithering extends Canvas {
    public BufferedImage ditheredIMG = new BufferedImage(481,480,
            BufferedImage.TYPE_BYTE_GRAY);

public void paint(Graphics g) {
    BufferedImage i = null;
    try {
        i = displayImage(g);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    getPixels(g, i);
    g.drawImage(ditheredIMG,480,0,this);



}
public static void main(String[] args) {
    Dithering d = new Dithering();
    JFrame f =new JFrame();
    f.add(d);
    f.setSize( 960,481);
    f.setVisible(true);
}


public BufferedImage displayImage(Graphics g) throws IOException {
    final File file = new File("Cat.jpg");
    final BufferedImage i = ImageIO.read(file);
    g.drawImage(i, 0,0,this);
    return i;
}

public void getPixels(Graphics g, BufferedImage i) {
    for (int y = 1; y < i.getHeight()-1; y++){
        for (int x = 1; x < i.getWidth()-1; x++) {
            int pixelValue = i.getRGB(x, y);
            int  red   = (pixelValue & 0x00ff0000) >> 16;
            int  green = (pixelValue & 0x0000ff00) >> 8;
            int  blue  =  pixelValue & 0x000000ff;
            int newRed = quantisePixel(red);
            int newGreen = quantisePixel(green);
            int newBlue = quantisePixel(blue);
            int newPixel = (newRed << 16) | (newGreen << 8) | newBlue;

            ditheredIMG.setRGB(x+1,y, (int) (calculateErr(pixelValue, newPixel) * (7/16.0)));
            ditheredIMG.setRGB(x-1,y+1, (int) (calculateErr(pixelValue, newPixel) * (3/16.0)));
            ditheredIMG.setRGB(x,y+1, (int) (calculateErr(pixelValue, newPixel) * (5/16.0)));
            ditheredIMG.setRGB(x+1,y+1, (int) (calculateErr(pixelValue, newPixel)* (1/16.0)));
       
        }
    }
}

public int calculateErr(int oldVal, int newVal){
    return oldVal-newVal;
}

public static int quantisePixel(int val){
    if(val > 127){
        return 255;
    } else{
        return 0;
    }

}

}

  • It looks as though you replace the surrounding pixels with the error term instead of adding it. And what happens in `calculateErr` where there's a component with a negative error? – tgdavies Jun 20 '22 at 06:10

1 Answers1

0

hey so here is the updated version but I am unsure if its working correctly if anyone can tell me if it is or is not that would be greatly appreciated. I've changed it so now its supposed to be updating the surrounding pixels correctly but from my eyes it looks to be the exact same as without updating the neighbours.

import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import static java.lang.Math.abs;

public class Dithering extends Canvas {
public BufferedImage ditheredIMG = new BufferedImage(481,480,
        BufferedImage.TYPE_BYTE_GRAY);

public void paint(Graphics g) {
    BufferedImage i = null;
    try {
        i = displayImage(g);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    getPixels(g, i);
    g.drawImage(ditheredIMG,480,0,this);



}
public static void main(String[] args) {
    Dithering d = new Dithering();
    JFrame f =new JFrame();
    f.add(d);
    f.setSize( 960,481);
    f.setVisible(true);
}


public BufferedImage displayImage(Graphics g) throws IOException {
    final File file = new File("Cat.jpg");
    final BufferedImage i = ImageIO.read(file);
    g.drawImage(i, 0,0,this);
    return i;
}

public void getPixels(Graphics g, BufferedImage i) {
    for (int y = 1; y < i.getHeight()-1; y++){
        for (int x = 1; x < i.getWidth()-1; x++) {
            int pixelValue = i.getRGB(x, y);
            int  red   = (pixelValue & 0x00ff0000) >> 16;
            int  green = (pixelValue & 0x0000ff00) >> 8;
            int  blue  =  pixelValue & 0x000000ff;
            int newRed = quantisePixel(red);
            int newGreen = quantisePixel(green);
            int newBlue = quantisePixel(blue);
            int newPixel = (newRed << 16) | (newGreen << 8) | newBlue;
            ditheredIMG.setRGB(x,y,newPixel);

            int newPixelValue = i.getRGB(x+1,y);
            ditheredIMG.setRGB(x+1,y,      (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (7/16.0)));
            newPixelValue = i.getRGB(x-1,y+1);
            ditheredIMG.setRGB(x-1,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (3/16.0)));
            newPixelValue = i.getRGB(x,y+1);
            ditheredIMG.setRGB(x,y+1,      (int) (newPixelValue + calculateErr(pixelValue, newPixel) * (5/16.0)));
            newPixelValue = i.getRGB(x+1,y+1);
            ditheredIMG.setRGB(x+1,y+1, (int) (newPixelValue + calculateErr(pixelValue, newPixel)* (1/16.0)));


        }
    }
}

public int calculateErr(int oldVal, int newVal){
    return oldVal-newVal;
}

public static int quantisePixel(int val){
    if(val > 127){
        return 255;
    } else{
        return 0;
    }

}

}

  • If this is your latest attempt, but it still does not work, I think the best way is to update the code in *the question*. It's not an *answer* unless it works as expected. That said, I think you need to calculate error per component, not the packed ARGB value. – Harald K Jun 21 '22 at 07:41