基本原理:主要是通过WiFi不断传输电脑端摄像头抓取的图像给Android手机端进行刷新显示,达到视频监控的效果。
实现方案:电脑端作为服务器端,通过Python编写代码;手机端作为客户端,通过Java实现。
主要思路:为手机客户端能实时显示服务器端传来的图片,服务器端在发送图片之前需发送图片的大小,客户端解码图片前先分配与图片大小等大的缓存区,将图片存入缓存区后再进行解码,发送给主界面进行实时显示。
注意事项:Android建立wifi连接以及接收图片需单独开辟线程,解码图片后再通过Handler传递给主界面进行显示。
Android客户端主要代码:
显示界面
public class MainTab_camera extends Fragment {
RevImageThread revImageThread;
Button Camera_control;
public static ImageView image;
private static Bitmap bitmap;
private static final int COMPLETED = 0x111;
private MyHandler handler;
public static boolean Run = false;
private Bitmap bmp;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.activity_camera, container, false);
Camera_control = (Button)view.findViewById(R.id.camera_control);//连接按钮
image=(ImageView)view.findViewById(imageView);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//addListener();
handler = new MyHandler();
revImageThread = new RevImageThread(handler);
Resources res = MainTab_camera.this.getResources();
bmp= BitmapFactory.decodeResource(res,R.drawable.tab_camera_pressed);
addListener();
//new Thread(revImageThread).start();
}
public void addListener()
{
Camera_control.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(!Run)
Run = true;
else Run = false;
if(Run) {
Camera_control.setBackgroundColor(Color.parseColor("red"));
Camera_control.setText("关闭视频监控");
new Thread(revImageThread).start();
}
else{
Camera_control.setBackgroundColor(Color.parseColor("#ff6eff2d"));
Camera_control.setText("打开视频监控");
image.setImageBitmap(bmp);
}
}
});
}
static class MyHandler extends Handler{
public void handleMessage(Message msg){
if (msg.what == COMPLETED) {
bitmap = (Bitmap)msg.obj;
image.setImageBitmap(bitmap);
super.handleMessage(msg);
}
}
}
}
接收图片线程
public class RevImageThread implements Runnable {
private Handler handler;
private Bitmap bitmap;
private static final int COMPLETED = 0x111;
public RevImageThread(Handler handler){
this.handler = handler;
}
public void run()
{
int imagesize = 0;
try {
while(Ca && Run && socket!=null&&!socket.isClosed()){
InputStream ins = socket.getInputStream();
byte[] header = new byte[10];//帧头大小
int len;
if((len = ins.read(header,0,header.length)) == 10) {
String str = new String(header);
if(str.startsWith("start")) {
imagesize = Integer.parseInt(str.split(",")[1]);//,为分隔符
}
}
byte[] data = new byte[imagesize];
len = ins.read(data,0,data.length);
if(len == imagesize ){
bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
Message msg =handler.obtainMessage();
msg.what = COMPLETED;
msg.obj = bitmap;
handler.sendMessage(msg);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}
Python服务器端主要代码:
class Ui_server_send(QThread):
def __init__(self, parent=None):
super(Ui_server_send, self).__init__(parent)
def Serve_send(self,Flag_send):
self.Flag_send = Flag_send
self.start()
def run(self):
while self.Flag_send:
self.xret, self.ximage = cap.read() # 标志位,获取图片信息
self.xshow = cv2.resize(self.ximage, (240, 200)) # 设置图片转化大小
pi = Image.fromarray(cv2.cvtColor(self.xshow, cv2.COLOR_BGR2RGB))
buf = io.BytesIO() # 缓存对象
pi.save(buf, format='JPEG') # 将PIL下的图像压缩成jpeg格式,存入buf中
jpeg = buf.getvalue() # 从buf中读出jpeg格式的图像
a = len(jpeg)
length = bytes(str(a), 'utf-8')
b = connected_sock.sendall(b'start,' + length + jpeg)
if b == None:
print('发送完成', length)