基于树莓派和安卓客户端的移动监控系统

文章目录[隐藏]


作者  :DevinTT

链接:http://blog.csdn.net/DevinTT/article/details/43865431

接触树莓派已经有2周了,在linux发现了好多很不错的工具,其中mjpg-streamphddns还有libcv什么的,都是很不错的工具。加上我会一点点安卓移动端的开发,所以结合一下自己掌握的技术,实现一个基于树莓派和安卓的监控系统。


为了方便大家学习,工程代码已经上传:http://download.csdn.net/detail/devintt/8447193(点击阅读原文进入)

一、安装mjpg-stream

以下技术参考http://blog.csdn.net/blueslime/article/details/12429411

下面的文字是使用githubjacksonliammjpg-streamer-experimental,在树莓派新版系统上可以进行完全编译,适合强迫症患者。而且还能支持树莓派的专用摄像头Pi Cam

项目工程:https://github.com/jacksonliam/mjpg-streamer

将工程下载后,传送到树莓派系统中解压:

  1. unzip mjpg-streamer-master.zip  

编译此工程需要用到cmake和支持库:

  1. sudo apt-get install cmake  

  2.   

  3. sudo apt-get install libjpeg8-dev  

然后进入工程mjpg-streamer-experimental,进行完全编译:

  1. make clean all  

进入树莓派设置菜单:

  1. sudo raspi-config  

移动到第五项“Enable Camera”,回车进入,按tab键切换到“Enable”回车确认。回到主菜单,tab键切换到“Finish”回车确认。树莓派会自动重启。

 

重启后,命令行进入mjpg-streamer-experimental目录

使用下面指令启动普通USB摄像头:

  1. ./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"  

启动树莓派专用摄像头RaspiCamera的指令是:


  1. ./mjpg_streamer -i "./input_raspicam.so" -o "./output_http.so -w ./www"  

 

查看图像,在PC端打开浏览器,输入下面网址可以看到静态截图:

  1. http://<树莓派IP>:8080/?action=snapshot  

输入下面两条网址可以看到动态图像:

  1. http://<树莓派IP>:8080/?action=stream   

  2. http://<树莓派IP>:8080/javascript_simple.html  

 

但是市面上大部分摄像头都是支持YUV的,而不是JPEG的。mjpg-stream支持JPEG和YUV两种格式。直接运行出现i: init_VideoIn failed错误,解决方法:


1、打开以下文件:

  1. sudo nano mjpg-streamer/plugins/input_uvc/input_uvc.c  


2、翻到大概第三页将一行中的:

int width = 640, height = 480, fps = -1, format = V4L2_PIX_FMT_MJPEG, i;

修改成:

int width = 640, height = 480, fps = -1, format = V4L2_PIX_FMT_YUYV, i;

需要重新编译才会有效。

二、编写安卓客户端

其实完成第一步就几乎完成了很大部分的工作了,用手机浏览器输入ip地址就可以查看。但是编写手机客户端有利于摄像头的管理和加入脸部捕获什么的,让监控系统更加逼格。


先介绍一下用http实现图片获取的方法,我在另一篇文章里面说的比较清晰,

http://blog.csdn.net/devintt/article/details/38893869

我在这里主要说说图片获取之后的处理和显示的方法。

http获取图片数据流

 

  1.   private void doGet() {  

  2.         //get http img  

  3.         String url = "http://192.168.0.105:8080/?action=snapshot";  

  4. //        Log.d(TAG, url);  

  5.         myHttpThreadGet = new HttpThreadGet(url, HttpThreadGet.GETIMG, handler);  

  6.         myHttpThreadGet.start();  

  7. }  

消息传递获取,这里只用了获取图片

 

  1. /************************** msg接收 *************************/  

  2.   

    从图2中我们能看到,PLC的模块化编程语言十分方便,把参数直接填写在模块的输入参量中即可。可见PLC编程语言的方便程度绝不是单片机/嵌入式能够媲美的。

  3.         handler = new Handler() {  

  4.             @Override  

  5.             public void handleMessage(Message msg) {  

  6.                 switch (msg.what) {  

  7.                     case HttpThreadPost.POST:  

  8.                         result = (String) msg.obj;  

  9.                         break;  

  10.                     case HttpThreadGet.GET:  

  11.                         result = (String) msg.obj;  

  12.                         break;  

  13.                     case HttpThreadGet.GETIMG:  

  14.                         buffer = (byte[])msg.obj;  

  15.                         try {  

  16.                             image = BitmapFactory.decodeByteArray(buffer, 0, buffer.length, BitmapFactoryinfo);  

  17.                             faceDetect(image);  

  18.                         } catch (Exception e) {  

  19.                             Log.e(TAG, e.toString());  

  20.                         }  

  21.                         doGet();    //再请求  

  22.                         break;  

  23.                     default:  

  24.                         break;  

  25.                 }  

  26.             }  

  27.         };  


由于图片是JPEG格式的数据流,需要通过BitmapFactory重新编码,如果要实现人脸识别FaceDetector的话需要将图片格式化Bitmap.Config.RGB_565

 

  1. /************************** format bitmap *************************/  

  2.   

  3.     private void detectSetup() {  

  4.         BitmapFactoryinfo = new BitmapFactory.Options();  

  5.         BitmapFactoryinfo.inPreferredConfig = Bitmap.Config.RGB_565;  //构造位图生成的参数,必须为565。类名+enum  

  6. }  

  7.   

  8.    


获取到图片并格式化之后就可以经行显示了,如果要加入人脸检测的话,就调用这个。

以下技术参考http://blog.csdn.net/zhandoushi1982/article/details/8613916

这里的方法可以将检测出来的人脸经行描绘出来,并且可以同时识别多个,由于我们的图片是静态一张一张的,所以我们用的是静态的方法。

 

  1. /************************** face detect *************************/  

  2.   

  3.     private void faceDetect(Bitmap fBitmap) {  

  4. //        myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.baby, BitmapFactoryOptionsbfo);  

  5.         int imageWidth = fBitmap.getWidth();  

  6.         int imageHeight = fBitmap.getHeight();  

  7.         myFace = new FaceDetector.Face[numberOfFace];       //分配人脸数组空间  

  8.         myFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace);  

  9.         numberOfFaceDetected = myFaceDetect.findFaces(fBitmap, myFace);    //FaceDetector 构造实例并解析人脸  

  10.         countertext.setText("numberOfFaceDetected is " + numberOfFaceDetected);  

  11.         Log.i(TAG,"numberOfFaceDetected is " + numberOfFaceDetected);  

  12.         Bitmap bitmapTemp = Bitmap.createBitmap(fBitmap.getWidth(), fBitmap.getHeight(), Bitmap.Config.RGB_565);  

  13.         Canvas canvas = new Canvas(bitmapTemp);  

  14.         canvas.drawColor(Color.TRANSPARENT);  

  15.         Paint myPaint = new Paint();  

  16.         myPaint.setColor(Color.GREEN);  

  17.         myPaint.setStyle(Paint.Style.STROKE);  

  18.         myPaint.setStrokeWidth(3);          //设置位图上paint操作的参数  

  19.         canvas.drawBitmap(fBitmap, 00, myPaint);  

  20.   

  21.         for(int i=0; i < numberOfFaceDetected; i++){  

  22.             Face face = myFace[i];  

  23.             PointF myMidPoint = new PointF();  

  24.             face.getMidPoint(myMidPoint);  

  25.             myEyesDistance = face.eyesDistance();   //得到人脸中心点和眼间距离参数,并对每个人脸进行画框  

  26.             canvas.drawRect(            //矩形框的位置参数  

  27.                     (int)(myMidPoint.x - myEyesDistance),  

  28.                     (int)(myMidPoint.y - myEyesDistance),  

  29.                     (int)(myMidPoint.x + myEyesDistance),  

  30.                     (int)(myMidPoint.y + myEyesDistance),  

  31.                     myPaint);  

  32.         }  

  33.         imageview.setImageBitmap(bitmapTemp);  

  34. }  

为了防止退出的时候没有关闭http通信,造成下次再打开会出现FC,所以需要中断http通信。

 

  1. @Override  

  2.     protected void onDestroy() {  

  3.         super.onDestroy();  

  4.         if(myHttpThreadGet.isAlive()) {  

  5.             myHttpThreadGet.interrupt();  

  6.         }  

  7. }  


最后附上效果图:


学习单片机技术必须注重“理论+实践”的方法。如果只学理论知识而不动手操作,则收效甚微;如果只进行实践操作而不学习理论知识,效果也不明显。因此,学好单片机技术必须做到理论、实践同时学,理论知识和实践技能就像人的两条腿,缺一不可。

生成海报
点赞 0

thePro

我还没有学会写个人说明!

相关推荐

树莓派做一个获取GPS时间的NTP服务器

由于单位用的是内部网络,机器时间无法与internet同步,导致内网的所有设备各自为政,对工作和管理带来的麻烦说不清,为解决这个问题,决定用手里的树莓派做通过GPS获取时间&

树莓派控制sg90舵机 驱动 Python详细教程|徐奥雯

灰色线为GND接地、红色线为VCC接5V供电、黄色线为脉冲输入 直接复制以下代码运行即可 运行前 请将脉冲输入所连接的树莓派GPIO引脚号 填写入下面的gpio_pin中 您可以直接运行此文件来测试他是否正常工作,你的舵机应该会开