wget --no-check-certificate https://curl.se/download/curl-7.71.1.tar.bz2
执行:
wget https://ftp.openssl.org/source/old/1.1.1/openssl-1.1.1i.tar.gz
报错:
解决wget错误:
wget --no-check-certificate https://ftp.openssl.org/source/old/1.1.1/openssl-1.1.1i.tar.gz
解压、配置、编译并安装
tar -xzf openssl-1.1.1i.tar.gz
cd openssl-1.1.1i/
./config
make -j4
sudo make install
因为祥云后台所要求的图片大小在200k左右
拍照的关键指令:
raspistill -q 5 -t 1 -o image.jpg
由于翔云人脸识别次数有限,无法通过每个一段时间拍一次照片,而是采用语音控制开启摄像头线程,识别到人脸就进行拍照,需要用到motion库的人脸识别和拍照指令
if(strcmp("OCR",CmdHandler->command) == 0){pthread_t cameraThread;pthread_create(&cameraThread,NULL,cameraThread_func,NULL);return; //执行拍照就不往下走了,返回
}
void *cameraThread_func(void* data)//起线程的函数有格式要求
{struct Devices *cameraTemp;cameraTemp = findDeviceByNum(pDeviceHead, "c1"); //摄像头的设备编号为c1if(cameraTemp == NULL){ //防止段错误的必需判断printf("find camera error\n");pthread_exit(NULL); //在线程中不用return}cameraTemp->justDoOnce(); //调用设备的justDoOnce函数
}
#include "controlDevice.h" //自定义设备类的文件
#include
#include
#include
#include
#include
#include
#include size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
//回调函数,把从后台的数据拷贝给ocrRetBuf
{strncpy(ocrRetBuf,ptr,1024);
}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
}char * getBase64FormFile(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;}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 photo.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);}}struct Devices camera = {.name = "camera",.serialNum = "c1",.justDoOnce = postUrl,.deviceInit = cameraInit,};struct Devices* addCameraToDeviceLink(struct Devices *phead) //餐厅灯(对象)加入设备链表函数
{if(phead == NULL){return &camera;}else{camera.next = phead; //以前的头变成.nextphead = &camera; //更新头return phead;}
}
#include //wiringPi库
#include
#include extren char ocrRetBuf[1024] = {'\0'};//全局变量,用来接收从OCR后台返回的数据struct Devices //设备类
{char deviceName[128]; //设备名int status; //状态int pinNum; //引脚号int (*Init)(int pinNum); //“初始化设备”函数指针int (*open)(int pinNum); //“打开设备”函数指针int (*close)(int pinNum); //“关闭设备”函数指针int (*readStatus)(int pinNum); //“读取设备状态”函数指针 为火灾报警器准备int (*changeStatus)(int status); //“改变设备状态”函数指针int (*justDoOnce)(); //调库人脸识别函数指针struct Devices *next;
};struct Devices* addBathroomLightToDeviceLink(struct Devices *phead); //“浴室灯”加入设备链表函数声明
struct Devices* addBedroomLightToDeviceLink(struct Devices *phead); //“卧室灯”加入设备链表函数声明
struct Devices* addRestaurantLightToDeviceLink(struct Devices *phead); //“餐厅灯”加入设备链表函数声明
struct Devices* addLivingroomLightToDeviceLink(struct Devices *phead); //“客厅灯”加入设备链表函数声明
struct Devices* addSmokeAlarmToDeviceLink(struct Devices *phead); //“烟雾报警器”加入设备链表函数声明
struct Devices* addBuzzerToDeviceLink(struct Devices *phead); //“蜂鸣器”加入设备链表函数声明
struct Devices* addCameraToDeviceLink(struct Devices *phead); //“人脸识别”加入设备链表函数声明
参考博文:智能家居 (11) ——树莓派摄像头捕捉人脸并识别
这种方式不开启线程,而是通过语音识别执行拍照,上传到翔云服务器放回对比结果,只需要用到拍照指令
#include "controlDevice.h"
#include
#include
#include
#include
#include
#include
#include
#include typedef unsigned int bool;//数据类型别名用typedef 有分号
#define true 1 //宏定义(替换)用define 无冒号
#define false 0size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
{strncpy(ocrRetBuf,ptr,1024);
}char* getBase64FromFile(char* filePath)
{char* base64Buf = NULL;char cmd[256] = {'\0'};sprintf(cmd,"base64 %s > tmpFile",filePath);//图片的base64流导入到文件中system(cmd);int fd = open("./tmpFile",O_RDWR);int fileLen = lseek(fd,0,SEEK_END); //计算文件大小lseek(fd,0,SEEK_SET); base64Buf = (char* )malloc(fileLen+8);memset(base64Buf,'\0',fileLen+8);read(fd,base64Buf,fileLen+8); //从文件中读取base64流到字符串 close(fd);system("rm -f tmpFile");return base64Buf;
}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
}bool postUrl() //根据文档,接口调用方法为post请求
{CURL *curl;CURLcode res;//根据翔云平台的接口要求 分开定义,然后字符串拼接char* base64BufPic1 = getFace();//图片base64流char* base64BufPic2 = getBase64FromFile("./zms.jpg");char* key = "xxxx";char* secret = "xxxx";int typeId = 21;char* format = "xml"; 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_COOKIEFILE, "/tmp/cookie.txt");// 指定cookie缓存文件 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString);//指定post传输内容,get请求将URL和postString一次性发送curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do");// 指定urlcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,readData); //回调函数读取返回值res = curl_easy_perform(curl);printf("OK:%d\n",res);curl_easy_cleanup(curl);}return true;
}struct Devices camera = {.deviceName = "camera",.justDoOnce = postUrl
};struct Devices* addCameraToDeviceLink(struct Devices *phead)
{if(phead == NULL){return &camera;}else{camera.next = phead; //以前的头变成.nextphead = &camera; //更新头return phead;}
}
#include
#include
#include //wiringPi库extern char ocrRetBuf[1024];struct Devices //设备类
{char deviceName[128]; //设备名int status; //状态int pinNum; //引脚号int (*Init)(int pinNum); //“初始化设备”函数指针int (*open)(int pinNum); //“打开设备”函数指针int (*close)(int pinNum); //“关闭设备”函数指针int (*readStatus)(int pinNum); //“读取设备状态”函数指针 为火灾报警器准备int (*changeStatus)(int status); //“改变设备状态”函数指针void (*justDoOnce)();struct Devices *next;
};struct Devices* addBathroomLightToDeviceLink(struct Devices *phead); //“浴室灯”加入设备链表函数声明
struct Devices* addBedroomLightToDeviceLink(struct Devices *phead); //“卧室灯”加入设备链表函数声明
struct Devices* addRestaurantLightToDeviceLink(struct Devices *phead); //“餐厅灯”加入设备链表函数声明
struct Devices* addLivingroomLightToDeviceLink(struct Devices *phead); //“客厅灯”加入设备链表函数声明
struct Devices* addSmokeAlarmToDeviceLink(struct Devices *phead); //“烟雾报警器”加入设备链表函数声明
struct Devices* addBuzzerToDeviceLink(struct Devices *phead); //“蜂鸣器”加入设备链表函数声明
struct Devices* addCameraToDeviceLink(struct Devices *phead);
在main.c文件Command(struct InputCommand* CmdHandler)函数添加
if(strcmp("OCR",CmdHandler->command) == 0){tmp = findDeviceByName("camera",pdeviceHead);if(tmp != NULL){tmp->justDoOnce();if(strstr(ocrRetBuf,"否") != NULL){ //字符串检索 判断翔云后台返回的一大堆字符串中有没有“否”printf("人脸比对失败\n");}else{printf("人脸比对成功\n");//可以将开锁开灯等函数添加在此处}}}
编译:
gcc *.c -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt -I ../https/curl-7.71.1/_install/include/ -L ../https/curl-7.71.1/_install/lib/ -lcurl
参考博文:智能家居(8) —— 香橙派摄像头加入设备工厂