回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【FireBeetle 2 ESP32-C5】API 连接与本地图像识别 简单

头像 无垠的广袤 2025.10.03 13 1

【FireBeetle 2 ESP32-C5】API 连接与本地图像识别

本文介绍了 FireBeetle 2 ESP32-C5 开发套件基于网络 HTTP 协议 API 实现本地图像识别的项目设计。

项目介绍

准备工作:包括开发板固件烧录、模型下载、Python 库部署等;

流程图:包括开发板代码和网页服务器代码对应的流程图;

工程代码:包括开发板板端执行代码、网页服务器端代码等;

工程测试:包括程序运行、图片上传、识别结果查看等;

准备工作

下载 YOLOv8n.pt 模型,或程序自动从 GitHub 网站下载;

开发板烧录 MicroPython 固件;

电脑安装 Thonny IDE 软件,用来调试板端程序;

电脑安装 Python 软件,并部署所需库函数,如 opencv-python 等,便于模型识别与调用。

详见:【LattePanda Mu 开发套件】AI 视觉应用开发——物体识别- Makelog(造物记) .

流程图

网页服务器代码流程图

flowchart_http_api_server.jpeg

ESP32-C5 代码流程图

flowchart_http_server_api_or_esp32_mpy.jpeg

工程代码

包括 ESP32-C5 代码、网页服务器执行代码两部分。

ESP32-C5 代码

打开 Thonny IDE 软件,新建 api_object_recognition.py 工程文件,并添加如下代码

# ------ ESP32-C5 one-shot send local JPG to YOLO server ----------
import network
import urequests
import sys

# ---------- Wi-Fi ----------
SSID = "xxx"
PWD = "xxx"
SERVER = "http://192.168.31.101:5000/detect"

sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.connect(SSID, PWD)
while not sta.isconnected():
pass
print("Wi-Fi ok:", sta.ifconfig()[0])

# ---------- send target picture ----------
LOCAL_JPG = "desktop.jpg"

with open(LOCAL_JPG, "rb") as f:
jpg = f.read()

boundary = "123456"
hdr = f"--{boundary}\r\n"
hdr += f'Content-Disposition: form-data; name="image"; filename="{LOCAL_JPG}"\r\n'
hdr += "Content-Type: image/jpeg\r\n\r\n"
end = f"\r\n--{boundary}--\r\n"
body = hdr.encode() + jpg + end.encode()

try:
rsp = urequests.post(SERVER,
data=body,
headers={"Content-Type": f"multipart/form-data; boundary={boundary}"})
data = rsp.json()
print("objects:", data["objects"])
print("result file:", data["result_file"])
except Exception as e:
print("err:", e)

# ---------- finish ----------
print("done – program ends")
sys.exit()

保存代码;

网页服务器代码

在模型文件上级目录创建 yolo_http_server.py 文件,添加如下代码

"""
YOLOv8 HTTP inference server
POST /detect → multipart JPEG upload
GET /last → shows last annotated image in browser
"""
import os
import uuid
import time
from pathlib import Path
from flask import Flask, request, jsonify, send_file
import cv2
from ultralytics import YOLO

app = Flask(__name__)

# ---------- config -------------------------------------------------
MODEL_PATH = "models/yolov8n.pt" # will auto-download first run
STORAGE_DIR = Path("img") # same folder you used before
STORAGE_DIR.mkdir(exist_ok=True)
ALLOWED_EXT = {".jpg", ".jpeg", ".png"}

# ---------- warm-up model once -------------------------------------
print("Loading YOLOv8 model …")
model = YOLO(MODEL_PATH)
print("Model ready.")

# ---------- helpers ------------------------------------------------
def save_upload(multipart_file):
"""store original file and return Path object"""
ext = Path(multipart_file.filename).suffix.lower()
if ext not in ALLOWED_EXT:
raise ValueError("Only .jpg .jpeg .png allowed")
name = f"{int(time.time()*1000)}_{uuid.uuid4().hex[:8]}{ext}"
path = STORAGE_DIR / name
multipart_file.save(path)
return path

def infer_and_annotate(image_path: Path):
"""run YOLOv8 + plot; return (results_list, annotated_cv2_image)"""
img_bgr = cv2.imread(str(image_path))
if img_bgr is None:
raise RuntimeError("Cannot decode image")

results = model(img_bgr) # ultralytics engine
annotated_bgr = results[0].plot() # boxes + labels drawn

# build serialisable list
objects = []
for box in results[0].boxes:
cls = int(box.cls)
conf = float(box.conf)
xyxy = box.xyxy[0].tolist() # [x1,y1,x2,y2]
objects.append({
"label": model.names[cls],
"conf": round(conf, 3),
"box": [int(x) for x in xyxy]
})
return objects, annotated_bgr

# ---------- routes -------------------------------------------------
@app.route("/detect", methods=["POST"])
def detect():
if "image" not in request.files:
return jsonify(error="missing 'image' multipart field"), 400

try:
original_path = save_upload(request.files["image"])
objects, annotated = infer_and_annotate(original_path)

# save annotated image side-by-side
annotated_name = original_path.stem + "_yolo.jpg"
annotated_path = STORAGE_DIR / annotated_name
cv2.imwrite(str(annotated_path), annotated)

return jsonify(
objects=objects,
result_file=annotated_name,
original_file=original_path.name
)
except Exception as e:
return jsonify(error=str(e)), 500

@app.route("/last")
def last_image():
"""convenience: show most recent _yolo.jpg in browser"""
files = sorted(STORAGE_DIR.glob("*_yolo.jpg"), key=os.path.getmtime, reverse=True)
if not files:
return "No annotated image yet", 404
return send_file(files[0], mimetype="image/jpeg")

@app.route("/")
def root():
return ("YOLOv8 inference server is running.
"
"POST to /detect (multipart JPEG)
"
"GET /last (newest annotated image)")
# ---------- entry --------------------------------------------------
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, threaded=True)

保存代码;

工程测试

命令行终端进入网页服务器代码所在文件夹;

终端执行 python yolo_http_server.py 指令;

or_http_server.JPG

打开终端提示的网址 http://192.168.31.109:5000/ 显示界面如下

http_or_server_face.JPG

表明模型加载成功且正在运行;

运行 Thonny IDE 并连接开发板,将目标图片 desktop.jpg 传输至板端根目录;

img_board_file.JPG

运行 api_object_recognition.py 程序,终端输出 WiFi 连接和物体识别结果;

or_print_web_api.JPG

打开网页 http://192.168.31.109:5000/last 查看图片识别结果;

http_api_or_img.JPG

总结

本文介绍了 FireBeetle 2 ESP32-C5 开发 HTTP 协议 API 实现本地图像识别的项目设计,包括网页服务器工程代码、板端执行代码、工程测试流程、识别结果查看等,为相关产品的开发设计和快速应用提供了参考。


评论

user-avatar
  • 舞动的枫叶

    舞动的枫叶2025.10.03

    很棒的作品!ESP32-C5支持蓝牙和WiFi6无线通信,可以蓝牙连接手机,手机发送图片,由ESP32-C5作为转发器,通过WiFi上传图片到网页服务器完成识别~

    0