我的问题是我有一个带有小透视的矩形,我想将它拉回来再次呈现为矩形。
为了直观地表现它,我目前在我的图像中有类似红色的形状,我有4 Points
(这个形状的每个角落)。结果我希望有一些像蓝色的形状,我已经有了Rectangle
对象。
我想知道是否有一种复制多边形的方法,并将其绘制为拉伸的另一个多边形。我找到了适合Android的东西(setPolyToPoly),但我找不到像这样的东西。
是否有一些参考或代码示例执行此操作,或者可能有些想法如何解决此问题?
答案 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添加点,它构造包含所有四个点的最小可能矩形,拉伸多边形。如果要将返回的矩形作为多边形,请检查第二个静态方法。图片:
答案 2 :(得分:1)
PerspectiveTransform建议使用@lbalazscs answer的基于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;
}
}
答案 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值。)