2016-06-08 100 views
2

我想从网络摄像头获取输入并在画布中绘制它。JavaFX画布不是绘制图像

为此,我写了下面的代码块:

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

如果我通过只有一个形象用手该功能,它的工作原理。

如果我通过两个Image 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) { 
     } 
} 

你能告诉我什么,我做错了什么?解决办法是什么?谢谢。

回答

2

所以你实际上是两个问题

1)如果我通过两个图像,然后只汲取最后一个。

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

更新:

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

两个可能的解决方案是:

1)只有Stage包含Canvas实际上是显示了当启动Thread。这将确保Canvas即使在第一张照片时也具有正确的高度和宽度。

2)聆听画布的宽度和高度变化,并根据需要重新绘制Image。这将确保每当画布被调整大小时,Image被重新绘制(其优点是图片始终适合屏幕,所以这是建议的方式)

该示例包含两种方法。

2)但是我在执行的线程,并从 线程不断调用它。该功能则涉及到仍站上线

我们将看到完整的代码什么都可以错,但要等到更新的帖子,包括每一个需要的就是发现问题的一部分,这里有一个例子其中每隔3秒更新一个背景线程的Image画布:

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); 
    } 
} 
+0

感谢您的回复。你误解了我的第一个问题。然后我也运行了一个线程,并在图像之间等待了10秒钟。这只是绘制的最后一张图片。它不应该画出第一张图片,然后等待(对于线程),然后再绘制第二张图片?而你的代码并没有解决我的问题,我试图实现它。你希望看到我的完整代码吗?如果是,那么我的电子邮件ID:bishwa420(at)gmail(dot)com。干杯。 –

+0

我添加了更多用于检测错误或错误的代码。 –

+0

我已经为你更新了答案。我几乎可以肯定,这导致了这个问题,两种方法都有效。具有听众的那个会更好,因为它可以确保图像始终得到调整。 – DVarga