智能家居 (6) ——人脸识别控制开关电磁锁

news/2025/1/16 4:41:31/

🔺1、前序文章:

【智能家居 (1) ——工厂模式继电器控制灯】

【智能家居 (2) ——工厂模式火焰报警器】

【智能家居 (3) ——语音识别控制端线程】

【智能家居 (4) ——网络控制端线程】

【智能家居 (5) ——前四章内容整合】

【基于 Libcurl 通过 https 访问翔云 OCR 实现人脸识别】

【树莓派安装mjpg-streamer使用摄像头】

🔺2、main.c 函数:

通过语音控制开启人脸识别,摄像头亮灯2秒拍照

此 main.c 函数仅用于 “人脸识别控制开关电磁锁” 功能调试

#include <stdio.h>
#include <string.h>
#include "equipment.h"
#include "command.h"
#include <pthread.h>
#include <unistd.h>#include <curl/curl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>char buf[1024] = {'\0'};		//用于存放翔云返回的数据struct Equipment *findEquipByName(char *name,struct Equipment *phead);		//一些函数声明
struct Command *findCommandByName(char *name,struct Command *phead);
void *voiceControlThread(void *data);
char *getPicBase64FromFile(char *filePath);
size_t readData(void *ptr, size_t size, size_t nmemb, void *stream);
unsigned int postUrl();struct Equipment *equiphead = NULL;			//设备工厂链表头节点
struct Command *cmdhead = NULL;				//指令控制工厂链表节点头int main()
{if(wiringPiSetup() == -1){					//使用wiringPi库需要初始化printf("wiringPiSetup failed!\n");return -1; }equiphead = addEleLockToLink(equiphead);			//各设备加入设备工厂cmdhead = addVoiceControlToLink(cmdhead);		//各指令控制加入指令控制工厂struct Equipment *tmpequiphead = equiphead;while(tmpequiphead != NULL){						//设备工厂所有设备初始化tmpequiphead->Init(tmpequiphead->pinNum);tmpequiphead = tmpequiphead->next;}pthread_t voiceControl_thread;pthread_create(&voiceControl_thread,NULL,voiceControlThread,NULL);		//创建线程:语音控制pthread_join(voiceControl_thread, NULL);		//主函数等待线程退出return 0;
}void *voiceControlThread(void *data)			//“语音控制线程”执行的函数
{int nread;char *temName = NULL;struct Command *voiceHandler = NULL;struct Equipment *linkHandler;voiceHandler = findCommandByName("voiceControl",cmdhead);		//寻找“语音控制”所在节点,返回给voiceHandlerif(voiceHandler == NULL){printf("find voiceHandler error\n");pthread_exit(NULL);}if(voiceHandler->Init(voiceHandler) < 0){				//“语音控制”功能初始化printf("voiceControl init error\n");pthread_exit(NULL);}while(1){nread = voiceHandler->getCommand(voiceHandler);			//获取指令if(nread == 0){											//没有获取到指令printf("No command received\n");}else{													//获取到指令printf("Get voice command:%s\n",voiceHandler->command);//以下为根据不同指令执行相应操作if(strstr("OpLock\r\n",voiceHandler->command) != NULL){linkHandler = findEquipByName("eleLock",equiphead);system("raspistill -o image.jpg");						//拍摄照片命名为 image.jpgsystem("convert -resize 400 image.jpg face2.jpg");		//降低拍摄的照片的大小,命名为 face2.jpgsystem("rm image.jpg");									//删除 image.jpg 临时照片// face1.jpg 为对比人脸照片,face2.jpg 为即拍人脸照片postUrl();system("rm face2.jpg");if(strstr(buf,"是") != NULL){							//如果返回对比数据是同一个人linkHandler->open(linkHandler->pinNum);			//开锁delay(10000);									//延时10000毫秒=10秒linkHandler->close(linkHandler->pinNum);		//关锁}}}}
}unsigned int postUrl()
{CURL *curl;CURLcode res;char *key = "xxxxxxxxxxxxxxxxxxxxxxxx";						//用户 OCR Key 值char *secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";			//用户 OCR Secret 值int typeId = 21;											//识别类型 21char *format = "xml";										//设置返回格式 "xml"char *postString;char *bufPic1 = getPicBase64FromFile("./face1.jpg");		//获取图片 1 的 base64流char *bufPic2 = getPicBase64FromFile("./face2.jpg");		//获取图片 2 的 base64流int len = strlen(key)+strlen(secret)+strlen(bufPic1)+strlen(bufPic2)+124;			//计算所需传参字符串大小postString = (char *)malloc(len);													//为传参字符串创建空间memset(postString,'\0',len);														//初始化传参字符串空间sprintf(postString,"&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",bufPic1,bufPic2,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");	//指定 urlcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);					//接收到数据,调用回调函数res = curl_easy_perform(curl);curl_easy_cleanup(curl);													//清除 curl}return 1;
}char *getPicBase64FromFile(char *filePath)
{int fd;int filelen;char cmd[128];char *bufPic;sprintf(cmd,"base64 %s > tmpFile",filePath);		//拼接系统调用字符串system(cmd);										//系统调用获取图片 base64流fd = open("./tmpFile",O_RDWR);						//存放图片 base64 流的临时文件filelen = lseek(fd,0,SEEK_END);						//计算文件字符数lseek(fd,0,SEEK_SET);								//指针回到文件头部bufPic = (char *)malloc(filelen+2);					//创建空间存放图片 base64流memset(bufPic,'\0',filelen+2);						//初始化空间read(fd,bufPic,filelen);							//文件内容读取到空间close(fd);											//关闭文件描述符system("rm -f tmpFile");							//忽略提示关闭临时文件return bufPic;										//返回图片 base64流
}size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)		//回调函数
{strncpy(buf,ptr,1024);
}struct Equipment *findEquipByName(char *name,struct Equipment *phead)		//根据名字寻找设备工厂链表链节函数,并返回链节
{struct Equipment *tmp = phead;if(phead == NULL){return NULL;}while(tmp != NULL){if(strcmp(name,tmp->equipName) == 0){return tmp;}tmp = tmp->next;}return NULL;
}struct Command *findCommandByName(char *name,struct Command *phead)			//根据名字寻找指令控制工厂链表链节函数,并返回链节
{struct Command *tmp = phead;if(phead == NULL){return NULL;}while(tmp != NULL){if(strcmp(name,tmp->commandName) == 0){return tmp;}tmp = tmp->next;}return NULL;
}

🔺3、分文件

(1)equipment.h 文件(设备类头文件):

#include <wiringPi.h>				//wiringPi库
#include <stdio.h>
#include <stdlib.h>struct Equipment								//设备工厂链表节点定义
{char equipName[128];						//设备名int pinNum;									//引脚号int status;									//“初始化设备”函数指针int (*Init)(int pinNum);					//“打开设备”函数指针int (*open)(int pinNum);					//“关闭设备”函数指针int (*close)(int pinNum);int (*readStatus)(int pinNum);				//“读取设备状态”函数指针int (*changeStatus)(int status);			//“改变设备状态函数指针”struct Equipment *next;
};struct Equipment *addEleLockToLink(struct Equipment *phead);				//“电磁锁”设备节点加入设备工厂链表函数声明

(2)electromagneticLock.c 文件:

#include "equipment.h"int eleLockInit(int pinNum);				//一些函数声明
int eleLockOpen(int pinNum);
int eleLockClose(int pinNum);
struct Equipment *addEleLockToLink(struct Equipment *phead);struct Equipment eleLock = {			//“电磁锁”设备链表节点.equipName = "eleLock",.pinNum = 1,						//树莓派gpio引脚 1.Init = eleLockInit,.open = eleLockOpen,.close = eleLockClose,
};int eleLockInit(int pinNum)			//初始化函数
{pinMode(pinNum,OUTPUT);					//配置引脚为输出引脚digitalWrite(pinNum,HIGH);				//引脚输出高电平,即默认为关闭状态
}int eleLockOpen(int pinNum)			//打开函数
{digitalWrite(pinNum,LOW);
}int eleLockClose(int pinNum)			//关闭函数
{digitalWrite(pinNum,HIGH);
}struct Equipment *addEleLockToLink(struct Equipment *phead)		//头插法将设备节点加入设备工厂链表函数
{if(phead == NULL){return &eleLock;}else{eleLock.next = phead;phead = &eleLock;return phead;}
}

(3)command.h 文件(指令控制类头文件):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>struct Command									//指令控制工厂链表节点定义
{char commandName[128];						//“控制方式”名字char deviceFilesName[128];					//存放初始化功能需要打开的文件的路径char command[32];							//存放指令int fd;										//存放文件描述符int (*Init)(struct Command *file);			//“初始化”函数指针int s_fd;									//存放套接字描述符char ipAdress[32];							//存放IP地址char port[12];								//存放端口号int (*getCommand)(struct Command *cmd);		//“获取指令”函数指针char log[1024];								//日志(暂未使用)struct Command *next;
};struct Command *addVoiceControlToLink(struct Command *phead);		//“语音控制”加入指令控制工厂链表函数声明

(4)voiceControl.c 文件(语音控制):

#include "command.h"
#include <unistd.h>int voiceControlInit(struct Command *file);							//“语音控制”功能初始化函数声明
int voiceControlGetCommand(struct Command *cmd);					//“获取指令”函数声明
struct Command *addVoiceControlToLink(struct Command *phead);		//“语音控制”加入指令控制工厂链表函数声明struct Command voiceControl = {				//“语音控制”链表节点.commandName = "voiceControl",.deviceFilesName = "/dev/ttyAMA0",.command = {'\0'},.Init = voiceControlInit,.getCommand = voiceControlGetCommand,.log = {'\0'},
};int voiceControlInit(struct Command *file)
{int fd;if((fd = serialOpen(file->deviceFilesName,9600)) == -1){		//打开树莓派串口,波特率为9600exit(-1);}file->fd = fd;				//打开串口文件成功,返回“文件描述符”到“语音控制”链表节点中
}int voiceControlGetCommand(struct Command *cmd)					//“获取指令”函数
{int nread = 0;memset(cmd->command,'\0',sizeof(cmd->command));					//读取串口nread = read(cmd->fd,cmd->command,sizeof(cmd->command));		//返回读取到数据的字节数return nread;
}struct Command *addVoiceControlToLink(struct Command *phead)		//头插法将“语音控制”链表节点加入指令控制工厂链表函数
{if(phead == NULL){return &voiceControl;}else{voiceControl.next = phead;phead = &voiceControl;return phead;}
}

🔺4、编译

在树莓派中,先安装好相应的库:

sudo apt install libssl-dev libcurl4-openssl-dev 

然后编译:

gcc main.c electromagneticLock.c voiceControl.c -lcurl -lwiringPi -lpthread -lssl

http://www.ppmy.cn/news/337837.html

相关文章

dell一键还原出厂设置(dell一键还原出厂设置找不到恢复环境)

戴尔笔记本一键还原。求详细步骤! 开机一直点F8键&#xff0c;然后选择恢复系统(好像是第一个选项&#xff0c;记不清了)&#xff0c;然后进入系统还原系统后&#xff0c;根据提示一步一步来吧&#xff0c;很简单的&#xff0c;具体步骤记不清了。戴尔笔记本可以通过使用系统隐…

系统还原软件哪个好?

听到系统还原这个词&#xff0c;大家不要头疼&#xff0c;不要以为还原个电脑系统很麻烦&#xff0c;其实只要选择的工具得当&#xff0c;那么就没有什么担心的了。想必大家肯定会问&#xff1a;那么哪个系统还原软件好呢&#xff1f; 根据小编的使用经验&#xff0c;发现还是有…

面部识别科普(刷脸支付)

又到了一周一次的科普时间了&#xff0c;关注生活的小细节&#xff0c;把握时代进步潮流。 最近支付宝刷脸支付&#xff08;支付宝打钱&#xff01;&#xff09;优惠还是蛮多的&#xff0c;目前支付完一次将会收到1.88红包&#xff0c;也算是一种促进消费吧。 所以我想刷脸支付…

人脸面部情绪识别(一)

人脸面部情绪识别 &#xff08;一&#xff09; 人脸面部情绪识别&#xff08;二&#xff09; 人脸面部情绪识别 age&gender&#xff08;三&#xff09; 根据人脸预测年龄性别和情绪代码实现 &#xff08;c caffe&#xff09;&#xff08;四&#xff09; 这里写代码片 …

深度linux怎么还原系统,深度一键还原怎么用 深度一键还原教程介绍

深度一键还原怎么用? 深度一键还原含GHOST工具箱、一键还原及镜像安装三部分&#xff0c;核心为GHOST11。 DOS由GRUB引导&#xff0c;可由GRUB从光驱启动&#xff0c;含备份、还原、手动GHOST、DOS命令行。 下面&#xff0c;我们就来看看这款简单好用的软件使用教程。 1、首先…

计算机电脑哪个是复位键,电脑一键还原按哪个键

问题一:台式电脑一键还原是按哪个键?心问友2011-12-07电脑重新启动后,进入系统前屏幕顶部就会出现“***Press[F11]to start recovery system***”的提示,这时按下F11键就可以使用“一键还原精灵”了,因是第一次使用,所以系统提示对C盘进行备份,这时按下F8 或是点击“备份…

在首次使用计算机前一定要按哪个键,技巧:计算机一键还原按哪个键[如何操作]...

如今&#xff0c;人们最大的帮助是计算机。在信息时代&#xff0c;计算机是必不可少的。他们帮助我们连接到Internet并了解各种信息。但是&#xff0c;频繁使用计算机将导致一些不可避免的问题&#xff0c;因为存在存储缓冲区。如果数据过多&#xff0c;则会出现卡纸&#xff0…

浅析基于AI智能识别技术的明厨亮灶智能化监管方案

以云计算、大数据、人工智能为代表的新兴技术&#xff0c;不断驱动着视频监控与视频应用等各领域业务层面的创新&#xff0c;同时AI计算机视觉技术的深度应用&#xff0c;也将成为各行各业有效的AI视频监控解决方案。 目前在视频监控领域应用较为广泛的AI技术有&#xff1a;智…