JavaFX画布未绘制图像
我试图从网络摄像头中获取输入并在画布中绘制它 为此,我编写了以下代码块:JavaFX画布未绘制图像,java,canvas,javafx,webcam,Java,Canvas,Javafx,Webcam,我试图从网络摄像头中获取输入并在画布中绘制它 为此,我编写了以下代码块: void addImageToCanvas(Image img){ GraphicsContext gc = canvas.getGraphicsContext2D(); gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight()); } 如果我用手在该函数中只传递一个图像,它就会工作 如果我通过两个图像s,那么它只绘制最后一个 但我正
void addImageToCanvas(Image img){
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
}
如果我用手在该函数中只传递一个图像,它就会工作
如果我通过两个图像
s,那么它只绘制最后一个
但我正在实现线程,并不断地从线程调用它。然后,该功能在线路上静止不动:
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
调用方法的代码部分:
public void run() {
try {
FrameGrabber grabber = new VideoInputFrameGrabber(cameraId);
CvMemStorage storage = CvMemStorage.create();
grabber.start();
IplImage grabbedImage;
BufferedImage bufImg;
int counter = 0;
while (primaryCameraChosen != null) {
grabbedImage = grabber.grab();
bufImg = grabbedImage.getBufferedImage();
addImageToCanvas(SwingFXUtils.toFXImage(bufImg, null));
try{
Thread.sleep(10000);
} catch(InterruptedException e){}
}
grabber.stop();
grabber.release();
} catch (Exception ex) {
}
}
你能告诉我我做错了什么吗?解决办法是什么?谢谢。所以你实际上有两个问题 1)如果我传递两个图像,那么它只绘制最后一个 您正在以相同的X、Y坐标、相同的高度和宽度绘制图像。其结果是(就像在现实生活中,如果您在现有的绘画上绘制某些东西),只有最后一个图形可见,因为它隐藏了第一个图形。这是预期的工作 OP评论后更新: 此行的问题:
gc.drawImage(img,0,0,canvas.getWidth(),canvas.getHeight())
是指,在第一个图像
时,它尝试使用画布
的实际高度和宽度绘制图像
,但很可能此时未绘制画布
本身,因此实际高度和宽度均为零,因此以零宽度和高度绘制图片
两种可能的解决办法是:
1)仅当包含画布的阶段实际显示时,才启动线程。这将确保画布
即使在第一张图片上也具有正确的高度和宽度
2)倾听画布的宽度和高度变化,并根据需要重新绘制图像。这将确保每当调整画布的大小时,图像
都会被重新绘制(其优点是图片始终适合屏幕,因此建议使用此方法)
该示例包含两种方法。
2)但我正在实现线程并从
线然后,该函数在线路上静止不动
我们将看到完整的代码可能有什么错误,但在您更新文章以包含检测问题所需的每个部分之前,这里有一个示例,它每隔3秒从背景线程更新画布上的图像
:
public class Main extends Application {
Canvas canvas;
@Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
canvas = new Canvas();
Pane pane = new Pane();
pane.getChildren().add(canvas);
canvas.widthProperty().bind(pane.widthProperty());
canvas.heightProperty().bind(pane.heightProperty());
root.setCenter(pane);
Thread thread = new Thread(new Runnable() {
private ObjectProperty<Image> imageToBeDrawn = new SimpleObjectProperty<Image>(new Image(getClass().getResource("a.jpg").toExternalForm()));
@Override
public void run() {
// Option 2: Listen to the width and height property change of the canvas and redraw the image
canvas.widthProperty().addListener(event -> addImageToCanvas(imageToBeDrawn.get()));
canvas.heightProperty().addListener(event -> addImageToCanvas(imageToBeDrawn.get()));
imageToBeDrawn.addListener(event -> addImageToCanvas(imageToBeDrawn.get()));
while(true){
Random rand = new Random();
if(rand.nextBoolean())
imageToBeDrawn.set(new Image(getClass().getResource("a.jpg").toExternalForm()));
else
imageToBeDrawn.set(new Image(getClass().getResource("b.jpg").toExternalForm()));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.setDaemon(true);
thread.start();
primaryStage.setScene(scene);
// Option 2: start the Thread only when the stage is showing
// primaryStage.showingProperty().addListener(new ChangeListener<Boolean>() {
//
// @Override
// public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
// if(newValue)
// thread.start();
//
// }
// });
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
void addImageToCanvas(Image img){
Platform.runLater(new Runnable(){
@Override
public void run() {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());
}});
}
public static void main(String[] args) {
launch(args);
}
}
public类主扩展应用程序{
帆布;
@凌驾
公共无效开始(阶段primaryStage){
试一试{
BorderPane根=新的BorderPane();
场景=新场景(根,400400);
画布=新画布();
窗格=新窗格();
pane.getChildren().add(画布);
canvas.widthProperty().bind(pane.widthProperty());
canvas.heightProperty().bind(pane.heightProperty());
root.setCenter(窗格);
Thread Thread=新线程(new Runnable(){
private ObjectProperty imageToBeDrawn=新的SimpleObject属性(新图像(getClass().getResource(“a.jpg”).toExternalForm());
@凌驾
公开募捐{
//选项2:聆听画布的宽度和高度属性更改,并重新绘制图像
canvas.widthProperty().addListener(事件->addImageToCanvas(imageToBeDrawn.get());
canvas.heightProperty().addListener(事件->addImageToCanvas(imageToBeDrawn.get());
addListener(事件->addImageToCanvas(imageToBeDrawn.get());
while(true){
Random rand=新的Random();
if(rand.nextBoolean())
set(新图像(getClass().getResource(“a.jpg”).toExternalForm());
其他的
set(新图像(getClass().getResource(“b.jpg”).toExternalForm());
试一试{
睡眠(1000);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
});
setDaemon(true);
thread.start();
初级阶段。场景(场景);
//选项2:仅当阶段显示时启动线程
//primaryStage.showingProperty().addListener(新的ChangeListener()){
//
//@覆盖
//public void已更改(谢谢您的回复。您误解了我的第一个问题。我当时也运行了一个线程,并在两个图像之间等待了10秒。这只是绘制的最后一个图像。它不应该绘制第一个图像,然后等待(线程)然后画第二个?你的代码并不能解决我的问题,我已经尝试过实现它。你想看我的完整代码吗?如果是,那么我的电子邮件id:bishwa420(at)gmail(dot)干杯。我添加了更多用于检测bug或错误的代码。我已经为您更新了答案。我几乎可以肯定这会导致问题,两种方法都会起作用。带有侦听器的方法更好,因为它可以确保始终调整图像的大小。事实上,我正在使用FXML在Netbeans中进行此操作。我尝试了您的第一种方法,但都是徒劳的。它是现在给出异常:线程“JavaFX应用程序线程”java.lang.RuntimeException中的异常:java.lang.reflect.InvocationTargetException
第行:private ObjectProperty imageToBeDrawn=new SimpleObjectProperty(新图像(getClass().getResource(“a.jpg”).toExternalForm())那是因为我写了一个例子,其中有两张图片,当然你没有,因此你必须修改它……它可以是简单的私有对象