一、翔云 人工智能开放平台
- API文档
- 开发示例下载
二、编译openSSL支持libcurl的https访问
- 安装SSL依赖库openSSL(使用工具wget)
- libcurl库重新配置,编译,安装
- 运行(运行需添加动态库为环境变量)
三、编程实现人脸识别
四、Base64编码
五、RGB颜色模型(用于表示图像中的颜色信息)
六、BMP 图像以像素矩阵的形式存储
七、Base64数据格式转换
八、加入图片base64编码
九、人脸识别完整代码及功能点实现现象
一、翔云 人工智能开放平台
翔云 人工智能开放平台
下面通过人工智能OCR识别平台翔云的使用,掌握调库调API开发的一般步骤,其他的平台也基本类似。
API文档
开发示例下载
C++示例代码
strPostData.Format(_T("img=%s&key=%s&secret=%s&typeId=%d&format=xml"),strImageBase64,strKey,strSecret,nTypeID);
Java示例代码
java大多直接调库,非常简洁,这也是它开发效率高的原因之一。
二、编译openSSL支持libcurl的https访问
那是因为在编译libcurl库的时候,由于翔云接口是https:开头的,需要选择支持SSL。
./configure --with -ssl
我们访问的接口是https开头的,要进行身份验证和数据加密的,体现在我们的key和secret。
那我们就要回到/curl-7.71.1
路径下,删除rm _install -rf
上次编译出来的文件夹,重新编译支持SSL的库。由/docs/INSTALL.md
我们可以得知要想支持SSL,就得./configure --with-ssl
chmod +x configure
sudo ./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
wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz
tar xvf openssl-1.1.1a.tar.gz
进入文件夹,直接去看他的INSTALL。
为了避免到时候编译这个curl又要去配置SSL这个库,我们直接把SSL安装到默认的系统位置去(一般默认是在/usr/local
底下),所以不指定安装路径了,直接在/openssl-1.1.1a
路径下,配置
./config
make
sudo make install
安装配置openssl库时间比较长建议网络稳定ssh建议用MobaXterm,vscodessh安装可能会掉
加 sudo就肯定安装在了usr/local
中,非工作目录无权限
libcurl库重新配置,编译,安装
回到/curl-7.71.1/目录下重新进行配置:
chmod +x configure
sudo ./configure --prefix=$PWD/_install --with-ssl
sudo make
make install
运行(运行需添加动态库为环境变量)
生成了可执行文件./a.out直接运行可能会报错(我没有报错,可能是我用的Ubuntu22.04)。
原因是运行时要链接动态库,没有添加环境变量
cd /home/orangepi/curl-7.71.1/_install/lib
export LD_LIBRARY_PATH=/home/orangepi/curl-7.71.1/_install/lib
永久有效,配置环境变量,要改配置文件
在Linux系统上,如果你希望将libcurl库的路径添加到永久环境变量中,你可以编辑shell配置文件,例如bash的.bashrc
文件。以下是在bash shell中将libcurl库路径添加到LD_LIBRARY_PATH
环境变量的步骤:
-
打开
.bashrc
文件,可以使用文本编辑器如nano
、vim
、gedit
等。nano ~/.bashrc
-
在文件的末尾添加以下行,其中
/path/to/libcurl
是libcurl库的实际路径。export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/libcurl
替换
/path/to/libcurl
为libcurl库的实际路径。 -
保存并关闭文件。
-
使更改生效。可以通过运行以下命令重新加载
.bashrc
文件:source ~/.bashrc
或者,你可以注销并重新登录。
现在,libcurl库的路径将在每次启动新shell时自动添加到LD_LIBRARY_PATH
中。这确保了libcurl库在系统范围内可用。请注意,这只对当前用户生效。如果你希望所有用户都能访问libcurl库,你可能需要将环境变量设置添加到/etc/environment
文件中,这需要超级用户权限。
echo $PATH // 获得当前环境变量的值
pwd // 获得当前路径
修改工作目录下的 .bashrc
隐藏文件,配置命令终端的
vi /home/orangepi/.bashrc
在文件最后一行加入:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/orangepi/curl-7.71.1/_install/lib
source /home/orangepi/.bashrc 加载配置文件,马上生效配置。
三、编程实现人脸识别
翔云人脸识别API文档
ocr.c
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>
// 定义bool类型和常量
typedef unsigned int bool; // 数据类型别名用typedef
#define true 1
#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);
return size * nmemb;
}
// 根据文档,接口调用方法为post请求
bool postUrl()
{
CURL *curl;
CURLcode res;
char *postString = NULL; // 空指针,要开辟空间
// 根据翔云平台的接口要求 分开定义,然后字符串拼接
char *img1 = NULL; // 图片base64流
char *img2 = NULL;
char *key = "JFD5c1iBh9LVqPkkZMxxxx";
char *secret = "76f444813fc945bd9543e4d7e086xxxx";
int typeId = 21;
char *format = "xml";
// 字符串拼接
postString = (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)
{
// 指定cookie缓存文件
if (curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt") != CURLE_OK)
{
fprintf(stderr, "Failed to set cookie file\n");
// 处理错误
return false; // 在设置失败时,直接返回
}
// 指定post传输内容,get请求将URL和postString一次性发送
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString);
// 指定url
curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do");
// 回调函数读取返回值
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);
// 执行请求
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
// 处理错误
return false;
}
// 清理资源
curl_easy_cleanup(curl);
}
// 释放动态分配的内存
free(postString);
return true;
}
int main(void)
{
postUrl();
return 0;
}
编译
gcc ocr.c -I /home/orangepi/curl-7.71.1/_install/include/ -L /home/orangepi/curl-7.71.1/_install/lib/ -lcurl
运行
成功运行后,已经可以看到已经收到了翔云后台的反馈:
四、Base64编码
Base64 是一种二进制到文本编码方式,通过将二进制数据编码为 ASCII 字符集中的字符,使得数据能够以文本形式传输,而不会被改变。Base64 编码通常用于在文本协议中传输二进制数据,例如电子邮件的附件、图片的网址传输等。
Base64 编码的基本原理是将每三个字节的数据(24 位)转换为四个 Base64 字符。这样,原始数据的大小会增加约 1/3。
Base64 字符集通常包含 64 个字符,包括:
- 26 个大写字母: A-Z
- 26 个小写字母: a-z
- 10 个数字: 0-9
- 两个额外字符: + 和 /
Base64 不使用常见的字符,因此它是一种安全的编码方式,适用于在文本协议中传输二进制数据。
编码过程如下:
- 将数据按每三个字节(24 位)进行分组。
- 将每组数据划分为四个 6 位的片段。
- 将这些 6 位的片段转换为 Base64 字符。
Base64 解码则是编码的逆过程,将 Base64 字符转换回原始的二进制数据。在编码和解码过程中,Base64 字符集提供了一种标准的、文本友好的表示形式,使得数据在各种环境中都能够被正确处理。
示例:
原始数据: Hello, World!
Base64 编码:SGVsbG8sIFdvcmxkIQ==
在编程中,大多数编程语言都提供了 Base64 编码和解码的库或函数,方便开发者在应用中使用。
五、RGB颜色模型(用于表示图像中的颜色信息)
RGB(Red, Green, Blue)是一种颜色模型,用于表示图像中的颜色信息。在 RGB 模型中,每个像素的颜色由红色(R)、绿色(G)、蓝色(B)三个分量的亮度组合而成。每个分量的取值通常在 0 到 255 之间,其中 0 表示最小亮度,255 表示最大亮度。
RGB 数据表示一个图像的颜色信息,通常以矩阵的形式存储。每个像素由一个或多个字节组成,其中每个字节对应一个颜色分量。在常见的图像文件格式中,像素的存储顺序通常是连续的,按行或按列排列。
以下是一个简单的示例,展示了一个 3x3 的图像的 RGB 数据:
| R0 G0 B0 | R1 G1 B1 | R2 G2 B2 |
| R3 G3 B3 | R4 G4 B4 | R5 G5 B5 |
| R6 G6 B6 | R7 G7 B7 | R8 G8 B8 |
这里,每组 R G B
表示一个像素的红、绿、蓝三个分量的值。在实际应用中,图像的大小可能是数百乃至数千像素,而 RGB 数据的表示会更加庞大。
在编程中,处理 RGB 数据通常需要使用专门的图像处理库,例如 OpenCV(Open Source Computer Vision Library)等。这些库提供了丰富的函数和工具,方便开发者对图像进行处理、分析和操作。
BMP(Bitmap)是一种位图图像文件格式,它是一种无损压缩的图像格式,通常以.bmp
为文件扩展名。BMP 文件格式最初由Microsoft开发,用于Windows平台。
六、BMP 图像以像素矩阵的形式存储
BMP 图像以像素矩阵的形式存储,每个像素可以用来表示图像中的一个点,而每个点的颜色信息则通过RGB(Red, Green, Blue)三个分量来表示。BMP 文件格式支持不同的颜色深度,包括1位、4位、8位、16位、24位和32位等多种格式。
BMP 文件的结构包括文件头和图像数据两个主要部分:
-
文件头(Bitmap File Header): 包含了文件的一些基本信息,比如文件类型、文件大小、图像的偏移等。
-
信息头(Bitmap Information Header): 包含了关于图像的详细信息,如图像的宽度、高度、颜色平面数、每像素比特数等。
-
颜色表(Color Table): 针对使用调色板的图像,包含了调色板中的颜色信息。
-
图像数据: 包含了图像的实际像素数据。
BMP 文件通常比较简单,易于理解和解析。然而,由于它不使用压缩算法,因此可能占用较大的存储空间,尤其是对于彩色图像。在实际应用中,更常见的图像格式如JPEG、PNG等采用了更高效的压缩算法。
常见的图像格式
有许多不同的图像格式,每种格式都有其特定的用途和优势。以下是一些常见的图像格式:
-
JPEG(Joint Photographic Experts Group): 一种有损压缩格式,适用于照片和真彩图像。它通过牺牲一些图像细节来实现更小的文件大小。
-
PNG(Portable Network Graphics): 一种无损压缩格式,适用于图标、图形和带有透明背景的图像。PNG支持多种颜色深度和透明度。
-
GIF(Graphics Interchange Format): 一种支持动画和透明度的格式。GIF适用于简单的图形,但由于其有限的颜色深度,不适用于照片。
-
BMP(Bitmap): 一种无损格式,适用于简单的图像。BMP文件通常较大,因为它们未经压缩。
-
TIFF(Tagged Image File Format): 一种灵活的格式,适用于存储高质量的图像和照片。TIFF支持无损压缩和多页文档。
-
WEBP: 由Google开发的一种图像格式,支持有损和无损压缩,同时具有较小的文件大小。
-
SVG(Scalable Vector Graphics): 一种矢量图形格式,适用于图标和图形。SVG图像可缩放而不失真。
-
RAW: 一种未经处理的图像格式,通常由数码相机生成。RAW格式保留了更多的图像信息,但文件较大。
-
ICO(Icon): 用于存储图标的格式,通常用于Windows应用程序。
这只是一小部分常见的图像格式,实际上还有许多其他专用格式和变种,每种都适用于不同的用途。选择图像格式时,通常要考虑图像的内容、用途、质量和文件大小。
七、Base64数据格式转换
Base64是一种将二进制数据编码成ASCII字符串的方法,通常用于在文本协议中传输二进制数据。你可以使用Base64编码工具对图像进行编码,以下是一个示例:
base64 test.jpg > test_base64.txt
这将把 test.jpg
图像文件编码为Base64,并将结果保存到 test_base64.txt
文件中。
如果你想要将Base64字符串解码回二进制数据,可以使用以下命令:
base64 -d test_base64.txt > test_decoded.jpg
这将从 test_base64.txt
文件中读取Base64字符串并将其解码为 test_decoded.jpg
图像文件。
请注意,Base64编码会增加数据的大小,因为它将二进制数据转换为文本形式。在网络传输中使用它可以确保数据以文本的形式传递,但需要考虑到编码和解码的性能开销。
常用的Base64加密解密工具网站
一些常用的Base64加密解密工具网站包括:
- Base64 编码解码 - 在线工具
- Online Base64 编码解码
- Base64 编码/解码工具
请记住在使用在线工具时要谨慎,特别是在处理敏感数据时,因为在线服务可能会记录你的数据。如果你处理敏感信息,请尽量使用本地工具。
八、加入图片base64编码
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,可用于在HTTP环境下传递较长的标识信息。
在Linux下生成图片的base64编码
base64 test.jpg
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
char* getBase64FromFile(const char* filePath)
{
char cmd[256] = {'\0'};
char* base64Buf = NULL;
// 使用安全的方式构建命令
snprintf(cmd, sizeof(cmd), "base64 %s | tr -d '\n' > tmpFile", filePath);//图片的base64流导入到文件中
if (system(cmd) == -1) {
perror("Error executing system command");
return NULL;
}
int fd = open("./tmpFile", O_RDWR);
if (fd == -1) {
perror("Error opening file");
return NULL;
}
// 计算文件大小
int fileLen = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
// 动态分配内存
base64Buf = (char*)malloc(fileLen + 1);
if (base64Buf == NULL) {
perror("Error allocating memory");
close(fd);
return NULL;
}
memset(base64Buf, '\0', fileLen + 1);
// 读取文件内容到字符串(base64流)
if (read(fd, base64Buf, fileLen) == -1) {
perror("Error reading file");
free(base64Buf);
close(fd);
return NULL;
}
close(fd);
// 删除临时文件
if (remove("tmpFile") == -1) {
perror("Error deleting temporary file");
}
return base64Buf;
}
int main() {
const char* filePath = "your_file_path_here";
char* base64String = getBase64FromFile(filePath);
if (base64String != NULL) {
printf("Base64 String:\n%s\n", base64String);
// 释放动态分配的内存
free(base64String);
}
return 0;
}
九、人脸识别完整代码及功能点实现现象
ocr.c
#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>
// 定义bool类型和常量
typedef unsigned int bool; // 数据类型别名用typedef
#define true 1
#define false 0
char ocrReturnBuf[1024] = {'\0'}; // 全局变量,用来接收从OCR后台返回的数据
// 回调函数,读取从OCR后台返回的数据(把从后台的数据拷贝给ocrReturnBuf)
size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
{
size_t totalSize = size * nmemb;
// 为了避免溢出,计算实际拷贝的长度
size_t copySize = (totalSize < (sizeof(ocrReturnBuf) - 1)) ? totalSize : (sizeof(ocrReturnBuf) - 1);
// 拷贝数据到 ocrRetBuf 中
memcpy(ocrReturnBuf, ptr, copySize);
// 手动添加字符串终结符
ocrReturnBuf[copySize] = '\0';
return totalSize;
}
char *getBase64FromFile(const char *filePath)
{
char cmd[256] = {'\0'};
char *base64Buf = NULL;
// 使用安全的方式构建命令
snprintf(cmd, sizeof(cmd), "base64 %s | tr -d '\n' > tmpFile", filePath);
if (system(cmd) == -1) {
perror("Error executing system command");
return NULL;
}
int fd = open("./tmpFile", O_RDWR);
if (fd == -1) {
perror("Error opening file");
return NULL;
}
// 计算文件大小
int fileLen = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
// 动态分配内存
base64Buf = (char *)malloc(fileLen + 1);
if (base64Buf == NULL) {
perror("Error allocating memory");
close(fd);
return NULL;
}
memset(base64Buf, '\0', fileLen + 1);
// 读取文件内容到字符串
if (read(fd, base64Buf, fileLen) == -1) {
perror("Error reading file");
free(base64Buf);
close(fd);
return NULL;
}
close(fd);
// 删除临时文件
if (remove("tmpFile") == -1) {
perror("Error deleting temporary file");
}
return base64Buf;
}
// 根据文档,接口调用方法为post请求
bool postUrl()
{
CURL *curl;
CURLcode res;
// 根据翔云平台的接口要求 分开定义,然后字符串拼接
char *img1 = getBase64FromFile("/home/orangepi/smart_home/test/test1_JPEG.webp"); // 图片base64流
char *img2 = getBase64FromFile("/home/orangepi/smart_home/test/test2_JPEG.webp");
char *key = "JFD5c1iBh9LVqPkkZMxxxx";
char *secret = "76f444813fc945bd9543e4d7e086xxxx";
int typeId = 21;
char *format = "xml";
int len = strlen(key) + strlen(secret) + strlen(img1) + strlen(img2) + 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", img1, img2, key, secret, typeId, format);
curl = curl_easy_init();
if (curl)
{
// 指定cookie缓存文件
// if (curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt") != CURLE_OK)
// {
// fprintf(stderr, "Failed to set cookie file\n");
// return false; // 在设置失败时,直接返回
// }
// 指定post传输内容,get请求将URL和postString一次性发送
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString);
// 指定url
curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do");
// 回调函数读取返回值
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);
// 执行请求
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
// 处理错误
return false;
}
//字符串检索 判断翔云后台返回的一大堆字符串中有没有“否”
if (strstr(ocrReturnBuf,"否") != NULL) {
printf("不是同一个人\n");
}
else{
printf("是同一个人\n");
}
// 清理资源
curl_easy_cleanup(curl);
}
// 释放动态分配的内存
free(img1);
free(img2);
free(postString);
return true;
}
int main(void)
{
postUrl();
return 0;
}
编译
gcc ocr.c -I /home/orangepi/curl-7.71.1/_install/include/ -L /home/orangepi/curl-7.71.1/_install/lib/ -lcurl
运行