【智能家居】七、人脸识别 & 翔云平台编程使用(编译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

运行


相关推荐
stm32发烧友2 小时前
基于STM32的智能家居环境监测系统设计
stm32·嵌入式硬件·智能家居
‍。。。2 小时前
使用Rust实现http/https正向代理
http·https·rust
田三番20 小时前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
lucy1530275107920 小时前
【青牛科技】GC2803:白色家电与安防领域中 ULN2803 的卓越替代者
科技·单片机·智能家居·能源·安防·开关电源·白色家电
圈圈的熊2 天前
HTTP 和 HTTPS 的区别
前端·网络协议·http·https
小黄编程快乐屋3 天前
HTTP和HTTPS的区别
网络协议·http·https
GDDGHS_3 天前
HTTP和HTTPS 的作用和应用场景 (python 爬虫简单入门)
爬虫·python·网络协议·http·https
尘浮生3 天前
Java项目实战II基于Spring Boot的智能家居系统(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·mysql·maven·智能家居
沐欣工作室_lvyiyi4 天前
基于单片机的智能家居排气扇系统设计
stm32·单片机·嵌入式硬件·物联网·智能家居