我想在我的java应用程序中为我的网络摄像头流式传输一些图像处理内容。我正在使用随附的OpenCV和Java Library文件。
我有如何捕捉图像,但如何像视频一样连续捕捉和显示帧。
请建议修改以下代码或其他方法。
我正在使用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 :(得分:2)
我有如何捕获图像,但如何像视频一样连续捕获和显示帧。
我从未使用过OpenCV API,所以我对这个库一无所知。但是我认为你的问题是由无限循环引起的典型线程阻塞问题:
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();
答案 1 :(得分:1)
dic19是正确的,您需要封装框架绘制过程并重新绘制SwingWorker中的Swing组件。但是我会避免Thread.sleep
和ImageIO
的使用,因为Swing组件上的实际输出会很差。
所以,我建议这些改变:
1:在SwingWorker的构造函数中初始化VideoCapture并在doInBackground()方法的循环中删除sleep:
@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样本,我相信你会在那里找到有用的东西。