查看PC实时摄像头视频,其实就是以大于24次/秒的速度,控制PC摄像头进行拍照,并把每一张拍得的图片发送到android手机端,在手机上展示这些图片,得到实时的视频。
主要解决两个问题一时调用PC摄像头拍摄图片,二是在PC和android之间传输图片。
利用JavaCV(简介见本文末尾)调用PC摄像头很简单
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0); grabber.start(); //调用grab()方法就能得到IplImage类的一个对象,进行进一步处理就能得到图片
传输图片涉及图片数据和字节流之间的转化
PC端将图片转化为字节流
while ((image = grabber.grab()) != null && writeImageSocket.isConnected()) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image.getBufferedImage(), "jpg", baos ); baos.flush(); byte[] imageInByte = baos.toByteArray(); baos.close(); dos.writeInt(imageInByte.length); dos.write(imageInByte,0,imageInByte.length); dos.flush(); }Android读取字节流转化为图片
while (true) { int size = dataInput.readInt(); Log.e("size in client", Integer.toString(size)); byte[] data = new byte[size]; int len = 0; while (len < size) { len += dataInput.read(data, len, size - len); } ByteArrayOutputStream outPut = new ByteArrayOutputStream(); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); bitmap.compress(CompressFormat.PNG, 100, outPut); Message message = new Message(); message.what = 1; mHandler.sendMessage(message); }具体代码
PC端服务程序的实现CameraSever.java
package com.giantpoplar.cameraserver; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.imageio.ImageIO; import com.googlecode.javacv.FrameGrabber.Exception; import com.googlecode.javacv.cpp.opencv_core.IplImage; import com.googlecode.javacv.OpenCVFrameGrabber; public class CameraSever { public CameraSever() { ServerSocket serversocket = null; Executor executor = null; OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0); try { serversocket = new ServerSocket(8888); executor = Executors.newCachedThreadPool(); grabber.start(); while (!serversocket.isClosed()) { Socket acceptedSocket = serversocket.accept(); executor.execute(new SendImageThread(acceptedSocket, grabber)); } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { if (serversocket != null) { try { serversocket.close(); grabber.stop(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } } private class SendImageThread implements Runnable { Socket writeImageSocket; OpenCVFrameGrabber grabber; public SendImageThread(Socket socket, OpenCVFrameGrabber grabber) { this.writeImageSocket = socket; this.grabber = grabber; } public void run() { IplImage image=null; DataOutputStream dos=null; try { dos = new DataOutputStream(writeImageSocket.getOutputStream()); while ((image = grabber.grab()) != null && writeImageSocket.isConnected()) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image.getBufferedImage(), "jpg", baos ); baos.flush(); byte[] imageInByte = baos.toByteArray(); baos.close(); dos.writeInt(imageInByte.length); dos.write(imageInByte,0,imageInByte.length); dos.flush(); } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { if(dos!=null)dos.close(); writeImageSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) { new CameraSever(); } }
package com.example.imagetest; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.net.UnknownHostException; import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.media.Image; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.StrictMode; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { private Button connectButton = null; private Socket clientSocket = null; private Handler mHandler = null; private ReceiveThread mReceiveThread = null; private ImageView iv; private Bitmap bitmap; /** Called when the activity is first created. */ @SuppressLint("NewApi") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); connectButton = (Button) this.findViewById(R.id.connectbutton); iv = (ImageView) findViewById(R.id.iv); if (android.os.Build.VERSION.SDK_INT > 9) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() .permitAll().build(); StrictMode.setThreadPolicy(policy); } connectButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { try { clientSocket = new Socket("127.0.0.1", 8888);//ip地址换成运行Camerasever.java程序的电脑的ip } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } displayToast("连接成功!"); try { mReceiveThread = new ReceiveThread(clientSocket); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mReceiveThread.start(); } }); // 消息处理 mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 1: iv.setImageBitmap(bitmap); // 在ImageView中显示Bitmap break; default: break; } super.handleMessage(msg); } }; } // 显示Toast函数 private void displayToast(String s) { Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); } private class ReceiveThread extends Thread implements OnClickListener { private Socket s; private Button button; private PrintWriter writer; private Boolean flag = false; DataInputStream dataInput; public ReceiveThread(Socket s) throws IOException { this.s=s; dataInput = new DataInputStream( s.getInputStream()); } public void run() { try { while (true) { Log.e("5555555555555", "11111111111"); int size = dataInput.readInt(); Log.e("size in client", Integer.toString(size)); byte[] data = new byte[size]; int len = 0; while (len < size) { len += dataInput.read(data, len, size - len); } ByteArrayOutputStream outPut = new ByteArrayOutputStream(); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); bitmap.compress(CompressFormat.PNG, 100, outPut); Message message = new Message(); message.what = 1; mHandler.sendMessage(message); // Thread.sleep(100); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onClick(View arg0) { // TODO Auto-generated method stub flag = true; } } }
JavaCV是一个开源的java语言实现的视觉计算库,封装了OpenCV,FFmpeg,libdc1394等常用的视觉计算库,使用也比较简单,相关文件可以到
https://code.google.com/p/javacv/downloads/list?can=1&q=&colspec=Filename+Summary+Uploaded+ReleaseDate+Size+DownloadCount下载,下载最新版本即可,其中javacv-examples-0.7-src.zip是该库作者提供的例子,供使用者学习,该库暂时没有文档;javacv-0.7-bin.zip是打包好的jar文件,需要引入javacpp.jar,javacv.jar,以及一个javacv-*.jar取决于系统,我用的是Windows8.1,64位,我用的是javacv-windows-x86_64.jar;javacv-0.7-cppjars.zip,是opencv的各版本的jar包,也是按照系统选择;javacv-0.7-src.zip是javacv的源代码,使用时导入即可。