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

时间:2013-05-25 08:52:08

标签: java graphics java-2d

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

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

enter image description here

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

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

4 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分: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);
}

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

答案 2 :(得分:1)

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

  • Toggle Perspective可以打开和关闭内容的透视效果。
  • Morph Perspective可以平滑地制作透视转换内容和非透视转换内容之间的转换。

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

答案 3 :(得分: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();

}
}

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

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