【问题标题】:How do I read pixels from a PNG file?如何从 PNG 文件中读取像素?
【发布时间】:2011-09-20 15:40:40
【问题描述】:

我知道如何使用 Robot、Windowtester 或 FEST 来截取屏幕截图。我也知道如何使用机器人从屏幕上读取像素。

int x = 10;
int y = 10; 
Color px = getPixelColor(int x, int y);

但是,我不知道如何从已捕获的图像中读取像素。我打算将当前图像与文件中的图像进行比较。可以说两者都是PNG。有什么框架可以用来逐像素比较图像吗?

【问题讨论】:

    标签: java pixel awtrobot image-capture fest


    【解决方案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 调用。
        猜你喜欢
        • 1970-01-01
        • 2016-05-18
        • 1970-01-01
        • 2016-06-18
        • 2011-02-03
        • 2011-05-22
        • 1970-01-01
        • 2014-03-19
        • 1970-01-01
        相关资源
        最近更新 更多