将图像转换为黑白图像

我使用如下命令将图像转换为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使图像变亮或变暗。

缩放后,图像变为B&W

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