Floyd-Steinberg算法的Java实现

Floyd-Steinberg算法的Java实现,java,algorithm,image-processing,java-2d,Java,Algorithm,Image Processing,Java 2d,我试图用Java实现Floyd Steinberg算法,使用Java.awt.image.BuffereImage 我已经使用了描述的算法 使用自定义调色板,我希望得到与wikipedia示例(或由Gimp生成的示例)大致相同的图像,但我得到的是一个非常不同的版本 你可以看到我得到了什么 我显然遗漏了一些东西(输出图像的颜色不属于我的调色板),但我不知道是什么 我做错了什么 代码如下: 导入javax.imageio.imageio; 导入java.awt.*; 导入java.awt.ima

我试图用Java实现Floyd Steinberg算法,使用Java.awt.image.BuffereImage

我已经使用了描述的算法 使用自定义调色板,我希望得到与wikipedia示例(或由Gimp生成的示例)大致相同的图像,但我得到的是一个非常不同的版本

你可以看到我得到了什么

我显然遗漏了一些东西(输出图像的颜色不属于我的调色板),但我不知道是什么

我做错了什么

代码如下:

导入javax.imageio.imageio;
导入java.awt.*;
导入java.awt.image.buffereImage;
导入java.awt.image.IndexColorModel;
导入java.io.File;
导入java.io.IOException;
公共类FloydSteinbergTest{
专用静态最终颜色[]调色板=新颜色[]{
新颜色(221221221221),
新颜色(19、125、62),
新颜色(179,80,188),
新颜色(107138201),
新颜色(177166 39),
新颜色(6517456),
新颜色(208、132、153),
新颜色(64,64,64),
新颜色(154161161),
新颜色(46110137),
新颜色(126、61、181),
新颜色(46、56、141),
新颜色(79,50,31),
新颜色(53,70,27),
新颜色(150,52,48),
新颜色(25,22,22)};
公共静态void main(字符串[]args){
字符串lImgFile=“/tmp/test.jpg”;
试一试{
//加载图像
buffereImage lImage=ImageIO.read(新文件(lImgFile));
BuffereImage lOutImage=applyDitheredPalette(图像、调色板);
write(lOutImage,“png”,新文件(“/tmp/out.png”);
}捕获(IOLex异常){
System.out.println(lEx.getMessage());
}
}
/**
*@param pPalette要应用的调色板。
*@param要应用调色板的图像。
*@return{@link java.awt.image.buffereImage}对应于使用朴素的Floyd Steinberg实现在pImage上应用的pPalette
*/
公共静态BuffereImage applyDitheredPalette(BuffereImage图像,颜色[]pPalette){
int lWidth=pImage.getWidth();
int lHeight=pImage.getHeight();
IndexColorModel lColorModel=paletteToColorModel(pPalette);
BuffereImage lImageOut=新的BuffereImage(lWidth、lHeight、BuffereImage.TYPE\u BYTE\u INDEXED、lColorModel);
对于(整数y=(lHeight-1);y>=0;y--){
对于(int x=0;x0&(y+1)
此网站用于提问,而不是调试。但至少要回答“我做错了什么?”这个问题:

  • 术语
    (7/16)
    将执行整数除法,结果将是
    0
    。改用
    (7.0/16.0)
  • 您不能对RGB值进行算术运算!当您有一个类似于
    0x000000FF
    (蓝色)的RGB值并将其乘以256时,结果将是
    0x0000FF00import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.awt.image.IndexColorModel;
    import java.io.File;
    import java.io.IOException;
    
    public class FloydSteinbergTest {
    
    private static final Color[] PALETTE = new Color[]{
            new Color(221, 221, 221),
            new Color(19, 125, 62),
            new Color(179, 80, 188),
            new Color(107, 138, 201),
            new Color(177, 166, 39),
            new Color(65, 174, 56),
            new Color(208, 132, 153),
            new Color(64, 64, 64),
            new Color(154, 161, 161),
            new Color(46, 110, 137),
            new Color(126, 61, 181),
            new Color(46, 56, 141),
            new Color(79, 50, 31),
            new Color(53, 70, 27),
            new Color(150, 52, 48),
            new Color(25, 22, 22)};
    
    public static void main(String[] args) {
    
        String lImgFile = "/tmp/test.jpg";
        try {
            // Load image
            BufferedImage lImage = ImageIO.read(new File(lImgFile));
    
            BufferedImage lOutImage = applyDitheredPalette(lImage, PALETTE);
            ImageIO.write(lOutImage, "png", new File("/tmp/out.png"));
        } catch (IOException lEx) {
            System.out.println(lEx.getMessage());
        }
    }
    
    /**
     * @param pPalette Color palette to apply.
     * @param pImage   Image to apply palette on.
     * @return {@link java.awt.image.BufferedImage} corresponding to pPalette applied on pImage using naive Floyd-Steinberg implementation
     */
    public static BufferedImage applyDitheredPalette(BufferedImage pImage, Color[] pPalette) {
        int lWidth = pImage.getWidth();
        int lHeight = pImage.getHeight();
        IndexColorModel lColorModel = paletteToColorModel(pPalette);
        BufferedImage lImageOut = new BufferedImage(lWidth, lHeight, BufferedImage.TYPE_BYTE_INDEXED, lColorModel);
        for (int y = (lHeight - 1); y >= 0; y--) {
            for (int x = 0; x < lWidth; x++) {
    
                // Get original pixel color channels
                int lInitialPixelColor = pImage.getRGB(x, y);
    
                // Finding nearest color in the palette
                Color lNearestColor = getNearestColor(lInitialPixelColor, pPalette);
    
                // Set quantized pixel
                lImageOut.setRGB(x, y, lNearestColor.getRGB());
    
                // Applying Floyd-Steinberg dithering
                int quantizationError = lInitialPixelColor - lNearestColor.getRGB();
    
                if ((x + 1) < lWidth) {
                    int lPixel = pImage.getRGB(x + 1, y);
                    lImageOut.setRGB(x + 1, y, lPixel + (quantizationError * (7 / 16)));
                }
    
                if ((x - 1) > 0 && (y + 1) < lHeight) {
                    int lPixel = pImage.getRGB(x - 1, y + 1);
                    lImageOut.setRGB(x - 1, y + 1, lPixel + (quantizationError * (3 / 16)));
                }
    
                if ((y + 1) < lHeight) {
                    int lPixel = pImage.getRGB(x, y + 1);
                    lImageOut.setRGB(x, y + 1, lPixel + (quantizationError * (5 / 16)));
                }
    
                if ((x + 1 < lWidth) && (y + 1 < lHeight)) {
                    int lPixel = pImage.getRGB(x + 1, y + 1);
                    lImageOut.setRGB(x + 1, y + 1, lPixel + (quantizationError * (1 / 16)));
                }
                // End of Floyd-Steinberg dithering
            }
        }
    
        return lImageOut;
    }
    
    /**
     * @param pPalette to load color model from
     * @return {@link java.awt.image.IndexColorModel} Color model initialized using pPalette colors
     */
    private static IndexColorModel paletteToColorModel(Color[] pPalette) {
        int lSize = pPalette.length;
    
        // Getting color component for each palette color
        byte[] lReds = new byte[lSize];
        byte[] lGreens = new byte[lSize];
        byte[] lBlues = new byte[lSize];
    
        for (int i = 0; i < lSize; i++) {
            Color lColor = pPalette[i];
            lReds[i] = (byte) lColor.getRed();
            lGreens[i] = (byte) lColor.getGreen();
            lBlues[i] = (byte) lColor.getBlue();
        }
    
        return new IndexColorModel(4, lSize, lReds, lGreens, lBlues);
    }
    
    /**
     * @param pColor   Color to approximate
     * @param pPalette Color palette to use for quantization
     * @return {@link java.awt.Color} nearest from pColor value took in pPalette
     */
    private static Color getNearestColor(int pColor, Color[] pPalette) {
        Color lNearestColor = null;
        double lNearestDistance = Integer.MAX_VALUE;
        double lTempDist;
        for (Color lColor : pPalette) {
            Color lRgb = new Color(pColor);
            lTempDist = distance(lRgb.getRed(), lRgb.getGreen(), lRgb.getBlue(), lColor.getRed(), lColor.getGreen(), lColor.getBlue());
            if (lTempDist < lNearestDistance) {
                lNearestDistance = lTempDist;
                lNearestColor = lColor;
            }
        }
        return lNearestColor;
    }
    
    /**
     * @return Distance between 2 pixels color channels.
     */
    private static double distance(int pR1, int pG1, int pB1, int pR2, int pG2, int pB2) {
        double lDist = Math.pow(pR1 - pR2, 2) + Math.pow(pG1 - pG2, 2) + Math.pow(pB1 - pB2, 2);
        return Math.sqrt(lDist);
    }}
    
    for (int y = (lHeight - 1); y >= 0; y--) 
    
    for (int y = 0; y < lHeight; y++)