智能家居 (10) ——人脸识别祥云平台编程使用(编译libcurl库支持SSL,安装SSL依赖库libssl、libcrypto)

目录

  • 说明
  • 人工智能OCR识别平台介绍
  • 人脸识别接口购买
  • 编程打通OCR后台实现人脸识别(ubuntu上实现)
    • 问题发现
    • 编译libcurl库支持SSL
    • 安装SSL依赖库openSSL(使用工具wget)
    • curl库重新配置,编译,安装
    • 开启SSL后重新编译人脸识别.C文件
    • 传入图片的base64流
    • 最终实现人脸识别程序
  • 往期文章

说明

本章使用的平台是上位机Ubuntu,树莓派的要跟着这篇文章来:树莓派4B开发笔记(四)c语言https访问百度AI人脸识别接口之安装相关库

人工智能OCR识别平台介绍

OCR (Optical Character Recognition,光学字符识别)

百度搜索OCR识别,可以发现有很多大厂都在做这个项目,比如百度OCR,腾讯OCR,科大讯飞OCR等等。

国内中小型公司,甚至是大公司在做项目时希望能够快速占领市场,比如人脸识别,车牌识别需要非常稳定的算法,如果需要本公司研发部的研发人员去做,可能要包含两个硕士一个博士还有几个本科生一同做研发,生产周期以及稳定性都是面临了巨大的挑战这时候,购买别人已经做好的方案,是非常划算的。

有个很好的例子,oppo手机vivo手机,未来要上5G,就得和华为合作,就是类似的原理。不是说他们搞不出来5G来,给他们时间肯定也搞得出来,但搞出来的时候已经晚了。

下面通过人工智能OCR识别平台翔云的使用,掌握调库调API开发的一般步骤,其他的平台也基本类似。

翔云注册登录

先看到【价格与购买】

在这里插入图片描述
在【产品】,看看人人脸识别的API文档

在这里插入图片描述

再看到【开发者中心】

点击图标下载看看能提供什么样子的案例

在这里插入图片描述

读一下这个C++示例代码

读取文档,捕捉类似这样的关键信息,一般注释都写得很清楚

在这里插入图片描述

strPostData.Format(_T("img=%s&key=%s&secret=%s&typeId=%d&format=xml"),strImageBase64,strKey,strSecret,nTypeID);
  • 1

虽然是C++写的,到最后也可以用C语言做出来

来看看java的代码

java大多直接调库,非常简洁,这也是它开发效率高的原因之一。

在这里插入图片描述

人脸识别接口购买

初次体验购买,人脸识别100次只需支付0.01元。

购买完成可以在【个人中心】可以看到自己的OCRkey和密码,这两句在代码中肯定要用上来访问OCR平台。

在这里插入图片描述

编程打通OCR后台实现人脸识别(ubuntu上实现)

问题发现

第一版调试,最终程序是一步步改进得来的,想看最终程序的建议跳转

程序大意:测试打通OCR后台,查看后台返回的数据

#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>typedef unsigned int bool;//数据类型别名用typedef
#define true 1            //宏定义用define 就是宏替换
#define false 0//回调函数,读取从OCR后台返回的数据  前面打通百度的例子是将内容读取到本地文件fd里面
size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
{char buf[1024] = {'\0'};strncpy(buf,ptr,1024);printf("===========get data ===========\n");printf("%s\n",buf);
}bool postUrl()       //根据文档,接口调用方法为post请求     
{CURL *curl;CURLcode res;char* postString;//野指针,要开辟空间//根据翔云平台的接口要求  分开定义,然后字符串拼接char* img1   = NULL;   //图片base64流 还未生成char* img2   = NULL;char* key    = "xxx";char* secret = "xxx";int   typeId = 21;char* format = "xml";//游标卡尺刻度                            //2个image+typeId+formatpostString = (char* )malloc(strlen(key)+strlen(secret)+2048);//字符串拼接函数                                                     仅测试,两张图片为空 sprintf(postString,"img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s","","",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;
}
int main(void)
{postUrl();
}

编译:

gcc OCR.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl

运行结果:

ok:1

证明失败了,正常应该返回200,没有跟翔云的后台接通,回调函数没有打印后台返回来的数据。

编译libcurl库支持SSL

那是因为在编译libcurl库的时候,由于翔云接口是https:开头的,需要选择支持SSL。./configure --with -ssl

我们访问的接口是https开头的,要进行身份验证和数据加密的,体现在我们的key和secret。

HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议

所以要重新编译,让我们编译出来的libcurl支持SSL.

回忆之前libcurl 的 INSTALL.md

在这里插入图片描述

那我们就要回到/curl-7.71.1路径下,删除rm _install -rf上次编译出来的文件夹,重新编译支持SSL的库。由/docs/INSTALL.md我们可以得知要想支持SSL,就得./configure --with-ssl

所以我们要这样配置(根据文档提示,如果你的openssl安装在/usr/local/ssl....如果安装在别的地方就要加一个环境变量,指定你openssl的安装位置)

./configure --prefix=$PWD/_install --with-ssl

编译错误,

cheking for SSL_connect in -lssl... (cached)no no
configure:error:openSSL libs and/or directories were not found where specified!

安装SSL依赖库openSSL(使用工具wget)

首先遇到问题,去百度搜索出现的提示内容。

查询到想要支持SSL必须要有依赖库,需要系统中已经安装好了SSL。

我们需要安装openSSL.tar

但是搜索的到的都是要钱的,如何免费下载呢?

利用linux的开源工具下载wget是Linux中的一个下载文件的工具,wget是在Linux下开发的开放源代码的软件。

百度搜索技巧:wget openSSL.tar

找到类似于这样:
在这里插入图片描述回到curl文件夹的上一级目录,执行命令(即安装在curl文件夹外面)

wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz

注意:!!!大坑,这个a在Ubuntu可以用,但是在树莓派不行,总是报错表示他链接不到库,烦死了!!最好是在下面这个网站下载openssl-1.1.1j.tar.gz

https://www.openssl.org/source/

解压

tar xvf openssl-1.1.1a.tar.gz

进入文件夹,直接去看他的INSTALL。

为了避免到时候编译这个curl又要去配置SSL这个库,我们直接把SSL安装到默认的系统位置去(一般默认是在/usr/local底下),所以不指定安装路径了,直接

/openssl-1.1.1a路径下,配置

./config

编译(起码编译了8,9分钟)

make

安装:

sudo make install

要加 sudo因为肯定安装在了usr/local中,非工作目录无权限

curl库重新配置,编译,安装

回到/curl-7.71.1/目录下重新进行配置:

./configure --prefix=$PWD/_install --with-ssl
make 
make install

开启SSL后重新编译人脸识别.C文件

gcc OCR.c -I ./curl-7.71.1/_install/include/ -L ./curl-7.71.1/_install/lib/ -lcurl

在树莓派上编译的时候一定要多链接两个库-lssl -lcrypto

否则会报错:

./curl-7.71.1/_install/lib//libcurl.so: undefined reference to `SSL_CTX_set_keylog_callback@OPENSSL_1_1_1'
./curl-7.71.1/_install/lib//libcurl.so: undefined reference to `SSL_CTX_set_post_handshake_auth@OPENSSL_1_1_1'
./curl-7.71.1/_install/lib//libcurl.so: undefined reference to `SSL_CTX_set_ciphersuites@OPENSSL_1_1_1'
collect2: error: ld returned 1 exit status

运行

可以看到已经收到了翔云后台的反馈:

===========get data ===========
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><data><message><status>-7</status><value>必传参数为空</value></message></data>
OK:23

必传参数为空的原因是:代码中没有传入图片给它识别

传入图片的base64流

在这里插入图片描述

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,可用于在HTTP环境下传递较长的标识信息。

在Linux下生成图片的base64编码

base64 photo.jpg

大致思路:(尚未进行封装)

system("base64 zhu1.jpg > tmpFile1");//把编码的结果保存到tmpFile1中int fdPic1 = open("./tmpFile1",O_RDWR);//创建文件保存编码
int fileLenPic1 = lseek(fdPic1,0,SEEK_END);//计算文件大小
lseek(fdPic1,0,SEEK_SET);              //文件指针回头char* bufPic1 = (char* )malloc(fileLenPic1+8);//稍微多加一点空间
memset(bufPic1,'\0',fileLenPic1+8);read(fdPic1,bufPic1,fileLenPic1);                   //把文件内容度进取buf中
//printf("%s\n",buf);                               //做个简单的测试
close(fdPic1);
AAAAAAAAAAAAAAAA

如果平台返回的数据死活提示你传参错误:当你打开tmpFile1想看看编码的结果,如果后面出现很长很大一段的这个,成千上万的AAAAAAAAAAAAA,我想你应该跟我一样,直接手机拍自己一张图片就扔进去了。

在这里插入图片描述
查看图片的大小,往往是4~5个M,非常大!!也不符合平台的要求。转化成小一点的这些AAAAA就消失了。

在这里插入图片描述怎样快速压缩图片大小??用QQ给图片截图,保存的时候转换为jpg格式,一般能够直接压缩到50多个K,非常好用。

最终实现人脸识别程序

程序大意:向OCR后台传入两张图片的base64流,后台经过判断返回数据,程序接收数据并判断是否含有“是”,若有,则输出人脸识别结果为“同一个人”。

#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>typedef unsigned int bool;//数据类型别名用typedef
#define true 1            //宏定义用define
#define false 0char ocrRetBuf[1024] = {'\0'};//全局变量,用来接收从OCR后台返回的数据size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)//回调函数,把从后台的数据拷贝给ocrRetBuf
{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;//指针变量随着子程序调用结束消失,但malloc开辟的空间地址还在,我拿到了这块地址,就能读
}bool postUrl()
{CURL *curl;CURLcode res;//分开定义,然后字符串拼接char* key    = "xxx";char* secret = "xxx";int   typeId = 21;char* format = "xml";char* base64BufPic1 = getBase64FromFile("./xiaoming1.jpg");char* base64BufPic2 = getBase64FromFile("./xiaoming2.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);//根据平台的传参格式编写//img1   img2两张图片的base64传给翔云OCR后台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);}return true;
}int main(void)
{postUrl();return 0;
}

我这里编译没问题,运行提示找不到libcurl.so,4这个库,将它所在路径加入到环境变量就解决了。
在这里插入图片描述

运行结果:

在这里插入图片描述

stack smashing detecte 栈溢出

在调试过程中出现了这样的问题:

*** stack smashing detected ***: terminated
已放弃 (核心已转储)

当-fstack-protector启用时,当其检测到缓冲区溢出时,会立即终止正在执行的程序,并提示其检测到缓冲区存在的溢出的问题

一检查发现是计算开辟空间的大小不够(错写成了写了两个Pic1),修改即可。

int len = strlen(key)+strlen(secret)+strlen(base64BufPic1)+strlen(base64BufPic1)+128;//分配空间不够会导致栈溢出   
char* postString = (char* )malloc(len);

引入下一篇:结合树莓派摄像头捕捉人脸

人脸识别API,调库会用了,那我们怎么样获取摄像头的数据,并且得到一张图片的base64流传给后台判断呢?

下一篇更新。

往期文章

智能家居 (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端控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

srs 服务关闭命令_【经验总结】如何做到网络版工作站与服务器时间同步?

随着行业发展&#xff0c;越来越多的实验室色谱数据工作站由原来的单机版&#xff0c;升级为网络版。升级后带来的益不必多说&#xff0c;那么升级带来的困难你遇到过吗&#xff1f;快来跟小析姐一起看看牛人是如何解决问题的吧。最近公司将色谱工作站进行了升级&#xff0c;采…

oss图片尺寸调用方式_是时候来一场轰轰烈烈的OSS升级了

【摘要】伴随5G和云网部署的持续推进&#xff0c;运营商OSS升级建设都已经在不断加速。| 科 | 技 | 杂 | 谈 |中国通信行业第一自媒体【1】运营商的IT支撑系统&#xff0c;正迫切需要新一轮的调整转型。今天&#xff0c;中国移动在2020全球合作伙伴大会上宣布&#xff0c;全球最…

由C过渡到C++-入门知识点

从C语言过渡到C&#xff0c;这些知识点应该是比较重要的。 目录 第一个C程序名称空间特性coutcin 缺省参数重载提问&#xff1a;为什么C语言不支持重载而C支持 引用常引用 引用与函数返回值对于指针和引用的区别引用的底层实现两者在语法上两者在物理上两者的不同之处 内联函数…

gdb pwndbg插件安装

环境&#xff1a; gdb 9.2ubuntu 20(x64) 连接 pwndbggdb9.2gdb9.2网盘连接 密码: kaq4GDB中文教程 编译gdb 由于发行的gdb比较老&#xff0c;pwndbg建议使用高版本GDB&#xff0c;因此我们下载最新的GDB9.2 安装依赖 #apt install texinfo解压GDB,卸载自带GDB #tar -vxf…

Android--UI之DatePicker、TimePicker...

前言 这一篇博客分别讲解Android平台下&#xff0c;关于日期和时间的几个相关控件。包括DatePicker&#xff08;日期选择控件&#xff09;、TimePicker&#xff08;时间选择控件&#xff09;、DatePickerDialog&#xff08;日期选择对话框&#xff09;、TimePickerDialog&#…

递归和迭代路由_静态路由在以太网接口中的不同书写会导致路由器怎样的操作结果?...

各位小伙伴们&#xff1a;大家好&#xff01;上一节和大家分享了在不同类型的网络中应该使用什么样的静态路由配置命令&#xff1b;今天我们再来看看在常见的多路访问(MBA)网络——以太网中&#xff0c;静态路由的不同书写方式将导致路由器执行那些不同的操作。如下图&#xff…

实验报告三

学 号 201521440010 中国人民公安大学 Chinese people’ public security university 网络对抗技术 实验报告 实验三 密码破解技术 学生姓名 邱景丛 年级 2015 区队 四 指导教师 高见 信息技术与网络安全学院 2016年11月7日 实验任务总纲 2016—2017 学年 第 一 …

设计前沿:25个设计师向您展示 iOS 7 界面

我们中的许多人都对新发布的 iOS 7 用户界面有点失望。扎眼的颜色搭配&#xff0c;难看的图标和可疑的设计决策&#xff0c;导致很多的设计师在 Dribbble 和 Behance 等社交网站分享自己对 iOS 界面设计的诠释。这篇文章集合了一些伟大的想法&#xff0c;改进苹果 iOS 7 的界面…

智能家居 (11) ——树莓派摄像头捕捉人脸并识别

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

centos上使用高版本gcc、g++

0x0 在centos7上gcc版本是4.85&#xff0c;在编译一些代码时需要使用g的一些新特性&#xff0c;而网上大多教程都是重新编译gcc&#xff0c;太麻烦了&#xff0c;在centos 7上默认是yum search不到高版本的gcc的 安装scl scl 是Software collections 的缩写&#xff0c;安装…

【Docker系列教程之一】docker入门

我们在理解 docker 之前&#xff0c;首先我们得先区分清楚两个概念&#xff0c;容器和虚拟机。 我们用的传统虚拟机如 VMware &#xff0c; VisualBox 之类的需要模拟整台机器包括硬件&#xff0c;每台虚拟机都需要有自己的操作系统&#xff0c;虚拟机一旦被开启&#xff0c;预…

Java基础 —— 变量,选择,循环,数组,输入与输出等

目录嵌入式学JAVAJava安卓开发环境搭建并运行HelloWorld概念引入JavaSE,EE,ME的区别JREJDK编程实操&#xff1a;从C面向过程转变变量定义与输出数组的定义与遍历(循环、控制、选择和C完全一样)函数的调用&#xff1a;类比c语言结构体的使用输入数据&#xff1a;Scanner嵌入式学…

ubuntu20 编译dpdk错误 -Werror=address-of-packed-member

0x0 在ubuntu20上编译dpdk 18.11报错&#xff0c;gcc 版本为9.3.0&#xff0c;报错如下&#xff1a; error: converting a packed ‘const struct ether_addr’ pointer (alignment 1) to a ‘unaligned_uint16_t’ {aka ‘const short unsigned int’} pointer (alignment 2…

Java 特性

Java有四大特性&#xff1a; 1.封装&#xff1a;隐藏对象的属性和实现细节&#xff0c;仅仅对外公开接口。 封装具有一下优点&#xff1a; 便于使用者正确、方便的使用系统&#xff0c;防止使用者错误修改系统属性&#xff1b;有助于建立各个系统之间的松耦合关系&#xff1b;…

MyBatis 传递多个参数

2019独角兽企业重金招聘Python工程师标准>>> 在MyBatis中可以用以下的方式来传递多个参数 1. 用java.util.Map来传递, Code 如下: public List<User> getAllUsersByUserName(String username, int start, int limit){Map<String,Object> params new H…

Linux stmac网卡代码分析----probe

probe 主要分析一下驱动的主要框架&#xff0c;必要地方细致分析下 文件位置&#xff1a; drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c 从文件的最后看起&#xff1a; module_pci_driver(stmmac_pci_driver); stmmac_pci_driver结构体如下&#xff0c;里面包含了id_…

Java面向对象(1) —— 封装

目录一、封装的概念二、类的封装以及使用三、访问修饰符四、属性封装的实现五、方法封装的实现六、UML类图七、类的构造方法与可重载八、this关键字九、static关键字十、方法重载&#xff1a;overload十一、包&#xff1a;package一、封装的概念 将字段&#xff08;C结构体中的…

linux下源码软件包的安装

我们在使用linux做服务器的时候&#xff0c;因为linux自带的软件包都有些老&#xff0c;不是最新的&#xff0c;但是有时候我们为了使用最新的软件&#xff0c;会使用最新的软件的源码来进行安装。所以我们需要用心去做了...在我们拿到一个软件的源码时&#xff0c;源码一般都是…

react-native 打包apk 并解决 图片 不出现问题

react-native官网打包apk方法&#xff1a;https://reactnative.cn/docs/signed-apk-android/ 解决办法&#xff1a; 找到项目 android目录下 gradle.properties文件 打开加入如下代码&#xff1a; android.enableAapt2false这段代码非常重要 官网缺少 。不然打包apk图片不出现。…

龙芯派2亚克力外壳

0x0 龙芯派自带的亚克力顶板没有风扇的孔位&#xff0c;在长时间运行时亚克力板很烫&#xff0c;因此我设计了个带风扇孔位的亚克力顶板 效果如下&#xff1a; 风扇规格 4X4风扇 供电由龙芯派的GPIO上的5V管脚供电 使用方法 1.某宝搜索亚克力板定制 2. 将本文件发送给店家…