如何从 PNG 文件中读取像素?
Posted
技术标签:
【中文标题】如何从 PNG 文件中读取像素?【英文标题】:How do I read pixels from a PNG file? 【发布时间】:2011-09-20 15:40:40 【问题描述】:我知道如何使用 Robot、Windowtester 或 FEST 来截取屏幕截图。我也知道如何使用机器人从屏幕上读取像素。
int x = 10;
int y = 10;
Color px = getPixelColor(int x, int y);
但是,我不知道如何从已捕获的图像中读取像素。我打算将当前图像与文件中的图像进行比较。可以说两者都是PNG。有什么框架可以用来逐像素比较图像吗?
【问题讨论】:
【参考方案1】:这是在 Java 中吗?如果是这样,您可以使用ImageIO.read( "yourImage.png" )
获取BufferedImage
。这将有一个getData()
方法,它将为您提供一个Raster
对象,您可以在该对象上调用getPixel
。见link
【讨论】:
你可以在BufferedImage
上拨打getRGB(x,y)
。【参考方案2】:
这应该可行:
javax.imageio.ImageIO.read(new File("filename.png"))
然后您可以遍历像素并与图像逐像素进行比较:
java.awt.image.BufferedImage.getRGB(int x, int y).
【讨论】:
【参考方案3】:您可以读取图片文件:Reading/Loading an Image。
然后使用getRGB
方法获取颜色。
【讨论】:
【参考方案4】:将它们加载为BufferedImage
实例,这相对容易。
这是创建带有文本的图像的代码的一部分,然后创建一个新图像以显示带有和不带有文本的图像之间的区别。
for (int xx=0; xx<width; xx++)
for (int yy=0; yy<height; yy++)
Color originalColor = new Color(originalImage.getRGB(xx,yy));
int r1 = originalColor.getRed();
int g1 = originalColor.getGreen();
int b1 = originalColor.getBlue();
Color newColor = new Color(textImage.getRGB(xx,yy));
int r2 = newColor.getRed();
int g2 = newColor.getGreen();
int b2 = newColor.getBlue();
Color bnw = Color.black;
if (r1==r2 && g1==g2 && b1==b2)
bnw = Color.white;
bnwImage.setRGB(xx, yy, bnw.getRGB());
int rD = Math.abs(r1-r2);
int gD = Math.abs(g1-g2);
int bD = Math.abs(b1-b2);
Color differenceColor = new Color(rD,gD,bD);
differenceImage.setRGB(xx, yy, differenceColor.getRGB());
屏幕截图
完整代码
import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.imageio.*;
import java.io.*;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import java.util.Locale;
class ImageWriteTest
private BufferedImage originalImage;
private BufferedImage textImage;
private BufferedImage differenceImage;
private BufferedImage bnwImage;
private JPanel gui;
private JCheckBox antialiasing;
private JCheckBox rendering;
private JCheckBox fractionalMetrics;
private JCheckBox strokeControl;
private JCheckBox colorRendering;
private JCheckBox dithering;
private JComboBox textAntialiasing;
private JComboBox textLcdContrast;
private JLabel label0_1;
private JLabel label0_4;
private JLabel label0_7;
private JLabel label1_0;
private JTextArea output;
final static Object[] VALUES_TEXT_ANTIALIASING =
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON,
RenderingHints.VALUE_TEXT_ANTIALIAS_GASP,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB
;
final static Object[] VALUES_TEXT_LCD_CONTRAST =
new Integer(100),
new Integer(150),
new Integer(200),
new Integer(250)
;
ImageWriteTest()
int width = 280;
int height = 100;
gui = new JPanel(new BorderLayout(0,4));
originalImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
textImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
differenceImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
bnwImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
JPanel controls = new JPanel(new GridLayout(0,2,0,0));
antialiasing = new JCheckBox("Anti-aliasing", false);
rendering = new JCheckBox("Rendering - Quality", true);
fractionalMetrics = new JCheckBox("Fractional Metrics", true);
strokeControl = new JCheckBox("Stroke Control - Pure", false);
colorRendering = new JCheckBox("Color Rendering - Quality", true);
dithering = new JCheckBox("Dithering", false);
controls.add(antialiasing);
controls.add(rendering);
controls.add(fractionalMetrics);
controls.add(colorRendering);
textLcdContrast = new JComboBox(VALUES_TEXT_LCD_CONTRAST);
JPanel lcdContrastPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
lcdContrastPanel.add(textLcdContrast);
lcdContrastPanel.add(new JLabel("Text LCD Contrast"));
controls.add(lcdContrastPanel);
controls.add(strokeControl);
textAntialiasing = new JComboBox(VALUES_TEXT_ANTIALIASING);
controls.add(textAntialiasing);
controls.add(dithering);
ItemListener itemListener = new ItemListener()
public void itemStateChanged(ItemEvent e)
updateImages();
;
antialiasing.addItemListener(itemListener);
rendering.addItemListener(itemListener);
fractionalMetrics.addItemListener(itemListener);
strokeControl.addItemListener(itemListener);
colorRendering.addItemListener(itemListener);
dithering.addItemListener(itemListener);
textAntialiasing.addItemListener(itemListener);
textLcdContrast.addItemListener(itemListener);
Graphics2D g2d = originalImage.createGraphics();
GradientPaint gp = new GradientPaint(
0f, 0f, Color.red,
(float)width, (float)height, Color.orange);
g2d.setPaint(gp);
g2d.fillRect(0,0, width, height);
g2d.setColor(Color.blue);
for (int ii=0; ii<width; ii+=10)
g2d.drawLine(ii, 0, ii, height);
g2d.setColor(Color.green);
for (int jj=0; jj<height; jj+=10)
g2d.drawLine(0, jj, width, jj);
updateImages();
gui.add(controls, BorderLayout.NORTH);
JPanel images = new JPanel(new GridLayout(0,2,0,0));
images.add(new JLabel(new ImageIcon(originalImage)));
images.add(new JLabel(new ImageIcon(textImage)));
images.add(new JLabel(new ImageIcon(differenceImage)));
images.add(new JLabel(new ImageIcon(bnwImage)));
try
label0_1 = new JLabel(new ImageIcon(getJpegCompressedImage(0.1f, textImage)));
images.add(label0_1);
label0_4 = new JLabel(new ImageIcon(getJpegCompressedImage(0.4f, textImage)));
images.add(label0_4);
label0_7 = new JLabel(new ImageIcon(getJpegCompressedImage(0.7f, textImage)));
images.add(label0_7);
label1_0 = new JLabel(new ImageIcon(getJpegCompressedImage(1.0f, textImage)));
images.add(label1_0);
catch(IOException ioe)
gui.add(images, BorderLayout.CENTER);
StringBuilder sb = new StringBuilder();
String[] names =
"java.vendor",
"java.version",
"java.vm.version",
"os.name",
"os.version"
;
for (String name : names)
addProperty(sb, name);
output = new JTextArea(sb.toString(),6,40);
gui.add(new JScrollPane(output), BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null, gui);
private static void addProperty(StringBuilder builder, String name)
builder.append( name + " \t" + System.getProperty(name) + "\n" );
/** Adapted from SO post by x4u. */
private Image getJpegCompressedImage(float quality, BufferedImage image) throws IOException
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ImageWriter imgWriter = ImageIO.getImageWritersByFormatName( "jpg" ).next();
ImageOutputStream iostream = ImageIO.createImageOutputStream( outStream );
imgWriter.setOutput( ioStream );
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam( Locale.getDefault() );
jpegParams.setCompressionMode( ImageWriteParam.MODE_EXPLICIT );
jpegParams.setCompressionQuality( quality );
imgWriter.write( null, new IIOImage( image, null, null ), jpegParams );
ioStream.flush();
ioStream.close();
imgWriter.dispose();
BufferedImage compressedImage = ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
JLabel label = new JLabel("Quality: " + quality);
label.setBackground(new Color(255,255,255,192));
label.setOpaque(true);
label.setSize(label.getPreferredSize());
label.paint(compressedImage.getGraphics());
return compressedImage;
private void updateImages()
int width = originalImage.getWidth();
int height = originalImage.getHeight();
Graphics2D g2dText = textImage.createGraphics();
if (antialiasing.isSelected())
g2dText.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
else
g2dText.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
if (rendering.isSelected())
g2dText.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
else
g2dText.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_SPEED);
if (fractionalMetrics.isSelected())
g2dText.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
else
g2dText.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
if (strokeControl.isSelected())
g2dText.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_NORMALIZE);
else
g2dText.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
if (dithering.isSelected())
g2dText.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
else
g2dText.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
if (colorRendering.isSelected())
g2dText.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
else
g2dText.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED);
g2dText.setRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST,
textLcdContrast.getSelectedItem());
g2dText.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
textAntialiasing.getSelectedItem());
g2dText.drawImage(originalImage, 0,0, null);
g2dText.setColor(Color.black);
g2dText.drawString("The quick brown fox jumped over the lazy dog.", 10,50);
Graphics2D g2dDifference = differenceImage.createGraphics();
Graphics2D g2dBnW = bnwImage.createGraphics();
for (int xx=0; xx<width; xx++)
for (int yy=0; yy<height; yy++)
Color originalColor = new Color(originalImage.getRGB(xx,yy));
int r1 = originalColor.getRed();
int g1 = originalColor.getGreen();
int b1 = originalColor.getBlue();
Color newColor = new Color(textImage.getRGB(xx,yy));
int r2 = newColor.getRed();
int g2 = newColor.getGreen();
int b2 = newColor.getBlue();
Color bnw = Color.black;
if (r1==r2 && g1==g2 && b1==b2)
bnw = Color.white;
bnwImage.setRGB(xx, yy, bnw.getRGB());
int rD = Math.abs(r1-r2);
int gD = Math.abs(g1-g2);
int bD = Math.abs(b1-b2);
Color differenceColor = new Color(rD,gD,bD);
differenceImage.setRGB(xx, yy, differenceColor.getRGB());
gui.repaint();
public static void main(String[] args)
SwingUtilities.invokeLater( new Runnable()
public void run()
ImageWriteTest iwt = new ImageWriteTest();
);
【讨论】:
很好的答案。 javascript应该改变什么? (我不知道它在javascript中是否有相同的,BufferedImage
)【参考方案5】:
在 C/C++ 中,如果您愿意要求最低版本的 Windows,这很容易,您可以使用 GDI+ 加载图像并将其绘制到内存位图,然后您可以使用返回的指针来获取像素数据。
使用GdiplusStartup()
和GdiplusShutdown()
初始化和取消初始化GDI+。
使用 GDI+ Image
对象,使用带文件名的重载来加载图像,然后使用方法 GetWidth()
和 GetHeight()
、BITMAPINFO
结构和 CreateDIBSection()
GDI 函数来创建内存位图。
然后使用CreateCompatibleDC()
为位图创建设备上下文,并使用SelectObject()
将位图选择到该设备上下文中。
然后您使用 GDI+ Graphics
对象,使用采用设备上下文的重载及其 DrawImage()
方法,使用采用 x
、y
、width
和 height
的重载,将图像绘制到位图的设备上下文中。
之后,您可以使用CreateDIBSection()
返回的指针获取/设置像素数据。
完成后,使用DeleteDC()
删除位图的设备上下文,然后使用DeleteObject()
删除位图。 GDI+ 图像对象也可用于以支持的格式保存图像,包括 PNG。
【讨论】:
人们对我的答案投了反对票,甚至在这样做时甚至没有批评任何事情,这是怎么回事?是不是因为我的回答比你的好?还是因为您不知道 C/C++ 和 Java 足够相似,无法从中得出解决方案?我发现 PASCAL 代码帮助我解决了我在 C/C++ 中遇到的问题,我不明白为什么我的 C/C++ 解决方案不能帮助解决有人使用 Java 编码遇到的问题,我知道它有效,因为我'我实际使用它,没有纯粹的理论,没有猜测,它实际上正在被应用,因此被证明是有效的。感谢 Alexander Petrov 改进它。 OP 在问一个 Java 问题(尽管最初的问题并不清楚)。因此,GDI+ 特定的答案根本不相关。建议的解决方案需要大量的 JNI 麻烦,甚至 尝试 来遵循您的解决方案。您的解决方案还对底层操作系统进行了假设——这使得 Java 代码无法在任何 Java 平台上运行。我认为这些是投反对票的原因 :) 我同意 算法 很容易跨语言应用。但是您说的是 Windows 特定的 API 调用。以上是关于如何从 PNG 文件中读取像素?的主要内容,如果未能解决你的问题,请参考以下文章