【智能家居】八、监控摄像采集、人脸识别比对进行开门功能点
一、使用 fswebcam 测试 USB 摄像头
二、根据demo来实现功能点
三、功能点编写编译运行实现
四、mjpg实现监控识别
五、V4L2 视频设备 Linux 内核模块的一部分
一、使用 fswebcam 测试 USB 摄像头
a. 安装 fswebcam
orangepi@orangepi:~$ sudo apt update
orangepi@orangepi:~$ sudo apt-get install -y fswebcam
b. 安装完 fswebcam 后可以使用下面的命令来拍照
a) -d 选项用于指定 USB 摄像头的设备节点
b) --no-banner 用于去除照片的水印
c) -r 选项用于指定照片的分辨率
d) -S 选项用设置于跳过前面的帧数
e) ./image.jpg 用于设置生成的照片的名字和路径
orangepi@orangepi:~$ sudo fswebcam -d /dev/video0 \ --no-banner -r 1280x720 -S 5 ./image.jpg
c. 在服务器版的 linux 系统中,拍完照后可以使用 scp 命令将拍好的图片传到
Ubuntu PC 上镜像观看
orangepi@orangepi:~$ scp image.jpg test@192.168.1.55:/home/test(根据实际情况修改 IP 地址和路径)
d. 在桌面版的 linux 系统中,可以通过 HDMI 显示器直接查看拍摄的图片
这里使用fswebcam进行拍照。参考用户手册
首先在/smart_home拍照,命名为imageComp.jpg
sudo fswebcam -d /dev/video0 --no-banner -r 1280x720 -S 5 ./imageComp.jpg
二、根据demo来实现功能点
demo.c
主要的功能是通过摄像头采集人脸数据,然后通过 cURL 发送 POST 请求到指定的 API 接口,接收 OCR 后台返回的数据。在这个过程中,你使用了一些全局变量、文件 I/O、cURL 库等。
以下是一些建议和注意事项:
-
错误处理: 在系统调用和库函数调用后,最好检查其返回值,以确保操作成功。例如,你可以在文件打开、内存分配等操作后添加错误检查,并在失败时输出错误信息。
-
函数封装: 考虑将一些相关的操作封装成函数,以提高代码的模块性和可读性。例如,可以将 cURL 相关的初始化和清理操作封装成函数。
-
全局变量的使用: 全局变量在函数间传递数据,但过度使用全局变量可能导致代码难以理解和维护。尽量将数据传递作为函数参数,以提高函数的可复用性。
-
内存释放: 在使用
malloc分配内存后,确保在不再需要使用该内存时调用free进行释放,以避免内存泄漏。 -
字符串操作: 在使用字符串拼接函数(如
sprintf)时,确保目标缓冲区足够大以防止缓冲区溢出。 -
资源释放顺序: 在释放资源时,注意释放的顺序,以避免悬挂指针或资源泄漏。
-
安全性: 尽量避免使用
system函数来执行外部命令,这可能带来安全风险。如果可能的话,考虑使用更安全的库函数或 API。
下面是一些可能的改进:
// 错误处理函数
void handleError(const char *message)
{perror(message);exit(EXIT_FAILURE);
}// 初始化 cURL
CURL *initCurl()
{CURL *curl = curl_easy_init();if (!curl){handleError("curl_easy_init failed");}return curl;
}// 释放 cURL 资源
void cleanupCurl(CURL *curl)
{curl_easy_cleanup(curl);
}// 发送 cURL POST 请求
bool sendPostRequest(const char *url, const char *postString, size_t (*writeCallback)(void *, size_t, size_t, void *))
{CURL *curl = initCurl();if (!curl){return false;}CURLcode res;// 设置 cURL 选项curl_easy_setopt(curl, CURLOPT_URL, url);curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);// 执行请求res = curl_easy_perform(curl);// 检查执行结果if (res != CURLE_OK){fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));cleanupCurl(curl);return false;}cleanupCurl(curl);return true;
}// 获取人脸数据
char *getFace()
{printf("人脸数据采集中...\n");system("sudo fswebcam -d /dev/video0 --no-banner -r 1280x720 -S 5 ./image.jpg");while (access("./image.jpg", F_OK) != 0){// 等待文件存在}printf("数据采集完毕\n");// 获取 base64 数据char *base64BufFaceRec = getBase64FromFile("./image.jpg");remove("./image.jpg"); // 采集完成删除,防止占内存return base64BufFaceRec;
}// 发送人脸数据到 OCR 后台
bool sendFaceToOcr()
{char *img1 = getFace(); // 图片 base64 流char *img2 = getBase64FromFile("/home/orangepi/smart_home/test/imageComp.jpg");char *key = "JFD5c1iBh9LVqPkkZMqM8Q";char *secret ="76f444813fc945bd9543e4d7e086ad87";int typeId = 21;char *format = "xml";// 分配足够的空间int len = strlen(key) + strlen(secret) + strlen(img1) + strlen(img2) + 128;char *postString = (char *)malloc(len);if (!postString){handleError("Memory allocation failed");}// 字符串拼接snprintf(postString, len, "img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s", img1, img2, key, secret, typeId, format);// 发送 POST 请求bool result = sendPostRequest("https://netocr.com/api/faceliu.do", postString, readData);// 释放动态分配的内存free(img1);free(img2);free(postString);return result;
}// 入口函数
int main(void)
{// 发送人脸数据到 OCR 后台if (sendFaceToOcr()){// 处理 OCR 后台返回的数据// ...}return 0;
}
这个版本进行了一些重构,提高了可读性和模块性,同时加入了错误处理。你可以根据需要进一步调整。
三、功能点编写编译运行实现
camera.c
#include "controlDevice.h"
#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>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;
}// 获取人脸数据
char *getFace()
{printf("人脸数据采集中...\n");system("sudo fswebcam -d /dev/video0 --no-banner -r 1280x720 -S 5 /home/orangepi/smart_home/test/image.jpg");while (access("./image.jpg", F_OK) != 0); // 判断是否拍照完毕printf("数据采集完毕\n");// 获取 base64 数据char *base64BufFaceRec = getBase64FromFile("./image.jpg");remove("./image.jpg"); // 采集完成删除,防止占内存return base64BufFaceRec; // 返回刚才拍照的base64
}// 根据文档,接口调用方法为post请求
void postUrl()
{CURL *curl;CURLcode res;// 根据翔云平台的接口要求 分开定义,然后字符串拼接char *img1 = getFace(); // 图片base64流char *img2 = getBase64FromFile("/home/orangepi/smart_home/test/imageComp.jpg");char *key = "JFD5c1iBh9LVqPkkZMqM8Q";char *secret = "76f444813fc945bd9543e4d7e086ad87";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);// 初始化 cURLcurl = 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);// 指定urlcurl_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));// 处理错误}// 释放 cURL 资源curl_easy_cleanup(curl);}// 释放动态分配的内存free(img1);free(img2);free(postString);
}struct Devices camera = {.deviceName = "camera",.justDoOnce = postUrl
};struct Devices *addCameraToDeviceLink(struct Devices *phead)
{if (phead == NULL) {return &camera;}else {camera.next = phead; // 以前的头变成.nextphead = &camera; // 更新头return phead;}
}
controlDevice.h
#include <wiringPi.h> //wiringPi库
#include <stdio.h>
#include <stdlib.h>// 设备结构体
struct Devices //设备类
{char deviceName[128]; //设备名int status; //状态int pinNum; //引脚号// 函数指针,用于设备控制int (*Init)(int pinNum); //“初始化设备”函数指针int (*open)(int pinNum); //“打开设备”函数指针int (*close)(int pinNum); //“关闭设备”函数指针int (*readStatus)(int pinNum); //“读取设备状态”函数指针 为火灾报警器准备int (*changeStatus)(int status); //“改变设备状态”函数指针void (*justDoOnce)(); // 仅执行一次的操作struct Devices *next;
};struct Devices* addBathroomLightToDeviceLink(struct Devices *phead); //“浴室灯”加入设备链表函数声明 2
struct Devices* addBedroomLightToDeviceLink(struct Devices *phead); //“卧室灯”加入设备链表函数声明 8
struct Devices* addRestaurantLightToDeviceLink(struct Devices *phead); //“餐厅灯”加入设备链表函数声明 13
struct Devices* addLivingroomLightToDeviceLink(struct Devices *phead); //“客厅灯”加入设备链表函数声明 16
struct Devices* addSmokeAlarmToDeviceLink(struct Devices *phead); //“烟雾报警器”加入设备链表函数声明 6
struct Devices* addBuzzerToDeviceLink(struct Devices *phead); //“蜂鸣器”加入设备链表函数声明 9
struct Devices *addCameraToDeviceLink(struct Devices *phead); // “摄像头”加入设备链表
struct Devices *addLockToDeviceLink(struct Devices *phead); // “门锁”加入设备链表 15
main.c
在main.c文件里的Command(struct InputCommand* CmdHandler)函数中添加
// OCR 指令:执行人脸识别功能进行开门if (strcmp("OCR", CmdHandler->command) == 0){tmp = findDeviceByName("camera", pdeviceHead);if (tmp != NULL){tmp->justDoOnce();// 字符串检索 判断翔云后台返回的一大堆字符串中有没有“否”if (strstr(ocrReturnBuf, "否") != NULL){printf("人脸比对失败\n");}else{printf("人脸比对成功\n");tmp = findDeviceByName("lock", pdeviceHead);if (tmp != NULL){tmp->open(tmp->pinNum);printf("已开门\n");delay(3000);tmp->close(tmp->pinNum);}}}}
这里的摄像头只是当作一个设备去用,目前实现通过串口指令然后system()进行拍照。然后翔云平台进行人脸对比,未实现自动人脸检测。
所以摄像头没有另创线程。但是做视频监控可以另创线程。
这样当串口发送OCR时,实现人脸对比并开锁,所以没有用线程去做
当然,要把camera、lock设备加入设备工厂
注意:ocrReturnBuf这个因为要再不同文件调用的全局变量所以要extern
编译运行
gcc *.c -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt -I /home/orangepi/curl-7.71.1/_install/include/ -L /home/orangepi/curl-7.71.1/_install/lib/ -lcurlsudo -E ./a.out

运行结果

四、mjpg实现监控识别
mjpg来实现也是一样的
通过前面智能垃圾分类章节【阿里云】图像识别 摄像模块 语音模块


五、V4L2 视频设备 Linux 内核模块的一部分
V4L2 是视频设备 Linux 内核模块的一部分,全名是 Video for Linux 2。它提供了一套标准的 API,用于控制和管理视频设备,比如摄像头、视频捕获卡等。V4L2 的设计旨在与 Linux 内核无缝集成,并提供用户空间应用程序与视频设备进行交互的标准接口。
V4L2 的主要特性和功能包括:
-
设备的打开和关闭: 使用 V4L2,可以打开和关闭视频设备。
-
格式和尺寸控制: V4L2 允许应用程序查询和设置视频设备支持的不同格式和分辨率。
-
帧缓冲管理: 应用程序可以通过 V4L2 分配、映射和取消映射帧缓冲。
-
视频捕获和输出: V4L2 允许应用程序启动视频捕获或输出操作,并控制捕获或输出的参数。
-
控制操作: V4L2 提供了对摄像头参数(如亮度、对比度、色彩饱和度等)的控制。
-
流 IO 操作: 支持单帧和多帧的 I/O 操作,用于捕获或输出视频流。
-
回调函数: V4L2 支持回调函数,使得应用程序可以在特定事件发生时得到通知。
V4L2 API 的使用一般包括在用户空间的应用程序中调用相应的系统调用,例如 open()、ioctl() 等,以与视频设备进行交互。在内核空间,V4L2 的实现则通过提供相应的结构体和函数指针来支持。
请注意,V4L2 的详细定义和使用方式可能会根据 Linux 内核版本的不同而有所变化,因此建议查阅相应版本的内核文档和头文件以获取准确的信息。
在 Linux 上,安装和配置 V4L2 通常涉及以下步骤:
-
检查内核支持: 确保你的 Linux 内核已启用 V4L2 支持。通常,大多数标准的 Linux 内核都包含了 V4L2 模块。你可以通过查看内核配置文件或使用
lsmod | grep videodev命令来检查是否加载了videodev模块。 -
安装 V4L2 工具: 有一些工具可用于测试和配置 V4L2 设备。其中一个常用的工具是
v4l-utils。你可以使用包管理工具安装它,例如:sudo apt-get install v4l-utils # 对于基于 Debian 的系统或
sudo yum install v4l-utils # 对于基于 Red Hat 的系统 -
配置设备权限: 确保用户具有访问视频设备的权限。你可以将用户添加到
video组,或者通过修改设备文件的权限来实现。设备文件通常在/dev目录下,例如/dev/video0。 -
加载 V4L2 模块: 如果你的内核未自动加载 V4L2 模块,你可以使用
modprobe命令手动加载:sudo modprobe videodev或者,如果你使用的是特定的摄像头或设备驱动程序,可能需要加载相关的模块。
-
测试设备: 使用
v4l2-ctl工具或其他 V4L2 相关工具测试你的视频设备。例如,你可以使用以下命令查看设备的基本信息:v4l2-ctl --list-devices或者使用以下命令查看摄像头的支持格式和参数:
v4l2-ctl --list-formats-ext -d /dev/video0
这些步骤提供了一个基本的 V4L2 安装和配置的概述。具体的步骤可能会因你的系统和设备而有所不同。请查阅相关的文档和手册以获取更详细的信息。
相关文章:
【智能家居】八、监控摄像采集、人脸识别比对进行开门功能点
一、使用 fswebcam 测试 USB 摄像头 二、根据demo来实现功能点 三、功能点编写编译运行实现 四、mjpg实现监控识别 五、V4L2 视频设备 Linux 内核模块的一部分 一、使用 fswebcam 测试 USB 摄像头 a. 安装 fswebcam orangepiorangepi:~$ sudo apt update orangepiorangepi:~…...
golang的文件操作
获取文件列表路径 package _caseimport ("fmt""log""os""strings" )// 获取文件路径 // 源文件目录 const sourceDir "file/"// 目标文件目录 const destDir "det_file/"// 拿到目录下完整的路径 func geFiles…...
数据库版本管理框架-Flyway(从入门到精通)
一、flyway简介 Flyway是一个简单开源数据库版本控制器(约定大于配置),主要提供migrate、clean、info、validate、baseline、repair等命令。它支持SQL(PL/SQL、T-SQL)方式和Java方式,支持命令行客户端等&am…...
外网访问内网服务器使用教程
如何在任何地方都能访问自己家里的笔记本上的应用?如何让局域网的服务器可以被任何地方访问到?有很多类似的需求,我们可以统一用一个解决方案:内网穿透。内网穿透的工具及方式有很多,如Ngrok、Ssh、autossh、Natapp、F…...
C# Dictionary 利用 ContainsValue 查询指定值是否已经存在
.NET Framework : 4.7.2IDE : Visual Studio Community 2022OS : Windows 10 x64typesetting : Markdownblog : niaoge.blog.csdn.net 简介 本文介绍如何查询Dictionary 中某个值是否已经存在。 ContainsValue 命名空间: System.Collections.Generic 程序集: System.Collect…...
招不到人?用C语言采集系统批量采集简历
虽说现在大环境不太好,很多人面临着失业再就业风险,包括企业则面临着招人人,找对口专业难得问题。想要找到适合自己公司的人员,还要得通过爬虫获取筛选简历才能从茫茫人海中找到公司得力干将。废话不多说,直接开整。 1…...
HXDSP2441-Demo板
板卡图示 下图为HXDSP2441DEMO板,HXDSP2441DEMO板是围绕HXDSP2441构建的芯片演示验证平台。 板卡简介 除了为HXDSP2441芯片提供供电、时钟、储存、网络及调试电路,来实现芯片最基本的功能,也添加了相关模块以搭建HXDSP2441的典型应用场景…...
静态路由的原理和配置
一.路由器的工作原理 首先我们知道路由器是工作在网络层的,那就是三层设备。网络层的功能主要为:不同网段之间通信、最佳路径选择也就是逻辑地址(ip地址)寻址、转发数据。 1.路由器是什么 路由器是能将数据包转发到正确的目的地…...
Ubuntu20.04降低linux版本到5.4.0-26-generic
前言 试用ubuntu20.04安装昇腾的驱动和cann的时,出现如下问题: (base) rootubuntu:/home/work# ./Ascend-hdk-910-npu-driver_23.0.rc3_linux-aarch64.run --full Verifying archive integrity... 100% SHA256 checksums are OK. All good. Uncompr…...
C++ 类型萃取
什么是 type_traits 在C中,类型萃取(type_traits)是一种编译时技术,用于在编译期间获取和操作类型的信息。 主要用于泛型编程以及在编译时做出决策。 类型萃取可以帮我们检查和处理类型特性,从而优化代码、避免错误或…...
【JVM从入门到实战】(四)类的生命周期
什么是类的生命周期 类的生命周期描述了一个类加载、连接、初始化、使用、卸载的整个过程 一个类完整的生命周期如下: 加载阶段 加载阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。 程序员可以使用Java代码拓展的不同的渠道…...
2023年度美食关键词-葱油花卷
2023年即将过去了,总结这一年的美食关键词,对于我来就,应该就是-大葱了。 前一周,朋友送了我5大葱,在北方,大葱是家家户户必不可少的食材,尤其对于面食爱好者来说,大葱的加入无疑让…...
「Verilog学习笔记」简易秒表
专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点,刷题网站用的是牛客网 timescale 1ns/1nsmodule count_module(input clk,input rst_n,output reg [5:0]second,output reg [5:0]minute);always (posedge clk or negedge rst_n) begin if (~rst…...
《每天一个Linux命令》 -- (12) file命令
欢迎阅读《每天一个Linux命令》系列 !在本篇文章中,将说明file命令用法。 概念 file命令是Linux系统下的文件类型识别命令,用于识别文件的类型。 命令操作 file命令的语法如下: file [选项] 文件命令详细解释 以下是 file 命…...
如何使用ArcGIS Pro制作类似CAD的尺寸注记
经常使用CAD制图的朋友应该比较熟悉CAD内的尺寸标注,这样的标注看起来直观且简洁,那么在ArcGIS Pro内能不能制作这样尺寸注记呢,答案是肯定的,这里为大家介绍一下制作的方法,希望能对你有所帮助。 数据来源 本教程所…...
Go语言bufio包的使用
准备文本文件 rpc_intro.txt RPC(Remote Procedure Call,远程过程调用)是一种计算机通信协议, 允许调用不同进程空间的程序。RPC 的客户端和服务器可以在一台机器上,也可以在不同的机器上。程序员使用时,就像调用本地程序一样&…...
计算机网络之IP篇
来源自小林Coding博客,阅读后部分精简笔记 目录 一、IP 的基本认识 二、DNS 三、ARP 四、DHCP 五、NAT 六、ICMP 七、IGMP 七、ping 的工作原理 ping-----查询报文的使用 traceroute —— 差错报文类型的使用 八、断网了还能 ping 通 127.0.0.1 吗&…...
Java中JDK类库常用的6种设计模式
Java中JDK类库常用的6种设计模式:1、抽象工厂。2、建造者模式。3、工厂模式。4、原型模式。5、单例模式。6、适配器模式。 1、抽象工厂 javax.xml.parsers.DocumentBuilderFactory抽象类。 public static DocumentBuilderFactory newInstance()方法。 类功能&…...
C++ 用法全面剖析
我们知道,参数的传递本质上是一次赋值的过程,赋值就是对内存进行拷贝。所谓内存拷贝,是指将一块内存上的数据复制到另一块内存上。 对于像 char、bool、int、float 等基本类型的数据,它们占用的内存往往只有几个字节,对…...
数据库结构
三级结构 内模式:也称为物理模式,它是数据库中数据的物理存储表示,描述了数据在存储介质上的存储方式和物理结构,通常由数据库管理员进行定义。 概念模式:也称为逻辑模式,它是对数据库中全体数据的逻辑表示…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...
