如何从 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() 方法,使用采用 xywidthheight 的重载,将图像绘制到位图的设备上下文中。

之后,您可以使用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 文件中读取像素?的主要内容,如果未能解决你的问题,请参考以下文章

C#位图从像素中读取不正确的颜色

如何使用excel vba从图片文件中读取像素?

如何从imageview中的png获取特定颜色的所有像素

Fread 返回 0,从 BMP 文件中读取像素

如何从 PNG 为 Tensorflow 2 中的每个像素分类创建 One-hot 编码矩阵

从 bmp 文件中读取 RGB 像素