在Java中如何翻转BufferedImage

13

我获取了RGB24字节数组,想在Java中显示它。

public void getByteArray(byte byteArray[]){     
        int count1 = 0;
        byte temp1 = 0;

        for (int i = 0; i < byteArray.length; i++) {       //The order of RGB24 is red,green and blue.Change the
            //order to blue,green and red so that java can use TYPE_3BYTE_BGR to recognize it
            if (count1 == 0) {
                temp1 = byteArray[i];  
                count1++;
            } else if(count1 == 1) {
                //do nothing
                count1++;
            } else if(count1 == 2) {
                byteArray[i - 2] = byteArray[i];
                byteArray[i] = temp1;
                count1=0;
            }
        }
        image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
        image.getWritableTile(0, 0).setDataElements(0, 0, width, height, byteArray);

        mainPanel.repaint();

然而,效果不符合我的要求,而且很奇怪。 输入图像描述在这里

我该如何将BufferedImage翻转到正确的方向,就像这样? 输入图像描述在这里


您想将图像旋转180度吗? - Braj
1
不清楚你的问题是什么。有三个答案:一个告诉你如何翻转图像,一个告诉你如何反转颜色,还有一个告诉你如何应用仿射变换。它们都不同,因为问题不明确。请编辑问题,提供更多关于你想要实现什么的信息。 - mttdbrd
问题已经修改。实际上,颜色呈现没有问题,我只是希望图像能够真实地呈现。 - Eugene
你是否在读取BMP文件? :-) 如果是的话,应该从底部到顶部读取每个扫描行,这是正确读取BMP文件的方式。 - Harald K
但是如何将RGB24颜色空间的图像字节数组转换为BMP格式? - Eugene
@upma 如果你想将字节顺序从BGR交换为RGB,你可以在读取时进行操作,或者使用一个带有反向波段(BGR顺序)的SampleModel。但这与颜色空间无关,两种情况下都是RGB。 - Harald K
6个回答

24

有3个选项:(编辑 ->:至少在你编辑问题之前,这里已经有3个选项了 <-)

  • 您可以垂直翻转图像
  • 您可以旋转图像
  • 您可以反转图像

下图显示了它们的区别:

ImageFlipTest01.png

根据您发布的图片,我假设您想要垂直翻转图像。这可以逐像素进行,或者(当需要高效处理时)使用AffineTransformOp或通过使用转换的Graphics2D直接绘制图像来完成。

import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ByteLookupTable;
import java.awt.image.LookupOp;
import java.awt.image.LookupTable;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ImageFlipTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new GridLayout(1, 1));

        BufferedImage image = null;
        try
        {
            image = convertToARGB(ImageIO.read(new File("lena512color.png")));
        }
        catch (IOException e1)
        {
            e1.printStackTrace();
        }

        JPanel panel = new JPanel(new GridLayout(2,2));
        panel.add(createComponent("Original", image));
        panel.add(createComponent("Flipped", createFlipped(image)));
        panel.add(createComponent("Rotated", createRotated(image)));
        panel.add(createComponent("Inverted", createInverted(image)));

        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static BufferedImage convertToARGB(BufferedImage image)
    {
        BufferedImage newImage = new BufferedImage(
            image.getWidth(), image.getHeight(),
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return newImage;
    }    

    private static BufferedImage createFlipped(BufferedImage image)
    {
        AffineTransform at = new AffineTransform();
        at.concatenate(AffineTransform.getScaleInstance(1, -1));
        at.concatenate(AffineTransform.getTranslateInstance(0, -image.getHeight()));
        return createTransformed(image, at);
    }

    private static BufferedImage createRotated(BufferedImage image)
    {
        AffineTransform at = AffineTransform.getRotateInstance(
            Math.PI, image.getWidth()/2, image.getHeight()/2.0);
        return createTransformed(image, at);
    }

    private static BufferedImage createTransformed(
        BufferedImage image, AffineTransform at)
    {
        BufferedImage newImage = new BufferedImage(
            image.getWidth(), image.getHeight(),
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = newImage.createGraphics();
        g.transform(at);
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return newImage;
    }

    private static BufferedImage createInverted(BufferedImage image)
    {
        if (image.getType() != BufferedImage.TYPE_INT_ARGB)
        {
            image = convertToARGB(image);
        }
        LookupTable lookup = new LookupTable(0, 4)
        {
            @Override
            public int[] lookupPixel(int[] src, int[] dest)
            {
                dest[0] = (int)(255-src[0]);
                dest[1] = (int)(255-src[1]);
                dest[2] = (int)(255-src[2]);
                return dest;
            }
        };
        LookupOp op = new LookupOp(lookup, new RenderingHints(null));
        return op.filter(image, null);
    }

    private static Component createComponent(
        String title, BufferedImage image)
    {
        JLabel label = new JLabel(new ImageIcon(image));
        JPanel panel = new JPanel(new GridLayout(1,1));
        panel.add(label);
        panel.setBorder(BorderFactory.createTitledBorder(title));
        return panel;
    }
}

1
这个(详细的)答案的部分意图是在问题澄清之前指出翻转、旋转和反转之间的区别,并同时回答三种可能的问题解释。现在它仍然可以作为代码片段的来源。 - Marco13
你帮助我更清楚地理解了我的问题,并且你提供的翻转函数确实有效。 - Eugene

4

你只需要在drawImage方法中以负宽度或负高度绘制bufferedImage即可。

//flip horizontally
g.drawImage(bufferedImage , x,y,-width,height,null);

//flip vertically
g.drawImage(bufferedImage , x,y,width,-height,null);

1
简单易用,但你必须记得分别偏移x和y。因此应该像这样:g.drawImage(bufferedImage, x + width, y, -width, height, null); g.drawImage(bufferedImage, x, y + height, width, -height, null); - Sbiera Bogdan

3

以下是将图像在任意角度翻转的代码:

public static GraphicsConfiguration getDefaultConfiguration() {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gd = ge.getDefaultScreenDevice();
    return gd.getDefaultConfiguration();
}

public static BufferedImage rotate(BufferedImage image, double angle) {
    int w = image.getWidth(), h = image.getHeight();
    GraphicsConfiguration gc = getDefaultConfiguration();
    BufferedImage result = gc.createCompatibleImage(w, h);
    Graphics2D g = result.createGraphics();
    g.rotate(Math.toRadians(angle), w / 2, h / 2);
    g.drawRenderedImage(image, null);
    g.dispose();
    return result;
}

1
这与翻转图像不同。旋转后,马的方向将会改变。 - Brandon
@Brandon 谢谢,我没有注意到这个。让我修改我的帖子。 - Braj
我仍然喜欢这段代码片段。我会将其加入书签。我认为你不应该删除它。 - Brandon

2
您可以像这样翻转图像:
public void flip(BufferedImage image)
{
    for (int i=0;i<image.getWidth();i++)
        for (int j=0;j<image.getHeight()/2;j++)
        {
            int tmp = image.getRGB(i, j);
            image.setRGB(i, j, image.getRGB(i, image.getHeight()-j-1));
            image.setRGB(i, image.getHeight()-j-1, tmp);
        }
}

1
如果您正在使用Swing的paintComponent()方法。
带有
 graphic.drawImage(img,
                   dx1, dy1, dx2, dy2,
                   sx1, sy1, sx2, sy2,
                   null);

只需将sx1sx2交换即可。

TADA!完成了。

enter image description here


                Source Image                     Destination panel

 sx1, sy1      
    +---------------+---------+        +-----------------------------+
    |               |         |        |                             |
    | region to     |         |        | dx1, dy1                    |
    |        draw   |         |        |    +----------+             |    
    |               |         |        |    |          |             |
    +---------------+         |        |    |          |             | 
    |           sx2, sy2      |        |    +----------+             |     
    |                         |        |            dx2, dy2         |
    |                         |        |                             |
    +-------------------------+        +-----------------------------+

这可能是一个很好的参考资料: drawImage()方法

0
也许你可以使用AffineTransform。
AffineTransform transform = new AffineTransform();
transform.rotate(radians, bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
bufferedImage = op.filter(bufferedImage, null);

这是否基本上相当于手动重新排列字节数组中的像素,还是在转换过程中会有一些数据丢失? - Denis Tulskiy
您提供了如何旋转图像的示例,但没有关于如何翻转图像的说明。您可以参考https://dev59.com/eGAg5IYBdhLWcg3wjrgZ#23458883,我认为这是最佳答案。 - Eugene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接