今天非常榮幸地向各位小伙伴分享一個(gè)由共創(chuàng)社成員完成的遠(yuǎn)程監(jiān)測(cè)及人臉識(shí)別項(xiàng)目,該項(xiàng)目依托ELF 1開(kāi)發(fā)板為核心硬件平臺(tái),構(gòu)建了一套完整的視頻監(jiān)控系統(tǒng),并在此基礎(chǔ)上集成了人臉識(shí)別功能。接下來(lái),就為各位小伙伴詳盡展示這一項(xiàng)目的相關(guān)細(xì)節(jié)。
項(xiàng)目實(shí)現(xiàn)步驟
1.視頻監(jiān)控
這一步驟中需要實(shí)現(xiàn)兩個(gè)程序:
(1)在連接攝像頭的ELF 1開(kāi)發(fā)板上實(shí)現(xiàn)一個(gè)服務(wù)器程序:它一邊讀取攝像頭數(shù)據(jù),一邊等待客戶端連接并發(fā)送數(shù)據(jù)??梢杂脙蓚€(gè)線程實(shí)現(xiàn),一個(gè)負(fù)責(zé)采集圖像信息;一個(gè)負(fù)責(zé)等待鏈接,并發(fā)送數(shù)據(jù)。
(2)在手機(jī)或電腦上,編寫(xiě)客戶端程序,它會(huì)從ELF 1開(kāi)發(fā)板上獲得數(shù)據(jù)并顯示出來(lái)。同樣,也可以用兩個(gè)線程來(lái)實(shí)現(xiàn)。一個(gè)負(fù)責(zé)接受數(shù)據(jù),一個(gè)負(fù)責(zé)顯示數(shù)據(jù)。這2個(gè)程序之間,并不需要實(shí)現(xiàn)復(fù)雜的協(xié)議。
MJPG‐streamer是一個(gè)開(kāi)源軟件。MJPG-streamer從Linux UVC兼容的網(wǎng)絡(luò)攝像頭、文件系統(tǒng)或其他輸入插件獲取JPG,并通過(guò)HTTP、RTSP、UDP等將其作為M-JPEG流式傳輸?shù)絎ebBrowser、VLC和其他軟件。
MJPG-streamer 需要很少的CPU和內(nèi)存資源就可以工作,大部分編碼工作都是攝像頭完成的,所以對(duì)于內(nèi)存和性能都有限的嵌入式系統(tǒng)十分適用。
將MJPG-streamer移植并運(yùn)行在ARM板上,在同一局域網(wǎng)內(nèi)的設(shè)備輸入正確的ip地址即可直接觀看到視頻畫(huà)面。對(duì)ARM板的性能要求不高,主頻200MHz的ARM芯片也能實(shí)現(xiàn)。
下載MJPG-streamer:
git clone https://github.com/shrkey/mjpg-streamer
啟動(dòng)MJPG-streamer后,輸入ip地址以及端口號(hào)即可看到攝像頭內(nèi)容如下圖:
同時(shí)后續(xù)人臉識(shí)別功能中需要能夠從視屏流中提取出照片,需要修改MJPG-streamer源碼,使其支持拍照功能。具體修改如下:
修改完成之后只要向有名管道/tmp/webcom寫(xiě)入相應(yīng)的字符串就能實(shí)現(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; //打開(kāi)管道
stop_num = 0; //拍照計(jì)數(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.人臉檢測(cè)
'haarcascade_frontalface_default.xml'是Opencv中已經(jīng)訓(xùn)練好的人臉?lè)诸惼魑募?。它是基于Haar特征的級(jí)聯(lián)分類器,可以用于檢測(cè)正面的人臉。該文件是通過(guò)大量的正負(fù)樣本訓(xùn)練而成,可以用于人臉檢測(cè)的應(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)入人臉級(jí)聯(lián)分類器引擎,'xml'文件包含訓(xùn)練好的人臉特征
face_cascade=cv2.CascadeClassifier('
/home/xuyang/test1/haarcascade_frontalface_default.xml')
#為防止報(bào)錯(cuò)使用該文件在opencv下的絕對(duì)路徑
# 用人臉級(jí)聯(lián)分類器引擎進(jìn)行人臉識(shí)別,返回的faces為人臉坐標(biāo)列表
faces = face_cascade.detectMultiScale(gray)
return faces
def myfaces_count(img,faces):
count = 0 #人臉計(jì)數(shù)初值
# 對(duì)每張臉,操作如下
for (x,y,w,h) in faces:
'''畫(huà)矩形圈出人臉
輸入?yún)?shù)依次為:圖片,右上角的點(diǎn)坐標(biāo),矩形大小,線條顏色,寬度
'''
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,255),2)
count += 1 # 累計(jì)人數(shù)
# 把統(tǒng)計(jì)人數(shù)顯示出來(lái)
cv2.putText(img,'{}'.format(count),(x,y-7),3,1.2,(0,0,255),2)
return img
#打開(kāi)mjpg-streamer視頻流(通過(guò)URL)
#cap = cv2.VideoCapture('http://192.168.106.128:8080/?action=stream')
#打開(kāi)視頻
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) #人臉識(shí)別特征每10次循環(huán)做一次 不然運(yù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)閉所有窗口及釋放對(duì)象
cap.release()
video_writer.release()
cv2.destroyAllWindows()
3.人臉識(shí)別
鑒于開(kāi)發(fā)板運(yùn)行人臉檢測(cè)模型已經(jīng)有一定的運(yùn)算壓力,同時(shí)為了豐富項(xiàng)目?jī)?nèi)容,人臉識(shí)別部分我們通過(guò)傳送照片在云端完成。
本文通過(guò)libcurl庫(kù)調(diào)用云端API實(shí)現(xiàn)人臉識(shí)別。需要libcurl庫(kù)支持https協(xié)議。要讓LibCurl庫(kù)支持https協(xié)議實(shí)現(xiàn)人臉識(shí)別,就需要安裝移植Openssl這個(gè)庫(kù)。此篇人臉識(shí)別介紹主要目的是判斷兩張人臉圖片的相似程度或者接近程度。安裝移植LibCurl庫(kù)和Openssl庫(kù)不多贅述。
首先是注冊(cè)一個(gè)OCR云識(shí)別平臺(tái)賬號(hào)如圖:
詢對(duì)應(yīng)平臺(tái)的API和接口地址:
下面是調(diào)用人臉識(shí)別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]={'