Stretching a polygon to another polygon using Java

My problem is that I have a rectangle presented with a small perspective, and I would like to stretch it to represent it again as a rectangle.

To visualize it visually, I have something like a red shape in my image, and I have 4 Points (each corner of this shape). As a result, I would like to have something like a blue shape, and I already have a Rectangle object.

enter image description here

I was wondering if there is a way to copy a polygon and draw it as a stretched other polygon. I found something for Android (setPolyToPoly), but I could not find something similar for java.

Is there any link or sample code that performs this operation, or maybe some ideas how I can solve this problem?

+4
source share
4 answers

I think I understand what you need: the so-called perspective transformation, which can be applied to the image. Java has a built-in AffineTransform , but affine conversion always keeps lines “parallel”, so you cannot use this.

Now, if you are searching the Internet for “Java perspective conversion”, you will find many options, such as JavaFX PerspectiveTransform , JAI PerspectiveTransform . If you only need to stretch the images, you can also use JHLabs PerspectiveFilter , and there are other options.

+3
source

Here is some code that turns a four-dot polygon into a rectangle.

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

Essentially, this uses the way points are added to an empty 2D rectangle, it builds the smallest possible rectangle containing all four points, stretching the polygon. Check out the second static method if you want the returned rectangle to be a polygon. Picture: enter image description here

+1
source

JavaFX-based solution using PerspectiveTransform as suggested by @lbalazscs answer .

  • Toggle Perspective turns on and off the perspective effect for content.
  • Morph Perspective seamlessly animates the transition between transformed perspective and non-perspective transformed content.

perspective offperspective on

 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; } } 
+1
source

I don’t know if this will help you, but let me give you what I did with understanding:

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

Well, as you can see, this code is more "PolyToSquare" more than PolyToRectangle, but the main thing was to show the "effect" of repainting using Thread.sleep in a, it is possible that the "visual stretching" is saying that the number of iterations per for depends on the number of pixels from points 1 and 2, to “stretch” from polygon to rectangle, this is a “handmade” effect, perhaps what @lbalazscs offers is the best solution, I hope to be useful, welcome.

EDIT: The code has been edited to be cleaner and more accurately follow your goal (now it is more PolyToRectangle, fixed values ​​bx and cx).

0
source

Source: https://habr.com/ru/post/1482699/


All Articles