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())那是因为我写了一个例子,其中有两张图片,当然你没有,因此你必须修改它……它可以是简单的
私有对象