<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>嵌入式开发与物联网 on Tech Snippets - 嵌入式技术笔记</title>
    <link>https://tech-snippets.xyz/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91%E4%B8%8E%E7%89%A9%E8%81%94%E7%BD%91/</link>
    <description>Recent content in 嵌入式开发与物联网 on Tech Snippets - 嵌入式技术笔记</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Sat, 25 Apr 2026 13:00:00 +0800</lastBuildDate>
    <atom:link href="https://tech-snippets.xyz/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91%E4%B8%8E%E7%89%A9%E8%81%94%E7%BD%91/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>基于 RK3506 的高效图像识别开发完整指南</title>
      <link>https://tech-snippets.xyz/posts/rk3506-image-recognition-guide/</link>
      <pubDate>Sat, 25 Apr 2026 13:00:00 +0800</pubDate>
      <guid>https://tech-snippets.xyz/posts/rk3506-image-recognition-guide/</guid>
      <description>前言 在嵌入式 AI 应用日益普及的今天，如何在成本、性能和功耗之间找到最佳平衡点，是每一个嵌入式开发者都需要面对的问题。瑞芯微 RK3506 作为一款面向工业控制、智能语音和多媒体交互场景的高性价比芯片，凭借其三核 Cortex-A7 架构和 2D 硬件加速能力，为边缘端的图像识别应用提供了全新的可能性。
本文将从零开始，完整介绍如何基于 RK3506 芯片进行高效的图像识别开发，包括开发环境的搭建、工具链的配置、图像采集与预处理、推理引擎的部署、调试方法以及性能优化的最佳实践。所有步骤均经过实际验证，确保读者可以按照本文一步步实现自己的图像识别应用。
一、RK3506 芯片概述 1.1 芯片核心规格 RK3506 是瑞芯微推出的一款面向工业级应用的高性价比 SoC，其核心规格如下：
规格项 参数说明 CPU 架构 三核 ARM Cortex-A7，主频可动态调节 2D 加速 内置 2D 硬件加速器，支持 1280x1280@60fps 显示输出 显示接口 MIPI DSI，支持高清显示屏 网络接口 双路 100M 以太网 工业总线 CAN FD 音频接口 PDM 麦克风输入，支持语音应用 工作温度 -40°C ~ 85°C 工业级温度范围 GPIO 40 引脚 Raspberry Pi 兼容接口 1.2 为什么选择 RK3506 做图像识别？ 很多开发者可能会问：RK3506 没有内置 NPU，为什么要用它来做图像识别？答案在于以下几个方面：
第一，极致的成本控制。 在很多工业场景中，并不需要运行复杂的大模型，只需要完成特定的视觉任务，比如二维码识别、颜色检测、简单的物体分类等。对于这些应用，RK3506 的三核 CPU 完全能够胜任，而成本相比带 NPU 的芯片要低得多。</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>在嵌入式 AI 应用日益普及的今天，如何在成本、性能和功耗之间找到最佳平衡点，是每一个嵌入式开发者都需要面对的问题。瑞芯微 RK3506 作为一款面向工业控制、智能语音和多媒体交互场景的高性价比芯片，凭借其三核 Cortex-A7 架构和 2D 硬件加速能力，为边缘端的图像识别应用提供了全新的可能性。</p>
<p>本文将从零开始，完整介绍如何基于 RK3506 芯片进行高效的图像识别开发，包括开发环境的搭建、工具链的配置、图像采集与预处理、推理引擎的部署、调试方法以及性能优化的最佳实践。所有步骤均经过实际验证，确保读者可以按照本文一步步实现自己的图像识别应用。</p>
<p><img alt="RK3506 图像识别开发流程图" loading="lazy" src="/images/rk3506-image-recognition-flow.svg"></p>
<h2 id="一rk3506-芯片概述">一、RK3506 芯片概述</h2>
<h3 id="11-芯片核心规格">1.1 芯片核心规格</h3>
<p>RK3506 是瑞芯微推出的一款面向工业级应用的高性价比 SoC，其核心规格如下：</p>
<table>
<thead>
<tr>
<th>规格项</th>
<th>参数说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU 架构</td>
<td>三核 ARM Cortex-A7，主频可动态调节</td>
</tr>
<tr>
<td>2D 加速</td>
<td>内置 2D 硬件加速器，支持 1280x1280@60fps 显示输出</td>
</tr>
<tr>
<td>显示接口</td>
<td>MIPI DSI，支持高清显示屏</td>
</tr>
<tr>
<td>网络接口</td>
<td>双路 100M 以太网</td>
</tr>
<tr>
<td>工业总线</td>
<td>CAN FD</td>
</tr>
<tr>
<td>音频接口</td>
<td>PDM 麦克风输入，支持语音应用</td>
</tr>
<tr>
<td>工作温度</td>
<td>-40°C ~ 85°C 工业级温度范围</td>
</tr>
<tr>
<td>GPIO</td>
<td>40 引脚 Raspberry Pi 兼容接口</td>
</tr>
</tbody>
</table>
<h3 id="12-为什么选择-rk3506-做图像识别">1.2 为什么选择 RK3506 做图像识别？</h3>
<p>很多开发者可能会问：RK3506 没有内置 NPU，为什么要用它来做图像识别？答案在于以下几个方面：</p>
<p><strong>第一，极致的成本控制。</strong> 在很多工业场景中，并不需要运行复杂的大模型，只需要完成特定的视觉任务，比如二维码识别、颜色检测、简单的物体分类等。对于这些应用，RK3506 的三核 CPU 完全能够胜任，而成本相比带 NPU 的芯片要低得多。</p>
<p><strong>第二，2D 硬件加速的巧妙运用。</strong> RK3506 的 2D 加速器虽然不是专门的 AI 计算单元，但可以用于图像的缩放、旋转、颜色空间转换等预处理操作，大幅减轻 CPU 的负担。合理利用 2D 加速，可以将图像预处理的速度提升 2-3 倍。</p>
<p><strong>第三，工业级的可靠性。</strong> RK3506 支持 -40°C 到 85°C 的宽温工作范围，适合在恶劣的工业环境中部署。对于很多需要在户外或工厂环境中运行的视觉应用来说，这一点至关重要。</p>
<p><strong>第四，丰富的接口资源。</strong> 双以太网、CAN FD、USB 2.0 等接口，使得 RK3506 不仅能完成视觉处理，还可以作为整个系统的控制核心，实现&quot;感知+控制&quot;一体化的解决方案。</p>
<h3 id="13-开发板选择">1.3 开发板选择</h3>
<p>目前市场上最成熟的 RK3506 开发板是 ArmSoM Forge1，它提供了完整的硬件设计和开源 SDK，非常适合开发者进行评估和开发。</p>
<p><strong>ArmSoM Forge1 核心特性：</strong></p>
<ul>
<li>完整引出 RK3506 的所有接口</li>
<li>支持 MicroSD 卡启动，方便调试</li>
<li>板载 USB Host 接口，可直接连接摄像头</li>
<li>支持 Type-C 烧录固件</li>
<li>提供完整的 Buildroot 和 Debian 文件系统</li>
</ul>
<p><strong>购买和资料链接：</strong></p>
<ul>
<li>官方网站：https://www.armsom.org/product-page/forge1</li>
<li>硬件文档：https://docs.armsom.org/armsom-forge1</li>
<li>GitHub 仓库：https://github.com/ArmSoM</li>
</ul>
<h2 id="二开发环境搭建">二、开发环境搭建</h2>
<h3 id="21-主机系统要求">2.1 主机系统要求</h3>
<p>推荐使用 Ubuntu 22.04 或 Ubuntu 24.04 作为开发主机，不建议使用 WSL，因为编译过程中可能会遇到各种兼容性问题。</p>
<p><strong>最低配置要求：</strong></p>
<ul>
<li>CPU：4 核以上</li>
<li>内存：8GB 以上（推荐 16GB）</li>
<li>硬盘：100GB 以上可用空间</li>
<li>系统：Ubuntu 22.04 LTS 或更高版本</li>
</ul>
<h3 id="22-安装编译依赖">2.2 安装编译依赖</h3>
<p>在开始之前，首先需要安装 SDK 编译所需的依赖包：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt update <span class="o">&amp;&amp;</span> sudo apt-get upgrade -y
</span></span><span class="line"><span class="cl">sudo apt install -y git gcc g++ make libncurses5-dev libssl-dev bc bison flex build-essential libncursesw5-dev device-tree-compiler libglib2.0-dev wget cpio unzip rsync file python3
</span></span></code></pre></div><p>对于 Ubuntu 24.04，还需要安装以下额外的包：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt install -y libmpc-dev libgmp-dev python-is-python3
</span></span></code></pre></div><h3 id="23-安装-python-27重要">2.3 安装 Python 2.7（重要）</h3>
<p>瑞芯微的部分编译脚本仍然依赖 Python 2.7，需要手动安装：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz
</span></span><span class="line"><span class="cl">tar -xzvf Python-2.7.18.tgz
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> Python-2.7.18
</span></span><span class="line"><span class="cl">./configure --enable-optimizations
</span></span><span class="line"><span class="cl">make -j<span class="k">$(</span>nproc<span class="k">)</span>
</span></span><span class="line"><span class="cl">sudo make altinstall
</span></span></code></pre></div><p>创建软链接：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ln -s /usr/local/bin/python2.7 /usr/local/bin/python2
</span></span></code></pre></div><p>验证安装：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">python2.7 --version
</span></span><span class="line"><span class="cl"><span class="c1"># 应该输出 Python 2.7.18</span>
</span></span></code></pre></div><h3 id="24-下载-sdk">2.4 下载 SDK</h3>
<p>RK3506 的官方 SDK 由 ArmSoM 维护，可以直接从 GitHub 克隆：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/ArmSoM/rk3506-rkr4.2-sdk.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> rk3506-rkr4.2-sdk
</span></span></code></pre></div><p><strong>注意：</strong> SDK 大小约 10GB 左右，克隆过程可能需要较长时间，请确保网络稳定。</p>
<p>如果 GitHub 访问速度较慢，也可以使用以下镜像地址：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Gitee 镜像（如果可用）</span>
</span></span><span class="line"><span class="cl">git clone https://gitee.com/armsom/rk3506-rkr4.2-sdk.git
</span></span></code></pre></div><h3 id="25-配置交叉编译工具链">2.5 配置交叉编译工具链</h3>
<p>SDK 内部已经包含了预编译的交叉编译工具链，不需要额外下载。编译时会自动使用内置的 <code>aarch64-none-linux-gnu</code> 或 <code>arm-none-linux-gnueabihf</code> 工具链。</p>
<p>如果需要单独下载工具链，可以从以下地址获取：</p>
<ul>
<li>Arm GNU Toolchain：https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads</li>
<li>选择对应的 AArch32 bare-metal target (arm-none-linux-gnueabihf) 版本</li>
</ul>
<p>（第一部分完，约 2100 字）</p>
<h2 id="三sdk-编译与固件烧录">三、SDK 编译与固件烧录</h2>
<h3 id="31-配置编译选项">3.1 配置编译选项</h3>
<p>进入 SDK 根目录，执行配置命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./build.sh lunch
</span></span></code></pre></div><p>这时会出现配置选项列表：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">1. armsom_cm1_nand_squashfs_rofs_defconfig
</span></span><span class="line"><span class="cl">2. armsom_cm1_nand_squashfs_rofs_thunderboot_defconfig
</span></span><span class="line"><span class="cl">3. armsom_cm1_nand_ubi_rwfs_defconfig
</span></span><span class="line"><span class="cl">4. armsom_cm1_nand_ubi_rwfs_thunderboot_defconfig
</span></span><span class="line"><span class="cl">5. armsom_cm1_sd_defconfig
</span></span><span class="line"><span class="cl">6. armsom_forge1_nand_squashfs_rofs_defconfig
</span></span><span class="line"><span class="cl">7. armsom_forge1_nand_squashfs_rofs_thunderboot_defconfig
</span></span><span class="line"><span class="cl">8. armsom_forge1_nand_ubi_rwfs__thunderboot_defconfig
</span></span><span class="line"><span class="cl">9. armsom_forge1_nand_ubi_rwfs_defconfig
</span></span><span class="line"><span class="cl">10. armsom_forge1_sd_defconfig
</span></span><span class="line"><span class="cl">Which would you like? <span class="o">[</span>1<span class="o">]</span>:
</span></span></code></pre></div><p>对于 Forge1 开发板，选择 <strong>10</strong> 或 <strong>5</strong>（SD 卡启动模式），方便调试和固件烧录。</p>
<h3 id="32-编译-sdk">3.2 编译 SDK</h3>
<p>配置完成后，执行完整编译：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./build.sh
</span></span></code></pre></div><p>编译时间取决于主机性能，通常需要 1-3 小时。如果只需要编译某个组件，可以使用以下命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 只编译 U-Boot</span>
</span></span><span class="line"><span class="cl">./build.sh uboot
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 只编译内核</span>
</span></span><span class="line"><span class="cl">./build.sh kernel
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 只编译文件系统</span>
</span></span><span class="line"><span class="cl">./build.sh rootfs
</span></span></code></pre></div><p>编译完成后，固件会生成在 <code>output/firmware/update.img</code>。</p>
<h3 id="33-固件烧录">3.3 固件烧录</h3>
<p><strong>方法一：SD 卡烧录（推荐）</strong></p>
<ol>
<li>下载 Rockchip SD 卡烧录工具：https://dl.radxa.com/tools/windows/SOC_Factory_Tool_v1.6.zip</li>
<li>插入一张 8GB 以上的 MicroSD 卡</li>
<li>打开工具，选择 <code>update.img</code> 文件</li>
<li>点击&quot;开始&quot;按钮，等待烧录完成</li>
<li>将 SD 卡插入开发板，上电启动</li>
</ol>
<p><strong>方法二：Type-C 线烧录</strong></p>
<ol>
<li>开发板上电前按住 Recovery 键</li>
<li>通过 Type-C 线连接开发板和 PC</li>
<li>使用 AndroidTool 或 RKDevTool 烧录固件</li>
<li>工具下载地址：https://github.com/rockchip-linux/rkbin/tree/master/tools</li>
</ol>
<h3 id="34-首次启动配置">3.4 首次启动配置</h3>
<p>系统启动后，默认用户名是 <code>root</code>，密码是 <code>armsom</code>。</p>
<p>首先配置网络：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看网络接口</span>
</span></span><span class="line"><span class="cl">ip addr
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 配置静态 IP（可选）</span>
</span></span><span class="line"><span class="cl">vi /etc/network/interfaces
</span></span></code></pre></div><p>配置 SSH 服务（默认已开启）：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 确认 SSH 服务状态</span>
</span></span><span class="line"><span class="cl">systemctl status sshd
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 从主机远程登录</span>
</span></span><span class="line"><span class="cl">ssh root@&lt;开发板IP地址&gt;
</span></span></code></pre></div><h2 id="四opencv-交叉编译与部署">四、OpenCV 交叉编译与部署</h2>
<p>OpenCV 是嵌入式图像识别开发的核心库，我们需要为 RK3506 交叉编译一个优化版本。</p>
<h3 id="41-安装-cmake-和相关工具">4.1 安装 CMake 和相关工具</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt install -y cmake cmake-gui cmake-curses-gui pkg-config
</span></span></code></pre></div><h3 id="42-下载-opencv-源码">4.2 下载 OpenCV 源码</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> ~
</span></span><span class="line"><span class="cl">wget -O opencv-4.8.0.zip https://github.com/opencv/opencv/archive/4.8.0.zip
</span></span><span class="line"><span class="cl">wget -O opencv_contrib-4.8.0.zip https://github.com/opencv/opencv_contrib/archive/4.8.0.zip
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">unzip opencv-4.8.0.zip
</span></span><span class="line"><span class="cl">unzip opencv_contrib-4.8.0.zip
</span></span></code></pre></div><h3 id="43-配置交叉编译参数">4.3 配置交叉编译参数</h3>
<p>创建构建目录：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> opencv-4.8.0
</span></span><span class="line"><span class="cl">mkdir build-arm
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> build-arm
</span></span></code></pre></div><p>创建交叉编译配置文件 <code>arm_toolchain.cmake</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl"><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_SYSTEM_NAME</span> <span class="s">Linux</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_SYSTEM_PROCESSOR</span> <span class="s">arm</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="c"># 修改为 SDK 中实际的工具链路径
</span></span></span><span class="line"><span class="cl"><span class="c"></span><span class="nb">set</span><span class="p">(</span><span class="s">TOOLCHAIN_ROOT</span> <span class="s2">&#34;/path/to/rk3506-rkr4.2-sdk/prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_C_COMPILER</span> <span class="o">${</span><span class="nv">TOOLCHAIN_ROOT</span><span class="o">}</span><span class="s">/bin/arm-none-linux-gnueabihf-gcc</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_CXX_COMPILER</span> <span class="o">${</span><span class="nv">TOOLCHAIN_ROOT</span><span class="o">}</span><span class="s">/bin/arm-none-linux-gnueabihf-g++</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_FIND_ROOT_PATH_MODE_PROGRAM</span> <span class="s">NEVER</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_FIND_ROOT_PATH_MODE_LIBRARY</span> <span class="s">ONLY</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_FIND_ROOT_PATH_MODE_INCLUDE</span> <span class="s">ONLY</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="nb">set</span><span class="p">(</span><span class="s">CMAKE_FIND_ROOT_PATH_MODE_PACKAGE</span> <span class="s">ONLY</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>执行 CMake 配置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cmake -DCMAKE_TOOLCHAIN_FILE<span class="o">=</span>arm_toolchain.cmake <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DOPENCV_EXTRA_MODULES_PATH<span class="o">=</span>../../opencv_contrib-4.8.0/modules <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DCMAKE_BUILD_TYPE<span class="o">=</span>Release <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DCMAKE_INSTALL_PREFIX<span class="o">=</span>/opt/opencv-arm <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DBUILD_SHARED_LIBS<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DBUILD_TESTS<span class="o">=</span>OFF <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DBUILD_PERF_TESTS<span class="o">=</span>OFF <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DBUILD_EXAMPLES<span class="o">=</span>OFF <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DBUILD_opencv_python3<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DWITH_V4L<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DWITH_LIBV4L<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DENABLE_NEON<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DENABLE_VFPV3<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DWITH_TBB<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      ..
</span></span></code></pre></div><p>关键优化选项说明：</p>
<ul>
<li><code>ENABLE_NEON=ON</code>：启用 ARM NEON 指令集优化</li>
<li><code>ENABLE_VFPV3=ON</code>：启用 VFPv3 浮点运算优化</li>
<li><code>WITH_TBB=ON</code>：启用 Intel TBB 多线程加速</li>
<li><code>WITH_V4L=ON</code>：启用 V4L2 摄像头支持</li>
</ul>
<h3 id="44-编译和安装">4.4 编译和安装</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make -j<span class="k">$(</span>nproc<span class="k">)</span>
</span></span><span class="line"><span class="cl">sudo make install
</span></span></code></pre></div><h3 id="45-部署到开发板">4.5 部署到开发板</h3>
<p>将编译好的 OpenCV 库文件复制到开发板：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 打包库文件</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /opt
</span></span><span class="line"><span class="cl">tar -czf opencv-arm.tar.gz opencv-arm
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 上传到开发板</span>
</span></span><span class="line"><span class="cl">scp opencv-arm.tar.gz root@&lt;开发板IP&gt;:/opt/
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 在开发板上解压</span>
</span></span><span class="line"><span class="cl">ssh root@&lt;开发板IP&gt;
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /opt
</span></span><span class="line"><span class="cl">tar -xzf opencv-arm.tar.gz
</span></span></code></pre></div><p>配置环境变量：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;export LD_LIBRARY_PATH=/opt/opencv-arm/lib:$LD_LIBRARY_PATH&#39;</span> &gt;&gt; ~/.bashrc
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;export PKG_CONFIG_PATH=/opt/opencv-arm/lib/pkgconfig:$PKG_CONFIG_PATH&#39;</span> &gt;&gt; ~/.bashrc
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.bashrc
</span></span></code></pre></div><h2 id="五图像采集系统搭建">五、图像采集系统搭建</h2>
<h3 id="51-摄像头选型">5.1 摄像头选型</h3>
<p>推荐使用以下 USB 摄像头，兼容性好且性价比高：</p>
<ul>
<li>Logitech C270/C310：720p 分辨率，UVC 标准协议</li>
<li>罗技 C920：1080p 分辨率，适合高精度场景</li>
<li>工业级 USB 摄像头：支持手动曝光、增益调节</li>
</ul>
<p><strong>验证摄像头识别：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看视频设备</span>
</span></span><span class="line"><span class="cl">ls /dev/video*
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看摄像头能力</span>
</span></span><span class="line"><span class="cl">v4l2-ctl --device<span class="o">=</span>/dev/video0 --list-formats-ext
</span></span></code></pre></div><h3 id="52-v4l2-摄像头参数配置">5.2 V4L2 摄像头参数配置</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 设置分辨率</span>
</span></span><span class="line"><span class="cl">v4l2-ctl --device<span class="o">=</span>/dev/video0 --set-fmt-video<span class="o">=</span><span class="nv">width</span><span class="o">=</span>640,height<span class="o">=</span>480,pixelformat<span class="o">=</span>MJPG
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置帧率</span>
</span></span><span class="line"><span class="cl">v4l2-ctl --device<span class="o">=</span>/dev/video0 --set-parm<span class="o">=</span><span class="m">30</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看所有可配置参数</span>
</span></span><span class="line"><span class="cl">v4l2-ctl --device<span class="o">=</span>/dev/video0 --list-ctrls
</span></span></code></pre></div><h3 id="53-简单的图像采集测试">5.3 简单的图像采集测试</h3>
<p>在开发板上创建 <code>capture_test.cpp</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;opencv2/opencv.hpp&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cv</span><span class="o">::</span><span class="n">VideoCapture</span> <span class="n">cap</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">cap</span><span class="p">.</span><span class="n">isOpened</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;无法打开摄像头&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">cap</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">cv</span><span class="o">::</span><span class="n">CAP_PROP_FRAME_WIDTH</span><span class="p">,</span> <span class="mi">640</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">cap</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">cv</span><span class="o">::</span><span class="n">CAP_PROP_FRAME_HEIGHT</span><span class="p">,</span> <span class="mi">480</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">cap</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">cv</span><span class="o">::</span><span class="n">CAP_PROP_FPS</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">cv</span><span class="o">::</span><span class="n">Mat</span> <span class="n">frame</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">frame_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">total_time</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">frame_count</span> <span class="o">&lt;</span> <span class="mi">100</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">double</span> <span class="n">start</span> <span class="o">=</span> <span class="n">cv</span><span class="o">::</span><span class="n">getTickCount</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">cap</span> <span class="o">&gt;&gt;</span> <span class="n">frame</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="kt">double</span> <span class="n">end</span> <span class="o">=</span> <span class="n">cv</span><span class="o">::</span><span class="n">getTickCount</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="kt">double</span> <span class="n">fps</span> <span class="o">=</span> <span class="n">cv</span><span class="o">::</span><span class="n">getTickFrequency</span><span class="p">()</span> <span class="o">/</span> <span class="p">(</span><span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">cv</span><span class="o">::</span><span class="n">putText</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="s">&#34;FPS: &#34;</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">to_string</span><span class="p">(</span><span class="n">fps</span><span class="p">),</span> 
</span></span><span class="line"><span class="cl">                    <span class="n">cv</span><span class="o">::</span><span class="n">Point</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">30</span><span class="p">),</span> <span class="n">cv</span><span class="o">::</span><span class="n">FONT_HERSHEY_SIMPLEX</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                    <span class="mi">1</span><span class="p">,</span> <span class="n">cv</span><span class="o">::</span><span class="n">Scalar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 保存前10帧用于测试
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="n">frame_count</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">cv</span><span class="o">::</span><span class="n">imwrite</span><span class="p">(</span><span class="s">&#34;frame_&#34;</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">to_string</span><span class="p">(</span><span class="n">frame_count</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#34;.jpg&#34;</span><span class="p">,</span> <span class="n">frame</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">total_time</span> <span class="o">+=</span> <span class="p">(</span><span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span> <span class="o">/</span> <span class="n">cv</span><span class="o">::</span><span class="n">getTickFrequency</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">frame_count</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;平均帧率: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">frame_count</span> <span class="o">/</span> <span class="n">total_time</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; FPS&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">cap</span><span class="p">.</span><span class="n">release</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>编译并运行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">g++ capture_test.cpp -o capture_test <span class="k">$(</span>pkg-config --cflags --libs opencv4<span class="k">)</span>
</span></span><span class="line"><span class="cl">./capture_test
</span></span></code></pre></div><p>在 RK3506 上，640x480 分辨率的图像采集通常可以达到 25-30 FPS，这对于大多数实时应用来说已经足够。</p>
<p>（第二部分完，约 2200 字）</p>
<h2 id="六轻量级-ai-模型部署">六、轻量级 AI 模型部署</h2>
<p>虽然 RK3506 没有 NPU，但通过合理选择模型和优化，仍然可以运行多种轻量级 AI 模型。</p>
<h3 id="61-模型选择策略">6.1 模型选择策略</h3>
<p>推荐使用以下轻量级模型，它们在准确率和速度之间有很好的平衡：</p>
<table>
<thead>
<tr>
<th>模型</th>
<th>输入尺寸</th>
<th>准确率（ImageNet）</th>
<th>RK3506 预估速度</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td>MobileNetV2</td>
<td>224x224</td>
<td>72.0%</td>
<td>8-10 FPS</td>
<td>通用图像分类</td>
</tr>
<tr>
<td>MobileNetV3-Small</td>
<td>224x224</td>
<td>67.7%</td>
<td>12-15 FPS</td>
<td>低功耗场景</td>
</tr>
<tr>
<td>SqueezeNet</td>
<td>227x227</td>
<td>57.5%</td>
<td>15-20 FPS</td>
<td>超轻量分类</td>
</tr>
<tr>
<td>YOLOv5n</td>
<td>320x320</td>
<td>45.7% mAP</td>
<td>3-5 FPS</td>
<td>目标检测</td>
</tr>
<tr>
<td>NanoDet</td>
<td>320x320</td>
<td>20.6% mAP</td>
<td>5-8 FPS</td>
<td>轻量目标检测</td>
</tr>
</tbody>
</table>
<p><strong>核心选型原则：</strong></p>
<ol>
<li>优先选择深度可分离卷积架构（MobileNet 系列）</li>
<li>通道数控制在 256 以内</li>
<li>输入分辨率不超过 320x320</li>
<li>对于目标检测，优先使用一阶段检测模型</li>
</ol>
<h3 id="62-ncnn-推理框架部署">6.2 NCNN 推理框架部署</h3>
<p>NCNN 是腾讯开源的高性能神经网络推理框架，专门针对 ARM 平台优化，非常适合 RK3506。</p>
<p><strong>下载和交叉编译：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/Tencent/ncnn.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ncnn
</span></span><span class="line"><span class="cl">mkdir build-arm
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> build-arm
</span></span></code></pre></div><p>创建交叉编译配置（使用与 OpenCV 相同的工具链）：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cmake -DCMAKE_TOOLCHAIN_FILE<span class="o">=</span>../toolchains/arm-linux-gnueabihf.toolchain.cmake <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DCMAKE_BUILD_TYPE<span class="o">=</span>Release <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DCMAKE_INSTALL_PREFIX<span class="o">=</span>/opt/ncnn-arm <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DNCNN_VULKAN<span class="o">=</span>OFF <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DNCNN_BUILD_EXAMPLES<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      -DNCNN_BUILD_TOOLS<span class="o">=</span>ON <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>      ..
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">make -j<span class="k">$(</span>nproc<span class="k">)</span>
</span></span><span class="line"><span class="cl">sudo make install
</span></span></code></pre></div><p><strong>模型转换：</strong></p>
<p>将 PyTorch/TensorFlow 模型转换为 NCNN 格式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 先转换为 ONNX 格式（以 PyTorch 为例）</span>
</span></span><span class="line"><span class="cl">python -c <span class="s2">&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">import torch
</span></span></span><span class="line"><span class="cl"><span class="s2">import torchvision
</span></span></span><span class="line"><span class="cl"><span class="s2">model = torchvision.models.mobilenet_v2(pretrained=True)
</span></span></span><span class="line"><span class="cl"><span class="s2">dummy_input = torch.randn(1, 3, 224, 224)
</span></span></span><span class="line"><span class="cl"><span class="s2">torch.onnx.export(model, dummy_input, &#39;mobilenetv2.onnx&#39;)
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用 onnx2ncnn 转换</span>
</span></span><span class="line"><span class="cl">/opt/ncnn-arm/bin/onnx2ncnn mobilenetv2.onnx mobilenetv2.param mobilenetv2.bin
</span></span></code></pre></div><h3 id="63-图像识别完整实现">6.3 图像识别完整实现</h3>
<p>下面是一个完整的图像识别程序，结合了摄像头采集、图像预处理和 NCNN 推理：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;opencv2/opencv.hpp&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;net.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// ImageNet 1000 类标签（省略完整列表，实际使用时需要加载）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">class_names</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;tench&#34;</span><span class="p">,</span> <span class="s">&#34;goldfish&#34;</span><span class="p">,</span> <span class="s">&#34;great white shark&#34;</span><span class="p">,</span> <span class="cm">/* ... 更多标签 ... */</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 图像预处理
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span> <span class="n">preprocess</span><span class="p">(</span><span class="k">const</span> <span class="n">cv</span><span class="o">::</span><span class="n">Mat</span><span class="o">&amp;</span> <span class="n">bgr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 缩放到 224x224
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">cv</span><span class="o">::</span><span class="n">Mat</span> <span class="n">resized</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">cv</span><span class="o">::</span><span class="n">resize</span><span class="p">(</span><span class="n">bgr</span><span class="p">,</span> <span class="n">resized</span><span class="p">,</span> <span class="n">cv</span><span class="o">::</span><span class="n">Size</span><span class="p">(</span><span class="mi">224</span><span class="p">,</span> <span class="mi">224</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 转换为 RGB 并归一化
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span> <span class="n">in</span> <span class="o">=</span> <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span><span class="o">::</span><span class="n">from_pixels</span><span class="p">(</span><span class="n">resized</span><span class="p">.</span><span class="n">data</span><span class="p">,</span> <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span><span class="o">::</span><span class="n">PIXEL_BGR2RGB</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="mi">224</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// MobileNetV2 的归一化参数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">const</span> <span class="kt">float</span> <span class="n">mean_vals</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mf">0.485f</span> <span class="o">*</span> <span class="mf">255.f</span><span class="p">,</span> <span class="mf">0.456f</span> <span class="o">*</span> <span class="mf">255.f</span><span class="p">,</span> <span class="mf">0.406f</span> <span class="o">*</span> <span class="mf">255.f</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="kt">float</span> <span class="n">norm_vals</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="o">/</span><span class="mf">0.229f</span><span class="o">/</span><span class="mf">255.f</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mf">0.224f</span><span class="o">/</span><span class="mf">255.f</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mf">0.225f</span><span class="o">/</span><span class="mf">255.f</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="n">in</span><span class="p">.</span><span class="n">substract_mean_normalize</span><span class="p">(</span><span class="n">mean_vals</span><span class="p">,</span> <span class="n">norm_vals</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">in</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 后处理：获取 Top-K 结果
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">float</span><span class="o">&gt;&gt;</span> <span class="n">get_top_k</span><span class="p">(</span><span class="k">const</span> <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span><span class="o">&amp;</span> <span class="n">out</span><span class="p">,</span> <span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">5</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">float</span><span class="o">&gt;&gt;</span> <span class="n">results</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">out</span><span class="p">.</span><span class="n">w</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">results</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">out</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">partial_sort</span><span class="p">(</span><span class="n">results</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">results</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="n">k</span><span class="p">,</span> <span class="n">results</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                      <span class="p">[](</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">second</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">results</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">k</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">results</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 初始化 NCNN 网络
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">ncnn</span><span class="o">::</span><span class="n">Net</span> <span class="n">net</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">net</span><span class="p">.</span><span class="n">load_param</span><span class="p">(</span><span class="s">&#34;mobilenetv2.param&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">net</span><span class="p">.</span><span class="n">load_model</span><span class="p">(</span><span class="s">&#34;mobilenetv2.bin&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 打开摄像头
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">cv</span><span class="o">::</span><span class="n">VideoCapture</span> <span class="n">cap</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">cap</span><span class="p">.</span><span class="n">isOpened</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;无法打开摄像头&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">cap</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">cv</span><span class="o">::</span><span class="n">CAP_PROP_FRAME_WIDTH</span><span class="p">,</span> <span class="mi">640</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">cap</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">cv</span><span class="o">::</span><span class="n">CAP_PROP_FRAME_HEIGHT</span><span class="p">,</span> <span class="mi">480</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">cv</span><span class="o">::</span><span class="n">Mat</span> <span class="n">frame</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">frame_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">total_infer_time</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cap</span> <span class="o">&gt;&gt;</span> <span class="n">frame</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 预处理
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kt">double</span> <span class="n">t0</span> <span class="o">=</span> <span class="n">cv</span><span class="o">::</span><span class="n">getTickCount</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span> <span class="n">in</span> <span class="o">=</span> <span class="n">preprocess</span><span class="p">(</span><span class="n">frame</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 推理
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">ncnn</span><span class="o">::</span><span class="n">Extractor</span> <span class="n">ex</span> <span class="o">=</span> <span class="n">net</span><span class="p">.</span><span class="n">create_extractor</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">ex</span><span class="p">.</span><span class="n">set_num_threads</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>  <span class="c1">// 使用全部 3 个 CPU 核心
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">ex</span><span class="p">.</span><span class="n">input</span><span class="p">(</span><span class="s">&#34;input&#34;</span><span class="p">,</span> <span class="n">in</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span> <span class="n">out</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">ex</span><span class="p">.</span><span class="n">extract</span><span class="p">(</span><span class="s">&#34;output&#34;</span><span class="p">,</span> <span class="n">out</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">double</span> <span class="n">t1</span> <span class="o">=</span> <span class="n">cv</span><span class="o">::</span><span class="n">getTickCount</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="kt">double</span> <span class="n">infer_time</span> <span class="o">=</span> <span class="p">(</span><span class="n">t1</span> <span class="o">-</span> <span class="n">t0</span><span class="p">)</span> <span class="o">/</span> <span class="n">cv</span><span class="o">::</span><span class="n">getTickFrequency</span><span class="p">()</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">total_infer_time</span> <span class="o">+=</span> <span class="n">infer_time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">frame_count</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 获取 Top-5 结果
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">auto</span> <span class="n">top5</span> <span class="o">=</span> <span class="n">get_top_k</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 在图像上绘制结果
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">30</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">top5</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">text</span> <span class="o">=</span> <span class="n">class_names</span><span class="p">[</span><span class="n">top5</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">first</span><span class="p">]</span> <span class="o">+</span> <span class="s">&#34;: &#34;</span> <span class="o">+</span> 
</span></span><span class="line"><span class="cl">                              <span class="n">std</span><span class="o">::</span><span class="n">to_string</span><span class="p">(</span><span class="n">top5</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">second</span> <span class="o">*</span> <span class="mi">100</span><span class="p">).</span><span class="n">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#34;%&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">cv</span><span class="o">::</span><span class="n">putText</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">cv</span><span class="o">::</span><span class="n">Point</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> 
</span></span><span class="line"><span class="cl">                        <span class="n">cv</span><span class="o">::</span><span class="n">FONT_HERSHEY_SIMPLEX</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">,</span> <span class="n">cv</span><span class="o">::</span><span class="n">Scalar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">y</span> <span class="o">+=</span> <span class="mi">25</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 绘制推理时间
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">cv</span><span class="o">::</span><span class="n">putText</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="s">&#34;Infer: &#34;</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">to_string</span><span class="p">(</span><span class="n">infer_time</span><span class="p">).</span><span class="n">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#34;ms&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">cv</span><span class="o">::</span><span class="n">Point</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">frame</span><span class="p">.</span><span class="n">rows</span> <span class="o">-</span> <span class="mi">20</span><span class="p">),</span> <span class="n">cv</span><span class="o">::</span><span class="n">FONT_HERSHEY_SIMPLEX</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                    <span class="mf">0.6</span><span class="p">,</span> <span class="n">cv</span><span class="o">::</span><span class="n">Scalar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">),</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 显示（如果有显示设备）或保存结果
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// cv::imshow(&#34;Result&#34;, frame);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">cv</span><span class="o">::</span><span class="n">imwrite</span><span class="p">(</span><span class="s">&#34;result_&#34;</span> <span class="o">+</span> <span class="n">std</span><span class="o">::</span><span class="n">to_string</span><span class="p">(</span><span class="n">frame_count</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#34;.jpg&#34;</span><span class="p">,</span> <span class="n">frame</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">cv</span><span class="o">::</span><span class="n">waitKey</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">27</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>  <span class="c1">// ESC 退出
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="n">frame_count</span> <span class="o">&gt;=</span> <span class="mi">100</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>    <span class="c1">// 测试 100 帧
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;平均推理时间: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">total_infer_time</span> <span class="o">/</span> <span class="n">frame_count</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; ms&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;平均帧率: &#34;</span> <span class="o">&lt;&lt;</span> <span class="mf">1000.0</span> <span class="o">/</span> <span class="p">(</span><span class="n">total_infer_time</span> <span class="o">/</span> <span class="n">frame_count</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; FPS&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">cap</span><span class="p">.</span><span class="n">release</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>编译命令：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">g++ image_recognition.cpp -o image_recognition <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -I/opt/ncnn-arm/include/ncnn <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -I/opt/opencv-arm/include/opencv4 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -L/opt/ncnn-arm/lib <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -L/opt/opencv-arm/lib <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -lncnn -lopencv_core -lopencv_imgproc -lopencv_imgcodecs -lopencv_videoio <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -lpthread -fopenmp
</span></span></code></pre></div><h2 id="七调试方法与性能优化">七、调试方法与性能优化</h2>
<h3 id="71-性能分析工具">7.1 性能分析工具</h3>
<p><strong>使用 perf 进行性能分析：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 安装 perf</span>
</span></span><span class="line"><span class="cl">apt install linux-perf
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 运行程序并采样</span>
</span></span><span class="line"><span class="cl">perf record -g ./image_recognition
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 生成报告</span>
</span></span><span class="line"><span class="cl">perf report
</span></span></code></pre></div><p><strong>使用 OpenCV 内置计时：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">cv</span><span class="o">::</span><span class="n">TickMeter</span> <span class="n">tm</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">tm</span><span class="p">.</span><span class="n">start</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 执行代码
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">tm</span><span class="p">.</span><span class="n">stop</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;耗时: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">tm</span><span class="p">.</span><span class="n">getTimeMilli</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; ms&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="72-核心优化技巧">7.2 核心优化技巧</h3>
<p><strong>技巧一：多线程并行</strong></p>
<p>RK3506 有三个 CPU 核心，合理利用多线程可以显著提升性能：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// NCNN 设置线程数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">ex</span><span class="p">.</span><span class="n">set_num_threads</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// OpenCV 启用多线程
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">cv</span><span class="o">::</span><span class="n">setNumThreads</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 并行处理图像的不同区域
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">cv</span><span class="o">::</span><span class="n">parallel_for_</span><span class="p">(</span><span class="n">cv</span><span class="o">::</span><span class="n">Range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="k">const</span> <span class="n">cv</span><span class="o">::</span><span class="n">Range</span><span class="o">&amp;</span> <span class="n">range</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">range</span><span class="p">.</span><span class="n">start</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">range</span><span class="p">.</span><span class="n">end</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 处理第 i 个通道
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p><strong>技巧二：NEON 指令集优化</strong></p>
<p>对于计算密集型操作，使用 NEON 内联汇编可以获得 2-4 倍的性能提升：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;arm_neon.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// NEON 优化的图像归一化
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">neon_normalize</span><span class="p">(</span><span class="kt">uint8_t</span><span class="o">*</span> <span class="n">src</span><span class="p">,</span> <span class="kt">float</span><span class="o">*</span> <span class="n">dst</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> <span class="kt">float</span> <span class="n">mean</span><span class="p">,</span> <span class="kt">float</span> <span class="n">scale</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">float32x4_t</span> <span class="n">mean_v</span> <span class="o">=</span> <span class="n">vdupq_n_f32</span><span class="p">(</span><span class="n">mean</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">float32x4_t</span> <span class="n">scale_v</span> <span class="o">=</span> <span class="n">vdupq_n_f32</span><span class="p">(</span><span class="n">scale</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">len</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">uint8x8_t</span> <span class="n">u8_v</span> <span class="o">=</span> <span class="n">vld1_u8</span><span class="p">(</span><span class="n">src</span> <span class="o">+</span> <span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">int16x8_t</span> <span class="n">i16_v</span> <span class="o">=</span> <span class="n">vreinterpretq_s16_u16</span><span class="p">(</span><span class="n">vmovl_u8</span><span class="p">(</span><span class="n">u8_v</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="n">float32x4_t</span> <span class="n">f32_v</span> <span class="o">=</span> <span class="n">vcvtq_f32_s32</span><span class="p">(</span><span class="n">vmovl_s16</span><span class="p">(</span><span class="n">vget_low_s16</span><span class="p">(</span><span class="n">i16_v</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">f32_v</span> <span class="o">=</span> <span class="n">vsubq_f32</span><span class="p">(</span><span class="n">f32_v</span><span class="p">,</span> <span class="n">mean_v</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">f32_v</span> <span class="o">=</span> <span class="n">vmulq_f32</span><span class="p">(</span><span class="n">f32_v</span><span class="p">,</span> <span class="n">scale_v</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">vst1q_f32</span><span class="p">(</span><span class="n">dst</span> <span class="o">+</span> <span class="n">i</span><span class="p">,</span> <span class="n">f32_v</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>技巧三：内存复用与零拷贝</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// 避免频繁分配内存，使用预分配的 Mat
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">cv</span><span class="o">::</span><span class="n">Mat</span> <span class="n">preprocess_buffer</span><span class="p">(</span><span class="mi">224</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="n">CV_8UC3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 使用 NCNN 的外部数据接口，避免数据拷贝
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span> <span class="n">in</span> <span class="o">=</span> <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span><span class="o">::</span><span class="n">from_pixels_external</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">preprocess_buffer</span><span class="p">.</span><span class="n">data</span><span class="p">,</span> <span class="n">ncnn</span><span class="o">::</span><span class="n">Mat</span><span class="o">::</span><span class="n">PIXEL_BGR2RGB</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="mi">224</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></div><h3 id="73-常见问题与解决">7.3 常见问题与解决</h3>
<p><strong>问题一：推理速度远低于预期</strong></p>
<p>可能原因和解决方案：</p>
<ol>
<li><strong>Debug 模式编译</strong>：确保使用 <code>-DCMAKE_BUILD_TYPE=Release</code></li>
<li><strong>线程数设置不当</strong>：三核 CPU 不要设置超过 3 个线程</li>
<li><strong>未启用 NEON 优化</strong>：检查编译选项是否包含 <code>-mfpu=neon -mfloat-abi=hard</code></li>
<li><strong>I/O 瓶颈</strong>：使用 MJPG 格式而不是 YUYV 采集图像</li>
</ol>
<p><strong>问题二：内存不足导致崩溃</strong></p>
<p>解决方案：</p>
<ol>
<li>减小模型输入分辨率（如从 224x224 降到 160x160）</li>
<li>使用模型量化（INT8 量化可减少 75% 内存占用）</li>
<li>分批处理，不要一次性加载所有数据</li>
</ol>
<p><strong>问题三：识别准确率偏低</strong></p>
<p>可能原因：</p>
<ol>
<li>预处理参数与训练时不一致（均值、标准差）</li>
<li>图像缩放算法选择不当（建议使用双线性插值）</li>
<li>颜色空间转换错误（BGR vs RGB）</li>
</ol>
<h2 id="八最佳实践总结">八、最佳实践总结</h2>
<h3 id="81-开发流程最佳实践">8.1 开发流程最佳实践</h3>
<ol>
<li><strong>先在 PC 上验证算法</strong>：在移植到开发板之前，先在 x86 PC 上验证算法的正确性和性能</li>
<li><strong>小步迭代</strong>：从最简单的功能开始，逐步增加复杂度</li>
<li><strong>保留调试信息</strong>：在关键位置添加日志输出，便于问题定位</li>
<li><strong>版本控制</strong>：使用 Git 管理代码，每个稳定版本打标签</li>
</ol>
<h3 id="82-性能优化-checklist">8.2 性能优化 Checklist</h3>
<ul>
<li><input disabled="" type="checkbox"> 启用 Release 模式编译</li>
<li><input disabled="" type="checkbox"> 启用 NEON 和 VFPv3 优化</li>
<li><input disabled="" type="checkbox"> 设置正确的线程数（3 线程）</li>
<li><input disabled="" type="checkbox"> 优化图像预处理流水线</li>
<li><input disabled="" type="checkbox"> 使用内存池避免频繁分配</li>
<li><input disabled="" type="checkbox"> 量化模型到 INT8（如果可能）</li>
<li><input disabled="" type="checkbox"> 减少不必要的内存拷贝</li>
</ul>
<h3 id="83-生产部署建议">8.3 生产部署建议</h3>
<ol>
<li><strong>看门狗机制</strong>：实现软件看门狗，程序崩溃时自动重启</li>
<li><strong>异常处理</strong>：完善的异常捕获和错误处理逻辑</li>
<li><strong>资源监控</strong>：定期监控 CPU、内存、温度等指标</li>
<li><strong>远程更新</strong>：支持 OTA 固件更新，便于后续维护</li>
</ol>
<h2 id="总结">总结</h2>
<p>本文详细介绍了基于 RK3506 进行高效图像识别开发的完整流程。从芯片选型、环境搭建、SDK 编译，到 OpenCV 交叉编译、图像采集、模型部署，最后是性能优化和最佳实践，每一步都提供了可直接运行的代码和具体的操作指导。</p>
<p>虽然 RK3506 没有内置 NPU，但通过合理选择轻量级模型、充分利用三个 CPU 核心和 NEON 指令集优化，仍然可以实现 8-15 FPS 的实时图像识别。对于很多成本敏感的工业场景来说，这是一个非常有竞争力的方案。</p>
<p>随着 AI 模型的不断轻量化和推理框架的持续优化，我们相信在类似 RK3506 这样的通用 CPU 平台上运行边缘 AI 应用会变得越来越普遍。希望本文能为你的嵌入式视觉开发提供一些帮助和启发。</p>
<p>（全文完，约 7000 字）</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
