C语言实现基于翔云平台的人脸识别demo2(树莓派)


运用翔云平台的人脸识别的方案,通过使用第三方libcurl的库,用HTTPS方式访问官网进行人脸识别的操作,并拿到人脸识别得到的结果;

实现目标

demo1的基础上,使用树莓派摄像头(CSI接口)获取第二张照片(访问者),再进行人脸识别;

树莓派安装mjpg-streamer

在树莓派下依次执行以下指令

sudo apt-get update     //更新软件列表
sudo apt-get upgrade    //更新软件

sudo apt-get install subversion
sudo apt-get install libjpeg8-dev  //JPEG支持库
sudo apt-get install imagemagick
sudo apt-get install libv4l-dev
sudo apt-get install cmake  //下载编译工具

sudo apt-get install git
git clone https://github.com/jacksonliam/mjpg-streamer.git
cd mjpg-streamer-master/mjpg-streamer-experimental

make all
sudo make install

修改start.sh文件(用来开启摄像头进行监控)

打开在mjpg-streamer-experimental目录下的start.sh文件

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

A:树莓派摄像头为CSI接口

第一步:将input_uvc.so修改为input_raspicam.so
第二步:将相对路径修改为绝对路径,使得在任意工作目录下调用start.sh文件,都能够成功开启摄像头进行监控。下面的绝对地址是我自己的,请修改为自己相应的绝对地址

/home/pi/mjpg-streamer/mjpg-streamer-experimental/mjpg_streamer -i "/home/pi/mjpg-streamer/mjpg-streamer-experimental/input_raspicam.so" -o "/home/pi/mjpg-streamer/mjpg-streamer-experimental/output_http.so -w /home/pi/mjpg-streamer/mjpg-streamer-experimental/www"

B:树莓派摄像头为USB接口

只需将相对路径修改为绝对路径即可

树莓派开启摄像头

执行以下代码

sudo raspi-config

界面如下:
在这里插入图片描述

按上下键选中第5个Interfacing Options后,敲击Enter键,如下图所示:
在这里插入图片描述
选中Camera,敲击Enter
在这里插入图片描述
选中yes,敲击Enter
在这里插入图片描述
按左右键选中Finish,敲击Enter
在这里插入图片描述
同意重启树莓派或执行以下代码进行重启

sudo reboot

mjpg-streamer监控功能的测试

运行start.sh可执行文件
若程序没有报错退出,则运行成功
通过网页访问: http://<树莓派地址>:8080
查看Stream那一栏,即可观察到实时的监控图像

实现方式

方式一(不带实时监控功能)

在调用getBase64()函数获取第二张的Base64流前,使用system函数让树莓派开启摄像头进行拍照。即在postUrl()函数的第五行加一句代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <curl/curl.h>

#define true  1
#define false 0
typedef unsigned int bool;

char* faceRes = NULL;

char* getBase64(char* photoPath){
    
    // 获取照片(jpg格式)的Base64的值
	char cmd[256] = {
    
    '\0'};

	sprintf(cmd, "base64 %s > photoBase64File", photoPath);
	system(cmd);// 通过执行"base64"这个指令即可得到照片的Base64值,在这里将得到的Base64值存放在photoBase64File文件中

	int fd,size;
	fd = open("./photoBase64File", O_RDWR);
	size = lseek(fd, 0, SEEK_END) + 1;
	lseek(fd, 0, SEEK_SET);
	
	char* res = (char*)malloc(size);
	memset(res, '\0', size);
	read(fd, res, size);// 从photoBase64File文件中读取照片的Base64值
	close(fd);
	
	system("rm photoBase64File");

	return res;
}

size_t handle(void *ptr, size_t size, size_t nmemb, void *stream){
    
    
	//拷贝返回来的结果字段
	int ssize = strlen(ptr) + 1;
	faceRes = (char*)malloc(ssize);
	memset(faceRes, '\0', ssize);
	strncpy(faceRes, ptr, ssize);
}

bool postUrl()
{
    
    
	CURL *curl;
	CURLcode res;

	char* message = NULL;

	// 调用getBase64()自定的函数获取存放在当前文件夹下的两个进行识别的图片的Base64值
	char* img1 = getBase64("./host.jpg");
	
/*************************添加的代码**************************************/

	//其中-w和-h:来设定照片的大小; -o:来设置生成的照片名字为visitor.jpg; ./:放在当前目录下
	system("raspistill -w 700 -h 525 -o ./visitor.jpg");

/************************************************************************/
	char* img2 = getBase64("./visitor.jpg");
	
	// key值和secret值是在翔云官网->个人中心的OCR Key和OCR secret两个的值
	char* key = "用自己的";
	char* secret = "用自己的";
	int typeId = 21;
	char* format = "xml";

	int size = strlen(img1)+strlen(img2)+strlen(key)+strlen(secret)+strlen(format)+3;
	message = (char*)malloc(size);
	memset(message, '\0', size);

	sprintf(message, "&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",
		img1, img2, key, secret, typeId, format);

	curl = curl_easy_init(); // 初始化
	if (curl)
	{
    
    
		curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do");// 指定url
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, message);// 指定post内容
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle);// 当拿到结果后,指定调用handle()该自定的函数进行处理
		res = curl_easy_perform(curl);// 进行访问官网、进行人脸识别的操作
		curl_easy_cleanup(curl);// 执行完后,对curl_easy_init()进行清理
	}

	if(res != 23){
    
    
		printf("post failed!\n");
		return false;
	}else{
    
    
		printf("post successful!\n");
	}

	printf("%s\n",faceRes);// 打印出人脸识别后返回来的结果字段

	if(strstr(faceRes, "是") != NULL){
    
    // 如果返回来的结果字段中有“是”这个字眼,代表是同一个人
		printf("This is the same person!\n");
	}else{
    
    
		printf("Tow different persons!\n");
	}
	
	free(faceRes);
	free(img1);
	free(img2);

}

int main(void)
{
    
    
	postUrl();
	return 0;
}

方式二(使用mjpg-streamer来进行拍照)

首先使用system函数调用在mjpg-streamer-experimental目录下的start.sh可执行文件来开启摄像头进行监控;
再在调用getBase64()函数获取第二张的Base64流前,使用system函数获取访问者的脸部照片;

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <curl/curl.h>

#define true  1
#define false 0
typedef unsigned int bool;

char* faceRes = NULL;

char* getBase64(char* photoPath){
    
    // 获取照片(jpg格式)的Base64的值
	char cmd[256] = {
    
    '\0'};

	sprintf(cmd, "base64 %s > photoBase64File", photoPath);
	system(cmd);// 通过执行"base64"这个指令即可得到照片的Base64值,在这里将得到的Base64值存放在photoBase64File文件中

	int fd,size;
	fd = open("./photoBase64File", O_RDWR);
	size = lseek(fd, 0, SEEK_END) + 1;
	lseek(fd, 0, SEEK_SET);
	
	char* res = (char*)malloc(size);
	memset(res, '\0', size);
	read(fd, res, size);// 从photoBase64File文件中读取照片的Base64值
	close(fd);
	
	system("rm photoBase64File");

	return res;
}

size_t handle(void *ptr, size_t size, size_t nmemb, void *stream){
    
    
	//拷贝返回来的结果字段
	int ssize = strlen(ptr) + 1;
	faceRes = (char*)malloc(ssize);
	memset(faceRes, '\0', ssize);
	strncpy(faceRes, ptr, ssize);
}

bool postUrl()
{
    
    
	CURL *curl;
	CURLcode res;

	char* message = NULL;

	// 调用getBase64()自定的函数获取存放在当前文件夹下的两个进行识别的图片的Base64值
	char* img1 = getBase64("./host.jpg");

/*************************添加的代码**************************************/
	
	//openCamera为start.sh可执行文件的绝对地址,请根据自己的路径改
	const char* openCamera = "/home/pi/mjpg-streamer/mjpg-streamer-experimental/start.sh";
	system(openCamera);	//调用start.sh可执行文件

	//获取访问者的照片
	system("wget http://<树莓派ip地址>:8080/?action=snapshot -O ./visitor.jpg");

/************************************************************************/
	char* img2 = getBase64("./visitor.jpg");
	
	// key值和secret值是在翔云官网->个人中心的OCR Key和OCR secret两个的值
	char* key = "用自己的";
	char* secret = "用自己的";
	int typeId = 21;
	char* format = "xml";

	int size = strlen(img1)+strlen(img2)+strlen(key)+strlen(secret)+strlen(format)+3;
	message = (char*)malloc(size);
	memset(message, '\0', size);

	sprintf(message, "&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",
		img1, img2, key, secret, typeId, format);

	curl = curl_easy_init(); // 初始化
	if (curl)
	{
    
    
		curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do");// 指定url
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, message);// 指定post内容
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle);// 当拿到结果后,指定调用handle()该自定的函数进行处理
		res = curl_easy_perform(curl);// 进行访问官网、进行人脸识别的操作
		curl_easy_cleanup(curl);// 执行完后,对curl_easy_init()进行清理
	}

	if(res != 23){
    
    
		printf("post failed!\n");
		return false;
	}else{
    
    
		printf("post successful!\n");
	}

	printf("%s\n",faceRes);// 打印出人脸识别后返回来的结果字段

	if(strstr(faceRes, "是") != NULL){
    
    // 如果返回来的结果字段中有“是”这个字眼,代表是同一个人
		printf("This is the same person!\n");
	}else{
    
    
		printf("Tow different persons!\n");
	}
	
	free(faceRes);
	free(img1);
	free(img2);

}

int main(void)
{
    
    
	postUrl();
	return 0;
}

实时监控和人脸识别开门

对第二种方式的代码进行修改和使用,即能完成

添加的器材:一个电磁门锁模块,一个5V的电池(给电磁门锁供电)、一个继电器(作为电磁门锁和5V电池之间的开关)

大概思路说明
1、添加接收命令端(如:语音识别模块、socket,也可通过scanf来获得)
2、先开启摄像头,即先执行start.sh可执行文件
3、让接收命令端不停地获取命令,并对得到的命令进行判断
4、若触发开门,则调用postUrl()函数,对返回值进行判断;
5、若为1,则将继电器的引脚电平拉低;否则,引脚电平为高

猜你喜欢

转载自blog.csdn.net/weixin_50438937/article/details/113763964