简体   繁体   English

旋转BufferedImage并去除黑边

[英]Rotate BufferedImage and remove black bound

I have the original image: 我有原始图片:

在此处输入图片说明

I rotate the image with the following Java code: 我使用以下Java代码旋转图像:

BufferedImage bi = ImageHelper.rotateImage(bi, -imageSkewAngle);

ImageIO.write(bi, "PNG", new File("out.png"));

as the result I have the following image: 结果,我得到以下图像:

在此处输入图片说明

How to remove black bound around the image and make it a proper white rectangle and to not spent much space.. use only the required size for the transformation... equal to original or larger if needed? 如何删除图像周围的黑色边框,并使其成为适当的白色矩形,并且不占用太多空间..仅使用所需的大小进行转换...等于原始尺寸,如果需要,可以更大?

The following program contains a method rotateImage that should be equivalent to the rotateImage method that was used in the question: It computes the bounds of the rotated image, creates a new image with the required size, and paints the original image into the center of the new one. 下面的程序包含一个方法rotateImage ,该方法应该与问题中使用的rotateImage方法等效:它计算旋转图像的边界,创建具有所需大小的新图像,并将原始图像绘制到图像的中心。新的一个。

The method additionally receives a Color backgroundColor that determines the background color. 该方法还接收用于确定背景颜色的Color backgroundColor In the example, this is set to Color.RED , to illustrate the effect. 在示例中,将其设置为Color.RED ,以说明效果。

The example also contains a method rotateImageInPlace . 该示例还包含一个方法rotateImageInPlace This method will always create an image that has the same size as the input image, and will also paint the (rotated) original image into the center of this image. 此方法将始终创建与输入图像具有相同大小的图像,并且还将(旋转的)原始图像绘制到该图像的中心。

The program creates two panels, the left one showing the result of rotateImage and the right one the result of rotateImageInPlace , together with a slider that allows changing the rotation angle. 该程序创建两个面板,左一个示出的结果rotateImage和右之一的结果rotateImageInPlace ,条件是允许改变的旋转角度的滑块一起。 So the output of this program is shown here: 因此,该程序的输出如下所示:

rotateImageInPlace

(Again, Color.RED is just used for illustration. Change it to Color.WHITE for your application) (同样, Color.RED仅用于说明。为您的应用程序将其更改为Color.WHITE

As discussed in the comments, the goal of not changing the image size may not always be achievable, depending on the contents of the image and the angle of rotation. 正如评论中所讨论的,根据图像的内容和旋转角度,不改变图像大小的目标可能并不总是可以实现的。 So for certain angles, the rotated image may not fit into the resulting image. 因此,对于某些角度,旋转后的图像可能不适合生成的图像。 But for the use case of the question, this should be OK: The use case is that the original image already contains a rotated rectangular "region of interest". 但是对于问题的用例来说,应该可以:用例是原始图像已经包含一个旋转的矩形“关注区域”。 So the parts that do not appear in the output should usually be the parts of the input image that do not contain relevant information anyhow. 因此,未出现在输出中的部分通常应该是输入图像中不包含任何相关信息的部分。

(Otherwise, it would be necessary to either provide more information about the structure of the input image, regarding the border size or the angle of rotation, or one would have to manually figure out the required size by examining the image, pixel by pixel, to see which pixels are black and which ones are white) (否则,有必要提供有关输入图像结构,边框大小或旋转角度的更多信息,或者必须通过逐像素检查图像来手动找出所需的大小,看看哪些像素是黑色的,哪些像素是白色的)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;

public class RotateImageWithoutBorder
{
    public static void main(String[] args) throws Exception
    {
        BufferedImage image = 
            ImageIO.read(new URL("https://i.stack.imgur.com/tMtFh.png"));


        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        ImagePanel imagePanel0 = new ImagePanel();
        imagePanel0.setBackground(Color.BLUE);

        ImagePanel imagePanel1 = new ImagePanel();
        imagePanel1.setBackground(Color.BLUE);

        JSlider slider = new JSlider(0, 100, 1);
        slider.addChangeListener(e -> 
        {
            double alpha = slider.getValue() / 100.0;
            double angleRad = alpha * Math.PI * 2;

            BufferedImage rotatedImage = rotateImage(
                image, angleRad, Color.RED);
            imagePanel0.setImage(rotatedImage);

            BufferedImage rotatedImageInPlace = rotateImageInPlace(
                image, angleRad, Color.RED);
            imagePanel1.setImage(rotatedImageInPlace);

            f.repaint();
        });
        slider.setValue(0);
        f.getContentPane().add(slider, BorderLayout.SOUTH);

        JPanel imagePanels = new JPanel(new GridLayout(1,2));
        imagePanels.add(imagePanel0);
        imagePanels.add(imagePanel1);
        f.getContentPane().add(imagePanels, BorderLayout.CENTER);

        f.setSize(800,500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);

    }

    private static BufferedImage rotateImage(
        BufferedImage image, double angleRad, Color backgroundColor)
    {
        int w = image.getWidth();
        int h = image.getHeight();
        AffineTransform at = AffineTransform.getRotateInstance(
            angleRad, w * 0.5, h * 0.5);
        Rectangle rotatedBounds = at.createTransformedShape(
            new Rectangle(0, 0, w, h)).getBounds();
        BufferedImage result = new BufferedImage(
            rotatedBounds.width, rotatedBounds.height, 
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = result.createGraphics();
        g.setColor(backgroundColor);
        g.fillRect(0, 0, rotatedBounds.width, rotatedBounds.height);
        at.preConcatenate(AffineTransform.getTranslateInstance(
            -rotatedBounds.x, -rotatedBounds.y));
        g.transform(at);
        g.setRenderingHint(
            RenderingHints.KEY_INTERPOLATION, 
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return result;        
    }

    private static BufferedImage rotateImageInPlace(
        BufferedImage image, double angleRad, Color backgroundColor)
    {
        int w = image.getWidth();
        int h = image.getHeight();
        AffineTransform at = AffineTransform.getRotateInstance(
            angleRad, w * 0.5, h * 0.5);
        Rectangle rotatedBounds = at.createTransformedShape(
            new Rectangle(0, 0, w, h)).getBounds();
        BufferedImage result = new BufferedImage(
            w, h, 
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = result.createGraphics();
        g.setColor(backgroundColor);
        g.fillRect(0, 0, w, h);
        at.preConcatenate(AffineTransform.getTranslateInstance(
            -rotatedBounds.x - (rotatedBounds.width - w) * 0.5, 
            -rotatedBounds.y - (rotatedBounds.height - h) * 0.5));
        g.transform(at);
        g.setRenderingHint(
            RenderingHints.KEY_INTERPOLATION, 
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return result;        
    }


    static class ImagePanel extends JPanel
    {
        private BufferedImage image;

        public void setImage(BufferedImage image)
        {
            this.image = image;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            if (image != null)
            {
                g.drawImage(image, 0, 0, null);
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM