使用Java将多边形拉伸到其他多边形

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

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

在此处输入图像描述

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

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

我想我理解你需要的东西:一种可以应用于图像的所谓透视变换。 Java有内置的AffineTransform ,但是仿射变换总是保留行的“并行性”,所以你不能使用它。

现在,如果您在网上搜索“java perspective transformation”,您会发现许多选项,如JavaFX PerspectiveTransform ,JAI PerspectiveTransform 。 如果您只需要拉伸图像,您也可以使用JHLabs PerspectiveFilter ,还有其他选项。

这里有一些代码可以将带有四个点的多边形拉伸到一个矩形。

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

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

使用PerspectiveTransform的基于JavaFX的解决方案,如@lbalazscs回答所示 。

  • 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() { @Override public void changed(ObservableValue 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() { @Override public void changed(ObservableValue 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; } } 

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

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

好的,你可以看到这个代码比PolyToRectangle更像是一个“PolyToSquare”,但主要是显示用for中的Thread.sleep重新绘制的“效果”,也许这就是你所说的“视觉延伸”,请注意,for上的迭代次数取决于从第1点和第2点到“从多边形到矩形”的“拉伸”的像素数,这是一种“手工制作”的效果,也许@lbalazscs建议的是最好的解决方案,希望乐于助人,问候。

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