ESP-VISION图像处理算法全家桶:从滤波到AprilTag,14个API一次讲透

📅 2026/7/16 10:26:31 👁️ 阅读次数 📝 编程学习
ESP-VISION图像处理算法全家桶:从滤波到AprilTag,14个API一次讲透

ESP-VISION图像处理算法全家桶:从滤波到AprilTag,14个API一次讲透

文章目录

  • ESP-VISION图像处理算法全家桶:从滤波到AprilTag,14个API一次讲透
    • 一、图像处理不是炫技,是解决问题
    • 二、典型处理流水线
    • 三、滤波算法:降噪是第一要务
      • 3.1 高斯滤波——标准降噪
      • 3.2 各滤波算法对比
      • 3.3 双边滤波:保边去噪的王者
    • 四、阈值化与分割:把目标从背景中分离
      • 4.1 二值化
      • 4.2 Blob检测——颜色追踪的核心
      • 4.3 形态学:清理二值图像的利器
    • 五、特征检测:找线、找圆、找矩形
      • 5.1 霍夫变换
      • 5.2 矩形检测
      • 5.3 模板匹配
    • 六、标记识别:二维码、条形码、AprilTag
      • 6.1 二维码
      • 6.2 条形码(仅ESP32-P4)
      • 6.3 AprilTag——6自由度位姿估计
    • 七、直方图与统计:自动调参的秘密武器
      • 7.1 自动计算阈值
      • 7.2 快速统计
    • 八、一个完整的工业检测案例
    • 参考链接
    • 总结与下篇预告

一、图像处理不是炫技,是解决问题

我见过不少嵌入式视觉项目,明明一个高斯滤波+二值化+Blob检测就能搞定,非得上深度学习模型。结果帧率从15fps掉到3fps,功耗从0.5W飙到2W,检测精度却没提升多少。

ESP-VISION的图像处理模块继承自OpenMV的imlib库,包含数十种经过嵌入式优化的算法。这些算法零依赖、纯C实现、内存占用可控,在MCU上跑起来比你想的流畅得多。

今天这篇文章,我把14个最常用的API按场景分类讲透。

二、典型处理流水线

大多数视觉检测脚本遵循这个流程:

采集
sensor.snapshot()

预处理
灰度/高斯/直方图

分割
二值化/阈值

分析
Blob/特征检测

输出
绘制/计数/控制

三、滤波算法:降噪是第一要务

3.1 高斯滤波——标准降噪

# 基础用法img.gaussian(ksize=3)# 3×3高斯核,标准降噪# 锐化模式img.gaussian(ksize=3,unsharp=True)# 反锐化掩膜,增强边缘# 配合阈值:一次遍历完成滤波+二值化img.gaussian(ksize=3,threshold=128)# 滤波后大于128的像素变白

3.2 各滤波算法对比

算法适用场景速度效果
mean()快速模糊,降低噪声最快边缘模糊严重
gaussian()标准降噪,保留边缘平衡好
median()椒盐噪声中等去噪极佳,边缘保留好
bilateral()保边去噪平滑平面+保留锐利边缘
laplacian()边缘检测二阶导数边缘响应
morph()自定义卷积核取决于核大小灵活

3.3 双边滤波:保边去噪的王者

# 双边滤波:同时考虑空间距离和颜色相似度img.bilateral(ksize=3,color_sigma=0.1,space_sigma=1)# space_sigma: 空间距离权重(越大越模糊)# color_sigma: 颜色相似度权重(越大越不保边)

使用建议:先用gaussian()快速试,效果不够再用bilateral()。bilateral虽然效果好,但计算量是gaussian的3-5倍。

四、阈值化与分割:把目标从背景中分离

4.1 二值化

# 颜色阈值二值化(LAB空间)img.binary([(30,100,15,127,15,127)])# 红色二值化# 灰度阈值gray=img.to_grayscale()gray.binary([(128,255)])# 大于128的变白# 多阈值:同时跟踪多种颜色img.binary([red_threshold,blue_threshold,green_threshold])

4.2 Blob检测——颜色追踪的核心

blobs=img.find_blobs([red_threshold],# 颜色阈值列表pixels_threshold=200,# 最小像素数(过滤噪声)area_threshold=200,# 最小面积(过滤小目标)merge=True,# 合并重叠区域margin=10# 合并边距)forblobinblobs:print(f"质心: ({blob.cx()},{blob.cy()})")print(f"外接框:{blob.rect()}")# (x, y, w, h)print(f"面积:{blob.area()}")print(f"圆度:{blob.roundness()}")# 1=完美圆print(f"实心度:{blob.solidity()}")# 面积/外接凸包面积print(f"旋转角度:{blob.rotation_deg()}")

4.3 形态学:清理二值图像的利器

# 腐蚀:消除小白点img.erode(ksize=3)# 膨胀:填充小黑洞img.dilate(ksize=3)# 开运算:先腐蚀再膨胀(去噪点)img.open(ksize=3)# 闭运算:先膨胀再腐蚀(填孔洞)img.close(ksize=3)

五、特征检测:找线、找圆、找矩形

5.1 霍夫变换

# 找直线lines=img.find_lines(threshold=1000,theta_margin=25,rho_margin=25)forlineinlines:img.draw_line(line.line())# 找圆circles=img.find_circles(threshold=2000,# 累加器阈值(越高越严格)x_margin=10,y_margin=10,# 合并近似重复的圆r_margin=10,r_min=10,r_max=100# 半径范围)forcircleincircles:img.draw_circle(circle.x(),circle.y(),circle.r())

5.2 矩形检测

rects=img.find_rects(threshold=10000)forrectinrects:# rect.corners() 返回四个角点img.draw_rectangle(rect.rect())

5.3 模板匹配

# 加载模板template=image.Image("template.pgm")# 匹配results=img.find_template(template,threshold=0.7)forrinresults:img.draw_rectangle(r.rect())

六、标记识别:二维码、条形码、AprilTag

6.1 二维码

qrcodes=img.find_qrcodes()forqrinqrcodes:print(f"内容:{qr.payload()}")img.draw_rectangle(qr.rect())

6.2 条形码(仅ESP32-P4)

# 需要ZXing-C++后端(P4板级配置启用)barcodes=img.find_barcodes()forbcinbarcodes:print(f"类型:{bc.type()}, 内容:{bc.payload()}")

6.3 AprilTag——6自由度位姿估计

# AprilTag检测(最有含金量的功能)tags=img.find_apriltags()fortagintags:print(f"ID:{tag.id()}, Family:{tag.family()}")print(f"位置: ({tag.cx()},{tag.cy()})")print(f"旋转:{tag.rotation()}")# 如果提供了相机内参,还能获取6自由度位姿# tag.x_translation(), tag.y_translation(), tag.z_translation()# tag.x_rotation(), tag.y_rotation(), tag.z_rotation()

七、直方图与统计:自动调参的秘密武器

7.1 自动计算阈值

# 获取直方图hist=img.get_histogram()# 自动计算Otsu阈值threshold=hist.get_threshold()# Otsu算法print(f"最优阈值:{threshold.value()}")# 获取统计量stats=hist.get_statistics()print(f"均值:{stats.mean()}, 中位数:{stats.median()}")print(f"标准差:{stats.stdev()}, 四分位数:{stats.lq()}-{stats.uq()}")# 用统计量自动设置阈值binary_threshold=(stats.median()-stats.stdev(),stats.median()+stats.stdev())

7.2 快速统计

# 直接获取图像统计量(不生成直方图)stats=img.get_statistics()print(f"L mean:{stats.l_mean()}, A mean:{stats.a_mean()}, B mean:{stats.b_mean()}")print(f"Min:{stats.min()}, Max:{stats.max()}")

八、一个完整的工业检测案例

""" 零件缺陷检测 - 基于Blob形状分析 """importsensor,image,timefrommicropythonimportconst# 配置MIN_AREA=const(200)MAX_AREA=const(5000)MIN_ROUNDNESS=const(0.7)# 圆度阈值MAX_HOLE_AREA=const(100)# 允许的最大孔洞sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.skip_frames(time=2000)clock=time.clock()definspect_part(img):"""检测零件缺陷"""# 1. 预处理:灰度+高斯滤波gray=img.to_grayscale()gray.gaussian(ksize=3)# 2. 二值化:Otsu自动阈值hist=gray.get_histogram()threshold=hist.get_threshold().value()gray.binary([(threshold,255)])# 3. 形态学:去噪点+填孔洞gray.open(ksize=3)gray.close(ksize=3)# 4. Blob检测blobs=gray.find_blobs([],pixels_threshold=MIN_AREA)defects=[]forblobinblobs:issue=Noneifblob.area()<MIN_AREA:issue="太小"elifblob.area()>MAX_AREA:issue="太大"elifblob.roundness()<MIN_ROUNDNESS:issue=f"不够圆({blob.roundness():.2f})"elifblob.solidity()<0.9:issue=f"有孔洞({blob.solidity():.2f})"ifissue:img.draw_rectangle(blob.rect(),color=(255,0,0))img.draw_string(blob.x(),blob.y()-10,issue,color=(255,0,0))else:img.draw_rectangle(blob.rect(),color=(0,255,0))returndefectswhileTrue:clock.tick()img=sensor.snapshot()defects=inspect_part(img)print(f"FPS:{clock.fps():.1f}| 缺陷:{len(defects)}")

参考链接

  • ESP-VISION 图像处理
  • ESP-VISION API - image模块

总结与下篇预告

ESP-VISION的图像处理算法虽然多,但大部分场景只需要掌握"高斯→二值化→Blob"这个三段式就够了。遇到复杂场景再加形态学或特征检测。记住:先降噪再分割,能ROI就不要全图,能用灰度就不用RGB

下篇我们拆解摄像头流水线——sensor.snapshot()这一行代码背后,从光子到image.Image经历了什么。


作者:码农阿虎

关键词:图像处理、滤波、Blob检测、AprilTag、霍夫变换、Otsu阈值