微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 Java 实现 1 位抖动?

如何解决如何使用 Java 实现 1 位抖动?

最近,我们的老师给了我们使用 Java 将彩色图像转换为 1 位图像的任务。经过一些实验,我得到了以下结果:

BufferedImage image = ...
for (int y = 0; y < image.getHeight(); y++) {
  for (int x = 0; x < image.getWidth(); x++) {
    int clr = image.getRGB(x,y);
    int  r   = (clr & 0x00ff0000) >> 16;
    int  g = (clr & 0x0000ff00) >> 8;
    int  b  =  clr & 0x000000ff;
                
    double mono = 0.2126*r + 0.7152*g + 0.0722*b;
                
    int c = mono < 128 ? 1 : 0;
    
    //Adding to image buffer
    buffer.add(c);
  }
}

好吧,它可以工作,但不幸的是丢失了很多细节。这是一个比较:

原文:

Original

输出

Converted Output

我想要的:(总部:https://i.stack.imgur.com/vlEAE.png

My goal

我正在考虑在我的转换器中添加抖动,但我还没有找到可行的方法,更不用说任何伪代码了。

有人可以帮我吗?

编辑:

所以我创建了一个 DitheringUtils-class:

import java.awt.Color;
import java.awt.image.BufferedImage;

public class DitheringUtils {
    
    public static BufferedImage dithering(BufferedImage image) {
        Color3i[] palette = new Color3i[] {
            new Color3i(0,0),new Color3i(255,255,255)
        };
        
        int width = image.getWidth();
        int height = image.getHeight();
        
        Color3i[][] buffer = new Color3i[height][width];
        
        for(int y=0;y<height;y++) {
            for(int x=0;x<width;x++) {
                buffer[y][x] = new Color3i(image.getRGB(x,y));
            }
        }
        
        for(int y=0; y<image.getHeight();y++) {
            for(int x=0; x<image.getWidth();x++) {
                Color3i old = buffer[y][x];
                Color3i nem = findClosestPaletteColor(old,palette);
                image.setRGB(x,y,nem.toColor().getRGB());
                
                Color3i error = old.sub(nem);
                
                if (x+1 < width)         buffer[y  ][x+1] = buffer[y  ][x+1].add(error.mul(7./16));
                if (x-1>=0 && y+1<height) buffer[y+1][x-1] = buffer[y+1][x-1].add(error.mul(3./16));
                if (y+1 < height)         buffer[y+1][x  ] = buffer[y+1][x  ].add(error.mul(5./16));
                if (x+1<width && y+1<height)  buffer[y+1][x+1] = buffer[y+1][x+1].add(error.mul(1./16));
            }
        }
        
        return image;
    }

    private static Color3i findClosestPaletteColor(Color3i match,Color3i[] palette) {
        Color3i closest = palette[0];
        
        for(Color3i color : palette) {
            if(color.diff(match) < closest.diff(match)) {
                closest = color;
            }
        }
        
        return closest;
    }
}

class Color3i {
    
    private int r,g,b;

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

    public Color3i add(Color3i o) {
        return new Color3i(r + o.r,g + o.g,b + o.b);
    }
    
    public Color3i sub(Color3i o) {
        return new Color3i(r - o.r,g - o.g,b - o.b);
    }
    
    public Color3i mul(double d) {
        return new Color3i((int) (d * r),(int) (d * g),(int) (d * b));
    }
    
    public int diff(Color3i 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));
    }
}

并将我的功能更改为:

for (int y = 0; y < dithImage.getHeight(); ++y) {
    for (int x = 0; x < dithImage.getWidth(); ++x) {
        final int clr = dithImage.getRGB(x,y);
        final int r = (clr & 0xFF0000) >> 16;
        final int g = (clr & 0xFF00) >> 8;
        final int b = clr & 0xFF;
                
        if(382.5>(r+g+b)) {
            buffer.add(0);
        } else {
            buffer.add(1);
        }
    }
}

输出最终看起来……很奇怪?

Trippy Output

我真的不明白为什么会有这样的波浪。

解决方法

我终于成功了!我改进了 diff 函数并将 if(382.5>(r+g+b)) 更改为 if(765==(r+g+b))

我的DitheringUtils级:

import java.awt.Color;
import java.awt.image.BufferedImage;

public class DitheringUtils {
    
    public static BufferedImage dithering(BufferedImage image) {
        Color3i[] palette = new Color3i[] {
            new Color3i(0,0),new Color3i(255,255,255)
        };
        
        int width = image.getWidth();
        int height = image.getHeight();
        
        Color3i[][] buffer = new Color3i[height][width];
        
        for(int y=0;y<height;y++) {
            for(int x=0;x<width;x++) {
                buffer[y][x] = new Color3i(image.getRGB(x,y));
            }
        }
        
        for(int y=0; y<image.getHeight();y++) {
            for(int x=0; x<image.getWidth();x++) {
                Color3i old = buffer[y][x];
                Color3i nem = findClosestPaletteColor(old,palette);
                image.setRGB(x,y,nem.toColor().getRGB());
                
                Color3i error = old.sub(nem);
                
                if (x+1 < width)         buffer[y  ][x+1] = buffer[y  ][x+1].add(error.mul(7./16));
                if (x-1>=0 && y+1<height) buffer[y+1][x-1] = buffer[y+1][x-1].add(error.mul(3./16));
                if (y+1 < height)         buffer[y+1][x  ] = buffer[y+1][x  ].add(error.mul(5./16));
                if (x+1<width && y+1<height)  buffer[y+1][x+1] = buffer[y+1][x+1].add(error.mul(1./16));
            }
        }
        
        return image;
    }

    private static Color3i findClosestPaletteColor(Color3i match,Color3i[] palette) {
        Color3i closest = palette[0];
        
        for(Color3i color : palette) {
            if(color.diff(match) < closest.diff(match)) {
                closest = color;
            }
        }
        
        return closest;
    }
}

class Color3i {
    
    private int r,g,b;

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

    public Color3i add(Color3i o) {
        return new Color3i(r + o.r,g + o.g,b + o.b);
    }
    
    public Color3i sub(Color3i o) {
        return new Color3i(r - o.r,g - o.g,b - o.b);
    }
    
    public Color3i mul(double d) {
        return new Color3i((int) (d * r),(int) (d * g),(int) (d * b));
    }
    
    public int diff(Color3i o) {
        int Rdiff = o.r - r;
        int Gdiff = o.g - g;
        int Bdiff = o.b - b;
        int distanceSquared = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff;
        return distanceSquared;
    }

    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));
    }
}

最终写入函数:

for (int y = 0; y < dithImage.getHeight(); ++y) {
    for (int x = 0; x < dithImage.getWidth(); ++x) {
        final int clr = dithImage.getRGB(x,y);
        final int r = (clr & 0xFF0000) >> 16;
        final int g = (clr & 0xFF00) >> 8;
        final int b = clr & 0xFF;
                
        if(765==(r+g+b)) {
            buffer.add(0);
        } else {
            buffer.add(1);
        }
    }
}

谢谢大家!

,
BufferedImage image = ...
for (int y = 0; y < image.getHeight(); y++) {
  for (int x = 0; x < image.getWidth(); x++) {
    Color color = new Color(image.getRGB(x,y));
    int red = color.getRed();
    int green = color.getGreen();
    int blue = color.getBlue();
    
    
    int mono = (red+green+blue)/255;
    
    //Adding to image buffer
    int col = (0 << 24) | (mono << 16) | (mono << 8) | mono;
    
    image.setRGB(x,col);
  }
}

试试这个

您做错的是,您没有尝试将图片转换为灰度,而是尝试将其转换为黑白。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。