打造pc端和Android端的远程视频监控系统

第一篇博客献给java和c#

最近做比赛需要远程视频接入pc端和安卓端,于是就有了本文。

首先,我们使用一块嵌入式板搭载摄像头,嵌入式板我由于比赛用的是Intel的upboard,当然也可以使用树莓派。

第一步:我们在树莓派上安装好系统,然后在terminal中输入ifconfig得到树莓派的内网ip地址。

第二步:我选用python写一个获取摄像头图片及服务端的脚本。以下是代码(python代码是搬运的,哈哈):

读取摄像头的代码:

#-*- coding: cp936 -*-
import cv2
import time
import socket
from PIL import Image
import StringIO

# 获取电脑自带摄像头,若用usb摄像头则把0改为1
cap = cv2.VideoCapture(0)
# 调整采集图像大小为640*480
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# 这里的HOST对应树莓派的IP地址(自己输入ifconfig查),端口号自己随便定一个即可,但注意后面的程序中要保持统一
HOST="192.168.1.105"
PORT=15023
# 连接服务器
sock =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST,PORT))

while True:
    # 获取一帧图像
    ret, img = cap.read()
    # 如果ret为false,表示没有获取到图像,退出循环
    if ret is False:
        print("can not get this frame")
        continue    

    # 将opencv下的图像转换为PIL支持的格式
    pi = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    buf = StringIO.StringIO()# 缓存对象
    pi.save(buf, format='JPEG')# 将PIL下的图像压缩成jpeg格式,存入buf中
    jpeg = buf.getvalue()# 从buf中读出jpeg格式的图像
    buf.close()
    sock.sendall(jpeg )# 通过socket传到服务器
    # time.sleep(0.2)

sock.close()

然后是服务器代码:

# -*- coding: cp936 -*-
import socket
import time


sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("192.168.1.105",15023))# 注意bind的这里,IP地址和端口号都要与前面的程序中一样
sock.listen(2)# 监听端口

# 等待数据源端连接
src, src_addr = sock.accept()
print "Source Connected by", src_addr

# 等待目标端连接
dst, dst_addr = sock.accept()
print "Destination Connected by", dst_addr

while True:
    msg = src.recv(1024 *1024)
    if not msg:
        break
    try:
        dst.sendall(msg)
    except Exception as ex:
        dst, dst_addr = sock.accept()
        print "Destination Connected Again by", dst_addr
    except KeyboardInterrupt:
        print "Interrupted"
        break

src.close()
dst.close()
sock.close()

以上代码有一个问题尚未解决,就是无法完全关闭摄像头进程,需要在杀第一个代码进程后再开一次再杀。。。

第三步就是我们的pc端了:

pc端我采用的是wpf界面来显示视频画面,代码由于夹杂着其他功能就不贴了。只是说一下重点部分,主要是多线程上的问题。在wpf中,ui线程没有办法直接在非主线程中直接更新,需要用控件的Invoke方法,如:

                this.picbox.Dispatcher.Invoke(new Action(() =>
                {
                    BitmapFrame frame = BitmapFrame.Create(bmpimg);
                    this.picbox.Source = frame;
                }));

其中注意BitmapFrame,只有这个玩意才能跨线程更新,而BitmapImage是不行的。

最后是安卓端:

package rosclient.pc.com.test;

import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import android.os.Handler;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

public class MainActivity extends AppCompatActivity {
    BufferedReader br = null;
    OutputStream os = null;
    Bitmap bmp=null;
    private ImageView imageView = null;
    private static final int COMPLETED = 0;
    Socket socket = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    protected void onResume() {
        super.onResume();

        Thread t1=new Thread(socketRun);
        t1.start();
    }

    private void showTip(final String tip) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, tip, Toast.LENGTH_SHORT).show();
            }
        });
    }

    Runnable socketRun=new Runnable() {
        @Override
        public void run() {

            try {
                // 创建socket
                socket = new Socket("192.168.1.105", 15023);
                socket.setReceiveBufferSize(1024*1024);
            }catch (Exception e) {

                showTip("Error:" + e);
            }
            while (true)
            {
                try{
                    InputStream in = socket.getInputStream();
                    bmp=BitmapFactory.decodeStream(in);
                }catch (Exception e) {

                    showTip("Error:" + e);
                }
                Message msg=new Message();
                msg.what=0;
                msg.obj=bmp;
                handle.sendMessage(msg);
            }
            }
    };
    private Handler handle = new Handler() {
        public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0:
                        Bitmap bmp = (Bitmap) msg.obj;
                        if (bmp != null) {
                            imageView = (ImageView) findViewById(R.id.imageView1);
                            imageView.setImageBitmap(bmp);
                        }
                        break;
                }
        };
    };
    public Bitmap getimg()
    {
        if(socket.isConnected())
        {
            try{
                InputStream in = socket.getInputStream();
                bmp=BitmapFactory.decodeStream(in);
            }catch (Exception e) {

                showTip("Error:" + e);
            }
        }
        return bmp;
    }
}

不过要记得在manifest里给网络权限。

其中我遇到的问题首先是无法在主线程中使用网络,所以必须开另一个线程去socket连接,但是控件又不允许在非主线程中更新,所以要使用Handler方法

    private Handler handle = new Handler() {
        public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0:
                        Bitmap bmp = (Bitmap) msg.obj;
                        if (bmp != null) {
                            imageView = (ImageView) findViewById(R.id.imageView1);
                            imageView.setImageBitmap(bmp);
                        }
                        break;
                }
        };
    };
以上就完成了,撒花!!!!



阅读更多
文章标签: PYTHON c# java android
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭