【智能家居】七、人脸识别 & 翔云平台编程使用(编译openSSL支持libcurl的https访问、安装SSL依赖库openSSL)

[一、翔云 人工智能开放平台](#一、翔云 人工智能开放平台)

  • API文档
  • 开发示例下载

二、编译openSSL支持libcurl的https访问

三、编程实现人脸识别
四、Base64编码
五、RGB颜色模型(用于表示图像中的颜色信息)
[六、BMP 图像以像素矩阵的形式存储](#六、BMP 图像以像素矩阵的形式存储)
七、Base64数据格式转换
八、加入图片base64编码
九、人脸识别完整代码及功能点实现现象

一、翔云 人工智能开放平台

翔云 人工智能开放平台

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




API文档

开发示例下载

C++示例代码



cpp 复制代码
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。

bash 复制代码
./configure --with -ssl

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

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

bash 复制代码
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

bash 复制代码
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路径下,配置

bash 复制代码
./config
make
sudo make install


安装配置openssl库时间比较长建议网络稳定ssh建议用MobaXtermvscode ssh安装可能会掉

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

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

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

bash 复制代码
chmod +x configure
sudo ./configure --prefix=$PWD/_install --with-ssl
sudo make 
make install


运行(运行需添加动态库为环境变量)

生成了可执行文件./a.out直接运行可能会报错(我没有报错,可能是我用的Ubuntu22.04)。

原因是运行时要链接动态库,没有添加环境变量

bash 复制代码
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环境变量的步骤:

  1. 打开.bashrc文件,可以使用文本编辑器如nanovimgedit等。

    bash 复制代码
    nano ~/.bashrc
  2. 在文件的末尾添加以下行,其中/path/to/libcurl是libcurl库的实际路径。

    bash 复制代码
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/libcurl

    替换/path/to/libcurl为libcurl库的实际路径。

  3. 保存并关闭文件。

  4. 使更改生效。可以通过运行以下命令重新加载.bashrc文件:

    bash 复制代码
    source ~/.bashrc

    或者,你可以注销并重新登录。

现在,libcurl库的路径将在每次启动新shell时自动添加到LD_LIBRARY_PATH中。这确保了libcurl库在系统范围内可用。请注意,这只对当前用户生效。如果你希望所有用户都能访问libcurl库,你可能需要将环境变量设置添加到/etc/environment文件中,这需要超级用户权限。

bash 复制代码
echo $PATH 	// 获得当前环境变量的值
pwd			// 获得当前路径

修改工作目录下的 .bashrc 隐藏文件,配置命令终端

bash 复制代码
vi /home/orangepi/.bashrc 

在文件最后一行加入:

bash 复制代码
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/orangepi/curl-7.71.1/_install/lib
bash 复制代码
source /home/orangepi/.bashrc 加载配置文件,马上生效配置。

三、编程实现人脸识别

翔云人脸识别API文档

ocr.c

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;
}

编译

bash 复制代码
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 个字符,包括:

  1. 26 个大写字母: A-Z
  2. 26 个小写字母: a-z
  3. 10 个数字: 0-9
  4. 两个额外字符: + 和 /

Base64 不使用常见的字符,因此它是一种安全的编码方式,适用于在文本协议中传输二进制数据。

编码过程如下:

  1. 将数据按每三个字节(24 位)进行分组。
  2. 将每组数据划分为四个 6 位的片段。
  3. 将这些 6 位的片段转换为 Base64 字符。

Base64 解码则是编码的逆过程,将 Base64 字符转换回原始的二进制数据。在编码和解码过程中,Base64 字符集提供了一种标准的、文本友好的表示形式,使得数据在各种环境中都能够被正确处理。

示例:

plaintext 复制代码
原始数据:   Hello, World!
Base64 编码:SGVsbG8sIFdvcmxkIQ==

在编程中,大多数编程语言都提供了 Base64 编码和解码的库或函数,方便开发者在应用中使用。

五、RGB颜色模型(用于表示图像中的颜色信息)

RGB(Red, Green, Blue)是一种颜色模型,用于表示图像中的颜色信息。在 RGB 模型中,每个像素的颜色由红色(R)、绿色(G)、蓝色(B)三个分量的亮度组合而成。每个分量的取值通常在 0 到 255 之间,其中 0 表示最小亮度,255 表示最大亮度。

RGB 数据表示一个图像的颜色信息,通常以矩阵的形式存储。每个像素由一个或多个字节组成,其中每个字节对应一个颜色分量。在常见的图像文件格式中,像素的存储顺序通常是连续的,按行或按列排列。

以下是一个简单的示例,展示了一个 3x3 的图像的 RGB 数据:

plaintext 复制代码
| 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 文件的结构包括文件头和图像数据两个主要部分:

  1. 文件头(Bitmap File Header): 包含了文件的一些基本信息,比如文件类型、文件大小、图像的偏移等。

  2. 信息头(Bitmap Information Header): 包含了关于图像的详细信息,如图像的宽度、高度、颜色平面数、每像素比特数等。

  3. 颜色表(Color Table): 针对使用调色板的图像,包含了调色板中的颜色信息。

  4. 图像数据: 包含了图像的实际像素数据。

BMP 文件通常比较简单,易于理解和解析。然而,由于它不使用压缩算法,因此可能占用较大的存储空间,尤其是对于彩色图像。在实际应用中,更常见的图像格式如JPEG、PNG等采用了更高效的压缩算法。

常见的图像格式

有许多不同的图像格式,每种格式都有其特定的用途和优势。以下是一些常见的图像格式:

  1. JPEG(Joint Photographic Experts Group): 一种有损压缩格式,适用于照片和真彩图像。它通过牺牲一些图像细节来实现更小的文件大小。

  2. PNG(Portable Network Graphics): 一种无损压缩格式,适用于图标、图形和带有透明背景的图像。PNG支持多种颜色深度和透明度。

  3. GIF(Graphics Interchange Format): 一种支持动画和透明度的格式。GIF适用于简单的图形,但由于其有限的颜色深度,不适用于照片。

  4. BMP(Bitmap): 一种无损格式,适用于简单的图像。BMP文件通常较大,因为它们未经压缩。

  5. TIFF(Tagged Image File Format): 一种灵活的格式,适用于存储高质量的图像和照片。TIFF支持无损压缩和多页文档。

  6. WEBP: 由Google开发的一种图像格式,支持有损和无损压缩,同时具有较小的文件大小。

  7. SVG(Scalable Vector Graphics): 一种矢量图形格式,适用于图标和图形。SVG图像可缩放而不失真。

  8. RAW: 一种未经处理的图像格式,通常由数码相机生成。RAW格式保留了更多的图像信息,但文件较大。

  9. ICO(Icon): 用于存储图标的格式,通常用于Windows应用程序。

这只是一小部分常见的图像格式,实际上还有许多其他专用格式和变种,每种都适用于不同的用途。选择图像格式时,通常要考虑图像的内容、用途、质量和文件大小。

七、Base64数据格式转换

Base64是一种将二进制数据编码成ASCII字符串的方法,通常用于在文本协议中传输二进制数据。你可以使用Base64编码工具对图像进行编码,以下是一个示例:

bash 复制代码
base64 test.jpg > test_base64.txt

这将把 test.jpg 图像文件编码为Base64,并将结果保存到 test_base64.txt 文件中。

如果你想要将Base64字符串解码回二进制数据,可以使用以下命令:

bash 复制代码
base64 -d test_base64.txt > test_decoded.jpg

这将从 test_base64.txt 文件中读取Base64字符串并将其解码为 test_decoded.jpg 图像文件。

请注意,Base64编码会增加数据的大小,因为它将二进制数据转换为文本形式。在网络传输中使用它可以确保数据以文本的形式传递,但需要考虑到编码和解码的性能开销。

常用的Base64加密解密工具网站

一些常用的Base64加密解密工具网站包括:

  1. Base64 编码解码 - 在线工具
  2. Online Base64 编码解码
  3. Base64 编码/解码工具

请记住在使用在线工具时要谨慎,特别是在处理敏感数据时,因为在线服务可能会记录你的数据。如果你处理敏感信息,请尽量使用本地工具。

八、加入图片base64编码

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

在Linux下生成图片的base64编码

bash 复制代码
base64 test.jpg
c 复制代码
#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

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;
}

编译

bash 复制代码
gcc ocr.c -I /home/orangepi/curl-7.71.1/_install/include/ -L /home/orangepi/curl-7.71.1/_install/lib/ -lcurl

运行


相关推荐
九天轩辕2 小时前
HTTPS 通信流程
https
yourkin6662 小时前
HTTPS(下)
服务器·网络协议·https
anddddoooo16 小时前
域内证书维权
服务器·网络·网络协议·安全·网络安全·https·ssl
九天轩辕21 小时前
HTTPS 证书交换流程
网络协议·https
码农诗人1 天前
调用openssl实现加解密算法
算法·openssl·ecdh算法
艾格北峰2 天前
STM32 物联网智能家居 (六) OLED显示设备
arm开发·stm32·单片机·嵌入式硬件·物联网·智能家居
遥遥远方 近在咫尺2 天前
HTTPS原理
网络协议·https
编程星空2 天前
HTTP 和 HTTPS 的区别
网络协议·http·https
Cedric_Anik2 天前
HTTP和HTTPS详解
网络协议·http·https
菠菠萝宝2 天前
【Java八股文】08-计算机网络面试篇
java·计算机网络·http·面试·https·udp·tcp