基于ImageAI与Flask的嵌入式图像识别服务器环境搭建指南
2026/6/13 17:45:29 网站建设 项目流程

1. 项目概述与核心思路

最近在捣鼓一个挺有意思的项目,想试试看能不能让一个资源受限的嵌入式设备,比如一块MCU开发板,也能玩转图片识别。这听起来有点“小马拉大车”的意思,毕竟图像识别通常需要大量的计算资源和成熟的软件框架,比如Python里的TensorFlow、PyTorch。直接让单片机跑这些框架,基本不可能。所以,我的思路是“分而治之,各司其职”。

这个项目的核心架构其实很简单,就是典型的“边缘设备+边缘计算服务器”模式。我打算用RT-Thread这款优秀的国产开源物联网操作系统跑在嵌入式设备上,它的任务很纯粹:通过摄像头模块采集图片,然后通过本地局域网(比如Wi-Fi或以太网)把图片数据发送出去。接收方是谁呢?是一台性能更强的“服务器”,在这个项目里,我用一台运行Ubuntu的虚拟机来扮演这个角色。虚拟机里搭建一个Python环境,运行基于ImageAI的图像识别模型。两者之间通过一个轻量级的Web框架Flask来搭建桥梁,RT-Thread设备作为HTTP客户端上传图片,Flask服务端接收、识别,再把结果返回。

整个流程就像个流水线:嵌入式端负责“感知”(采集)和“传输”,服务器端负责“思考”(识别)。这个系列的开端,我们先不急着碰硬件和RT-Thread,而是把后端,也就是Ubuntu虚拟机里的图像识别环境给搭稳了。环境搭建是后面一切工作的基石,这块搞不定或者搞得不顺,后续的联调会非常痛苦。我自己在搭建过程中就遇到了几个不大不小的坑,正好记录下来,如果你也打算尝试类似的项目,希望能帮你省点时间。

2. 环境搭建:虚拟机与基础系统准备

2.1 虚拟机平台与Ubuntu版本选择

首先得有个“服务器”。对于学习和开发阶段,在个人电脑上用虚拟机是最方便的选择。VMware Workstation Player(免费版)或VirtualBox都是不错的选择,我个人更习惯用VMware,它在文件共享、网络配置上相对更直观一些。

重点在于Ubuntu系统的版本选择。原文提到了最好用16.04以上,这个建议非常关键。ImageAI及其依赖的深度学习库(如TensorFlow, Keras)对系统库的版本有特定要求。太老的系统(如14.04)可能需要手动编译安装大量新版本的库,过程极其繁琐且易出错。我强烈推荐使用Ubuntu 18.04 LTS或20.04 LTS。LTS(长期支持)版本能获得长达数年的安全更新,稳定性有保障,并且社区资料最为丰富。我这次演示用的是Ubuntu 20.04 LTS,在软件源和包兼容性上表现良好。

安装过程本身网上教程汗牛充栋,无非是分配内存(建议至少2GB,4GB更佳)、硬盘空间(20GB起步)、选择镜像文件等,这里不再赘述。安装完成后,第一件事不是急着装Python包,而是做好虚拟机和宿主机的“沟通”准备。

2.2 安装VMware Tools与配置共享文件夹

在VMware中安装完Ubuntu后,你应该会看到提示安装VMware Tools。这个工具包至关重要,它提供了:

  1. 更好的图形性能与屏幕自适应分辨率
  2. 宿主机与虚拟机之间的剪贴板共享,方便复制命令和文本。
  3. 最重要的:文件共享功能。后期我们需要将RT-Thread交叉编译工具链、程序源码等从宿主机(你的Windows或Mac)方便地放到虚拟机里,或者把虚拟机里生成的模型文件拿出来,没有共享文件夹会非常麻烦。

安装步骤通常如下:

  1. 在VMware菜单栏,点击“虚拟机” -> “安装VMware Tools”。这会在虚拟机内挂载一个虚拟光盘。
  2. 在Ubuntu桌面,你会看到一个光盘图标,里面有一个名为VMwareTools-xxx.tar.gz的压缩包。
  3. 打开终端,将这个压缩包复制到一个你有权限解压的目录,比如/tmp,或者直接在家目录下操作。
    cp /media/你的用户名/VMware\ Tools/VMwareTools-*.tar.gz /tmp/ cd /tmp tar -xzvf VMwareTools-*.tar.gz
  4. 进入解压出的目录,执行安装脚本。这里需要root权限
    cd vmware-tools-distrib/ sudo ./vmware-install.pl
  5. 安装过程中,会出现大量提示,一路按回车选择默认选项即可。安装完成后,重启虚拟机。

注意:如果遇到“无法找到内核头文件”之类的错误,可能是你的系统还没安装开发工具包。可以先运行sudo apt update && sudo apt install build-essential linux-headers-$(uname -r)来安装必要的包,然后再重试安装VMware Tools。

安装好VMware Tools后,就可以配置共享文件夹了。在VMware的虚拟机设置里,找到“选项”->“共享文件夹”,添加一个你宿主机上的目录,并勾选“总是启用”。在Ubuntu里,共享文件夹通常位于/mnt/hgfs/目录下。你可以通过ls /mnt/hgfs查看是否能看到你共享的文件夹。

2.3 优化软件源与系统更新

Ubuntu默认的软件源服务器可能在国外,下载速度慢且不稳定。替换为国内镜像源能极大提升后续安装软件包的速度。清华大学开源软件镜像站是个很好的选择。

操作步骤如下:

  1. 备份原始源列表:这是一个好习惯,万一新源有问题可以快速回退。

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
  2. 编辑源列表文件:使用geditvimnano等编辑器。

    sudo gedit /etc/apt/sources.list
  3. 替换内容:将文件里所有内容删除,替换为以下适用于Ubuntu 20.04(Focal Fossa)的清华源。(注意:原文中给出的是16.04 Xenial的源,如果你用20.04,必须换)

    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
  4. 更新软件包列表:让系统识别新的软件源。

    sudo apt update

    这个命令可能会遇到一个常见错误:

    E: Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable) E: Unable to lock directory /var/lib/apt/lists/

    这通常是因为有另一个apt进程(如软件更新器)正在运行,锁定了资源。解决方法:

    • 方法一(推荐):等待几分钟,让其他进程完成。
    • 方法二:找出并结束占用进程。使用ps aux | grep apt找到相关进程ID,用sudo kill -9 <进程ID>结束它。但需谨慎,避免中断系统关键更新。
    • 方法三(强制):直接删除锁文件。sudo rm /var/lib/apt/lists/lock。这是原文提到的方法,见效快,但属于“暴力”解决,仅在确认无其他重要apt操作时使用。
  5. 升级已有软件包(可选但推荐):

    sudo apt upgrade

3. Python环境与ImageAI核心依赖部署

3.1 Python3与pip3环境确认

Ubuntu 20.04默认已经安装了Python 3.8。我们可以通过命令确认:

python3 --version pip3 --version

正常情况下,pip3也应该已经安装。如果没有,可以通过sudo apt install python3-pip来安装。

3.2 安装ImageAI及其深度学习后端

ImageAI是一个让图像识别变得极其简单的Python库,它封装了底层复杂的模型加载和预测过程。根据 ImageAI官方文档 ,它支持多种深度学习后端,最常用的是TensorFlow

安装命令看起来很简单:

pip3 install imageai --upgrade

但实际上,这条命令会触发一系列依赖包的安装,其中最关键的就是TensorFlow。在安装过程中,你可能会遇到第一个坑。

实操心得:关于TensorFlow版本的选择ImageAI对TensorFlow的版本有特定要求。直接pip install tensorflow会安装最新的2.x版本,而一些较老的ImageAI版本可能更适配TensorFlow 1.x。不过,目前ImageAI的新版本已经支持TF 2.x。为了减少兼容性问题,我建议明确指定一个经过验证的版本组合。我们可以使用以下命令一次性安装兼容性较好的组合:

pip3 install imageai --upgrade pip3 install tensorflow==2.4.0 keras==2.4.3 numpy==1.19.3

这里我固定了TensorFlow为2.4.0,Keras为2.4.3,NumPy为1.19.3。这是一个在Ubuntu 20.04上验证过能稳定工作的版本组合。NumPy版本的锁定很重要,因为最新版的NumPy可能与旧版TensorFlow不兼容。

3.3 解决安装过程中的典型报错

即便指定了版本,安装过程也可能并非一帆风顺。下面记录两个我遇到的高频问题。

问题一:pip3自身版本或路径问题在执行pip3 install时,可能会报错提示pip版本过低,或者出现一些奇怪的main函数找不到的错误。这通常是由于pip的安装方式或Python环境混乱导致的。

解决方法

  1. 首先尝试升级pip本身:
    sudo pip3 install --upgrade pip
    注意,命令是pip不是pip3pip3是调用工具,pip是要升级的包名。
  2. 如果升级后,运行pip3 --version或执行安装命令时出现类似“ModuleNotFoundError: No module named ‘pip._internal.cli.main’”的错误,则需要手动修复pip的启动脚本。 按照原文的思路,编辑/usr/bin/pip3文件:
    sudo gedit /usr/bin/pip3
    将其内容替换为更通用的形式:
    #!/usr/bin/python3 import sys from pip._internal.cli.main import main if __name__ == '__main__': sys.exit(main())
    保存退出后,再试一次pip3 --version,应该能正常显示版本信息。

问题二:Matplotlib等高阶依赖安装失败ImageAI的依赖链中可能包含matplotlib,用于示例中的绘图。在安装时可能会因为依赖冲突而失败,例如提示找不到合适的freetype库版本。

解决方法

  1. 优先使用系统包管理器安装:对于像matplotlib这样依赖复杂C库的Python包,先通过apt安装其系统依赖和预编译的版本,往往更省心。
    sudo apt update sudo apt install python3-matplotlib
    这样安装的matplotlib版本可能与pip要安装的版本不同,但通常能保证基础功能可用,且解决了底层库依赖。
  2. 如果必须用pip安装,且遇到版本冲突:可以像原文一样,指定一个稍旧的、已知兼容的版本。
    pip3 install matplotlib==3.3.3
    版本号3.0有些太老了,3.3.3是一个比较折中的选择。
  3. 安装编译依赖:如果pip安装时提示缺少freetypepng等头文件,需要安装开发包:
    sudo apt install libfreetype6-dev pkg-config
    然后再用pip安装。

3.4 验证ImageAI安装与模型下载

环境安装好后,需要验证ImageAI是否能正常工作。ImageAI的强大之处在于它内置了使用预训练模型的能力,我们不需要自己训练模型(那需要海量数据和计算资源)。

写一个最简单的测试脚本test_imageai.py

from imageai.Prediction import ImagePrediction import os execution_path = os.getcwd() # 创建预测器实例 prediction = ImagePrediction() # 指定使用ResNet模型(体积、精度、速度平衡) prediction.setModelTypeAsResNet() # 指定模型文件路径,这里我们先不下载,测试导入是否成功 prediction.setModelPath(os.path.join(execution_path, "resnet50_weights_tf_dim_ordering_tf_kernels.h5")) # 尝试加载模型(这行会报错,因为模型文件不存在,但可以测试环境是否正常) try: prediction.loadModel() print("ImageAI 环境导入成功!") except Exception as e: print(f"环境导入成功,但模型未找到。错误信息: {e}") print("下一步需要下载模型文件。")

运行这个脚本:python3 test_imageai.py。如果没有任何关于imageaitensorflow的导入错误,只是提示找不到模型文件,那就说明Python环境基本OK。

模型下载: ImageAI需要下载预训练的模型文件才能进行识别。以ResNet50为例:

  1. 访问ImageAI的GitHub发布页面或官方文档提供的链接,找到模型下载地址。例如,ResNet50模型文件通常是一个.h5文件。
  2. 你可以手动下载,然后放到你的项目目录。也可以通过代码(在网络通畅的情况下)提示下载。更可靠的方式是,在已知可访问的地址(如一些镜像站或你的稳定存储位置)预先下载好模型文件,通过之前设置的共享文件夹拷贝到虚拟机中。

重要注意事项:预训练模型文件通常很大(ResNet50约100MB),请确保虚拟机磁盘空间充足。首次加载模型时,TensorFlow会进行一些初始化,可能需要几十秒到一分钟,请耐心等待。

4. 搭建Flask图片识别服务端

4.1 Flask框架安装与最小化应用

现在,我们有了图像识别的能力,接下来需要创建一个Web服务,让RT-Thread设备能够通过网络把图片传过来。我们选择Flask,因为它是一个极其轻量级的Python Web框架,适合快速构建API。

安装Flask:

pip3 install flask

创建一个最简单的Flask应用app.py

from flask import Flask, request, jsonify import os from werkzeug.utils import secure_filename app = Flask(__name__) # 设置一个文件夹来保存上传的图片 UPLOAD_FOLDER = './uploads' if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER) app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER # 允许上传的文件类型 ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp'} def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS @app.route('/') def index(): return 'Image Recognition Server is Running!' @app.route('/upload', methods=['POST']) def upload_file(): # 检查请求中是否有文件部分 if 'file' not in request.files: return jsonify({'error': 'No file part'}), 400 file = request.files['file'] # 如果用户没有选择文件,浏览器也可能提交一个空文件 if file.filename == '': return jsonify({'error': 'No selected file'}), 400 if file and allowed_file(file.filename): filename = secure_filename(file.filename) filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(filepath) # 这里先简单返回成功消息,识别功能后续添加 return jsonify({'message': 'File uploaded successfully', 'filename': filename}), 200 else: return jsonify({'error': 'File type not allowed'}), 400 if __name__ == '__main__': # 设置为0.0.0.0可以让同一局域网内的其他设备访问 app.run(host='0.0.0.0', port=5000, debug=True)

这个应用提供了两个端点:根目录/返回一个状态信息;/upload接口用于接收POST请求上传的图片文件,并将其保存到本地的uploads目录。

运行它:python3 app.py。你应该能看到输出提示服务运行在http://127.0.0.1:5000/。在虚拟机浏览器里访问这个地址,能看到欢迎信息。

4.2 集成ImageAI识别功能

接下来,我们将识别功能集成到上传接口中。修改/upload路由的处理函数:

from imageai.Prediction import ImagePrediction import os # ... (之前的Flask初始化代码不变) ... # 初始化ImageAI预测器(在全局范围初始化,避免每次请求都重复加载模型,耗时极长) prediction = None MODEL_PATH = os.path.join(os.getcwd(), "models", "resnet50_weights_tf_dim_ordering_tf_kernels.h5") def init_predictor(): global prediction if prediction is None: print("Loading ImageAI model, this may take a while...") prediction = ImagePrediction() prediction.setModelTypeAsResNet() prediction.setModelPath(MODEL_PATH) prediction.loadModel() print("Model loaded successfully.") # 在应用启动前或第一次请求前初始化模型 init_predictor() @app.route('/upload', methods=['POST']) def upload_file(): # ... (文件接收和保存的代码不变) ... if file and allowed_file(file.filename): filename = secure_filename(file.filename) filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(filepath) # 进行图像识别 try: # 执行预测,result_count指定返回最可能的5个结果 predictions, probabilities = prediction.predictImage(filepath, result_count=5) result_list = [] for eachPrediction, eachProbability in zip(predictions, probabilities): result_list.append({"object": eachPrediction, "probability": f"{eachProbability:.2f}%"}) return jsonify({ 'message': 'File uploaded and recognized successfully', 'filename': filename, 'predictions': result_list }), 200 except Exception as e: return jsonify({'error': f'Recognition failed: {str(e)}'}), 500 # ... (其他错误处理不变) ...

4.3 服务配置与局域网访问测试

现在,一个完整的图片识别服务端就搭建好了。运行app.py后,服务监听在0.0.0.0:5000。这意味着它不仅可以从虚拟机内部访问,也可以从宿主机的浏览器,甚至与宿主机在同一局域网下的其他设备(包括我们后续要用的RT-Thread设备)访问。

关键点:获取虚拟机的IP地址在Ubuntu终端输入ip addr showifconfig(如果未安装net-tools,需先运行sudo apt install net-tools)。找到你正在使用的网络接口(通常是ens33eth0),记下inet后面的IP地址,例如192.168.1.105

测试

  1. 虚拟机内部测试:在Ubuntu终端用curl命令测试。
    curl -X POST -F "file=@/path/to/your/test.jpg" http://127.0.0.1:5000/upload
  2. 宿主机测试:打开宿主机浏览器,访问http://<虚拟机IP>:5000/,应该能看到服务运行提示。你还可以使用图形化的API测试工具如Postman,向http://<虚拟机IP>:5000/upload发送一个POST请求,表单中包含一个文件字段file,选择一张图片上传。观察返回的JSON是否包含识别结果。

防火墙注意:如果宿主机或虚拟机防火墙阻止了5000端口的访问,你需要开放此端口。在Ubuntu上,可以使用sudo ufw allow 5000/tcp(如果UFW防火墙已启用)。

5. 环境搭建常见问题与深度排查

即便按照步骤操作,环境搭建也难免遇到问题。这里将一些典型问题及其排查思路整理成表,方便快速定位。

问题现象可能原因排查步骤与解决方案
pip3 install失败,提示SSL证书错误或连接超时网络问题,无法连接PyPI官方源1.更换国内PyPI镜像源:临时使用pip3 install package_name -i https://pypi.tuna.tsinghua.edu.cn/simple
2.永久配置:创建或修改~/.pip/pip.conf,写入:[global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple
运行Flask应用时报错Address already in use5000端口被其他进程占用1. 查找占用端口的进程:sudo lsof -i :5000
2. 终止该进程:sudo kill -9 <PID>
3. 或者修改Flask应用的启动端口:app.run(port=5001)
ImageAI加载模型时卡住或报TensorFlow相关错误1. 模型文件损坏或路径错误。
2. TensorFlow版本与ImageAI或CUDA/cuDNN(如果使用GPU)不兼容。
3. 内存不足。
1.检查模型文件:确认文件路径正确,文件完整(可尝试重新下载)。
2.验证TensorFlow安装:在Python交互环境执行import tensorflow as tf; print(tf.__version__),看是否能正常导入。
3.CPU模式确认:对于没有NVIDIA GPU的环境,务必安装的是TensorFlow CPU版本。pip install tensorflow-cpu==2.4.0
4.查看详细错误:仔细阅读终端输出的完整错误堆栈,往往最后几行是关键。
Flask服务能被虚拟机访问,但宿主机无法访问1. 虚拟机网络模式设置问题。
2. 宿主机/虚拟机防火墙阻止。
3. Flask未监听0.0.0.0
1.检查网络模式:在VMware中,将虚拟机网络适配器设置为“桥接模式”或“NAT模式”。桥接模式会使虚拟机获得一个与宿主机同网段的独立IP,更易于访问。
2.检查监听地址:确认Flaskapp.run()host参数为'0.0.0.0',而不是默认的'127.0.0.1'
3.关闭防火墙测试:临时关闭宿主机和虚拟机的防火墙,判断是否为防火墙问题。
识别结果不准或概率极低1. 输入图片质量差、尺寸过小或主体不清晰。
2. 预训练模型类别限制。ResNet是在ImageNet数据集上训练的,包含1000个常见类别。
1.预处理图片:确保上传的图片是模型常见的对象(猫、狗、汽车、杯子等),且图片清晰。
2.尝试其他模型:ImageAI支持MobileNet(速度快、体积小、精度稍低)、DenseNet、InceptionV3等,可以换模型试试。
3.理解输出:模型返回的是概率分布,最高概率可能也只有70%,这是正常现象。关注Top-5结果。
sudo pip3安装后,普通用户无法导入包pip将包安装到了root用户的site-packages目录,可能与当前用户环境隔离。1.优先使用pip3 install --user为当前用户安装,避免使用sudo。
2. 如果必须全局安装,检查Python路径。可以使用python3 -m site查看包搜索路径。确保安装位置在sys.path中。

一个深度排查案例:TensorFlow报“Illegal instruction (core dumped)”我在一台老旧的服务器上部署时遇到过这个问题。错误发生在导入TensorFlow或加载模型时。这通常是因为该CPU不支持TensorFlow二进制版本使用的某些指令集(如AVX, AVX2)。

解决方案

  1. 检查CPU型号cat /proc/cpuinfo | grep flags,查看是否包含avxavx2sse4.1等。
  2. 安装兼容版本:如果CPU太老(比如一些Intel Atom或老款至强),可能不支持AVX。需要从源码编译TensorFlow(极其复杂),或者寻找他人编译好的、针对老CPU优化的版本(如一些社区维护的wheel包)。
  3. 使用更轻量的替代方案:如果只是做实验,可以考虑使用不需要TensorFlow的轻量级图像识别库,或者使用ONNX Runtime等支持多种后端且对老硬件更友好的推理引擎。但这意味着要部分重写识别服务。

6. 为嵌入式端联调做准备

后端服务搭好了,接下来我们的重心就要转向嵌入式端。在结束环境搭建部分之前,还有几项准备工作可以为后续的联调扫清障碍。

1. 固化服务IP地址虚拟机通过DHCP获取的IP可能会变,这会导致RT-Thread设备配置的服务器地址失效。最好在虚拟机中设置静态IP,或者在路由器上为虚拟机的MAC地址分配固定的IP。

2. 编写一个更健壮的服务脚本目前的app.py在终端关闭后服务就停止了。我们可以使用nohupsystemd将其作为后台服务运行。

nohup python3 app.py > flask.log 2>&1 &

这样服务就在后台运行,输出重定向到flask.log文件。可以用ps aux | grep app.py查看进程,用kill <PID>结束它。

3. 考虑性能与优化

  • 图片尺寸:嵌入式设备摄像头分辨率可能不高,上传前可在设备端或服务端对图片进行缩放(如缩放到224x224,这是很多CNN模型的标准输入尺寸),能显著减少传输数据量和识别时间。
  • 并发处理:当前的Flask应用是单线程的,如果同时有多个请求,会排队处理。对于测试来说够用,如果要求更高,可以考虑使用gevent或部署到gunicorn
  • 模型选择:ResNet50精度高但速度慢、体积大。如果嵌入式设备传输速度慢或要求实时性,可以尝试ImageAI支持的MobileNet模型,它在精度和速度间取得了更好的平衡。

4. 设计通信协议我们目前使用的是最简单的HTTP表单上传。对于嵌入式设备,可能需要考虑:

  • 数据格式:除了图片二进制流,可能还需要附加设备ID、时间戳等信息。可以设计成JSON格式,包含一个image_data的base64编码字段。
  • 错误处理与重试:网络可能不稳定,嵌入式端代码需要包含超时机制和失败重试逻辑。
  • 结果解析:确保嵌入式端能够正确解析服务端返回的JSON格式的识别结果。

至此,一个基于Ubuntu、ImageAI和Flask的本地图片识别服务器就完全准备就绪了。它静静地运行在虚拟机上,等待着来自局域网的图片,并准备返回它的“认知”。在下一部分,我们将把目光投向另一端,开始构建运行RT-Thread的嵌入式设备,并让它学会如何“看见”并“讲述”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询