今天非常榮幸地向各位小伙伴分享一個由共創(chuàng)社成員完成的遠程監(jiān)測及人臉識別項目,該項目依托ELF 1開發(fā)板為核心硬件平臺,構(gòu)建了一套完整的視頻監(jiān)控系統(tǒng),并在此基礎(chǔ)上集成了人臉識別功能。接下來,就為各位小伙伴詳盡展示這一項目的相關(guān)細節(jié)。
項目實現(xiàn)步驟
1.視頻監(jiān)控
這一步驟中需要實現(xiàn)兩個程序:
(1)在連接攝像頭的ELF 1開發(fā)板上實現(xiàn)一個服務(wù)器程序:它一邊讀取攝像頭數(shù)據(jù),一邊等待客戶端連接并發(fā)送數(shù)據(jù)??梢杂脙蓚€線程實現(xiàn),一個負責(zé)采集圖像信息;一個負責(zé)等待鏈接,并發(fā)送數(shù)據(jù)。
(2)在手機或電腦上,編寫客戶端程序,它會從ELF 1開發(fā)板上獲得數(shù)據(jù)并顯示出來。同樣,也可以用兩個線程來實現(xiàn)。一個負責(zé)接受數(shù)據(jù),一個負責(zé)顯示數(shù)據(jù)。這2個程序之間,并不需要實現(xiàn)復(fù)雜的協(xié)議。
MJPG‐streamer是一個開源軟件。MJPG-streamer從Linux UVC兼容的網(wǎng)絡(luò)攝像頭、文件系統(tǒng)或其他輸入插件獲取JPG,并通過HTTP、RTSP、UDP等將其作為M-JPEG流式傳輸?shù)絎ebBrowser、VLC和其他軟件。
MJPG-streamer 需要很少的CPU和內(nèi)存資源就可以工作,大部分編碼工作都是攝像頭完成的,所以對于內(nèi)存和性能都有限的嵌入式系統(tǒng)十分適用。
將MJPG-streamer移植并運行在ARM板上,在同一局域網(wǎng)內(nèi)的設(shè)備輸入正確的ip地址即可直接觀看到視頻畫面。對ARM板的性能要求不高,主頻200MHz的ARM芯片也能實現(xiàn)。
下載MJPG-streamer:
git clone https://github.com/shrkey/mjpg-streamer
啟動MJPG-streamer后,輸入ip地址以及端口號即可看到攝像頭內(nèi)容如下圖:
同時后續(xù)人臉識別功能中需要能夠從視屏流中提取出照片,需要修改MJPG-streamer源碼,使其支持拍照功能。具體修改如下:
修改完成之后只要向有名管道/tmp/webcom寫入相應(yīng)的字符串就能實現(xiàn)拍照功能。
# cd mjpg-streamer-rc63/plugins/output_file
# vim output_file.c
//在96行 函數(shù) void*worker_thread(void *arg) 體中加入以下代碼:
charbuf[10]; //
intflags = 0; //
intfd_com = 0; //打開管道
stop_num = 0; //拍照計數(shù)
if ( access(“/tmp/webcom”,F_OK) < 0 ) //創(chuàng)建有名管道用于接收拍照命令
{
if ( mkfifo(“/tmp/webcom”,0666 ) < 0)
{
Printf(“ photo fifo create failedn”);
}
}
fd_com = open (“/tmp/webcom”,O_RDONLY,0666);
if (fd < 0)
{
perror (“open the file webcom error”);
}
//在while( ok >= 0 && !pglobal->stop){ 后加入
if (flags == 0)
{
while(1)
{
reade(fd_com,buf,sizeof(buf));
if(strncmp(buf,”danger”,6) == 0) //拍11張照片
{
flags = 1;
bzero(buf,sizeof(buf));
break;
}
if(strncmp(buf,”one”,3) == 0) //拍1張照片
{
flags = 2;
bzero(buf,sizeof(buf));
break;
}
}
}
//在if (delay > 0){
usleep(1000*delay);
}后加入
stop_num++
if(flags == 1) //判斷拍照的數(shù)量
{
if ( stop_num > 9)
{
stop_num= 0;
flsgs= 0;
}
}
elseif (flags == 2)
{
stop_num= 0;
flags= 0;
}
2.人臉檢測
'haarcascade_frontalface_default.xml'是Opencv中已經(jīng)訓(xùn)練好的人臉分類器文件。它是基于Haar特征的級聯(lián)分類器,可以用于檢測正面的人臉。該文件是通過大量的正負樣本訓(xùn)練而成,可以用于人臉檢測的應(yīng)用中。具體調(diào)用代碼如下:
#! user/bin/python
#- * -coding:UTF-8 - * -
import cv2
import numpy as np
def myfilter(img):
# 圖像轉(zhuǎn)化為灰度格式
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 導(dǎo)入人臉級聯(lián)分類器引擎,'xml'文件包含訓(xùn)練好的人臉特征
face_cascade=cv2.CascadeClassifier('
/home/xuyang/test1/haarcascade_frontalface_default.xml')
#為防止報錯使用該文件在opencv下的絕對路徑
# 用人臉級聯(lián)分類器引擎進行人臉識別,返回的faces為人臉坐標(biāo)列表
faces = face_cascade.detectMultiScale(gray)
return faces
def myfaces_count(img,faces):
count = 0 #人臉計數(shù)初值
# 對每張臉,操作如下
for (x,y,w,h) in faces:
'''畫矩形圈出人臉
輸入?yún)?shù)依次為:圖片,右上角的點坐標(biāo),矩形大小,線條顏色,寬度
'''
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,255),2)
count += 1 # 累計人數(shù)
# 把統(tǒng)計人數(shù)顯示出來
cv2.putText(img,'{}'.format(count),(x,y-7),3,1.2,(0,0,255),2)
return img
#打開mjpg-streamer視頻流(通過URL)
#cap = cv2.VideoCapture('http://192.168.106.128:8080/?action=stream')
#打開視頻
cap = cv2.VideoCapture('video.mp4')
y = 0
#獲取視頻相關(guān)數(shù)據(jù)以便于保存視頻
width = int(cap.get(3))
height = int(cap.get(4))
fps = cap.get(5)
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
output_file = 'output_video.mp4'
video_writer = cv2.VideoWriter(output_file,fourcc,fps,(width,height),isColor = True)
while True:
# 讀取每一幀圖像
ret, frame = cap.read()
if not ret:
break
if y == 0:
faces = myfilter(frame) #人臉識別特征每10次循環(huán)做一次 不然運行速度太慢了
y = y + 1
if y == 10:
y =0
frame = myfaces_count(frame,faces)
# 在窗口上顯示當(dāng)前幀的圖像
cv2.imshow("Frame", frame)
video_writer.write(frame) #保存視頻
# 按下 'q' 退出循環(huán)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 關(guān)閉所有窗口及釋放對象
cap.release()
video_writer.release()
cv2.destroyAllWindows()
3.人臉識別
鑒于開發(fā)板運行人臉檢測模型已經(jīng)有一定的運算壓力,同時為了豐富項目內(nèi)容,人臉識別部分我們通過傳送照片在云端完成。
本文通過libcurl庫調(diào)用云端API實現(xiàn)人臉識別。需要libcurl庫支持https協(xié)議。要讓LibCurl庫支持https協(xié)議實現(xiàn)人臉識別,就需要安裝移植Openssl這個庫。此篇人臉識別介紹主要目的是判斷兩張人臉圖片的相似程度或者接近程度。安裝移植LibCurl庫和Openssl庫不多贅述。
首先是注冊一個OCR云識別平臺賬號如圖:
詢對應(yīng)平臺的API和接口地址:
下面是調(diào)用人臉識別API的代碼:
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
typedef unsigned int bool;
#define true 1
#define false 0
char buf[1024]={'