我使用如下命令在 imagemagick 中将图像转换为黑白:
convert myimg.png -monochrome out3.png
我想知道它是否有可能在 Java 中实现相同的结果?不使用 Im4Java 或 JMagick?
我使用如下命令在 imagemagick 中将图像转换为黑白:
convert myimg.png -monochrome out3.png
我想知道它是否有可能在 Java 中实现相同的结果?不使用 Im4Java 或 JMagick?
我想这取决于你所说的“单色”/“黑白”是什么意思......
public class TestBlackAndWhite {
public static void main(String[] args) {
new TestBlackAndWhite();
}
public TestBlackAndWhite() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage grayScale;
private BufferedImage blackWhite;
public TestPane() {
try {
master = ImageIO.read(new File("C:/Users/shane/Dropbox/pictures/439px-Join!_It's_your_duty!.jpg"));
grayScale = ImageIO.read(new File("C:/Users/shane/Dropbox/pictures/439px-Join!_It's_your_duty!.jpg"));
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
op.filter(grayScale, grayScale);
blackWhite = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g2d = blackWhite.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (master != null) {
size = new Dimension(master.getWidth() * 3, master.getHeight());
}
return size;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (master != null) {
int x = (getWidth() - (master.getWidth() * 3)) / 2;
int y = (getHeight() - master.getHeight()) / 2;
g.drawImage(master, x, y, this);
x += master.getWidth();
g.drawImage(grayScale, x, y, this);
x += master.getWidth();
g.drawImage(blackWhite, x, y, this);
}
}
}
}
试试这个粗略的例子。我们首先使用 使图像变亮或变暗RescaleOp
。
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
class ColorToBlackAndWhite {
/**
* Returns the supplied src image brightened by a float value from 0 to 10.
* Float values below 1.0f actually darken the source image.
*/
public static BufferedImage brighten(BufferedImage src, float level) {
BufferedImage dst = new BufferedImage(
src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
float[] scales = {level, level, level};
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);
Graphics2D g = dst.createGraphics();
g.drawImage(src, rop, 0, 0);
g.dispose();
return dst;
}
public static void main(String[] args) throws Exception {
URL colorURL = new URL("http://i.stack.imgur.com/AuY9o.png");
final BufferedImage colorImage = ImageIO.read(colorURL);
float[] scales = {2f, 2f, 2f};
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);
final BufferedImage scaledImage = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaledImage.createGraphics();
g.drawImage(colorImage, rop, 0, 0);
final BufferedImage grayImage = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_BYTE_GRAY);
g = grayImage.createGraphics();
g.drawImage(colorImage, 0, 0, null);
final BufferedImage blackAndWhiteImage = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
g = blackAndWhiteImage.createGraphics();
g.drawImage(colorImage, 0, 0, null);
g.dispose();
Runnable r = new Runnable() {
@Override
public void run() {
JPanel gui = new JPanel(new BorderLayout(2, 2));
JPanel images = new JPanel(new GridLayout(0, 2, 2, 2));
gui.add(images, BorderLayout.CENTER);
final JLabel scaled = new JLabel(new ImageIcon(scaledImage));
final JSlider brighten = new JSlider(0, 1000, 100);
gui.add(brighten, BorderLayout.PAGE_START);
ChangeListener cl = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int val = brighten.getValue();
float valFloat = val / 1000f;
BufferedImage bi = brighten(colorImage, valFloat);
BufferedImage bw = new BufferedImage(
colorImage.getWidth(),
colorImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
Graphics g = bw.createGraphics();
g.drawImage(bi, 0, 0, null);
g.dispose();
scaled.setIcon(new ImageIcon(bw));
}
};
brighten.addChangeListener(cl);
images.add(new JLabel(new ImageIcon(colorImage)));
images.add(scaled);
images.add(new JLabel(new ImageIcon(grayImage)));
images.add(new JLabel(new ImageIcon(blackAndWhiteImage)));
JOptionPane.showMessageDialog(null, gui);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
您实现的效果不是通过预定义阈值的二值化,而是通过一种称为抖动的技术完成的。许多抖动方法通过传播误差(当前图像中的强度 - 给定点的二进制输出)来工作,从而调整下一个输出。这样做是为了创建一种视觉效果,如果您不仔细看的话,结果图像可能看起来不是黑白的。
Floyd-Steinberg 采用了一种这样简单且众所周知的方法,它的伪代码是:
for y := 1 to image height
for x := 1 to image width
v := im(y, x)
if v < 128 then
result(y, x) := 0
else
result(y, x) := 255
error := v - result(y, x)
propagate_error(im, y, x, error)
在哪里propagate_error
可以给出这种方法(不考虑边界情况):
im(y, x+1) := im(y, x+1) + (7/16) * error
im(y+1, x+1) := im(y+1, x+1) + (1/16) * error
im(y+1, x ) := im(y+1, x ) + (5/16) * error
im(y+1, x-1) := im(y+1, x-1) + (3/16) * error
考虑到给出的伪代码的直接实现,右下图是左图的二进制版本。事实上,右图只有黑白两种颜色,这对于知道这种方法的人来说是小事,但对于那些不知道的人来说,这似乎是不可能的。创建的图案给人的印象是有几种灰色调,这取决于您从远处看图像。
- 试试下面的简单代码,
package com.bethecoder.tutorials.imageio;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class BlackAndWhiteTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
File file = new File("C:/Temp/stpatricks_08.gif");
BufferedImage orginalImage = ImageIO.read(file);
BufferedImage blackAndWhiteImg = new BufferedImage(
orginalImage.getWidth(), orginalImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
Graphics2D graphics = blackAndWhiteImg.createGraphics();
graphics.drawImage(orginalImage, 0, 0, null);
ImageIO.write(blackAndWhiteImg, "png", new File("c:/Temp/stpatricks_08_bw.png"));
}
}