智能家居项目

一.项目分析

1.1 实现的功能

  • 控制端
  1. 支持客户端发送指令
  2. 支持语音识别,发送指令
  • 外设端
  1. 支持人脸识别开锁
  2. 支持监控
  3. 支持火灾报警
  4. 支持所有的灯光控制
  5. 支持窗帘和泳池灯的遥控
  6. 支持电风扇,电视机,空调,小夜灯的遥控

1.2硬件

  • 主控芯片:树莓派:
    优点:
    1. 支持串口,无线蓝牙,WiFi等多种通信方式
    2. GPIO的引脚比较多(大概可用的GPIO引脚有42个,可以满足我们的需求),可以编程自己配置驱动和引脚功能
    3. 支持摄像头,可以用来实现监控和人脸识别解锁
    4. 可以远程登录SSH界面操作
    5. 学习过成中用的多,比较熟悉
    缺点:
    1. 响应速度可能没有单片机那么快,特别是语音识别那块
    2. 串口只有一对,我后面的433M射频模块和红外编解码模块都需要串口
  • 辅助外设:
    1. WemosD1:扩充了串口和GPIO引脚
    2. 语音模块YS-LDV7:语音识别,传送指令给服务器
    3. USB转串口模块:用于WemosD1和语音模块程序的烧写和调试
    4. 433M射频编解码模块:用于泳池灯和窗帘的遥控
    5. 红外编解码模块:用于破解电风扇,电视机,空调,小夜灯的红外信号,实现自己遥控
    6. 蜂鸣器
    7. 电磁锁
    8. 热感应设备,热敏电阻或者可以反馈高低电平的那种装置

1.3大概思路

在这里插入图片描述

  1. 指令接收部分,使用客户端服务器模型。
  2. 服务器调用线程处理语音模块和客户端的指令,然后给继电器引脚配置高低电平,或者给WemosD1发送信号指令。
  3. WemosD1一旦识别到有效指令,会通过串口,继续向433M和红外模块传递指令,进而使家用设备动作。
  4. 摄像头单独调用一个线程,不断通过辅助平台比对摄像头的图像,一旦识别成功,会开启电磁锁。
  5. 火灾报警根据选用设备的不同有两种思路:
    (1)热敏电阻:可以设计一个继电器控制电路,一旦感应温度超高,会接通控制电路,进而接通蜂鸣器报警。这样就只要提供一个控制电源即可,个人感觉更简单
    (2)当然,如果有感应装置会反馈高低电平,也可以调用线程,配置输出引脚,同样可以控制蜂鸣器。

二.程序结构设计

2.1采用工厂设计模式:

  • 什么是设计模式:
    1. 设计模式,描述了一组相互紧密作用的类和对象
    2. C : 面向过程,一门面向对象不友好的语言
    Java:面向对象
    3. 建筑设计领域引入到计算机科学来的
    4. 一共23中,代码容易被他人理解,保证代码的可靠性,程序的重要性

  • 什么是类和对象
    1. 类就相当于,C语言中的结构体类型,对象就是类的具象化
    2. 举例:

#include<stdio.h>

struct animals {

	char *name;
	char *sex;
	void (*doing)();
	void (*eat)();


};

void dogdoing(char *name){

	printf("%s看家护院\n",name);

}

void pdoing(char *name){

	printf("%s不干人事\n",name);

}

int main()
{
	struct animals dog ={

		.name  = "小黄",
		.doing = dogdoing//给函数指针赋值,即给函数执行的首地址赋值

	};

	struct animals p ={

		.name  = "老王",
		.doing = pdoing
	};		

	dog.doing(dog.name);//调用函数
	p.doing(p.name);




	return 0;
}

ztj@ubuntu:~$ ./a.out
小黄看家护院
老王不干人事
ztj@ubuntu:~$ ^C

  • 引入 工厂设计模式
    1. 可以看到,我们这种编码方式,还是显得很乱,并且暴露了代码逻辑,为了合理化代码的结构,简化开发过程,就引入了工厂模式
    2. 什么是工厂模式?
      工厂模式是 最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式
      在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象

2.2 具体如何实现工厂模式?

  1. 根据智能家居项目,大致可以将其分为命令输入模块和输出模块
  2. 因此,可以将项目划分出两大 工厂
  3. 每个工厂都有若干设备,我们主要是对这些设备进行操作,以实现功能
  4. 因此,设计出两个结构体,用来分别储存两边设备的一些信息,以及功能实现的函数指针
  5. 使用链表的形式,将两边的结构体各自联系到一起
  6. 当我们需要对某个设备进行操作时,只需要知道其链表头节点和设备名或者其他一些信息,就可以匹配到相关设备
  7. 这样做的好处是,将项目面向对象编程,需要什么,就查找什么
  8. 同时,后期想添加一些功能,必然会添加一些设备,就简单了许多,因为将项目的实现,完全划分了各自区域,互不影响。
  9. 我么只需要将新功能涉及的设备直接添加到链表离去。功能的具体实现,就留到main函数中调用线程管理

2.3 模拟一下过程

  • 指令处理的过程
  1. 链表的创建并返回头节点,头节点因为可能线程和函数中会用到,直接设为全局变量。
  2. 设备的初始化设置
  3. 命令输入进模块中,通过模块或者socket得到相应的命令,储存在buf中
  4. 通过字符命令匹配到相应的设备,并将字符命令一并储存在输出设备中去
  5. 通过字符串命令和设备内部的指令编码
  6. 根据指令,执行设备内部的指令处理函数,做引脚输入或输出,又或者执行相关的操作
  • main函数部分
  1. 依次插入设备,构建输入和输出两个链表
  2. 初始化设置
  3. 创建线程,处理不同部分的指令:语音线程,server线程,摄像头线程,火灾线程

三.代码

3.1 两个头文件

  • 这里主要是,对针对两个结构体,根据功能需求,进行了构思,可能有些部分后期没有用到,有些是后期做到具体部分有补充添加的,这里我都保留了。当然还有一些函数和结构体的声明
    -controlDevice.h
#include<wiringPi.h>
#include<string.h>
#include<stdio.h>


struct device {

	char deviceName[32];//设备名	
	char  fileName[32];//文件名
	int writePinNum;//输出引脚
	int readPinNum;//写入引脚
	char key[32];//指令编码
		
	char commandBuf[32];//设备接收的指令
	int status;//设备状态码,检测摄像头是否打开,或者火灾是否触发
	FILE *fp;//摄像头返回的文件流

	void (*open)(struct device *p);//打开设备
	void (*close)(struct device *p);//关闭设备
	void (*commandhandle)(struct device *p);//执行指令
	void (*deviceInit)(struct device *p);//初始化设备

	
	int (*readStatus)(struct device *p);//读取火灾报警器状态
	char (*createFile)(char *fileName);//创建文件,人脸识别备用

	
	
	struct device *next;//下一个设备节点
};


// 客厅有关声明
struct device *addLivingRoomLighttoLink(struct device *phead);
struct  device  livingRoomLight;


//餐厅有关声明
struct device *addDiningRoomLighttoLink(struct device *phead);
struct  device  diningRoomLight;


//二楼灯有关声明
struct device *addUpstairRoomLighttoLink(struct device *phead);
struct  device  upstairRoomLight;


//卫生间灯有关声明
struct device *addBathRoomLighttoLink(struct device *phead);
struct  device  bathRoomLight;


//人脸锁相关声明
struct device *addFaceLocktoLink(struct device *phead);
struct  device  faceLock;


//火灾报警有关声明
struct device *addFireAlarmtoLink(struct device *phead);
struct  device  fireAlarm;

//摄像头相关
struct device *addCameratoLink(struct device *phead);
struct  device  camera;




-inputCommand.h

#include<wiringPi.h>


struct inputCommand{

	char commandName[32];//输入指令的名字
	char command[32];//用于指令的操作
	char inPutDeviceName[32];//输入设备
	char outPutDevicename[32];//输出设备
	int s_fd;//服务器句柄
	int c_fd;//客户端句柄
	int fd;//串口句柄

	int (*Init)(struct inputCommand *p,char *ipAddress,char *port);//指令初始化
	int (*getInputCommand)(struct inputCommand *p);//获取指令


	struct inputCommand *next ;

};


//语音设备相关声明
struct inputCommand *addVoicetoLink(struct inputCommand *phead);
struct inputCommand voice;

//Server相关声明

struct inputCommand *addServertoLink(struct inputCommand *phead);
struct inputCommand server;



3.2 第一个设备文件作为模板

  • 前面说了,工厂模式的好处,有利于后期的添加新模块,和代码的可读性,这一点在编写的过程中,也是有体现的,我只要做出一个模板,那么其他的部分就可以套用,简化了开发过程
  • 这里我直接调用了wiringPi的库,进行了引脚的操作,实际上也可以自己编译一个引脚的驱动出来,但调库肯定是快一些的,实用为王
  • 如何写IO字符驱动
  • bathroomlight.c
#include"controlDevice.h"
#include"inputCommand.h"
#include<stdio.h>
#include<stdlib.h>



void bathRoomLightOpen(struct device *p){
	
	digitalWrite(p->writePinNum,LOW);

}

void bathRoomLightClose(struct device *p){

	digitalWrite(p->writePinNum,HIGH);
	
}

void bathRoomLightInit(struct device *p){

	pinMode(p->writePinNum,OUTPUT);
	digitalWrite(p->writePinNum,HIGH);

}

void bathRoomLightCommandHandle(struct device *p){

	char *buf = p->commandBuf;
	
	if(strcmp(buf,"031") == 0){
		
		p->open(p);
		
	}else if(strcmp(buf,"032") == 0){
		
		p->close(p);
	}else{

		printf("bathRoomLightCommandHandle  fail\n");
	}

}




struct  device  bathRoomLight = {
	
	.deviceName = "bathRoomLight",
	.writePinNum = 24,
	.key ="031&032",
	.open = bathRoomLightOpen,
	.close = bathRoomLightClose,
	.commandhandle = bathRoomLightCommandHandle,
	.deviceInit = bathRoomLightInit 
}; 

struct device *addBathRoomLighttoLink(struct device *phead){

		struct device *p;

		if(phead == NULL){
				
			phead = &bathRoomLight;
			phead->next = NULL;

			return phead;
		}else{
		
			p = &bathRoomLight;
			p->next = phead;
			phead = p;
				
			return phead;	
		}


}







3.3 语音输入设备

  • 这部分是基于ld_v7(基于ld_3320)板子的一个二次开发,厂家为我提供了开发资料,不需要关心LD3320这块芯片如何处理声音,只需要修改模板,主要是对源码的阅读,然后修改其中的关键字个词条
  • 语音模块是通过串口连接的,烧写时通过TTL转USB连接电脑,用stc-isp工具烧写。
  • 下面是和芯片对接的语音控制部分代码,和第一个设备模板差不多,稍作修改
#include"controlDevice.h"
#include"inputCommand.h"
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <wiringSerial.h>
#include<string.h>




int voiceInit(struct inputCommand *voice,char *ipAddress,char *port){

	int fd;

	if((fd = serialOpen(voice->inPutDeviceName,9600) ) == -1){
	
		exit(-1);

	}

	voice->fd = fd;
	
		
	return fd;
}

int voiceGetCommand(struct inputCommand *voice){

	int nread;
	
	memset(voice->command,'\0',32);
	nread = read(voice->fd,voice->command,sizeof(voice->command));

	if(nread == 0){

		printf("uart for voice over time\n");

	}else{
	
		return nread;
	}

}


struct inputCommand voice = {

	.commandName = "voice",
	.command = {'\0'},
	.inPutDeviceName = "/dev/ttyAMA0",
	.outPutDevicename = {'\0'},
	.Init = voiceInit,
	.getInputCommand = voiceGetCommand,
	.next = NULL

};


struct inputCommand *addVoicetoLink(struct inputCommand *phead){

		struct inputCommand *p;

		if(phead == NULL){
				
			phead = &voice;
			phead->next = NULL;

			return phead;
		}else{
		
			p = &voice;
			p->next = phead;
			phead = p;
				
			return phead;	
		}

	
}			

3.4 server/client控制设备部分

  • 这部分就是把socket抽象一个输入设备,主要是套接字,并返回描述符
#include<stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include<wiringPi.h>
#include <wiringSerial.h>
#include"inputCommand.h"
#include"controlDevice.h"





int serverInit(struct inputCommand *server,char *ipAddress,char *port){

	int s_fd;
	
	struct sockaddr_in s_addr;
	memset(&s_addr,0,sizeof(struct sockaddr_in));
	
	//1.socket创建套接字
			
    s_fd = socket(AF_INET,SOCK_STREAM, 0);
	if(s_fd == -1){
	
		perror("socket");
		exit(-1);
	}

	//2.bind(为套接字绑定地址和端口号)
	
	s_addr.sin_family = AF_INET;//IPV4 因特网
	s_addr.sin_port   = htons( atoi(port) );//小端变大端
	inet_aton(ipAddress,&s_addr.sin_addr) ;//字符串变网络形式

	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

	server->s_fd = s_fd;
	printf("socket init success\n");
		
	return s_fd;
}

int serverGetCommand(struct inputCommand *server){

/*	int nread;
	
	memset(server->command,'\0',32);
	nread = read(server->c_fd,server->command,strlen(server->command));

	return nread;*/
	
	return 0;
}




struct inputCommand server = {

	.commandName = "server",
	.inPutDeviceName = {'\0'},
	.outPutDevicename = {'\0'},
	.command = {'\0'},
	.Init = serverInit,
	.getInputCommand = serverGetCommand,
	.next = NULL

};


struct inputCommand *addServertoLink(struct inputCommand *phead){

		struct inputCommand *p;

		if(phead == NULL){
				
			phead = &server;
			phead->next = NULL;

			return phead;
		}else{
		
			p = &server;
			p->next = phead;
			phead = p;
				
			return phead;	
		}
}

3.5 main 函数部分

  • 这部分是对各功能模块的一个汇总,主要就是四大线程
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"inputCommand.h"
#include"controlDevice.h"
#include <unistd.h>
#include <wiringSerial.h>
#include <pthread.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>



struct inputCommand *commandHead = NULL;//指令输入工厂头节点
struct device *deviceHead = NULL;//设备工厂头节点
struct inputCommand *sockethandle1 = NULL;//socket线程工具
struct device *sockethandle2 = NULL;
struct inputCommand *voicethandle1 = NULL;//voice线程工具
struct device *voicethandle2 = NULL;
struct device  *camerahandle1 = NULL;//camera线程工具
struct device  *camerahandle2 = NULL;

char *p = NULL;//客户端地址



//根据设备名字查找设备
struct device *findDeviceByName(char *name,struct device *deviceHead){    

	struct device *p;
	p = deviceHead; 
	
	while(p != NULL){

		if(strcmp(name,p->deviceName ) == 0 ){

			return p;

		}
	
		p = p->next;
	}

	return NULL;
}

//通过命令类型查找设备输入设备
struct inputCommand *findInputByName(char *name,struct inputCommand *commandHead){    

	struct inputCommand *p;
	p = commandHead; 
	
	while(p != NULL){

		if(strcmp(name,p->commandName ) == 0 ){

			return p;

		}
	
		p = p->next;
	}

	return NULL;
}




struct device *findDeviceByCommand(char *command,struct device *deviceHead){
	
	struct device *p;
	p = deviceHead; 
	while(p != NULL){

		if(strstr(p->key,command ) != NULL ){

			return p;

		}
	
		p = p->next;
	}

	return NULL;





}

void *voicePthread(){

	int nread;
	voicethandle1 = findInputByName("voice",commandHead);
	if(voicethandle1 == NULL){

		printf("find voicehandle  error\n");
		pthread_exit(NULL);
	}else{

		if( voicethandle1->Init(voicethandle1,NULL,NULL) < 0){

			printf("voice init error\n");
			pthread_exit(NULL);

		}

		while(1){

				nread = voicethandle1->getInputCommand(voicethandle1);
				if(nread == 0){
				
					printf("voice no data\n");
				}else{

					printf("readvoice %s,%dByte \n",voicethandle1->command,nread);
					voicethandle2 = findDeviceByCommand(voicethandle1->command,deviceHead);//找设备
					if(voicethandle2 != NULL){//找到设备

						strcpy(voicethandle2->commandBuf,voicethandle1->command);//传递指令到设备
						voicethandle2->commandhandle(voicethandle2);//设备执行指令
					}				
						

				}



		}

	}


	return NULL;
}
void *readPthread(){

	int nread;
	while(1){
		
		memset(sockethandle1->command,'\0',32);
		nread = read(sockethandle1->c_fd,sockethandle1->command,sizeof(sockethandle1->command));
		if(nread == -1){
			perror("read");
		}else if(nread > 0){

			printf("readclient %s,%dByte \n",sockethandle1->command,nread);
			sockethandle2 = findDeviceByCommand(sockethandle1->command,deviceHead);//找设备
			if(sockethandle2 != NULL){//找到设备

				strcpy(sockethandle2->commandBuf,sockethandle1->command);//传递指令到设备
				sockethandle2->commandhandle(sockethandle2);//设备执行指令
			}
			
		}else{

			printf("%s client quit\n",p);

			pthread_exit(NULL);
		}
	}
	return NULL;
}



void *serverPthread(){

	int nread = 0;
	pthread_t read_thread;
	
	struct sockaddr_in c_addr;
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	int sizec_addr = sizeof(struct sockaddr_in);

	sockethandle1 = findInputByName("server",commandHead);
	if(sockethandle1 == NULL){
		
		printf("find sockethandle  error\n");
		pthread_exit(NULL);
	}
	
	//socket初始化	
	sockethandle1->Init(sockethandle1,"192.168.0.16","8088");

	// listen()监听	
	listen(sockethandle1->s_fd,10 );
	printf("socket listen...\n");
	
	while(1){
		
		//	不断地接收客户端请求,接收到就创建一个线程		
	    sockethandle1->c_fd = accept(sockethandle1->s_fd, (struct sockaddr *)&c_addr, &sizec_addr);
		if( sockethandle1->c_fd != -1){
			
			p = inet_ntoa(c_addr.sin_addr);			
			printf("client %s connect\n",p);
			pthread_create(&read_thread,NULL,readPthread,NULL);
		}
		
		pthread_join(read_thread,NULL);
	}
	
	return NULL;
}




void *cameraPthread(){

	camerahandle1 = findDeviceByName("camera",deviceHead);
	camerahandle2 = findDeviceByName("faceLock",deviceHead);
	while(1){
		
		if( strcmp(camerahandle1->commandBuf ,"113") == 0 && camerahandle1->fp ==NULL && camerahandle1->status == 0  ){

			system("fswebcam /dev/video0  ~/photo/tmp.jpg");
			fflush(stdout);
			chdir("/home/pi/httphandle");
			fflush(stdout);
			FILE* pp =popen("/home/pi/httphandle/post","r");
			fflush(stdout);
			if(pp != NULL){
		        char *retbuf =(char *)malloc(128);
				memset(retbuf,'\0',128);
		        fread(retbuf,1,64,pp);
				if(strstr(retbuf,"Face recognition successful") != NULL){
					printf("\n======================sucsessful========================\n\n");
					camerahandle2->open(camerahandle2);
				}else{
					
					printf("\n======================failed========================\n\n");

					camerahandle2->close(camerahandle2);
				}

				free(retbuf);
				pclose(pp);

				memset(camerahandle1->commandBuf,'\0',32); 
				
			}

		}else{

			continue;
		}
	}

	return NULL;
}


void *fireAlarmPthread(){


	return NULL;
}
int main(){



	pthread_t voice_thread;//语音线程
	pthread_t server_thread;//服务器线程
	pthread_t camera_thread;//摄像头线程
	pthread_t fireAlarm_thread;//火灾线程

	if(-1 == wiringPiSetup()){

			return -1;
	}

	//1.工厂模式链表创建
	deviceHead = addLivingRoomLighttoLink(deviceHead);
	deviceHead = addDiningRoomLighttoLink(deviceHead);
	deviceHead = addUpstairRoomLighttoLink(deviceHead);
	deviceHead = addBathRoomLighttoLink(deviceHead);
	deviceHead = addFaceLocktoLink(deviceHead);
	deviceHead = addFireAlarmtoLink(deviceHead);
	deviceHead = addCameratoLink(deviceHead);

	
	commandHead = addVoicetoLink(commandHead);
	commandHead = addServertoLink(commandHead);
	
	//2.初始化

	livingRoomLight.deviceInit(&livingRoomLight);
	diningRoomLight.deviceInit(&diningRoomLight);
	upstairRoomLight.deviceInit(&upstairRoomLight);
	bathRoomLight.deviceInit(&bathRoomLight);
	faceLock.deviceInit(&faceLock);
	fireAlarm .deviceInit(&fireAlarm);
	camera.deviceInit(&camera);



	



	//3.线程池建立:
	
		//3.1 语音线程
		
		int ret1 = pthread_create(&voice_thread,NULL,voicePthread,NULL);//注意第4参数类型void *
		if(ret1 != 0){
			
			printf("creat voice_thread fail\n");
			exit(-1);
		}
		
		//3.2  server线程
		int ret2 = pthread_create(&server_thread,NULL,serverPthread,NULL);
		if(ret2 != 0){
			
			printf("creat server_thread fail\n");
			exit(-1);
		}		
		
		//3.3 摄像头线程
		int ret3 = pthread_create(&camera_thread,NULL,cameraPthread,NULL);
		if(ret3 != 0){
			
			printf("creat camera_thread fail\n");
			exit(-1);
		}		
		//3.4 火灾线程
		int ret4 = pthread_create(&fireAlarm_thread,NULL,fireAlarmPthread,NULL);
		if(ret4 != 0){
			
			printf("creat fireAlarm_thread fail\n");
			exit(-1);
		}



		
	//4.阻塞主进程,等待线程退出
	pthread_join(voice_thread,NULL);
	pthread_join(server_thread,NULL);
	pthread_join(camera_thread,NULL);
	pthread_join(fireAlarm_thread,NULL);
	

	return 0;

}

3.6 摄像头功能

  • 摄像头和人脸识别,这两部分我是单独写的,由main函数去调用和关闭
  • 首先是摄像头,由sci和usb两种摄像头接口,使用方法其实是一样的,依赖mjpg-streamer的库,我使用的就是usb接口
  • 先下载一个mjpg-streamer的库,并且安装好。里面有READMED等详细的开发文档,配合网上的一些教程,安装好就行了
  • 进到源码目录下,.先进入sudo raspi-config,确保打开camera服务,然后 /start.sh脚本文件启动摄像头,也可以打开start.sh编辑它,更改一些设置,比如使用的的接口模式,分辨率等
  • 然后浏览器下登陆平台,http://+你的IP地址+:8080,选择streamer可以看到图像
  • 8080是端口号

3.7 人脸识别功能

  • 人脸识别,通过访问第三方平台(我访问的是翔云OCR平台),可以搜索翔云OCR
  • 我们通过摄像头拍照。将两张图片上传到平台,再把结果接收回来,就可以完成人脸识别
  • 采用的协议是HTTPS,post请求方式
  • http相关博文
  • 注意要购买人脸识别产品,有免费的次数,获取key 和secreat
  • 注意先安装lcurl和openssl的库,支持https协议
#include <stdio.h>
#include <curl/curl.h>
#include<string.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>


#define false 0
#define true  1 

typedef unsigned int bool;

char buf[10240] = {'\0'};

size_t readData(void *ptr, size_t size, size_t nmemb,void *stream){

	memset(buf,'\0',10240);
	strcpy(buf,ptr);
//	printf("===============================get data==================================\n");
//	printf("%s\n",buf);

}

char *getImgBase64ByPath(char* path){

	char *bufpic;
	char cmd[128] = {'\0'};
	
	sprintf(cmd,"base64 %s > tmpFile",path);
	system(cmd);

	int fd = open("./tmpFile",O_RDWR);
	int filelen = lseek(fd,0,SEEK_END);
	lseek(fd,0,SEEK_SET);

	bufpic = (char*)malloc(filelen+2);
	memset(bufpic,'\0',filelen+2);

	read(fd,bufpic,filelen);
	close(fd);

	system("rm -f tmpFile");
	

	return bufpic;

}



bool postUrl()
{
	CURL *curl; //提供curl库一个操作句柄
	CURLcode res;//curl_easy_perform(curl)的返回值
	char* poststring;//post请求主体内容
	char *img1; //人脸识别静态照片,开始为jpg格式,要转化成base64流
        char *img2;//人脸识别动态照片	 
	char* key = "4VaSoqfU3wtZtpsHKinsdx";
	char* secret ="f4dd11a61fc8441c95b1e4777f54c264";
	int typeId = 21;
	char* format ="xml"; 

	img1 = getImgBase64ByPath("/home/pi/photo/ztj.jpg");
	img2 = getImgBase64ByPath("/home/pi/photo/tmp.jpg");


	int len = strlen(key)+strlen(secret)+strlen(img1)+strlen(img2)+248;
	poststring = (char *)malloc(len);
	memset(poststring,'\0',len);

	sprintf(poststring,"img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",img1,img2,key,secret,typeId,format);
	
        curl_global_init(CURL_GLOBAL_ALL);
	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);//将http头输出到fp所指向的文件
		res = curl_easy_perform(curl);
		curl_easy_cleanup(curl);
	}
	
		if(strstr(buf,"是") != NULL){

			printf("=========================Face recognition successful===========================\n");
			return true;	
		}else{
		
			printf("===========================Face recognition failed==============================\n");
			return false;
		}
}

int main(void)
{
	
	bool res;
	//getUrl("/tmp/get.html");
	res = postUrl();


	return res;

}
  • 1
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

elaot

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值