2011-05-09 80 views

回答

31

使用image.getRGB(x, y)image.setRGB(x, y, color)並使用wikipedia article中的pseudocode。請注意,wiki上的代碼沒有說明如何「減」,「添加」和「繁殖」顏色。 (下面的T3類處理 「顏色」 操作。)

下面的代碼會產生這個截圖:

screenshot

class Test { 
    private static BufferedImage floydSteinbergDithering(BufferedImage img) { 

    C3[] palette = new C3[] { 
     new C3( 0, 0, 0), 
     new C3( 0, 0, 255), 
     new C3( 0, 255, 0), 
     new C3( 0, 255, 255), 
     new C3(255, 0, 0), 
     new C3(255, 0, 255), 
     new C3(255, 255, 0), 
     new C3(255, 255, 255) 
    }; 

    int w = img.getWidth(); 
    int h = img.getHeight(); 

    C3[][] d = new C3[h][w]; 

    for (int y = 0; y < h; y++) 
     for (int x = 0; x < w; x++) 
     d[y][x] = new C3(img.getRGB(x, y)); 

    for (int y = 0; y < img.getHeight(); y++) { 
     for (int x = 0; x < img.getWidth(); x++) { 

     C3 oldColor = d[y][x]; 
     C3 newColor = findClosestPaletteColor(oldColor, palette); 
     img.setRGB(x, y, newColor.toColor().getRGB()); 

     C3 err = oldColor.sub(newColor); 

     if (x+1 < w)   d[y ][x+1] = d[y ][x+1].add(err.mul(7./16)); 
     if (x-1>=0 && y+1<h) d[y+1][x-1] = d[y+1][x-1].add(err.mul(3./16)); 
     if (y+1 < h)   d[y+1][x ] = d[y+1][x ].add(err.mul(5./16)); 
     if (x+1<w && y+1<h) d[y+1][x+1] = d[y+1][x+1].add(err.mul(1./16)); 
     } 
    } 

    return img; 
    } 

    private static C3 findClosestPaletteColor(C3 c, C3[] palette) { 
    C3 closest = palette[0]; 

    for (C3 n : palette) 
     if (n.diff(c) < closest.diff(c)) 
     closest = n; 

    return closest; 
    } 

    public static void main(String[] args) throws IOException { 

    final BufferedImage normal = ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png")).getSubimage(100, 100, 300, 300); 
    final BufferedImage dietered = floydSteinbergDithering(ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png"))).getSubimage(100, 100, 300, 300); 

    JFrame frame = new JFrame("Test"); 
    frame.setLayout(new GridLayout(1, 2)); 

    frame.add(new JComponent() { 
     @Override 
     protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.drawImage(normal, 0, 0, this); 
     } 
    }); 
    frame.add(new JComponent() { 
     @Override 
     protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.drawImage(dietered, 0, 0, this); 
     } 
    }); 

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setSize(400, 400); 
    frame.setVisible(true); 
    } 


    static class C3 { 
    int r, g, b; 

    public C3(int c) { 
     Color color = new Color(c); 
     this.r = color.getRed(); 
     this.g = color.getGreen(); 
     this.b = color.getBlue(); 
    } 
    public C3(int r, int g, int b) { 
     this.r = r; 
     this.g = g; 
     this.b = b; 
    } 

    public C3 add(C3 o) { 
     return new C3(r + o.r, g + o.g, b + o.b); 
    } 
    public C3 sub(C3 o) { 
     return new C3(r - o.r, g - o.g, b - o.b); 
    } 
    public C3 mul(double d) { 
     return new C3((int) (d * r), (int) (d * g), (int) (d * b)); 
    } 
    public int diff(C3 o) { 
     return Math.abs(r - o.r) + Math.abs(g - o.g) + Math.abs(b - o.b); 
    } 

    public int toRGB() { 
     return toColor().getRGB(); 
    } 
    public Color toColor() { 
     return new Color(clamp(r), clamp(g), clamp(b)); 
    } 
    public int clamp(int c) { 
     return Math.max(0, Math.min(255, c)); 
    } 
    } 
} 
+1

+1 WOW真棒發表@dacwe – pixelbobby 2011-05-09 18:57:50

+5

@pixelbobby:是的,我喜歡這種形象太;)http://en.wikipedia.org/wiki/Lenna – dacwe 2011-05-09 19:06:12

+0

這段代碼很特定於3位轉換,不適用於任何其他位深度,並且不允許使用優化的調色板。還很高興看到一個例子的工作代碼。 – 2011-05-09 19:11:20

2

源代碼需要在靜態類C3中缺少方法「diff」。 否則,它不會編譯或工作。

這裏的缺失DIFF方法:

public int diff(C3 o) { 
    int Rdiff = o.r - this.r; 
    int Gdiff = o.g - this.g; 
    int Bdiff = o.b - this.b; 
    int distanceSquared = Rdiff*Rdiff + Gdiff*Gdiff + Bdiff*Bdiff; 
    return distanceSquared; 
}