How to bend an Image in java

会有一股神秘感。 提交于 2020-01-13 06:00:29

问题


Is there any way to bend a BufferedImage in Java?

I thought that if I crop the image into smaller pieces and rotate them then I would essentially bend the image, but it doesn't seem to work.

Here is the method I created:

/**
 * This is a recursive method that will accept an image the point where the bending will start and the point where the bending will end, as well as the angle of bending
 * 
 * @param original:the original image
 * @param startingPoint: the point where the bending should start
 * @param endingPoint: the point where the bending should end
 * @param radiands: the angle
 * @return the bent image
 */
public static BufferedImage getBentImage(BufferedImage original, int startingPoint, int endingPoint, double radians) {
    if (startingPoint >= endingPoint)
        return original;

    int type = BufferedImage.TYPE_INT_ARGB;
    int width = original.getWidth();
    int height = original.getHeight();

    BufferedImage crop = original.getSubimage(0, 0, startingPoint, height);
    BufferedImage crop0 = original.getSubimage(startingPoint, 0, width - startingPoint, height);
    BufferedImage bendCrop = new BufferedImage(width, height, type);
    BufferedImage image = new BufferedImage(width, height, type);

    AffineTransform rotation = new AffineTransform();
    rotation.translate(0, 0);
    rotation.rotate(radians);

    Graphics2D g = bendCrop.createGraphics();
    g.drawImage(crop0, rotation, null);
    g.dispose();

    g = image.createGraphics();
    g.drawImage(crop, 0, 0, null);
    g.drawImage(bendCrop, startingPoint, 0, null);
    g.dispose();

    return getBentImage(image, startingPoint + 1, endingPoint, radians);
}

This is the original Image:

And this is the result of this getBentImage(image, 200, 220, Math.toRadians(1)):

I was expecting something closer to:

Any ideas on how to actually implement a getBentImage() method?


回答1:


As suggested in the comments, a simple approach is to divide the image into 3 parts:

  1. Identical to the original.
  2. Bent according to the bending transformation.
  3. Constant diagonal continuation.

Here is a quick and a bit messy example that shows the original shape and the resulting shape below it. I just used a label icon for the images instead of doing custom painting. (Also I didn't adhere to the Java naming conventions with final variables because it's math and not typical coding.)

Since there are quite a few variables in the calculation code, I added a sketch at the end that shows what the variables represent.

public class Main extends JFrame {

    static BufferedImage image;

    public static void main(String[] args) {

        try {
            image = ImageIO.read(ClassLoader.getSystemResource("img.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Main();
    }

    public Main() {

        getContentPane().setLayout(new BorderLayout(5, 10));
        BufferedImage img2 = transform(15, 100, 300);

        JLabel label1 = new JLabel(new ImageIcon(image));
        label1.setHorizontalAlignment(JLabel.LEFT);
        label1.setOpaque(true);
        label1.setBackground(Color.YELLOW);
        add(label1, BorderLayout.NORTH);

        JLabel label2 = new JLabel(new ImageIcon(img2));
        label2.setHorizontalAlignment(JLabel.LEFT);
        label2.setOpaque(true);
        label2.setBackground(Color.CYAN);
        add(label2);

        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    static BufferedImage transform(int t, int x1, int x2) {

        final double TH = Math.toRadians(t);
        final int D = x2 - x1;
        final int W = image.getWidth();
        final int H = image.getHeight();

        final int dD = (int) (D / (2 * TH) * Math.sin(2 * TH));
        final int dH = (int) (D / TH * Math.pow(Math.sin(TH), 2));
        final int pH = (int) ((W - x2) * Math.tan(2 * TH));

        final int width = W - (D - dD);
        final int height = (int) (H + dH + pH);

        System.out.println(W + " " + H + " -> " + width + " " + height);

        BufferedImage img2 = new BufferedImage(width, height, image.getType());

        for (int x = 0; x < x1; x++) {
            for (int y = 0; y < H; y++) {
                int rgb = image.getRGB(x, y);
                img2.setRGB(x, y, rgb);
            }
        }

        for (int x = x1; x < x2; x++) {
            for (int y = 0; y < H; y++) {
                int rgb = image.getRGB(x, y);
                int dx = (int) (D / (2 * TH) * Math.sin(2 * (x-x1) * TH / D));
                int dy = (int) (D / TH * Math.pow(Math.sin((x-x1) * TH / D), 2));
                img2.setRGB(x1 + dx, y + dy, rgb);
            }
        }

        for (int x = x2; x < W; x++) {
            for (int y = 0; y < H; y++) {
                int rgb = image.getRGB(x, y);
                int dp = (int) ((x - x2) * Math.tan(2 * TH));
                img2.setRGB(x - (D - dD), y + dH + dp, rgb);
            }
        }

        return img2;
    }
}

As for the calculations, I'll leave it for you as homework; it's just geometry/trigonometry which belongs on Math.SE more than on SO. If you can't figure it out I'll give you a direction.

Note that this method might not be fast at all and could certainly be optimized, I'll leave that to you also. Oh, and rounding doubles to ints carelessly, so the result is not pixel-perfect.




回答2:


I dont know what you mean by bending but essentially you have a rectangle and you break one piece of it and rotate it:

so the algorithm is as follows:

rotate line(x, 0, width-1, 0)
rotate line(x, height-1, width-1, height-1)
connect the pieces

So essentially you are looking for rotate line.



来源:https://stackoverflow.com/questions/38502480/how-to-bend-an-image-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!