【问题标题】:JavaFX Canvas is not drawing imageJavaFX Canvas 未绘制图像
【发布时间】:2016-06-08 07:24:45
【问题描述】:

我正在尝试从网络摄像头获取输入并将其绘制在画布上。

为此,我编写了以下代码块:

void addImageToCanvas(Image img){
    GraphicsContext gc = canvas.getGraphicsContext2D();
    gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight());  
 }

如果我只在该函数中手动传递一个图像,它就可以工作。

如果我通过了两个Images,那么它只会绘制最后一个。

但我正在实现线程并从线程中连续调用它。然后函数就到了就行了:

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

你能告诉我我在这里做错了什么吗?解决办法是什么?谢谢。

【问题讨论】:

    标签: java canvas javafx webcam


    【解决方案1】:

    所以你实际上有两个问题

    1)如果我传递了两张图片,那么它只会绘制最后一张。

    您将图像绘制到相同的 X、Y 坐标,具有相同的高度和宽度。结果是(就像在现实生活中,如果你在现有的画上画一些东西)只有最后一幅画是可见的,因为它隐藏了第一幅画。这是预期的工作。

    OP 评论后更新:

    这一行的问题:gc.drawImage(img, 0, 0, canvas.getWidth(), canvas.getHeight()); 是,在第一个Image 它尝试使用Canvas 的实际高度和宽度来绘制Image,但此时很可能是@987654325 @ 本身没有绘制,所以实际的高度和宽度都为零,因此图片被绘制为零宽度和高度。

    两种可能的解决方案是:

    1) 只有在实际显示包含CanvasStage 时才启动Thread。这将确保Canvas 即使在第一张图片中也具有正确的高度和宽度。

    2) 监听画布的宽度和高度变化,如果需要重绘Image。这将确保,每当调整画布大小时,都会重绘 Image(它的优点是图片始终适合屏幕,因此这是建议的方式)

    该示例包含这两种方法。

    2) 但我正在实现线程并从 线。然后函数就到了就停不动就行了

    我们将看到可能有问题的完整代码,但是在您更新帖子以包含检测问题所需的每个部分之前,这里有一个示例,它使用来自后台线程的 Image 更新画布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);
        }
    }
    

    【讨论】:

    • 感谢您的回复。你误解了我的第一个问题。然后我还运行了一个线程,并在图像之间等待了 10 秒。这只是绘制的最后一张图像。它不应该绘制第一张图像然后等待(线程)然后绘制第二张吗?而且您的代码不能解决我的问题,我已经尝试实现它。你想看我的完整代码吗?如果是,那么我的电子邮件 ID:bishwa420(at)gmail(dot)com。干杯。
    • 我添加了更多用于检测错误或错误的代码。
    • 我已经为你更新了答案。我几乎可以肯定这会导致问题,两种方法都可以。带有侦听器的更好,因为它可以确保始终调整图像大小。
    • 其实我是在 Netbeans 中使用 FXML 做的。我尝试了您的第一个选项,但徒劳无功。它现在给了我例外:Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException 在线:private ObjectProperty&lt;Image&gt; imageToBeDrawn = new SimpleObjectProperty&lt;Image&gt;(new Image(getClass().getResource("a.jpg").toExternalForm()));
    • 那是因为我写了一个例子,里面有两张你当然没有的图片,所以你必须适应它......可以简单的private ObjectProperty&lt;Image&gt; imageToBeDrawn = new SimpleObjectProperty&lt;Image&gt;();,然后在运行@987654337 @。重点是更新属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    相关资源
    最近更新 更多