4

我的问题是我有一个小视角的矩形,我想将它拉伸回来再次呈现为一个矩形。

为了直观地表示它,我目前在我的图像中有类似红色形状的东西,我有 4 个Points(这个形状的每个角)。结果,我想要蓝色形状的东西,而且我已经有了Rectangle它的对象。

在此处输入图像描述

我想知道是否有一种方法可以复制多边形并将其绘制为另一个多边形拉伸。我找到了适用于 Android 的东西(setPolyToPoly),但我找不到适用于 java 的东西。

是否有一些执行此操作的参考或代码示例,或者可能有一些想法如何解决这个问题?

4

4 回答 4

3

我想我明白你需要什么:可以应用于图像的所谓透视变换。Java 具有内置的AffineTransform,但仿射变换始终保持行的“平行性”,因此您不能使用它。

现在,如果您在网上搜索“java 透视变换”,您会发现很多选项,例如 JavaFX PerspectiveTransform、 JAI PerspectiveTransform。如果您只需要拉伸图像,您还可以使用 JHLabs PerspectiveFilter并且还有其他选项。

于 2013-05-28T16:49:27.047 回答
1

这是一些代码,可以将具有四个点的多边形拉伸为矩形。

public static Rectangle2D polyToRect(Polygon polygon) {
    if (polygon.xpoints.length != 4 || polygon.ypoints.length != 4)
        throw new IllegalArgumentException(
                "More than four points, this cannot be fitted to a rectangle");


    Rectangle2D rect = new Rectangle2D.Double();
    for (int i = 0; i < 4; i++) {
        Point2D point = new Point2D.Double(polygon.xpoints[i],
                polygon.ypoints[i]);
        rect.add(point);
    }
    return rect;
}

public static Polygon rectangleToPolygon(Rectangle2D rect) {
    Polygon poly = new Polygon();
    poly.addPoint((int) rect.getX(), (int) rect.getY());
    poly.addPoint((int) (rect.getX() + rect.getWidth()), (int) rect.getY());
    poly.addPoint((int) (rect.getX() + rect.getWidth()),
            (int) (rect.getY() + rect.getHeight()));
    poly.addPoint((int) rect.getX(), (int) (rect.getY() + rect.getHeight()));
    return poly;
}


public static class drawPolyAndRect extends JPanel {
    Polygon poly = new Polygon();

    public drawPolyAndRect() {
        poly.addPoint(0, 0);
        poly.addPoint(400, 40);
        poly.addPoint(400, 250);
        poly.addPoint(0, 400);

    }

    @Override
    @Transient
    public Dimension getPreferredSize() {
        return new Dimension(1000, 1000);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.green);
        g2d.fill(poly);
        Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                0.5f);
        g2d.setColor(Color.blue);
        g2d.setComposite(c);
        Rectangle2D polyToRect = polyToRect(poly);
        g2d.fill(polyToRect);

        // displace for drawing
        polyToRect.setFrame(polyToRect.getX() + 100,
                polyToRect.getY() + 100, polyToRect.getWidth(),
                polyToRect.getHeight());

        Polygon polyToRectToPoly = rectangleToPolygon(polyToRect);
        g2d.fill(polyToRectToPoly);

        g2d.dispose();
    }

}

public static void main(String[] args) {
    JFrame frame = new JFrame("Poly to rect");
    frame.getContentPane().add(new drawPolyAndRect());
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}

本质上,这使用了将点添加到空的 rectangle2d 的工作原理,它构造了包含所有四个点的最小可能矩形,从而拉伸了多边形。如果要将返回的矩形作为多边形,请检查第二个静态方法。图片: 在此处输入图像描述

于 2013-05-25T18:11:20.240 回答
1

使用@lbalazscs answer建议的PerspectiveTransform的基于 JavaFX 的解决方案。

  • Toggle Perspective打开和关闭内容的透视效果。
  • Morph Perspective在透视变换和非透视变换内容之间平滑地动画过渡。

透视  观点

import javafx.animation.*;
import javafx.application.*;
import javafx.beans.value.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.ToggleButton;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.*;
import javafx.stage.Stage;
import javafx.util.Duration;

public class PerspectiveMovement extends Application {
  // perspective transformed group width and height.
  private final int W = 280;
  private final int H = 96;

  // upper right and lower right co-ordinates of perspective transformed group.
  private final int URY = 35;
  private final int LRY = 65;

  @Override public void start(Stage stage) {
    final PerspectiveTransform perspectiveTransform = createPerspectiveTransform();

    final Group group = new Group();
    group.setCache(true);
    setContent(group);

    final ToggleButton perspectiveToggle = createToggle(
      group, 
      perspectiveTransform
    );

    VBox layout = new VBox(10);
    layout.setAlignment(Pos.CENTER);
    layout.getChildren().setAll(
      perspectiveToggle,
      createMorph(perspectiveToggle, group, perspectiveTransform),
      group
    );
    layout.setStyle("-fx-padding: 10px; -fx-background-color: rgb(17, 20, 25);");

    stage.setScene(new Scene(layout));
    stage.show();
  }

  private void setContent(Group group) {
    Rectangle rect = new Rectangle(0, 5, W, 80);
    rect.setFill(Color.web("0x3b596d"));

    Text text = new Text();
    text.setX(4.0);
    text.setY(60.0);
    text.setText("A long time ago");
    text.setFill(Color.ALICEBLUE);
    text.setFont(Font.font(null, FontWeight.BOLD, 36));

    Image image = new Image(
      "http://icons.iconarchive.com/icons/danrabbit/elementary/96/Star-icon.png"
    );
    ImageView imageView = new ImageView(image);
    imageView.setX(50);

    group.getChildren().addAll(rect, imageView, text);
  }

  private PerspectiveTransform createPerspectiveTransform() {
    PerspectiveTransform perspectiveTransform = new PerspectiveTransform();

    perspectiveTransform.setUlx(0.0);
    perspectiveTransform.setUly(0.0);
    perspectiveTransform.setUrx(W);
    perspectiveTransform.setUry(URY);
    perspectiveTransform.setLrx(W);
    perspectiveTransform.setLry(LRY);
    perspectiveTransform.setLlx(0.0);
    perspectiveTransform.setLly(H);

    return perspectiveTransform;
  }

  private ToggleButton createToggle(final Group group, final PerspectiveTransform perspectiveTransform) {
    final ToggleButton toggle = new ToggleButton("Toggle Perspective");
    toggle.selectedProperty().addListener(new ChangeListener<Boolean>() {
      @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean wasSelected, Boolean selected) {
        if (selected) {
          perspectiveTransform.setUry(URY);
          perspectiveTransform.setLry(LRY);
          group.setEffect(perspectiveTransform);
        } else {
          group.setEffect(null);
        }
      }
    });

    return toggle;
  }

  private ToggleButton createMorph(final ToggleButton perspectiveToggle, final Group group, final PerspectiveTransform perspectiveTransform) {
    final Timeline distorter = new Timeline(
      new KeyFrame(
        Duration.seconds(0), 
        new KeyValue(perspectiveTransform.uryProperty(), 0,  Interpolator.LINEAR),
        new KeyValue(perspectiveTransform.lryProperty(), H, Interpolator.LINEAR)
      ),
      new KeyFrame(
        Duration.seconds(3), 
        new KeyValue(perspectiveTransform.uryProperty(), URY, Interpolator.LINEAR),
        new KeyValue(perspectiveTransform.lryProperty(), LRY, Interpolator.LINEAR)
      )
    );

    final ToggleButton morphToggle = new ToggleButton("Morph Perspective");
    morphToggle.selectedProperty().addListener(new ChangeListener<Boolean>() {
      @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean wasSelected, Boolean selected) {
        if (!perspectiveToggle.isSelected()) {
          perspectiveToggle.fire();
        }
        if (selected) {
          distorter.setRate(1);
          distorter.play();
        } else {
          distorter.setRate(-1);
          distorter.play();
        }
      }
    });

    return morphToggle;
  }
}
于 2013-05-28T22:42:34.717 回答
0

我不知道这是否可以帮助你,但让我给你我所理解的东西:

import javax.swing.*;
import java.awt.*;

public class PolyToRectangle extends JPanel {
public static final int SPEED = 50; //less = more fast.
private int ax = 0, bx = 800, cx = 800, dx = 0, 
            ay = 0, by = 40, cy = 250, dy = 400;
private Polygon poly;


public PolyToRectangle() {
    setPreferredSize(new Dimension(1200, 720));
    poly = new Polygon(new int[]{ax, bx, cx, dx}, new int[]{ay, by, cy, dy}, 4);
}

@Override
public void paintComponent(Graphics g) {

    Graphics2D g2d = (Graphics2D) g;
    g2d.draw(poly);
    g2d.fill(poly);
}

public void polyToRectangle() throws InterruptedException {
    int flag = 0;
    for (int i = 0; i < 150; i++) {
        flag++;
        poly.addPoint(ax, ay);
        poly.addPoint(bx, (by = flag % 3 == 0 ? --by : by));
        poly.addPoint(cx, cy++);
        poly.addPoint(dx, dy);
        Thread.sleep(SPEED);
        repaint();
    }
}

protected void clear(Graphics g) {
    super.paintComponent(g);
}

public static void main(String[] args) throws InterruptedException {
    Frame frame = new JFrame();
    PolyToRectangle se = new PolyToRectangle();
    frame.add(se);
    frame.pack();
    frame.setVisible(true);
    se.polyToRectangle();

}
}

好的,正如您所看到的,这段代码更像是“PolyToSquare”而不是 PolyToRectangle,但主要是显示在 for 中使用 Thread.sleep 重新绘制的“效果”,也许这就是您所说的“视觉拉伸”,请注意,for 上的迭代次数取决于从点 1 和 2 到从多边形到矩形“拉伸”的像素数,这是“手工制作”的效果,也许 @lbalazscs 建议的是最好的解决方案,希望有帮助,问候。

编辑:编辑代码更干净,并以更具体的方式遵循您的目标(现在更多的是 PolyToRectangle,修复了 bx 和 cx 值)。

于 2013-05-28T21:10:48.347 回答