1. 项目概述与核心思路最近在捣鼓一个挺有意思的小项目想试试看能不能让一个资源受限的嵌入式设备比如一块MCU开发板也能玩转图片识别。这听起来有点“小马拉大车”的意思毕竟主流的AI推理框架动不动就几个G对内存和算力的要求都不是MCU能轻易承受的。直接让MCU跑一个复杂的图像识别模型比如YOLO或者ResNet基本不现实。所以我的思路是“分工协作”让专业的设备干专业的事。我的方案是在本地局域网内构建一个微型的“边缘AI”系统。核心由两部分组成一端是运行RT-Thread操作系统的嵌入式设备作为数据采集和传输端另一端是一台性能稍强的机器比如一台PC或者树莓派运行Ubuntu系统并部署Python的AI推理服务作为计算中心。嵌入式设备通过摄像头模块捕获图像然后通过Wi-Fi或以太网将图片数据以HTTP POST请求的方式发送给局域网内的Ubuntu服务器。服务器上的Python服务我用的是Flask框架搭建的接收到图片后调用预训练好的模型比如用ImageAI库进行识别最后将识别结果比如“这是一只猫置信度92%”返回给嵌入式设备。设备再通过屏幕、串口或者LED等方式将结果显示出来。这个系列文章我就打算把这个从零搭建的过程包括环境配置、代码编写、联调测试中踩过的坑和积累的经验完整地记录下来。今天是系列的开端我们先从最基础但也最容易出问题的环节开始——搭建Ubuntu虚拟机环境并配置好ImageAI图像识别库。为什么用虚拟机因为它能提供一个干净、可复现的Linux环境方便我们隔离开发环境也便于后续教程的读者跟着操作。虽然最终部署到树莓派或常开主机上更贴近实际但虚拟机无疑是学习和原型开发的最佳起点。2. 虚拟机环境搭建与关键配置解析2.1 Ubuntu版本选择与虚拟机工具安装我选择了Ubuntu 18.04 LTS作为基础系统。选择LTS长期支持版本是嵌入式开发中的一个好习惯因为它能提供长达数年的稳定更新和支持避免在开发中途因为系统版本过期而遇到兼容性问题。虽然原文提到了16.04以上但我更推荐18.04或20.04 LTS它们在软件包可用性和社区支持上目前是更好的平衡点。我用的是VMware WorkstationVirtualBox也是完全可行的。安装完Ubuntu系统后第一件要紧事就是安装VMware ToolsVMware或VirtualBox Guest AdditionsVirtualBox。这一步至关重要但也是新手容易卡住的地方。它的核心作用有三个实现宿主机和虚拟机之间的文件拖拽/共享文件夹、改善虚拟机显示性能和分辨率自适应、启用剪贴板共享。对于开发来说文件共享是刚需你肯定不想每次都通过SCP或者U盘来传递代码和图片。安装过程中的一个关键细节是权限问题。以VMware Tools为例下载的安装包通常是一个.tar.gz压缩文件。你需要将其解压到某个目录比如/home/你的用户名/下。然后打开终端cd进入解压后的文件夹里面会有一个vmware-install.pl的Perl脚本。这里最容易犯的错误就是直接运行./vmware-install.pl。在大多数新安装的Ubuntu系统中你需要使用sudo来获取root权限执行安装sudo ./vmware-install.pl。安装过程中它会交互式地问你很多问题关于安装路径、内核模块编译等。我的经验是对于绝大多数问题直接一路按回车Enter键采用默认选项即可。除非你非常清楚某个配置的含义否则不要轻易修改。安装完成后通常需要重启虚拟机才能生效。注意如果安装后共享文件夹仍然不显示可以手动在VMware的虚拟机设置中指定一个宿主机目录作为共享文件夹然后在Ubuntu的/mnt/hgfs/路径下查看。有时需要手动创建这个目录或重新安装工具。2.2 软件源配置与系统更新系统装好工具也齐了接下来就是配置一个“高速下载通道”——替换软件源。Ubuntu默认的软件源服务器可能在国外下载速度慢如蜗牛还经常超时。将其替换为国内的镜像源比如清华源、阿里云源或中科大源能极大提升后续安装软件包的速度和成功率。操作步骤本身不复杂但每一步都需要小心备份原始源列表这是必须养成的习惯。命令是sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup。万一新源有问题我们可以轻松回滚。编辑源列表文件使用sudo gedit /etc/apt/sources.list如果你用的是GNOME桌面或者sudo vim /etc/apt/sources.list如果熟悉vim。将文件里所有的内容注释掉或删除。填入镜像源地址这里需要根据你安装的Ubuntu版本代号来填写。例如Ubuntu 18.04的代号是bionic。你不能把原文中给xenial16.04的源直接用于18.04。以清华源为例18.04的源配置应该是deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse务必确认版本代号正确否则apt-get update会报错提示找不到仓库。更新软件包列表执行sudo apt-get update。这个命令并不会升级任何已安装的软件它只是从你刚配置的源服务器下载最新的软件包列表信息刷新本地的数据库。这里有一个非常经典的“锁”问题在执行sudo apt-get update或sudo apt-get install时可能会遇到类似“E: Could not get lock /var/lib/apt/lists/lock”的错误。这通常是因为有另一个APT进程比如软件更新器或另一个终端里的apt命令正在运行占用了这个锁文件。解决方法不是直接暴力删除而是按顺序尝试首先等一会儿可能另一个操作马上就结束了。如果不行使用ps aux | grep apt查找相关的进程并用sudo kill -9 进程ID结束它们。如果还是不行再使用sudo rm /var/lib/apt/lists/lock和sudo rm /var/cache/apt/archives/lock删除锁文件。但务必确保没有其他重要的apt进程在运行否则可能导致软件包管理系统状态异常。2.3 Python3环境与Pip3管理Ubuntu 18.04默认已经安装了Python 3.6。我们需要确保pip3Python3的包管理工具是最新的并且能正常工作。直接运行pip3 --version查看。如果版本较旧比如低于19.0建议升级。升级命令通常是sudo pip3 install --upgrade pip。注意这里的目标包名是pip不是pip3。pip3是命令行工具而pip是Python包。升级后你可能会遇到一个经典问题命令行输入pip3 --version会报错提示“ModuleNotFoundError: No module named ‘pip’”。这是因为升级过程中pip的安装路径和系统pip3这个命令脚本所指向的Python模块路径可能出现了不一致。解决方案是修改/usr/bin/pip3这个脚本文件。使用sudo gedit /usr/bin/pip3打开你会看到类似原文中的内容。关键是要将脚本中导入pip模块并执行的方式修改为与新版本pip兼容的格式。一个更通用、更少出错的修改方法是直接将文件内容替换为以下更简洁的版本#!/usr/bin/python3 import sys from pip._internal.cli.main import main if __name__ __main__: sys.exit(main())保存退出后再运行pip3 --version就应该正常显示版本号了。这个问题的本质是pip在版本10之后重构了内部模块结构导致旧的启动脚本找不到入口点。记住在Linux下搞Python环境pip和pip3的路径、权限问题是个常客。3. ImageAI库安装与依赖问题深度排坑3.1 安装流程与核心依赖ImageAI是一个让图像识别变得极其简单的Python库它封装了深度学习框架如TensorFlow、Keras和模型如RetinaNet、YOLOv3让你用几行代码就能完成对象检测、图像预测等任务。根据 官方文档 安装ImageAI的核心命令是sudo pip3 install imageai --upgrade但是pip install一个库时它会自动安装这个库所声明的所有依赖项。ImageAI的依赖项相当重量级主要包括TensorFlow谷歌开源的机器学习框架是ImageAI的后端引擎之一。Keras一个高层神经网络API通常运行在TensorFlow之上。OpenCV计算机视觉库用于图像处理。Matplotlib绘图库用于显示结果。NumPy, SciPy, Pillow等科学计算和图像处理基础库。这些依赖尤其是TensorFlow体积庞大编译复杂如果从源码安装。pip会尝试下载预编译的二进制包wheel这通常是最顺利的方式。整个安装过程可能会耗时几分钟到十几分钟取决于你的网络速度。3.2 典型错误与针对性解决在实际安装中几乎不可能一帆风顺。下面是我遇到的几个有代表性的问题及其根因和解决方案问题一matplotlib安装失败或版本冲突这是原文中提到的问题。错误信息可能五花八门比如抱怨找不到freetype库或者某些C扩展编译失败。其根本原因在于matplotlib是一个功能强大的绘图库它底层依赖许多C语言编写的图形和字体库如libpng,freetype。如果你的Ubuntu系统缺少这些开发包pip在尝试从源码编译matplotlib时就会失败。解决方案不是简单地指定一个旧版本如matplotlib3.0虽然这有时能绕开问题。更根本、更一劳永逸的方法是在安装Python包之前先通过系统包管理器apt安装这些底层依赖。执行以下命令sudo apt-get update sudo apt-get install -y python3-dev python3-pip python3-setuptools sudo apt-get install -y build-essential cmake sudo apt-get install -y libjpeg-dev libtiff5-dev libjasper-dev libpng-dev sudo apt-get install -y libavcodec-dev libavformat-dev libswscale-dev libv4l-dev sudo apt-get install -y libxvidcore-dev libx264-dev sudo apt-get install -y libfontconfig1-dev libfreetype6-dev sudo apt-get install -y libgtk2.0-dev libgtk-3-dev sudo apt-get install -y libatlas-base-dev gfortran sudo apt-get install -y libhdf5-dev libhdf5-serial-dev libhdf5-103这一长串命令看起来吓人但它们分别安装了Python开发环境、编译工具、图像编解码库、视频IO库、字体库、GUI库以及数学优化库。安装完这些系统级依赖后再使用pip3 install matplotlib你会发现它很可能直接下载预编译的wheel包速度飞快且一次成功。这才是符合Linux哲学的做法让系统的包管理器管理系统的原生库让pip管理Python生态的纯Python包或封装好的二进制包。问题二TensorFlow安装版本与系统环境不兼容TensorFlow有CPU和GPU两个版本。对于虚拟机环境我们当然安装CPU版本。但是TensorFlow的不同版本对Python版本、CPU指令集如AVX有要求。如果你安装最新的TensorFlow 2.x而你的Python是3.6可能兼容性很好。但有时最新版的TensorFlow可能尚未提供与你Python环境完全匹配的预编译轮子。解决方案是明确指定一个经过广泛测试的稳定版本组合。对于Ubuntu 18.04 Python 3.6的环境一个非常稳定的组合是sudo pip3 install tensorflow1.15.0TensorFlow 1.15是1.x系列的最后一个版本非常稳定且ImageAI对其支持良好。或者如果你想使用TensorFlow 2.x可以尝试sudo pip3 install tensorflow2.3.0在安装ImageAI时你也可以指定一个稍早的、已知稳定的版本以避免自动拉取最新的、可能不稳定的依赖。例如sudo pip3 install imageai2.1.5问题三权限不足导致的安装错误在全局Python环境/usr/lib/python3/dist-packages/中使用pip3安装包时必须使用sudo。但有时即使加了sudo也可能因为临时目录权限或缓存问题导致失败。如果遇到奇怪的权限错误Permission denied可以尝试清除pip缓存sudo pip3 cache purge使用--no-cache-dir选项重新安装sudo pip3 install imageai --upgrade --no-cache-dir最彻底但不推荐长期使用的方法是使用--user标志安装到用户目录但这样可能需要配置PYTHONPATH对于系统级服务来说管理更麻烦。在这个项目背景下我们后续的Flask服务可能需要系统级的Python包所以还是建议用sudo解决权限问题。3.3 验证安装与初步测试所有库安装完毕后务必进行验证。创建一个简单的Python测试脚本比如test_imageai.pyfrom imageai.Prediction import ImagePrediction import os execution_path os.getcwd() prediction ImagePrediction() prediction.setModelTypeAsResNet50() # 指定模型类型 prediction.setModelPath(os.path.join(execution_path, resnet50_imagenet_tf.2.0.h5)) # 你需要先下载模型文件 prediction.loadModel() predictions, probabilities prediction.predictImage(os.path.join(execution_path, example.jpg), result_count5) for eachPrediction, eachProbability in zip(predictions, probabilities): print(eachPrediction , : , eachProbability)运行这个脚本前你需要根据ImageAI文档下载对应的预训练模型文件如ResNet50。首次运行会下载模型这可能耗时较长。如果最终能成功输出图片的预测类别和概率那么恭喜你ImageAI环境就算真正搭建成功了。这个过程可能会因为网络问题下载模型失败可以考虑手动下载模型文件并放到指定路径这是后续实际开发中也会遇到的常见操作。4. 虚拟网络配置与宿主机通信准备4.1 网络模式选择Bridged vs NAT我们的项目需要Ubuntu虚拟机与宿主机Windows/Mac以及后续模拟的RT-Thread设备同样在宿主机上通过QEMU运行处于同一个局域网内能够通过IP地址相互访问。因此虚拟机的网络配置是关键一步。VMware或VirtualBox通常提供几种网络模式NAT模式虚拟机共享宿主机的IP地址上网对外部网络来说只有宿主机是可见的。虚拟机可以访问外部网络和宿主机但外部网络包括宿主机所在局域网的其他机器通常不能直接访问虚拟机。这是默认模式上网方便但不利于局域网内设备互联。桥接模式虚拟机会虚拟出一张独立的网卡直接连接到宿主机所在的物理网络上。它会从你的家庭或公司路由器那里获取一个和宿主机同网段的IP地址如192.168.1.x。此时虚拟机在网络层面上就像一台真实存在的电脑宿主机、局域网内其他设备都可以直接通过这个IP访问它。为了实现RT-Thread设备与Ubuntu服务的通信我们必须将虚拟机的网络适配器设置为“桥接模式”。在VMware中可以在虚拟机设置 - 网络适配器 - 网络连接中选择“桥接模式”并勾选“复制物理网络连接状态”。在VirtualBox中选择“桥接网卡”并选中你宿主机正在使用的物理网卡名称。设置完成后启动Ubuntu虚拟机打开终端使用ifconfig或ip addr show命令查看网络接口通常是ens33或eth0。你应该能看到一个与宿主机IP在同一网段的地址例如宿主机是192.168.1.100虚拟机可能是192.168.1.101。在宿主机上打开命令行ping一下这个虚拟机的IP地址如果能通说明网络桥接成功。4.2 防火墙配置与端口开放即使网络通了如果Ubuntu的防火墙阻止了外部连接我们的Flask服务依然无法被访问。Ubuntu 18.04默认使用的是ufw防火墙且初始状态可能是关闭的。我们需要确保相应端口比如我们后续Flask服务使用的5000端口是开放的。首先检查防火墙状态sudo ufw status。如果状态是inactive表示防火墙未启用那么所有端口默认都是开放的这在进行内部开发测试时问题不大但要注意安全。如果状态是active你需要为Flask服务开放端口sudo ufw allow 5000/tcp这条命令允许TCP协议访问5000端口。如果你计划使用其他端口替换5000即可。操作完成后可以再次使用sudo ufw status查看规则是否已添加。一个更彻底的测试方法是在Ubuntu上临时启动一个简单的HTTP服务器然后在宿主机上用浏览器访问。在Ubuntu终端输入python3 -m http.server 8080这会在8080端口启动一个简单的文件服务器。然后在宿主机的浏览器中输入http://虚拟机IP:8080如果能看到Ubuntu当前目录的文件列表就证明网络和防火墙配置完全正确宿主机可以访问虚拟机上的服务了。这个测试方法简单有效在后续开发任何网络服务时都可以先用它来验证基础连通性。5. 开发环境辅助工具配置5.1 代码编辑器的选择与远程开发在虚拟机里直接写代码体验可能不如宿主机上的IDE流畅。这里我推荐两种高效的工作流使用VS Code的远程开发插件在宿主机的VS Code中安装“Remote - SSH”或“Remote - WSL”插件。将虚拟机配置为一个远程主机你就可以在熟悉的VS Code界面里直接编辑虚拟机上的文件使用虚拟机内的Python环境进行调试。这是目前最优雅的方式之一它结合了宿主机IDE的强大和虚拟机环境的纯净。使用共享文件夹配合宿主机IDE利用之前安装的VMware Tools建立的共享文件夹。将项目代码放在共享文件夹内这样在宿主机上用你喜欢的IDE如PyCharm, VS Code, Sublime Text编写代码保存后文件自动同步到虚拟机中。然后在虚拟机终端里运行和调试。这种方式简单直接适合文件量不大的项目。我个人更倾向于第一种因为调试、终端集成、环境管理都更加无缝。但对于初学者第二种方式更容易上手。5.2 版本控制Git的安装与配置无论采用哪种工作流为项目初始化Git仓库都是个好习惯。在Ubuntu中安装Git很简单sudo apt-get install git。安装后配置你的用户名和邮箱git config --global user.name Your Name git config --global user.email your.emailexample.com在项目根目录执行git init然后创建.gitignore文件忽略掉虚拟环境目录如venv/、模型文件、缓存文件如__pycache__/等不需要版本控制的文件。定期git commit可以让你安心地尝试各种修改出了问题也能轻松回滚。对于这个项目你可以将RT-Thread端的代码、Python服务端的代码、文档和配置文件都纳入版本管理。5.3 创建Python虚拟环境虽然我们在系统全局安装了ImageAI但对于一个正式项目最佳实践是使用Python虚拟环境。虚拟环境可以为每个项目创建独立的Python包安装空间避免项目间的依赖冲突。例如项目A需要TensorFlow 1.15项目B需要TensorFlow 2.8全局安装只能满足一个。使用虚拟环境则可以完美隔离。安装虚拟环境工具sudo pip3 install virtualenv。 为我们的图片识别项目创建一个虚拟环境virtualenv venv_imageai --pythonpython3。 激活虚拟环境source venv_imageai/bin/activate。激活后终端提示符前会出现(venv_imageai)字样。 在激活的环境下再次安装项目所需的包如pip install imageai tensorflow1.15.0 flask。这些包只会安装在这个虚拟环境里不会影响系统全局环境。 当你需要退出这个环境时执行deactivate即可。使用虚拟环境配合VS Code的远程开发或PyCharm的远程解释器设置可以构建一个非常专业且可控的开发环境。虽然本系列开端为了简化直接在全局环境操作但当你准备进行更深入的开发或部署时强烈建议切换到虚拟环境。6. 环境验证与下一步规划至此一个为“基于RT-Thread的本地局域网图片识别”项目准备的Ubuntu侧基础环境已经搭建完毕。让我们做一次最终的完整性检查网络连通性宿主机能ping通虚拟机的桥接IP地址。Python与核心库在终端输入python3 --version和pip3 --version确认版本无误。运行一个简单的Python脚本导入tensorflow和imageai不报错。基础服务测试在Ubuntu上运行python3 -m http.server 8000在宿主机浏览器访问http://虚拟机IP:8000能显示目录列表。文件共享宿主机和虚拟机之间可以通过共享文件夹或拖拽方便地传输文件。如果以上检查全部通过那么你的环境就是健康的可以承载后续的开发任务。在接下来的系列文章中我将带领大家使用QEMU模拟器搭建一个能运行RT-Thread操作系统的虚拟“开发板”。我们会配置网络让这个虚拟设备也能加入到我们的局域网中。编写RT-Thread端的应用程序实现图像捕获模拟或真实并通过HTTP客户端库将图片数据POST到我们的Ubuntu服务器。完善Ubuntu端的Python Flask服务接收图片调用ImageAI进行识别并返回结构化的JSON结果。实现RT-Thread端对结果的解析与显示完成整个闭环。探讨如何优化例如使用更轻量的模型、压缩图片数据、设计简单的通信协议以减少延迟等。环境搭建是万里长征的第一步也是最容易让人放弃的一步因为你会遇到各种依赖、版本、网络和权限问题。但一旦环境配妥后面的代码编写和逻辑实现反而会顺畅很多。希望这篇详细的记录能帮你扫清这些前期障碍。如果在搭建过程中遇到了本文未涵盖的奇怪问题欢迎在评论区交流很可能你踩到的坑正是别人需要的解药。