更多干货推荐可以去牛客网看看,他们现在的IT题库内容很丰富,属于国内做的很好的了,而且是课程+刷题+面经+求职+讨论区分享,一站式求职学习网站,最最最重要的里面的资源全部免费!!!点击进入--------------》跳转接口
更多干货推荐可以去牛客网看看,他们现在的IT题库内容很丰富,属于国内做的很好的了,而且是课程+刷题+面经+求职+讨论区分享,一站式求职学习网站,最最最重要的里面的资源全部免费!!!点击进入--------------》跳转接口
目录
- 实现思路
- 主要功能代码
- 功能验证
- 往期文章
实现思路
学完前面在Ubuntu系统下的人脸识别内容,本节我们将实现在树莓派上通过一个指令启动摄像头进行拍照并且完成人脸识别,为后面我们的智能家居系统加入人脸识别开锁功能做准备。
首先,去扩容一下SD卡
【树莓派】让你的SD卡快速扩容
其次,使用指令拍一张照片
【树莓派】CSI摄像头简单配置
上文介绍的拍照指令,运行即可拍照:
raspistill -o image3.jpg
如果直接使用上面这个指令,那拍出来的图片大概有1.3M左右,不符合祥云后台所要求的图片大小在200k以下
那么我们可以对图片进行压缩,可以改变摄像头的参数,降低摄像头输出的图片质量。通过查阅树莓派摄像头参数设置,做如下配置:
raspistill -q 5 -t 1 -o image.jpg
-q
是图片质量,在0~100之间,我们调成5,压缩图片质量
-t
是拍照延时,设定1s后拍照
经过测试,拍出来的图片由原来的1.3M变成了90多K,而且图片还很清晰。
做好上述准备工作,我们就可以发送指令open-c1
启动摄像头线程了,在这个线程中,需要完成下列操作:
①摄像头拍照返回base64流,
②然后用翔云平台进行对比识别,
③返回识别的结果
线程结束完成一次拍照识别
主要功能代码
(1)通过拍照指令提取当前人脸数据的base64流
上面介绍了树莓派的拍照指令,问题是拍照的时机怎么确定?
- 原始手动的话,采用按钮方式人脸靠近手动拍照;
- 自动的话一种方式是通过每隔一秒拍照一次,不断对比,很快就会将OCR识别次数用完;
- 另一种方式我们可以识别人物动作,发现有人来再进行拍照识别,具体可参照这篇博文:树莓派摄像头使用Motion监测人物动作
char* getFace()
{printf("人脸数据采集中...\n");system("raspistill -q 5 -t 1 -o image.jpg");while(access("./image.jpg",F_OK) != 0); //判断是否拍照完毕printf("数据采集完毕\n");char* base64BufFaceRec = getBase64FromFile("./image.jpg");system("rm image.jpg"); //采集完成删除,防止占内存return base64BufFaceRec; //返回刚才拍照的base64
}
(2)通过命令起摄像头线程
if(0 == strcmp(devName,"c1")){ //open-c1起摄像头线程pthread_t cameraThread;pthread_create(&cameraThread,NULL,cameraThread_func,NULL);return; //执行拍照就不往下走了,返回
}
(3)线程函数
void *cameraThread_func(void* data)//起线程的函数有格式要求
{struct Devices *cameraTemp;cameraTemp = findDeviceByNum(pDeviceHead, "c1"); //摄像头的设备编号为c1if(cameraTemp == NULL){ //防止段错误的必需判断,当给指针赋值是,一定要考虑NULL的情况,否则后续操作都是空谈printf("find camera error\n");pthread_exit(NULL); //在线程中不用return}cameraTemp->justDoOnce(); //设备都要从工厂里面取出来.可不能camera.justDoOnce,谁认识你这个camera!
}
(4)摄像头的结构体
struct Devices camera = {.name = "camera",.serialNum = "c1",.justDoOnce = postUrl,.deviceInit = cameraInit,};
(5)调库人脸识别函数
void postUrl()
{CURL *curl;CURLcode res;//分开定义,然后字符串拼接char* key = "xxx";char* secret = "xxx";int typeId = 21;char* format = "xml";char* base64BufPic1 = getFace();//摄像头拍照获取的照片char* base64BufPic2 = getBase64FromFile("./Your phtot.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");// 指定urlcurl_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);}}
(6)回调函数
char ocrRetBuf[1024] = {'\0'};//全局变量,用来接收从OCR后台返回的数据size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
//回调函数,把从后台的数据拷贝给ocrRetBuf
{strncpy(ocrRetBuf,ptr,1024);
}
功能验证
提前拍好自己的一张帅气照片放到树莓派里面,靠近树莓派摄像头识别成功,相应的继电器打开,锁开启。
后面我将摄像头识别线程完整的实现代码整合到智能家居里面展示,具体在下一篇博文介绍。
往期文章
智能家居 (1) ——智能家居整体功能框架
智能家居 (2) ——设计模式的引入
智能家居 (3) ——工厂模式继电器控制灯
智能家居 (4) ——工厂模式火焰报警
智能家居 (5) —— LD3320语音模块二次开发
智能家居 (6) ——语音识别线程控制
智能家居 (7) ——网络服务器线程控制
智能家居 (8) ——智能家居项目整合(网络控制线程、语音控制线程,火灾报警线程)
网络编程知识预备(1) ——了解OSI网络模型
网络编程知识预备(2) ——浅显易懂的三次握手与四次挥手
网络编程知识预备(3) ——SOCKET、TCP、HTTP之间的区别与联系
网络编程知识预备(4) ——了解HTTP协议与HTTPS协议
网络编程知识预备(5) ——libcurl库简介及其编程访问百度首页
智能家居 (9) ——人脸识别摄像头安装实现监控功能
智能家居 (10) ——人脸识别祥云平台编程使用
智能家居 (11) ——树莓派摄像头捕捉人脸并识别
智能家居 (12) ——人脸识别整合到智能家居系统
智能家居 (13) ——智能家居加入手机app端控制