2014-09-03 128 views
1

我想在我的Java應用程序中流式傳輸我的攝像頭以獲得一些圖像處理內容。我正在使用OpenCV和Java庫文件。使用Java在opencv中的攝像頭流

我得到了如何捕捉圖像,但如何像視頻一樣捕捉和顯示幀。

請在下面的代碼或其他替代方法建議修改。

我使用Java Swing Application開發。

package openc; 
import org.opencv.core.*; 

public class openc { 

private JFrame frame; 

/** 
* Launch the application. 
*/ 
public static void main(String[] args) { 
    EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      try { 
       openc window = new openc(); 
       window.frame.setVisible(true); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

/** 
* Create the application. 
*/ 
public openc() { 
    initialize(); 
} 

/** 
* Initialize the contents of the frame. 
*/ 
private void initialize() { 
    frame = new JFrame(); 
    frame.setBounds(100, 100, 450, 300); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    Canvas canvas = new Canvas(); 
    frame.getContentPane().add(canvas, BorderLayout.CENTER); 

      System.loadLibrary(Core.NATIVE_LIBRARY_NAME); 
      VideoCapture camera = new VideoCapture(0); 
      if(!camera.isOpened()){ 
       System.out.println("Error"); 
      } 
      else { 
       Mat iframe = new Mat(); 
       while(true){ 
        if (camera.read(iframe)){ 
         System.out.println("Frame Obtained"); 
         System.out.println("Captured Frame Width " + 
         iframe.width() + " Height " + iframe.height()); 
         while(true){ 
         Highgui.imwrite(canvas, iframe); 
         } 


        } 
       } 
      } 
      camera.release(); 

} 

} 
+0

Highgui.imwrite(canvas,iframe); //可能不會編譯 – berak 2014-09-03 13:49:32

+0

檢查JavaCV。可能你會在那裏得到教程! – 2014-09-03 13:54:46

回答

2

我如何捕捉圖像,而是如何像一個視頻連續捕捉和顯示幀。

我從來沒有用過OpenCV API,所以我對這個庫一無所知。不過我覺得你的問題是引起無限循環一個tipical線程阻塞問題:

while(true){ // infinite loop 

    if (camera.read(iframe)) { 
     System.out.println("Frame Obtained"); 
     System.out.println("Captured Frame Width " + 
     iframe.width() + " Height " + iframe.height()); 

     while(true) { // another infinite loop 
      Highgui.imwrite(canvas, iframe); 
     } 
    } 
} 

您有卡住Event Dispatch Thread導致您的GUI會停止響應兩個無限循環。 Swing是單線程的,您必須格外小心您如何創建/更新Swing組件。

在這種特殊情況下,我認爲您可以使用SwingWorker定期在後臺線程中讀取相機數據,並更新EDT中的Canvas對象。事情是這樣的:

SwingWorker<Void, Mat> worker = new SwingWorker<Void, Mat>() { 
    @Override 
    protected Void doInBackground() throws Exception {    
     while(!isCancelled()) { 
      if (camera.read(iframe)) { 
       publish(iframe); 
      } 
      Thread.sleep(500); // prudential time to avoid block the event queue 
     }    
     return null; 
    } 

    @Override 
    protected void process(List<Mat> chunks) { 
     Mat lastFrame = chuncks.get(chunks.size() - 1); 
     Highgui.imwrite(canvas, lastFrame); 
    }   
}; 

worker.execute(); 
+0

嘿,謝謝喜歡你的想法,但是這在處理複雜的圖像處理算法時需要處理時間。有沒有辦法只使用opencv? – Gates 2014-09-04 07:57:24

+0

正如我所說我不知道​​這個API,所以我不知道,但如果你的目標是使用Swing顯示圖像/視頻,那麼你將不得不處理[併發在Swing](http:// docs .oracle.com/javase/tutorial/uiswing/concurrency/index.html)。當我看到問題時,您基本上需要兩件事:1)通過InputStream從相機讀取數據(這就是我猜測的OpenCV)。 2)相應地更新您的GUI。這兩個任務可以(也應該)在不同的線程中完成,這就是爲什麼我建議使用SwingWorker。 @Gates – dic19 2014-09-04 11:31:23

1

dic19是正確的,你需要封裝框架graping和重新粉刷在SwingWorker的Swing組件的過程。不過,我會避免Thread.sleep和使用ImageIO,因爲Swing組件上的實際輸出將表現不佳。

所以,建議這些變化:

1 .:初始化在的SwingWorker的構造函數的VideoCapture和doInBackground()方法的環內取出睡眠:

@Override 
protected Void doInBackground() throws Exception { 
    Mat webcamImage = new Mat(); 
    while (!isCancelled()) { 
     camera.read(webcamImage); 
     if (!webcamImage.empty()) { 
      videoPanel.updateImage(webcamImage); 
     } else { 
      break; 
     } 
    } 

    return null; 
} 

2。 :在呈現圖像的Swing組件中,應該使用System.arraycopy。它快於ImageIO

public void updateImage(Mat matrix) { 
    int type = BufferedImage.TYPE_BYTE_GRAY; 
    if (matrix.channels() > 1) { 
     type = BufferedImage.TYPE_3BYTE_BGR; 
    } 
    byte[] b = new byte[matrix.channels() * matrix.cols() * matrix.rows()]; 
    matrix.get(0, 0, b); 
    image = new BufferedImage(matrix.cols(), matrix.rows(), type); 
    final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); 
    System.arraycopy(b, 0, targetPixels, 0, b.length); 

    repaint(); 
} 

最後,覆蓋paintComponent()方法:

@Override 
public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    if (image == null) { 
     return; 
    } 
    g.drawImage(this.image, 1, 1, this.image.getWidth(), this.image.getHeight(), null); 
} 

搜索GitHub樣品,我敢肯定你會發現一些有益的存在。