树莓派摄像头捕捉人脸并识别
参考原文: https://blog.csdn.net/NRWHF/article/details/127970690
一、USB摄像头监控、拍照
参照之前博文:https://blog.csdn.net/weixin_44999992/article/details/130437955
二、树莓派安装libcurl和openssl库
- 下载libcurl库
wget --no-check-certificate https://curl.se/download/curl-7.71.1.tar.bz2 - 下载openssl库
wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz - 解压openssl
tar vxf openssl-1.1.1a.tar.gz - 安装openssl,默认安装在系统路径下,这样编译的时候就不用加动态库的环境变量路径,也不用指定动态库。
./config - 编译
make - 安装
sudo make install - 安装完openssl后重新配置curl
./configure --prefix=/home/jiangyo/Desktop/httpHandler/curl-7.71.1/_install --with-ssl - 编译
make - 安装
make install - 重新进行编译文件
gcc *.c -lpthread -I …/curl-7.71.1/_install/include/ -L …/curl-7.71.1/_install/lib/ -lcurl -lwiringPi - 运行a.out的时候会报错,解决办法。
sudo apt-get update
sudo apt-get install libcurl4-openssl-dev
三、拍照的关键指令:
fswebcam --no-banner -r 640x480 image.jpg
-r 指定图片的分辨率,最后的是照片保存的路径。
fswebcam -S 10 image.jpg: -S 参数来跳过前面几帧解决。
四、源码及步骤
由于翔云人脸识别次数有限,无法通过每个一段时间拍一次照片,而是采用语音控制开启摄像头线程。
camera.c
拍照、并将照片通过翔云平台进行比对。
#include "contrlDevices.h" //自定义设备类的文件
#include <curl/curl.h>
#include <fcntl.h>
char ocrRetBuf[256];
size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
//回调函数,把从后台的数据拷贝给ocrRetBuf
{
strncpy(ocrRetBuf,ptr,1024);
//printf("===============================readdata========================\n");
//printf("%s\n", ocrRetBuf);
}
char *getBase64FromFile(char * filePath){
char *baseBuff =NULL;
char cmd[256] = {'\0'};
sprintf(cmd,"base64 %s >tmpFile",filePath);
system(cmd);
int fp = open("./tmpFile",O_RDWR);
int fileLen = lseek(fp,0,SEEK_END);
baseBuff = (char *)malloc(fileLen+8);
lseek(fp,0,SEEK_SET);
memset(baseBuff,'\0',fileLen+8);
read(fp,baseBuff,fileLen+8);
close(fp);
system("rm -rf tmpFile");
return baseBuff;
}
char* getFace()
{
printf("人脸数据采集中...\n");
system("fswebcam --no-banner -r 640x480 image.jpg");//关键命令
while(access("./image.jpg",F_OK) != 0); //判断是否拍照完毕
printf("数据采集完毕\n");
char* base64BufFaceRec = getBase64FromFile("./image.jpg");
system("rm image.jpg"); //采集完成删除,防止占内存
return base64BufFaceRec; //返回刚才拍照的base64
}
void postUrl()
{
CURL *curl;
CURLcode res;
//分开定义,然后字符串拼接
char* key = "xxx";
char* secret = "xxx";
int typeId = 21;
char* format = "xml";
char* base64BufPic1 = getFace();//摄像头拍照获取的照片
char* base64BufPic2 = getBase64FromFile("./image2.jpg");//个人照片
int len = strlen(key)+strlen(secret)+strlen(base64BufPic1)+strlen(base64BufPic2)+128;//分配空间不够会>导致栈溢出
char* postString = (char* )malloc(len);
memset(postString,'\0',len);//因为postString是一个指针,不能用sizeof来计算其指向的大小
sprintf(postString,"img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",base64BufPic1,base64BufPic2,key,secret,typeId,format);//根据平台的传参格式编写
curl = curl_easy_init();
if(curl){
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString); //指定post内容,传入参数
curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do");// 指定url
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,readData); //回调函数readDate读取返回值
res = curl_easy_perform(curl); //类似于状态码
printf("OK:%d\n",res);
if(strstr(ocrRetBuf,"否") != NULL){ //判断翔云后台返回的字符串中有没有“是”
printf("不是同一个人\n");
}
else{
printf("是同一个人\n");//这里识别成功,去开锁!
}
curl_easy_cleanup(curl);
}
}
struct Devices camera = {
.devicesName = "camera",
.justDoOnce = postUrl,
.next = NULL
};
struct Devices* addCameraToDeviceLink(struct Devices *phead) //摄像头加入设备链表函数
{
if(phead == NULL){
return &camera;
}else{
camera.next = phead; //以前的头变成.next
return &camera;
}
}
在语音识别线程中,根据识别到“请进行人脸识别”语句后,创建摄像头线程。
case 'W':
printf("open camera\n");
findDevice = findDeviceByName("camera", pdeviceHead);
if(findDevice != NULL) {
pthread_t cameraThread;
pthread_create(&cameraThread,NULL,cameraThread_func,NULL);
}
else {
printf("camera = NULL!\n");
}
findDevice = NULL;
break;
启动摄像头线程。进行拍照并人脸识别
void *cameraThread_func(void* data)//起线程的函数有格式要求
{
struct Devices *cameraTemp;
cameraTemp = findDeviceByName("camera", pdeviceHead);
if(cameraTemp == NULL){ //防止段错误的必需判断
printf("find camera error\n");
pthread_exit(NULL); //在线程中不用return
}
cameraTemp->justDoOnce(); //调用设备的justDoOnce函数
}