java - 如何在java中弯曲图像

标签 java swing graphics bufferedimage affinetransform

有什么方法可以在Java中弯曲BufferedImage吗?

我认为如果我将图像裁剪成更小的部分并旋转它们,那么我基本上会弯曲图像,但它似乎不起作用。

这是我创建的方法:

/**
 * 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);
}

这是原始图片:

original Image

这是 getBentImage(image, 200, 220, Math.toRadians(1)) 的结果:

result

我期待更接近的东西:

expected result

关于如何实际实现 getBentImage() 方法有什么想法吗?

最佳答案

正如评论中所建议的,一个简单的方法是将图像分为三部分:

  1. 与原件相同。
  2. 根据弯曲变换进行弯曲。
  3. 恒定对角延续。

这是一个快速但有点困惑的示例,显示了原始形状及其下方的结果形状。我只是为图像使用了标签图标,而不是进行自定义绘画。 (此外,我没有遵守 Java 变量 final 命名约定,因为它是数学而不是典型的编码。)

由于计算代码中有相当多的变量,所以我在最后添加了一个草图来显示变量代表的含义。

enter image description here

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;
    }
}

enter image description here

至于计算,我留给你做作业;它只是几何/三角学,更属于Math.SE而不是SO。如果你不明白,我会给你指导。

请注意,此方法可能根本不快,但肯定可以优化,我也将其留给您。哦,而且不小心将 double 舍入为 int,因此结果不是像素完美的。

关于java - 如何在java中弯曲图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38502480/

相关文章:

java - Java中字符串的最大长度-调用length()方法

java - JOptionPane.showOptionDialog 不显示按钮?

java - 多个 JPanel 在 JLayeredPane 中绘制图像

math - 如何将凸多边形分解为在 X 轴和 Y 轴上对齐的直角三角形?

java - 如何在 Java 中编写方法签名 "T that implements Comparable<T>"?

java - 添加附加 stub 时调用第一个 stub

Java JList 滚动到所选项目

java - 使用 Point2D.Double 绘制点时出现问题

r - ggplot2,顶部和边缘的图例

java - 使用数组矩阵RGB java将图像转换为灰度