diff --git a/Cpp_example/.gitignore b/Cpp_example/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..b5ccccc4b4e16e122a303e88d6dd3f6259ab7ed8
--- /dev/null
+++ b/Cpp_example/.gitignore
@@ -0,0 +1,11 @@
+TestFacePlate_lcd/
+T-Helmetdetect/
+T-electronic_fence/
+T-smart_inspection/
+RGA/
+T/
+D17_handmark/
+D18_facemesh/
+D18_shufflenet-backbone/
+D19-tinpypose/
+Vision/
diff --git a/Cpp_example/D16_LPRNet/README.md b/Cpp_example/D16_LPRNet/README.md
index aeeac4de2c409a309938ff6f5ee32286807b0537..63507f16da12a399420386989eb54a6a104d13b6 100644
--- a/Cpp_example/D16_LPRNet/README.md
+++ b/Cpp_example/D16_LPRNet/README.md
@@ -191,7 +191,7 @@ chmod 777 Test-lprnet
程序运行后,控制台会输出识别到的车牌号码:
```
-The car plate is 京A12345
+The car plate is 湘F 6CL03
```
## 5. 总结
diff --git a/F&Q/faq.md b/F&Q/faq.md
index 8d2e919818711df2a43e1ad3409a4ffa147685b7..124dd0232e817756464940d45016d7babd13a140 100644
--- a/F&Q/faq.md
+++ b/F&Q/faq.md
@@ -87,4 +87,15 @@ git clone https://gitee.com/LockzhinerAI/arm-rockchip830-linux-uclibcgnueabihf.g
自己写的文件保存了,然后在自己文件这一栏右键打开终端然后生成可执行文件,但是它一直是生成的标准历程里的可执行文件
```
+## 板卡使用
+当编译出来的文件在板卡上运行时,出现以下提示:
+```markdown
+
+root@lockzhiner_vision_module:/root/shufflenet# ./Test-shufflenet shufflenet-backbone.rknn 1.JPEG
+
+/root/shufflenet/Test-shufflenet: symbol '_ZTVN24lockzhiner_vision_module6vision18ShuffleNetBackboneE': can't resolve symbol
+root@lockzhiner_vision_module:/root/shufflenet#
+```
+可以排查动态库是否是最新版本
+
请根据**自定义文件名**修改cmak,如果不知到如何修改的话,可以拷贝一个例程,不修改文件名,只修改里面的内容(同时如果需要视觉功能最好使用E或D例程进行替换可以减少写cmake的麻烦)
\ No newline at end of file
diff --git a/README.md b/README.md
index ff82894e46e8fc1a40ae01f8fe6ac53eaef12ce2..e405f8c745c2bf04ce7809ce6dcd8ebb68a135ba 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,24 @@
>
> * 更详细的参数请参考 [凌智视觉模块设备详细参数文档](./docs/device_parameters.md)
+## 支持模型列表
+|模型名称|模型类型|备注|
+|---|---|---|
+|PicoDet|目标检测模型||
+|YoloV5|目标检测模型||
+|YoloV8|目标检测模型||
+|PicoClas|图像分类模型||
+|PP-HumanSeg|人像分割模型|执行速度慢,不满足实时要求|
+|PFLD|人脸关键点检测模型||
+|LPRNet|车牌识别模型||
+|PP-OCRv3-Rec|文本识别模型||
+|PP-OCRv4-Det|文本检测模型||
+|CRNN-Lite|文本识别模型||
+|DB-Net|文本检测模型||
+|Retainface|人脸特征点提取模型||
+|blazehand_landmark|手部关键点提取模型|meidiapipe 手部关键点提取模型|
+
+
## 🔄 最新日志
## 🎁 购买链接
@@ -106,6 +124,12 @@ Lockzhiner Vision Module 拥有丰富的 IO 接口,其接口图片如下图所
* [凌智视觉模块 PWM 使用指南](./example/periphery/pwm)
* [凌智视觉模块 USART(串口) 使用指南](./example/periphery/usart)
+### 🔌 无线图传案例
+
+无线图传,全称“无线图像传输”,是指利用无线电波将视频图像信号从发送端(如摄像机、视觉模块)实时传输到接收端(如监视器、手机、PC),并在接收端还原显示的技术。简单来说,就是给摄像头“剪掉”视频线,换成无形的电磁波。为降低使用成本,在本模块中,我们提供了基于 socket 实现的无线图传功能示例。
+
+* [凌智视觉模块无线图传案例](./example/periphery/wifi)
+
## 🧠 深度学习视觉部署教程
这一部分教程将引导你从零开始训练并部署各种深度学习模型,包括分类模型、检测模型、分割模型和 OCR 模型。通过这些实战教程,你将学习到如何利用 Lockzhiner Vision Module 的高性能计算能力以及借助飞桨生态系统的丰富资源,轻松实现视觉任务的训练和部署。
diff --git a/docs/wifi/README.md b/docs/wifi/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f84cb5d2f6f0745eb8f07e17b8616cbd684edf28
--- /dev/null
+++ b/docs/wifi/README.md
@@ -0,0 +1,70 @@
+# 凌智视觉模块 Wi-Fi 使用指南
+
+发布版本:V1.0
+日期:2026-07-21
+文件密级:■公开
+
+---
+
+## 免责声明
+
+本文档按“现状”提供,福州凌睿智捷电子有限公司(以下简称“本公司”)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。
+
+由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。
+
+## 读者对象
+
+- 技术支持工程师
+- 软件开发工程师
+
+## 修订记录
+
+| 日期 | 版本 | 作者 | 修改说明 |
+| ---------- | ---- | ------ | ------------ |
+| 2026/07/21 | V1.0 | 钟海滨 | 初始正式版本 |
+
+---
+
+
+## 1 性能测试
+
+为评估 Wi‑Fi 实际传输性能,推荐使用以下两种方法。测试时,开发板作为服务端或客户端均可。
+
+### 1.1 FTP 文件传输(模拟真实业务)
+
+在理想环境下,单向 FTP 吞吐量可达 **30~40 Mbps**(约 4~5 MB/s)。若测速明显偏低,请检查:
+- 天线是否牢固连接;
+- 信道是否存在干扰;
+- CPU 负载是否过高(可用 `top` 命令观察)。
+
+### 1.2 iperf3 网络吞吐测试(压力测试)
+
+使用 iperf3 进行 TCP 吞吐量测试,结果如下(测试环境同第2节说明):
+
+| 测试条件 | 平均带宽(发送) | 平均带宽(接收) | 重传次数 | 瞬时峰值 |
+| -------------------------------- | :--------------: | :--------------: | :------: | :------: |
+| 单流默认(-t 60) | 13.2 Mbps | 13.1 Mbps | 0 | ~20 Mbps |
+| 单流大块(-l 1M -t 30) | 18.9 Mbps | 18.5 Mbps | 6 | ~29 Mbps |
+| **4 流并发(-P 4 -t 30)** | **26.9 Mbps** | **26.4 Mbps** | 0 | **37.0 Mbps** |
+| 反向单流(-R -t 10) | ~13 Mbps | ~13 Mbps | 0 | ~15 Mbps |
+
+**结果解读**:
+- 重传次数为 0(或极低)表明 Wi‑Fi 空口环境优良,无丢包和干扰。
+- 多流并发能有效利用 CPU 的中断处理能力,总带宽提升明显,瞬时峰值可达 37 Mbps,接近 FTP 实测水平。
+- 单流带宽受限主要源于 CPU 内存拷贝开销,而 FTP 利用零拷贝(`sendfile`)技术可绕过该瓶颈,故实际文件传输性能更高。
+
+**综合结论**:该模块的 Wi‑Fi 硬件与驱动状态正常,具备稳定提供 30~40 Mbps 实际业务吞吐量的能力。iperf3 可作为链路质量的辅助验证工具,但最终应用性能应以 FTP 文件传输为准。
+
+---
+
+## 2 注意事项
+
+1. **天线必接**:务必在首次上电前连接好天线,避免射频功放损坏。
+2. **配置保存**:修改配置文件后,请使用 `reboot` 命令正常重启,切勿直接断电。
+3. **性能验证**:实际使用中,请根据自身应用场景进行带宽测试,确保性能满足需求。
+4. **干扰规避**:2.4 GHz 频段易受蓝牙、微波炉等设备干扰,建议选择干扰较少的信道。
+5. **固件升级**:如遇连接异常,可检查固件版本,必要时联系技术支持获取更新。
+
+---
+
+*本文档最终解释权归福州凌睿智捷电子有限公司所有。*
diff --git "a/docs/\346\235\277\345\215\241\344\277\241\346\201\257/cpuinfo.md" "b/docs/\346\235\277\345\215\241\344\277\241\346\201\257/cpuinfo.md"
new file mode 100644
index 0000000000000000000000000000000000000000..61ad511f5e01054965c4b8a1d94066f744434de5
--- /dev/null
+++ "b/docs/\346\235\277\345\215\241\344\277\241\346\201\257/cpuinfo.md"
@@ -0,0 +1,38 @@
+# 命令:查看CPU信息
+```bash
+cat /proc/cpuinfo
+```
+# 返回信息
+```markdown
+
+root@lockzhiner_vision_module:/proc# cat /proc/cpuinfo
+processor : 0
+model name : ARMv7 Processor rev 5 (v7l)
+BogoMIPS : 69.82
+Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x0
+CPU part : 0xc07
+CPU revision : 5
+
+Hardware : Rockchip (Device Tree)
+Revision : 0000
+Serial : 85503951ea2d8830
+
+```
+# 解读
+| 字段 | 当前值 | 含义 / 说明 |
+|------|--------|-------------|
+| **processor** | `0` | 当前系统识别的 CPU 核心编号(仅识别到 1 个核心,常见于单核 Cortex‑A7 或未开启其他核心) |
+| **model name** | `ARMv7 Processor rev 5 (v7l)` | 32 位 ARMv7 架构,`v7l` 表示小端模式(Little‑Endian),修订版本为 r5 |
+| **BogoMIPS** | `35.95` | 内核启动时计算的**粗略速度值**,仅用于调度校准,**并非实际主频** |
+| **Features** | `half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae` | 支持的指令集与硬件特性:
• NEON / VFP:多媒体与浮点加速
• 硬件整数除法 (`idiva`, `idivt`)
• 大物理地址扩展 (`lpae`,支持 >4GB 内存寻址) |
+| **CPU implementer** | `0x41` | 处理器厂商代码,`0x41` 代表 **ARM** 公司 |
+| **CPU architecture** | `7` | ARM 架构版本号,即 ARMv7 |
+| **CPU variant** | `0x0` | 处理器变体(通常用于标识芯片步进) |
+| **CPU part** | `0xc07` | **核心型号编码**,`0xC07` 对应 **Cortex‑A7** |
+| **CPU revision** | `5` | 该核心的修订版本号 |
+| **Hardware** | `Rockchip (Device Tree)` | 硬件平台为 **瑞芯微(Rockchip)**,内核采用设备树(Device Tree)驱动 |
+| **Revision** | `0000` | 板级硬件版本号(此处为默认值,可能未在 U‑Boot 中烧录具体版本) |
+| **Serial** | `85503951ea2d8830` | SoC 芯片的**唯一硬件序列号**,常用于设备绑定、授权或加密 |
diff --git a/example/periphery/wifi/README.md b/example/periphery/wifi/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3c03ca6418d5ed90beda3c4d8c5b7793ba0d53a4
--- /dev/null
+++ b/example/periphery/wifi/README.md
@@ -0,0 +1,127 @@
+# 凌智视觉模块 Wi-Fi 使用指南
+
+发布版本:V1.0
+日期:2026-07-21
+文件密级:■公开
+
+---
+
+## 免责声明
+
+本文档按“现状”提供,福州凌睿智捷电子有限公司(以下简称“本公司”)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。
+
+由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。
+
+## 读者对象
+
+- 技术支持工程师
+- 软件开发工程师
+
+## 修订记录
+
+| 日期 | 版本 | 作者 | 修改说明 |
+| ---------- | ---- | ------ | ------------ |
+| 2026/07/21 | V1.0 | 钟海滨 | 初始正式版本 |
+
+---
+
+## 1 简介
+### 1.1 WIFI 模组概述
+Wi‑Fi 是一种用于连接计算机与外部设备并进行数据传输的无线通信技术。凌智视觉模块(Lockzhiner Vision Module)搭载了 Wi‑Fi 模组,支持 2.4 GHz 频段的无线网络连接。
+
+本指南将指导您完成 Wi‑Fi 的连接配置,并通过 FTP 和 iperf3 工具验证无线性能。
+
+wifi模组示意图
+
+
+
+
+
+在连接时请确保wifi模块连接引脚,同视觉模块相互对应。
+
+
+---
+### 1.2 Wi‑Fi 系统特点
+
+本模块搭载标准 Linux/RTOS 操作系统,内置全功能 TCP/IP 网络协议栈。开发时直接调用标准 BSD Socket API 进行网络编程(与 PC 端开发无异),无需依赖串口 AT 指令集中转数据。
+
+相较于传统的“MCU主控 + ESP8266 AT固件”方案,本方案具有以下优势:
+
+- 开发便捷:直接使用 socket、select 等标准接口,无需拼接与解析 AT 命令字符串。
+- 高吞吐率:摄像头数据在模块内部通过系统总线直接交由 Wi-Fi 网卡发送,无串口速率瓶颈,可支撑 30fps 实时图传。
+- 灵活调优:可借助 iptables、tc 等 Linux 原生网络工具进行深度流量控制与性能优化。
+
+## 2 设备参数
+
+| 项目 | 参数 |
+| -------------- | ----------------------------------- |
+| Wi‑Fi 核心芯片 | RTL8723DS(或 RTL8723 系列) |
+| 支持频段 | 2.4 GHz |
+| 协议标准 | IEEE 802.11n(Wi‑Fi 4) |
+| 最高连接速率 | 150 Mbps(40 MHz 频宽) |
+| 实际吞吐量 | 约 30~40 Mbps(FTP 应用层测试) |
+
+> **说明**:150 Mbps 为物理层协商速率,实际有效载荷受协议开销、环境干扰、CPU 负载等因素影响,应用层速率在 30~40 Mbps 属正常范围。本文所有性能数据均在开发板与无线路由器直线距离 2 米、无遮挡、外接天线的环境下测得。
+
+---
+
+## 3 Wi‑Fi 连接配置方式
+
+模块支持多种 Wi‑Fi 配置方式,按优先级从高到低排列如下:
+
+
+❗ **注意事项**:使用 wifi 时需要烧录 wifi 版本的镜像,否则 wifi 模块无法使用。
+
+### 3.1 U盘配置文件(优先级最高)
+
+1. 将格式化为 FAT32 的 U 盘插入模块 USB 接口。
+2. 模块会自动在 U 盘根目录生成 `LockzhinerVisionModule.cfg` 配置文件(若不存在)。
+3. 使用文本编辑器打开该文件,修改以下两项:
+ ```
+ wifi_ssid=你的Wi‑Fi名称
+ wifi_passwd=你的Wi‑Fi密码
+ ```
+4. 保存文件并安全弹出 U 盘。
+5. 执行 `reboot` 命令复位模块(**切勿直接断电**,否则配置可能未保存)。
+
+> 当 U 盘配置文件存在时,系统将优先使用其中的设置,忽略其他配置。
+
+### 3.2 开机自动连接脚本
+
+若未插入 U 盘或 U 盘中无配置文件,系统将使用内置脚本 `/etc/init.d/S51wifi_connect` 中的参数。
+
+编辑该脚本,修改以下变量:
+```bash
+WIFISSID="你的Wi‑Fi名称"
+WIFIPWD="你的Wi‑Fi密码"
+TARGET_IP_ALIAS="172.32.0.144" # 固定IP别名,可选
+```
+保存后重启模块即可生效。
+
+### 3.3 手动连接命令
+
+在命令行终端中,可使用以下工具手动连接:
+- **连接指定 Wi‑Fi**:
+ ```bash
+ wifi_start.sh "要连接的Wi‑Fi名" "密码"
+ ```
+- **查看当前连接信息**(信号强度、IP 地址等):
+ ```bash
+ wifi_signal.sh
+ ```
+
+### 3.4 网络地址说明
+
+- `wlan0` 接口默认通过 DHCP 获取动态 IP。
+- 系统同时为 `wlan0` 配置了固定 IP 别名 `172.32.0.144/16`,以便在 DHCP 分配地址未知时仍能访问模块。
+- 若需从电脑访问该别名地址,请确保电脑与模块在同一局域网,并在电脑的对应网卡 IPv4 高级设置中添加静态 IP:`172.32.0.1`,子网掩码 `255.255.0.0`。
+
+---
+
+## 4 图传测试例程
+
+### 4.1 python 测试例程
+
+[python 测试例程](./python)分为 lockai 部分和 接收部分,在使用时需先启动 lockai 部分,再启动接收部分。
+
+*本文档最终解释权归福州凌睿智捷电子有限公司所有。*
diff --git a/example/periphery/wifi/images/runtime.jpg b/example/periphery/wifi/images/runtime.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3a1413c0f25564eeb7be864d93f8c30d2f4c5102
Binary files /dev/null and b/example/periphery/wifi/images/runtime.jpg differ
diff --git a/example/periphery/wifi/images/simple_gui.jpg b/example/periphery/wifi/images/simple_gui.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0b06f18f251877d53f950c1465f6d29810b8f86a
Binary files /dev/null and b/example/periphery/wifi/images/simple_gui.jpg differ
diff --git a/example/periphery/wifi/images/wifi_module_1.jpg b/example/periphery/wifi/images/wifi_module_1.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a23d4feab7b315ab509ca3ce98a4c2eb50cac257
Binary files /dev/null and b/example/periphery/wifi/images/wifi_module_1.jpg differ
diff --git a/example/periphery/wifi/images/wifi_module_2.jpg b/example/periphery/wifi/images/wifi_module_2.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e984de65fd1d4f7facf4742eb42ba47f4dc92aa0
Binary files /dev/null and b/example/periphery/wifi/images/wifi_module_2.jpg differ
diff --git a/example/periphery/wifi/images/wifi_module_3.jpg b/example/periphery/wifi/images/wifi_module_3.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cedff48d4c09c3ac227408d5274317f530431fad
Binary files /dev/null and b/example/periphery/wifi/images/wifi_module_3.jpg differ
diff --git a/example/periphery/wifi/python/README.md b/example/periphery/wifi/python/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..2d8930810c3a7f4288a983c88e7232f32b0babc6
--- /dev/null
+++ b/example/periphery/wifi/python/README.md
@@ -0,0 +1,154 @@
+# 凌智视觉模块无线图传测试例程
+
+发布版本:V1.0
+日期:2026-07-22
+文件密级:■公开
+
+---
+
+## 免责声明
+
+本文档按“现状”提供,福州凌睿智捷电子有限公司(以下简称“本公司”)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。
+
+由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。
+
+## 读者对象
+
+- 技术支持工程师
+- 软件开发工程师
+
+## 修订记录
+
+| 日期 | 版本 | 作者 | 修改说明 |
+| ---------- | ---- | ------ | ------------ |
+| 2026/07/22 | V1.0 | 钟海滨 | 初始正式版本 |
+
+---
+
+## 1 简介
+
+本测试例程用于测试凌智视觉模块的无线图传功能。通过TCP协议将摄像头采集的视频流实时传输到客户端,客户端接收并显示、保存视频流。该例程包含服务端(推流端)和客户端(接收端)两部分,采用纯Python实现,依赖OpenCV库,适用于嵌入式视觉模块或通用Linux/Windows平台。
+
+**主要特性:**
+- 服务端:持续采集摄像头图像,通过TCP发送JPEG压缩帧,支持帧率控制和发送缓冲机制。
+- 客户端:接收JPEG数据并解码,实时显示视频,同时保存为AVI文件,支持FPS统计。
+- 连接管理:服务端支持多客户端依次连接(单连接模式),自动检测客户端断开。
+- 精简通信:仅传输视频数据,无额外命令交互,降低开销。
+
+---
+
+## 2 系统架构
+```mermaid
+sequenceDiagram
+ participant Server
+ participant Client
+ Server->>Server: 监听端口6810
+ Client->>Server: TCP连接请求
+ Server-->>Client: 连接建立
+ loop 每帧
+ Server->>Server: 读取摄像头帧
+ Server->>Server: JPEG编码
+ Server->>Client: 发送4字节长度头 + JPEG数据
+ Client->>Client: 解码显示
+ Client->>Client: 写入AVI文件
+ end
+ Client->>Server: 断开连接(或超时)
+ Server->>Server: 关闭连接,等待下一客户端
+```
+### 2.1 服务端(推流端)
+
+- **语言**:Python 3
+- **依赖库**:`lockzhiner_vision_module.cv2`(基于OpenCV)、`threading`、`socket`、`select`、`time`
+- **功能模块**:
+ - **主线程**:创建TCP服务端监听,接收客户端连接,启动发送与接收子线程。
+ - **发送线程(`stream_sender`)**:以固定帧率(默认30fps)读取摄像头,使用JPEG编码(质量75),通过非阻塞select检查发送缓冲区,丢弃过载帧,确保实时性。
+ - **接收线程(`client_receiver`)**:仅监测客户端连接状态,若客户端断开则设置停止事件,通知发送线程退出。
+
+### 2.2 客户端(接收端)
+
+- **语言**:Python 3
+- **依赖库**:`opencv-python`、`numpy`、`socket`、`time`
+- **功能模块**:
+ - 连接服务端后,循环接收每帧数据(4字节长度头 + JPEG数据)。
+ - 解码为BGR图像,显示在窗口中,并写入本地AVI视频文件。
+ - 实时计算并显示接收FPS,支持按`q`键退出。
+
+### 2.3 通信协议
+
+- **传输层**:TCP(IPv4)
+- **帧格式**:
+ - 4字节大端整数表示JPEG数据长度(`data_length`)
+ - 紧接`data_length`字节的JPEG图像数据
+- **端口**:6810(可配置)
+- **IP**:服务端绑定`192.168.1.62`(可根据实际网络修改)
+
+---
+
+## 3 环境要求
+
+### 3.1 硬件
+- 凌智视觉模块(或其他搭载摄像头且支持Python的嵌入式平台)
+- PC(客户端)与模块处于同一局域网(Wi-Fi或以太网)
+
+### 3.2 软件
+- Python 3.6+
+- OpenCV(服务端使用`lockzhiner_vision_module.cv2`,客户端使用标准`cv2`)
+- Numpy(客户端)
+
+### 3.3 网络配置
+- 服务端IP:`192.168.1.62`(示例,请根据实际修改)
+- 客户端需能ping通服务端IP
+
+---
+
+## 4 部署步骤
+
+### 4.1 服务端部署(凌智视觉模块)
+
+1. 将服务端代码(`tcp_rv1106.py`)拷贝至模块。
+2. 确保模块已安装`lockzhiner_vision_module`库(含OpenCV)。
+3. 运行服务端:
+ ```bash
+ python tcp_rv1106.py
+ ```
+ 输出示例:
+ ```
+ Camera ready
+ Server listening on 192.168.1.62:6810
+ ```
+4. 等待客户端连接。
+
+### 4.2 客户端部署(PC)
+
+1. 安装Python依赖:
+ ```bash
+ pip install opencv-python numpy
+ ```
+2. 将客户端代码(`tcp_pc.py`)保存到PC。
+3. 若服务端IP不是`192.168.1.62`,需修改客户端中的`HOST`变量。
+4. 运行客户端:
+ ```bash
+ python tcp_pc.py
+ ```
+ 连接成功后会弹出视频窗口,并开始录制。
+
+### 4.3 停止与退出
+- 服务端:按`Ctrl+C`终止。
+- 客户端:在视频窗口按`q`键,或`Ctrl+C`。
+
+
+## 5 gui 界面
+
+为了方便测试使用,提供了一个简单的 gui 界面版本,在 pc 上运行,只需修改服务器IP和端口号即可。
+
+
+运行时界面
+
+
+
+
+如果需要打包为可执行文件,可使用 `pyinstaller` 工具。
+
+```bash
+pyinstaller --onefile --windowed gui-test.py
+```
diff --git a/example/periphery/wifi/python/code/gui-test.py b/example/periphery/wifi/python/code/gui-test.py
new file mode 100644
index 0000000000000000000000000000000000000000..67fcf9f5e31bed456e2dbac1b438eb1b439e0fcf
--- /dev/null
+++ b/example/periphery/wifi/python/code/gui-test.py
@@ -0,0 +1,174 @@
+import socket
+import cv2
+import numpy as np
+import time
+import json
+import os
+import tkinter as tk
+from tkinter import messagebox
+
+# ---------- 配置管理 ----------
+CONFIG_FILE = "client_config.json"
+
+def load_config():
+ """加载配置文件,若不存在返回默认值"""
+ default = {"host": "192.168.1.62", "port": 6810}
+ if os.path.exists(CONFIG_FILE):
+ try:
+ with open(CONFIG_FILE, "r") as f:
+ cfg = json.load(f)
+ # 确保有host和port字段
+ if "host" in cfg and "port" in cfg:
+ return cfg
+ except Exception:
+ pass
+ return default
+
+def save_config(host, port):
+ """保存配置到文件"""
+ with open(CONFIG_FILE, "w") as f:
+ json.dump({"host": host, "port": port}, f, indent=2)
+
+# ---------- 视频接收函数 ----------
+def receive_image(conn, timeout=5):
+ """从连接接收一帧JPEG图像,返回解码后的BGR图像或None"""
+ conn.settimeout(timeout)
+ try:
+ length_data = conn.recv(4)
+ if len(length_data) != 4:
+ return None
+ data_length = int.from_bytes(length_data, byteorder='big')
+ image_data = b''
+ received = 0
+ while received < data_length:
+ chunk = conn.recv(min(4096, data_length - received))
+ if not chunk:
+ break
+ image_data += chunk
+ received += len(chunk)
+ if received != data_length:
+ return None
+ img_np = np.frombuffer(image_data, dtype=np.uint8)
+ frame = cv2.imdecode(img_np, cv2.IMREAD_COLOR)
+ return frame
+ except (socket.timeout, ConnectionError, OSError):
+ return None
+
+# ---------- 视频流主循环 ----------
+def start_stream(host, port):
+ """连接服务器并显示视频流,按q退出"""
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ try:
+ sock.connect((host, port))
+ print(f"Connected to {host}:{port}")
+ except Exception as e:
+ messagebox.showerror("连接失败", f"无法连接到 {host}:{port}\n错误: {e}")
+ return
+
+ fps_start = time.time()
+ fps_count = 0
+ fps_display_interval = 1.0
+
+ print("Receiving video stream. Press 'q' in the display window to stop.")
+ try:
+ while True:
+ frame = receive_image(sock, timeout=2)
+ if frame is None:
+ print("No frame received (timeout or connection lost), retrying...")
+ time.sleep(0.5)
+ # 这里简单重试,若长时间无数据可退出
+ continue
+
+ # 更新FPS并显示
+ fps_count += 1
+ now = time.time()
+ if now - fps_start >= fps_display_interval:
+ fps = fps_count / (now - fps_start)
+ print(f"Current FPS: {fps:.2f}")
+ cv2.putText(frame, f"FPS: {fps:.2f}", (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
+ fps_start = now
+ fps_count = 0
+
+ cv2.imshow('Video Stream', frame)
+ key = cv2.waitKey(1) & 0xFF
+ if key == ord('q'):
+ print("'q' pressed, stopping...")
+ break
+
+ except KeyboardInterrupt:
+ print("Interrupted by user")
+ except Exception as e:
+ print(f"Error during receiving: {e}")
+ finally:
+ cv2.destroyAllWindows()
+ sock.close()
+ print("Stream stopped.")
+
+# ---------- GUI 配置窗口 ----------
+def show_config_window():
+ """显示配置窗口,返回 (host, port) 或 (None, None) 表示取消"""
+ cfg = load_config()
+ window = tk.Tk()
+ window.title("视频客户端配置")
+ window.geometry("300x150")
+ window.resizable(False, False)
+
+ tk.Label(window, text="服务器IP:").grid(row=0, column=0, padx=10, pady=10, sticky='e')
+ entry_host = tk.Entry(window, width=20)
+ entry_host.grid(row=0, column=1, padx=10, pady=10)
+ entry_host.insert(0, cfg["host"])
+
+ tk.Label(window, text="端口:").grid(row=1, column=0, padx=10, pady=10, sticky='e')
+ entry_port = tk.Entry(window, width=20)
+ entry_port.grid(row=1, column=1, padx=10, pady=10)
+ entry_port.insert(0, str(cfg["port"]))
+
+ result = {"host": None, "port": None, "cancelled": True}
+
+ def on_connect():
+ host = entry_host.get().strip()
+ port_str = entry_port.get().strip()
+ if not host:
+ messagebox.showerror("错误", "请输入服务器IP")
+ return
+ try:
+ port = int(port_str)
+ if port <= 0 or port > 65535:
+ raise ValueError
+ except ValueError:
+ messagebox.showerror("错误", "端口必须是1-65535的整数")
+ return
+ # 保存配置
+ save_config(host, port)
+ result["host"] = host
+ result["port"] = port
+ result["cancelled"] = False
+ window.destroy()
+
+ def on_cancel():
+ result["cancelled"] = True
+ window.destroy()
+
+ btn_frame = tk.Frame(window)
+ btn_frame.grid(row=2, column=0, columnspan=2, pady=10)
+ tk.Button(btn_frame, text="连接", command=on_connect, width=8).pack(side=tk.LEFT, padx=5)
+ tk.Button(btn_frame, text="取消", command=on_cancel, width=8).pack(side=tk.LEFT, padx=5)
+
+ window.mainloop()
+
+ if result["cancelled"]:
+ return None, None
+ return result["host"], result["port"]
+
+# ---------- 主函数 ----------
+def main():
+ host, port = show_config_window()
+ if host is None or port is None:
+ print("用户取消,退出程序")
+ return
+ start_stream(host, port)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/example/periphery/wifi/python/code/tcp_pc.py b/example/periphery/wifi/python/code/tcp_pc.py
new file mode 100644
index 0000000000000000000000000000000000000000..543a312df01d85577953472d97e7dc05e3072737
--- /dev/null
+++ b/example/periphery/wifi/python/code/tcp_pc.py
@@ -0,0 +1,117 @@
+import socket
+import cv2
+import numpy as np
+import time
+
+def receive_image(conn, timeout=5):
+ """从连接接收一帧JPEG图像,返回解码后的BGR图像或None"""
+ conn.settimeout(timeout)
+ try:
+ # 1. 读取4字节长度(大端)
+ length_data = conn.recv(4)
+ if len(length_data) != 4:
+ return None
+ data_length = int.from_bytes(length_data, byteorder='big')
+ # 2. 循环读取图像数据
+ image_data = b''
+ received = 0
+ while received < data_length:
+ chunk = conn.recv(min(4096, data_length - received))
+ if not chunk:
+ break
+ image_data += chunk
+ received += len(chunk)
+ if received != data_length:
+ return None
+ # 3. 解码为OpenCV图像
+ img_np = np.frombuffer(image_data, dtype=np.uint8)
+ frame = cv2.imdecode(img_np, cv2.IMREAD_COLOR)
+ return frame
+ except (socket.timeout, ConnectionError, OSError):
+ return None
+
+def main():
+ HOST = '192.168.1.62'
+ PORT = 6810
+
+ # 连接服务器
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ try:
+ sock.connect((HOST, PORT))
+ print(f"Connected to {HOST}:{PORT}")
+ except Exception as e:
+ print(f"Connection failed: {e}")
+ return
+
+ # 准备视频保存
+ timestamp = int(time.time() * 1000)
+ video_filename = f"video_stream_{timestamp}.avi"
+ fourcc = cv2.VideoWriter_fourcc(*'XVID')
+ video_writer = None
+ first_frame = True
+
+ # FPS统计
+ fps_start = time.time()
+ fps_count = 0
+ fps_display_interval = 1.0 # 每秒更新一次FPS显示
+
+ print("Receiving video stream. Press 'q' in the display window to stop and save.")
+
+ try:
+ while True:
+ frame = receive_image(sock, timeout=2)
+ if frame is None:
+ print("No frame received (timeout or connection lost), retrying...")
+ time.sleep(0.5)
+ # 尝试重新连接(简单处理:break并退出)
+ # 此处为演示,直接退出;实际可尝试重连
+ break
+
+ # 首次帧初始化VideoWriter
+ if first_frame:
+ height, width, _ = frame.shape
+ video_writer = cv2.VideoWriter(video_filename, fourcc, 20.0, (width, height))
+ if not video_writer.isOpened():
+ print("Failed to create video writer")
+ break
+ first_frame = False
+ print(f"Recording started, resolution {width}x{height}")
+
+ # 更新FPS
+ fps_count += 1
+ now = time.time()
+ if now - fps_start >= fps_display_interval:
+ fps = fps_count / (now - fps_start)
+ print(f"Current FPS: {fps:.2f}")
+ # 在图像上显示FPS(可选)
+ cv2.putText(frame, f"FPS: {fps:.2f}", (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
+ fps_start = now
+ fps_count = 0
+
+ # 显示并写入
+ cv2.imshow('Video Stream', frame)
+ video_writer.write(frame)
+
+ # 按q退出
+ key = cv2.waitKey(1) & 0xFF
+ if key == ord('q'):
+ print("'q' pressed, stopping...")
+ break
+
+ except KeyboardInterrupt:
+ print("Interrupted by user")
+ except Exception as e:
+ print(f"Error during receiving: {e}")
+ finally:
+ # 清理资源
+ if video_writer is not None:
+ video_writer.release()
+ print(f"Video saved as {video_filename}")
+ cv2.destroyAllWindows()
+ sock.close()
+ print("Client stopped.")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/example/periphery/wifi/python/code/tcp_rv1106.py b/example/periphery/wifi/python/code/tcp_rv1106.py
new file mode 100644
index 0000000000000000000000000000000000000000..71843f3737429c11dfb8b233e5128c7a0bccb6c3
--- /dev/null
+++ b/example/periphery/wifi/python/code/tcp_rv1106.py
@@ -0,0 +1,151 @@
+import lockzhiner_vision_module.cv2 as cv2
+from threading import Thread, Event
+import socket
+import time
+import select
+
+# ---------- 发送函数 ----------
+def send_frame(conn, frame, quality=75):
+ """压缩并发送一帧,返回是否成功"""
+ try:
+ ret, img_encode = cv2.imencode('.jpg', frame, quality)
+ if not ret:
+ return False
+ data = img_encode
+ # 发送长度(4字节大端) + 图像数据
+ payload = len(data).to_bytes(4,byteorder='big') + data
+ conn.sendall(payload)
+ # conn.sendall(len(data).to_bytes(4, byteorder='big'))
+ # conn.sendall(data)
+ return True
+ except (ConnectionResetError, OSError, BrokenPipeError):
+ return False
+
+# ---------- 发送线程 ----------
+def stream_sender(conn, shutdown_event, cap):
+ """
+ 纯推流线程,持续从摄像头读取并发送,不受外部命令控制。
+ 内含帧率限制(默认30fps)和缓冲区拥塞丢弃机制。
+ """
+ FPS_TARGET = 30
+ QUALITY = 75 # 质量85可平衡画质与大小,可根据需要调整
+ frame_interval = 1.0 / FPS_TARGET
+
+ frame_counter = 0
+ start_time = time.time()
+ last_send_time = 0
+
+ while not shutdown_event.is_set():
+ # 帧率控制:不到时间不发送
+ now = time.time()
+ if now - last_send_time < frame_interval:
+ # 短暂休眠,避免忙等
+ time.sleep(0.001)
+ continue
+ last_send_time = now
+
+ # 读取一帧
+ ret, frame = cap.read()
+ if not ret:
+ time.sleep(0.01) # 读取失败时短暂等待
+ continue
+
+ # 检查发送缓冲区是否可写(非阻塞检查,避免积压)
+ # 若缓冲区满,则丢弃该帧,不编码不发送
+ _, wlist, _ = select.select([], [conn], [], 0.001)
+ if not wlist:
+ # 缓冲区满,丢帧,继续下一轮循环
+ continue
+
+ # 编码并发送
+ if not send_frame(conn, frame, QUALITY):
+ # 发送失败(连接断开),通知退出
+ shutdown_event.set()
+ break
+
+ # 统计FPS
+ frame_counter += 1
+ if now - start_time >= 1.0:
+ print(f"Stream FPS: {frame_counter / (now - start_time):.1f}")
+ frame_counter = 0
+ start_time = now
+
+# ---------- 接收线程 ----------
+def client_receiver(conn, shutdown_event):
+ """
+ 仅负责检测客户端是否断开,不处理任何命令。
+ 若客户端主动关闭,则设置shutdown_event通知发送线程退出。
+ """
+ try:
+ while not shutdown_event.is_set():
+ # 使用非阻塞方式检查数据,一旦收到数据则忽略(因为不再需要命令)
+ # 但为了检测断开,只需尝试recv(1),若返回空则断开
+ try:
+ data = conn.recv(1024)
+ if not data: # 客户端关闭连接
+ print("Client disconnected.")
+ break
+ # 若有数据,不做任何处理,继续循环
+ except BlockingIOError:
+ # 非阻塞模式下无数据则继续
+ time.sleep(0.01)
+ continue
+ except (ConnectionResetError, OSError):
+ print("Connection error.")
+ break
+ finally:
+ shutdown_event.set() # 通知发送线程退出
+
+# ---------- 主服务器 ----------
+if __name__ == "__main__":
+ HOST = '192.168.1.62'
+ PORT = 6810
+
+ # 打开摄像头
+ cap = cv2.VideoCapture()
+ if not cap.open(0):
+ print("Failed to open camera")
+ exit(1)
+ # 设置分辨率(可选)
+ cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
+ cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
+ print("Camera ready")
+
+ # 创建事件
+ shutdown_event = Event()
+
+ # 创建TCP服务器
+ server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ server_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # 禁用Nagle
+ server_socket.bind((HOST, PORT))
+ server_socket.listen(5)
+ print(f"Server listening on {HOST}:{PORT}")
+
+ try:
+ while not shutdown_event.is_set():
+ conn, addr = server_socket.accept()
+ conn.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 256 * 1024)
+ conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # 对客户端也设置
+ print(f"New connection from {addr}")
+ snd_buf = conn.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
+ print(f"Send buffer size: {snd_buf} bytes")
+
+ # 启动发送和接收线程
+ sender = Thread(target=stream_sender, args=(conn, shutdown_event, cap))
+ receiver = Thread(target=client_receiver, args=(conn, shutdown_event))
+ sender.start()
+ receiver.start()
+
+ # 等待线程结束(连接断开后重新进入accept)
+ sender.join()
+ receiver.join()
+ conn.close()
+ print(f"Connection with {addr} closed, waiting for next client...")
+ except KeyboardInterrupt:
+ print("Server interrupted by user.")
+ finally:
+ shutdown_event.set()
+ cap.release()
+ server_socket.close()
+ print("Server stopped.")
\ No newline at end of file
diff --git a/example/vision/detetcion/python/test_detection.py b/example/vision/detetcion/python/test_detection.py
index 6ee2b9215273747d8f4741cb272737d02b14e386..dead3d5775840a04628ec937265a98946dd02c10 100644
--- a/example/vision/detetcion/python/test_detection.py
+++ b/example/vision/detetcion/python/test_detection.py
@@ -1,4 +1,5 @@
from lockzhiner_vision_module.cv2 import VideoCapture
+import lockzhiner_vision_module.cv2 as cv2
from lockzhiner_vision_module.vision import PaddleDet, visualize
from lockzhiner_vision_module.edit import Edit
import time
@@ -9,7 +10,7 @@ if __name__ == "__main__":
if len(args) != 2:
print("Need model path. Example: python test_detection.py LZ-Picodet.rknn")
exit(1)
-
+
edit = Edit()
edit.start_and_accept_connection()
@@ -45,9 +46,11 @@ if __name__ == "__main__":
box = result.box
score = result.score
label_id = result.label_id
+ cv2.imwrite("result.jpg", cv2.cropImage(mat, result.box.x, result.box.y, result.box.width, result.box.height))
+
print(
f"(x,y,w,h,score,label_id): [{box.x},{box.y},{box.width},{box.height},{score},{label_id}]"
)
vis_mat = visualize(mat, results)
edit.print(vis_mat)
- print(f"FPS is {1.0 / (total_time_ms/read_index)}")
\ No newline at end of file
+ print(f"FPS is {1.0 / (total_time_ms/read_index)}")
diff --git a/example/vision/meidiapipe/handlandmark/python/test_hand_landmark.py b/example/vision/meidiapipe/handlandmark/python/test_hand_landmark.py
new file mode 100644
index 0000000000000000000000000000000000000000..1be67f981b57d57e8526b4d9d696b0473562bafc
--- /dev/null
+++ b/example/vision/meidiapipe/handlandmark/python/test_hand_landmark.py
@@ -0,0 +1,46 @@
+from lockzhiner_vision_module.vision import HandLandmark, visualize
+import lockzhiner_vision_module.cv2 as cv2
+import time
+import sys
+
+NUM_HAND_LANDMARKS = 21
+LANDMARK_DIMS = 3
+
+if __name__ == "__main__":
+ args = sys.argv
+ if len(args) != 3:
+ print("Usage: python test_hand_landmark.py ")
+ exit(1)
+
+ model = HandLandmark()
+ if not model.initialize(args[1]):
+ print("Model initialization failed.")
+ exit(1)
+
+ img = cv2.imread(args[2])
+ if img is None:
+ print("Failed to read image.")
+ exit(1)
+
+ t1 = time.time()
+ result = model.predict(img)
+ t2 = time.time()
+ elapsed = t2 - t1
+
+ print(f"Inference time: {elapsed:.4f}s")
+ print(f"Presence score: {result.presence_score}")
+ print(f"Handedness: {result.handedness} (0 = left, 1 = right)")
+
+ if result.presence_score > 0.5:
+ print("\nHand landmarks:")
+ for i in range(NUM_HAND_LANDMARKS):
+ x = result.landmarks[i * 3]
+ y = result.landmarks[i * 3 + 1]
+ z = result.landmarks[i * 3 + 2]
+ print(f"Landmark {i}: ({x:.4f}, {y:.4f}, {z:.4f})")
+
+ output = visualize(img, result)
+ cv2.imwrite("hand_landmark_result.jpg", output)
+ print("\nResult image saved as: hand_landmark_result.jpg")
+ else:
+ print("No hand detected (presence score too low)")
\ No newline at end of file