1. 项目缘起从“看见”到“识别”的硬件实践最近在折腾一个智能小车项目核心需求是让小车能自动识别并追踪特定颜色的目标。市面上现成的视觉模块不少但要么是“黑盒”内部算法不透明调试起来像在猜谜要么价格不菲对于个人开发者或教学场景来说成本太高。我的想法很简单能不能用最经典的树莓派生态加上开源的计算机视觉库自己从零搭建一套稳定、可定制且成本可控的颜色识别系统这个念头让我把目光投向了reTerminal和Pi Camera这对组合。reTerminal 本质上是一款基于树莓派 CM4 计算模块的工业级开发板它自带了一块高分辨率的触摸屏省去了外接显示器的麻烦对于需要现场调试和展示的视觉项目来说简直是“神器”。而 Pi Camera这里特指通过 CSI 接口连接的官方或兼容摄像头模块如 OV5647则能提供稳定、低延迟的图像输入这是保证识别实时性的硬件基础。软件层面OpenCV无疑是计算机视觉领域的“瑞士军刀”其强大的图像处理能力和丰富的颜色空间转换函数正是实现颜色检测的核心。所以这个项目的目标非常明确在 reTerminal 上驱动 Pi Camera 捕获实时视频流利用 OpenCV 将图像转换到更适合颜色分割的 HSV 色彩空间然后通过设定阈值来提取我们感兴趣的颜色区域最终在屏幕上实时框出这些区域。整个过程从硬件接线、系统配置到算法调参、代码编写完全透明可控。无论你是想学习嵌入式视觉开发还是为自己的机器人、自动化项目添加“眼睛”这套方案都能提供一个扎实的起点。接下来我就把搭建过程中的关键步骤、核心原理以及那些容易踩坑的细节毫无保留地分享出来。2. 硬件准备与环境搭建让 reTerminal “看见”世界工欲善其事必先利其器。在开始写代码之前确保硬件连接正确和软件环境就绪是成功的第一步。这部分看似基础但很多问题都源于此值得仔细梳理。2.1 硬件连接与摄像头启用首先你需要准备好以下硬件reTerminal 主机已安装好 Raspberry Pi OS。Pi Camera 模块如 OV5647。注意区分 CSI 接口和 USB 摄像头前者延迟更低集成度更好。连接 Pi Camera 与 reTerminal 的柔性排线FPC。连接步骤很简单但有个关键细节排线的金属触点面必须朝向 reTerminal 板载的 CSI 接口插座外侧通常是远离 HDMI 接口的一侧。插入后轻轻锁紧 CSI 接口的黑色卡扣。如果连接反了或没锁紧系统是无法识别到摄像头的。硬件连接好后启动 reTerminal我们需要在系统中启用摄像头接口。由于 reTerminal 基于树莓派 CM4其配置方式与普通树莓派相同。打开终端执行sudo raspi-config命令通过方向键和回车键进入菜单选择Interface Options-Camera- 选择Yes来启用摄像头接口。完成后选择Finish并重启系统。重启后可以通过一个简单的命令来测试摄像头是否工作正常libcamera-hello -t 0。这个命令会打开一个实时预览窗口。如果能看到摄像头拍摄的画面说明硬件连接和驱动一切正常。这里我推荐使用libcamera系列工具进行初步测试因为它是树莓派官方主推的新一代摄像头栈比旧的raspistill/raspivid兼容性更好也为后续与 OpenCV 配合打下了基础。2.2 OpenCV 的安装权衡与选择接下来是软件环境的核心安装 OpenCV。在树莓派包括 reTerminal上安装 OpenCV 有多种方式每种方式各有优劣选择哪种取决于你的需求和时间。方式一通过 apt 包管理器安装最快但版本可能较旧sudo apt update sudo apt install python3-opencv这种方式安装速度极快几乎是开箱即用。但缺点是软件源中的 OpenCV 版本通常不是最新的例如 Raspberry Pi OS Bullseye 默认可能是 OpenCV 4.5.x且只包含核心模块一些额外的功能模块如 contrib 模块可能没有。如果你的项目对最新特性没有强需求只是想快速验证和入门这是最推荐的方式。方式二从源码编译安装最灵活但耗时极长这是最“硬核”的方式。你需要从 OpenCV 官网下载源码在本地进行编译。好处是可以自定义编译选项启用所有需要的功能如 CUDA 支持、额外的模块并且能安装绝对最新的版本。但巨大的缺点是在树莓派这类 ARM 设备上编译非常耗时动辄数小时且对内存和交换空间有要求过程容易出错。除非你有非常特殊的模块需求否则不建议初学者采用。方式三使用预编译的轮子Wheel文件平衡之选这是社区提供的折中方案。有一些开发者会为树莓派 ARM 架构预编译好 OpenCV 的 Python 包.whl 文件。你可以下载对应的文件然后用 pip 直接安装。这比从源码编译快得多又能获得比 apt 更新的版本。你可以在 GitHub 上搜索 “raspberry pi opencv wheel” 找到相关资源。安装命令类似pip install opencv_contrib_python-4.8.1.78-cp37-abi3-linux_armv7l.whl。务必选择与你的 Python 版本和系统架构匹配的 wheel 文件。对于本项目我选择了方式一即通过apt安装python3-opencv。因为颜色检测属于 OpenCV 的基础功能所有版本都支持得很好稳定性和便捷性优先。安装完成后可以在 Python 中运行import cv2和print(cv2.__version__)来验证是否成功。注意如果你在 Python 虚拟环境中开发需要确保在虚拟环境中也安装了 opencv-python 包例如pip install opencv-python-headlessheadless 版本不含 GUI 相关库在服务器或终端环境下更节省资源因为系统 apt 安装的包在虚拟环境中可能不可见。3. 核心原理为什么是 HSV 色彩空间当我们谈论“检测红色”或“追踪绿色”时直觉上会想到 RGB红绿蓝色彩空间。但在实际图像处理中直接用 RGB 值来定义颜色范围是一个非常糟糕的主意。原因在于RGB 空间对光照变化极其敏感。同一个红色的物体在强光下看起来可能接近白色RGB值都很高在阴影中则显得暗红RGB值都低。这会导致你设定的 RGB 阈值范围必须非常宽才能覆盖不同光照下的同一颜色但阈值一宽又容易把其他颜色也误判进来。这就是我们需要引入HSV 色彩空间的原因。HSV 将颜色信息从亮度中分离出来它由三个分量构成HHue色调表示颜色的种类如红、黄、绿、蓝。它的值通常用一个 0° 到 360° 的圆锥环来表示但在 OpenCV 中为了用一个字节8位表示这个范围被压缩到了 0-179。SSaturation饱和度表示颜色的纯度或鲜艳程度。饱和度越高颜色越纯越低则越接近灰色。VValue明度表示颜色的明亮程度。明度越高颜色越亮越低则越暗。这种分离带来的巨大优势是我们可以主要依靠 H色调通道来定义颜色而让 S饱和度和 V明度在一个较宽的范围内变化以容忍光照的强弱变化。例如要检测红色我们只需要设定 H 值在一个表示红色的区间内在 OpenCV 中红色位于色调环的两端所以通常需要两个区间如 0-10 和 170-180然后设定 S 和 V 的下限比如 S50 V50以避免将太暗或太灰的区域误判为红色。这样无论这个红色物体是在阳光下还是灯光下只要它的色调是红的我们就能稳定地检测到它。理解了 HSV 的优势我们的颜色检测流程就清晰了捕获图像从 Pi Camera 获取一帧 BGR 格式的图像OpenCV 默认格式。色彩空间转换使用cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)将图像从 BGR 转换到 HSV 空间。定义阈值范围根据目标颜色设定 HSV 的下限和上限形成一个三元组例如lower_red (0, 50, 50)upper_red (10, 255, 255)。生成掩膜使用cv2.inRange(hsv_frame, lower_bound, upper_bound)函数。这个函数会遍历 HSV 图像的每一个像素如果其值在设定的上下限范围内则输出掩膜Mask图像中对应位置为白色255否则为黑色0。这样我们就得到了一张二值图其中白色区域就是疑似目标颜色的区域。后处理与标记对掩膜进行一些形态学操作如腐蚀、膨胀以消除噪声和小斑点然后找到白色区域的轮廓最后在原图上绘制出这些轮廓的矩形框。4. 代码实战从捕获到框选的完整流程理论清楚了现在让我们把思路变成代码。下面是一个完整的、带有详细注释的 Python 脚本你可以在 reTerminal 上直接运行它。import cv2 import numpy as np from picamera2 import Picamera2 import time # 初始化 Picamera2 picam2 Picamera2() # 配置预览格式和大小。这里选择 RGB888 格式便于 OpenCV 直接处理。 # 分辨率可以根据需要调整更高的分辨率处理更慢。 preview_config picam2.create_preview_configuration(main{size: (640, 480), format: RGB888}) picam2.configure(preview_config) picam2.start() # 稍等摄像头启动 time.sleep(2) print(摄像头已启动按 q 键退出程序。) # 定义想要检测的颜色的 HSV 阈值范围 # 这里以检测“蓝色”为例。你需要根据实际环境调整这些值。 # OpenCV 中 H 范围是 0-179S 和 V 是 0-255。 # 蓝色在 HSV 色调环中大约在 100-125 之间。 lower_blue np.array([100, 50, 50]) # HSV 下限 upper_blue np.array([130, 255, 255]) # HSV 上限 while True: # 从摄像头捕获一帧图像 # Picamera2 返回的是 numpy 数组格式为 RGB。 frame picam2.capture_array() # Picamera2 返回 RGB但 OpenCV 常用 BGR如果需要可以转换。 # 但因为我们不直接显示原图而是显示处理后的结果且颜色转换在 HSV 步骤进行这里可以跳过。 # 如果后续需要显示原图记得转换frame_bgr cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) # 将图像从 RGB 转换到 HSV 色彩空间 hsv_frame cv2.cvtColor(frame, cv2.COLOR_RGB2HSV) # 根据阈值创建掩膜 (Mask) mask cv2.inRange(hsv_frame, lower_blue, upper_blue) # 可选对掩膜进行形态学操作消除小噪声点连接相邻区域 kernel np.ones((5,5), np.uint8) mask cv2.erode(mask, kernel, iterations1) # 腐蚀使白色区域变小消除小白点 mask cv2.dilate(mask, kernel, iterations2) # 膨胀使白色区域变大连接断裂部分 # 在原始图像上只显示被掩膜选中的颜色区域可选用于调试 # result cv2.bitwise_and(frame, frame, maskmask) # 寻找掩膜中的轮廓 contours, _ cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 遍历所有轮廓并框出足够大的区域 for contour in contours: area cv2.contourArea(contour) if area 500: # 忽略面积太小的轮廓可能是噪声 x, y, w, h cv2.boundingRect(contour) # 在原始帧上绘制绿色矩形框 cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2) # 可选在框上方标注面积 cv2.putText(frame, fArea: {int(area)}, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) # 显示结果 # 在 reTerminal 屏幕上我们可以直接显示处理后的 frame (RGB格式) cv2.imshow(Color Detection - Blue, frame) # 显示掩膜图像有助于调试阈值可选 cv2.imshow(Mask, mask) # 按 q 键退出循环 if cv2.waitKey(1) 0xFF ord(q): break # 释放资源 picam2.stop() cv2.destroyAllWindows()代码关键点解析Picamera2 vs OpenCV 的 VideoCapture我们没有使用 OpenCV 传统的cv2.VideoCapture(0)来调用摄像头。因为在树莓派上通过libcamera驱动的 CSI 摄像头用VideoCapture调用可能有问题或效率不高。Picamera2库是树莓派官方推荐的用于访问摄像头的新 API它提供了更直接、更高效的控制方式。picam2.capture_array()能直接返回一个 numpy 数组无缝对接 OpenCV。色彩空间转换的源头注意代码中是cv2.cvtColor(frame, cv2.COLOR_RGB2HSV)。因为Picamera2默认返回 RGB 数组。如果你错误地使用了COLOR_BGR2HSV会导致颜色识别完全错乱。这是一个非常常见的坑。阈值范围的确定代码中的lower_blue和upper_blue是示例。如何找到你要检测的颜色的准确 HSV 范围一个实用的方法是写一个简单的调试程序用滑杆Trackbar动态调整 HSV 的上下限实时观察掩膜的变化直到它能较好地框出目标物体。这比死记硬背数值要有效得多。形态学操作的意义cv2.erode腐蚀和cv2.dilate膨胀是图像处理中常用的“形态学开运算”和“闭运算”的组成部分。这里先腐蚀后膨胀开运算的目的是去除掩膜中因噪声产生的小白点让目标区域更干净。迭代次数 (iterations) 可以根据图像噪声大小调整。轮廓面积过滤if area 500:这一行至关重要。它过滤掉了那些面积过小的轮廓这些轮廓通常是图像噪声或微小的反光点而非真正的目标物体。这个面积阈值需要根据你的摄像头分辨率、目标物体距离的远近进行实验调整。5. 阈值调优与动态校准让检测更精准上一节的代码提供了一个可运行的框架但里面的 HSV 阈值[100, 50, 50]到[130, 255, 255]只是一个示例。在实际环境中光线、物体表面材质、摄像头白平衡都会影响颜色的表现固定的阈值很难在所有场景下都工作良好。因此掌握动态确定阈值的方法是让项目从“能跑”到“好用”的关键。5.1 使用 OpenCV 滑杆进行实时调参最好的方法就是写一个交互式的调试工具。下面这个脚本会在屏幕上创建多个滑杆让你可以实时调整 HSV 的上下限并立即看到掩膜和检测结果的变化。import cv2 import numpy as np from picamera2 import Picamera2 def nothing(x): # 滑杆回调函数必须存在但可以为空 pass picam2 Picamera2() preview_config picam2.create_preview_configuration(main{size: (640, 480), format: RGB888}) picam2.configure(preview_config) picam2.start() # 创建一个窗口 cv2.namedWindow(Trackbars) # 创建六个滑杆分别对应 HSV 下限和上限 # 参数滑杆名窗口名默认值最大值回调函数 cv2.createTrackbar(LH, Trackbars, 0, 179, nothing) cv2.createTrackbar(LS, Trackbars, 0, 255, nothing) cv2.createTrackbar(LV, Trackbars, 0, 255, nothing) cv2.createTrackbar(UH, Trackbars, 179, 179, nothing) cv2.createTrackbar(US, Trackbars, 255, 255, nothing) cv2.createTrackbar(UV, Trackbars, 255, 255, nothing) # 设置一些常见颜色的初始值例如蓝色 cv2.setTrackbarPos(LH, Trackbars, 100) cv2.setTrackbarPos(LS, Trackbars, 50) cv2.setTrackbarPos(LV, Trackbars, 50) cv2.setTrackbarPos(UH, Trackbars, 130) cv2.setTrackbarPos(US, Trackbars, 255) cv2.setTrackbarPos(UV, Trackbars, 255) print(调整滑杆以校准颜色阈值。按 q 退出。) while True: frame picam2.capture_array() hsv cv2.cvtColor(frame, cv2.COLOR_RGB2HSV) # 从滑杆获取当前阈值 l_h cv2.getTrackbarPos(LH, Trackbars) l_s cv2.getTrackbarPos(LS, Trackbars) l_v cv2.getTrackbarPos(LV, Trackbars) u_h cv2.getTrackbarPos(UH, Trackbars) u_s cv2.getTrackbarPos(US, Trackbars) u_v cv2.getTrackbarPos(UV, Trackbars) lower_bound np.array([l_h, l_s, l_v]) upper_bound np.array([u_h, u_s, u_v]) mask cv2.inRange(hsv, lower_bound, upper_bound) # 对掩膜进行简单的开运算去噪 kernel np.ones((3,3), np.uint8) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 将掩膜与原图进行“与”操作只显示目标颜色 result cv2.bitwise_and(frame, frame, maskmask) # 显示原图、掩膜和结果 cv2.imshow(Original, frame) cv2.imshow(Mask, mask) cv2.imshow(Result, result) if cv2.waitKey(1) 0xFF ord(q): break picam2.stop() cv2.destroyAllWindows()运行这个脚本你会看到三个窗口。调整LH/UH色调下限/上限、LS/US饱和度下限/上限、LV/UV明度下限/上限这六个滑杆。目标是在Mask窗口中只有你想要检测的物体区域是白色的其他区域尽可能为黑色在Result窗口中只有该物体有颜色背景为黑色。当你调整到满意状态时记下此时的六个数值它们就是你当前环境下的最佳 HSV 阈值。5.2 处理“红色”的特殊情况在 HSV 色调环上红色位于 0° 和 180°即 0 和 179附近。这意味着一个单一的阈值区间如 0-10无法覆盖所有红色因为接近 180 的深红色会被遗漏。因此检测红色通常需要两个阈值区间并将它们的掩膜合并。# 假设通过滑杆调试得到红色的两个区间 # 区间1: 低色调部分 (0-10) lower_red1 np.array([0, 50, 50]) upper_red1 np.array([10, 255, 255]) # 区间2: 高色调部分 (170-179) lower_red2 np.array([170, 50, 50]) upper_red2 np.array([179, 255, 255]) mask1 cv2.inRange(hsv_frame, lower_red1, upper_red1) mask2 cv2.inRange(hsv_frame, lower_red2, upper_red2) # 合并两个掩膜 red_mask cv2.bitwise_or(mask1, mask2)这样red_mask就包含了所有色调上的红色区域。5.3 环境光变化的应对策略即使调好了阈值环境光一变可能又不对了。有几种思路可以提升鲁棒性自动白平衡确保摄像头开启了自动白平衡AWBPicamera2默认是开启的这有助于在不同色温光源下保持颜色相对一致。区域曝光如果背景复杂可以尝试只对图像中特定区域ROI进行颜色检测避开过亮或过暗的背景。自适应阈值对于更高级的应用可以考虑使用颜色直方图反向投影或者训练一个简单的机器学习分类器但这超出了基础颜色检测的范围。对于大多数项目精心调试的固定 HSV 阈值配合适度的形态学处理已经足够稳定。6. 性能优化与工程化思考在 reTerminal 上运行实时视觉应用性能是需要考虑的问题。树莓派 CM4 的性能虽然不错但优化得当可以让程序跑得更流畅帧率更高。6.1 降低处理分辨率这是最直接有效的优化手段。在create_preview_configuration中将size从(640, 480)降至(320, 240)需要处理的像素数减少为原来的四分之一速度会有显著提升。对于颜色检测这种任务很多时候并不需要太高清的图像只要目标物体在图像中占据足够多的像素即可。6.2 优化处理流程审视你的循环每一步都是必须的吗减少不必要的转换如果不需要显示原图可以不用cv2.cvtColor转 BGR如果后续显示需要。降低轮廓查找频率不一定每一帧都进行完整的轮廓查找和绘制。可以每 2 帧或 3 帧处理一次中间帧沿用上一帧的结果这对于移动速度不快的目标很有效。限制检测区域使用cv2.rectangle在帧上划定一个 ROI (Region of Interest)然后只对这个区域内的图像进行 HSV 转换和阈值处理。这不仅能提速有时还能避免背景干扰。while True: frame picam2.capture_array() # 定义 ROI: (x_start, y_start, width, height) roi frame[100:400, 200:500] # 只处理图像中心区域 hsv_roi cv2.cvtColor(roi, cv2.COLOR_RGB2HSV) mask_roi cv2.inRange(hsv_roi, lower_blue, upper_blue) # ... 后续处理只在 roi 和 mask_roi 上进行 # 注意找到的轮廓坐标是基于 roi 的绘制回原图时需要加上偏移量 (x_start, y_start)6.3 多颜色检测与逻辑判断实际项目中往往需要检测多种颜色并做出不同决策。实现起来很简单就是为每种颜色定义一组阈值生成各自的掩膜然后分别处理。# 定义多种颜色阈值 colors { blue: ([100, 50, 50], [130, 255, 255]), green: ([40, 50, 50], [80, 255, 255]), red: ([0, 50, 50], [10, 255, 255], [170, 50, 50], [179, 255, 255]) # 红色有两个区间 } while True: frame picam2.capture_array() hsv cv2.cvtColor(frame, cv2.COLOR_RGB2HSV) detected_colors [] for color_name, bounds in colors.items(): if color_name red: lower1, upper1, lower2, upper2 bounds mask1 cv2.inRange(hsv, np.array(lower1), np.array(upper1)) mask2 cv2.inRange(hsv, np.array(lower2), np.array(upper2)) mask cv2.bitwise_or(mask1, mask2) else: lower, upper bounds mask cv2.inRange(hsv, np.array(lower), np.array(upper)) # 查找该颜色掩膜中的轮廓 contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: if cv2.contourArea(cnt) 500: x, y, w, h cv2.boundingRect(cnt) # 用不同颜色绘制不同物体的框 if color_name blue: cv2.rectangle(frame, (x,y), (xw, yh), (255, 0, 0), 2) # 蓝色框 elif color_name green: cv2.rectangle(frame, (x,y), (xw, yh), (0, 255, 0), 2) # 绿色框 elif color_name red: cv2.rectangle(frame, (x,y), (xw, yh), (0, 0, 255), 2) # 红色框 detected_colors.append(color_name) # 可以在屏幕上显示检测到的颜色列表 cv2.putText(frame, fDetected: {, .join(detected_colors)}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) cv2.imshow(Multi-Color Detection, frame) # ... 退出逻辑6.4 从检测到控制形成闭环颜色检测本身不是目的它通常是一个感知环节。在 reTerminal 上我们可以很容易地将检测结果转化为控制信号。例如在智能小车项目中如果检测到蓝色区域在图像左侧则控制小车向左转。如果红色区域面积大于某个阈值则控制机械臂执行抓取动作。可以通过 GPIO 库如RPi.GPIO或gpiozero控制电机、舵机或 LED。这需要你将视觉处理线程或循环与逻辑控制线程结合起来。一个简单的架构是在主循环中视觉模块不断更新一个全局变量如target_x_center目标物体的中心点X坐标或target_area目标物体面积另一个控制线程或函数定期读取这个变量根据一定的控制算法如 PID 控制器计算出电机 PWM 占空比并输出到 GPIO。这样一个基于视觉反馈的自动控制系统就搭建起来了。7. 常见问题排查与经验心得在 reTerminal 上玩转 Pi Camera 和 OpenCV我踩过不少坑也积累了一些经验这里集中分享一下。问题一运行脚本时报错 “Failed to create Picamera2 object” 或 “No camera found”。检查硬件连接首先确认摄像头排线已正确插入 CSI 接口并锁紧。可以尝试重新拔插。检查摄像头启用确保已通过sudo raspi-config启用了摄像头接口并已重启。检查摄像头型号兼容性确认你的摄像头模块与树莓派/CM4兼容。一些非官方的 CSI 摄像头可能需要额外的驱动或配置。检查其他进程占用确保没有其他程序如之前的脚本未正确关闭在占用摄像头。可以尝试重启 reTerminal。问题二图像显示卡顿帧率很低。降低分辨率这是最有效的方法将采集分辨率从 1080p 降到 480p 或更低。优化代码参考第6节的性能优化建议减少不必要的运算和显示。检查 CPU 负载在终端运行htop命令查看 CPU 使用率。如果某个核心长期 100%说明处理能力已达上限。使用硬件加速Picamera2库本身利用了一些硬件加速。确保你使用的是它而不是cv2.VideoCapture。问题三颜色检测不稳定时好时坏。环境光干扰这是最常见的原因。避免强光直射摄像头或目标物体避免在日光灯可能有频闪下测试。尝试在光线均匀的环境中进行。阈值需要校准务必使用第5节的滑杆调试工具在当前光照环境下重新校准 HSV 阈值。早上、中午、晚上、开灯、关灯阈值都可能不同。白平衡问题尝试在Picamera2配置中固定白平衡模式而不是使用自动模式。例如controls {AwbMode: controls.AwbModeEnum.日光}这可以减少色温变化带来的影响。目标物体材质光滑、反光的表面如塑料、金属容易产生高光导致局部过曝V值接近255S值接近0从而逃离 HSV 阈值范围。可以考虑适当提高 V 的上限或降低 S 的下限来包容这些区域或者从物理上调整光源角度。问题四检测到的区域有多个小碎片或者一个大物体被拆分成多个轮廓。调整形态学操作增加cv2.dilate膨胀的迭代次数可以帮助连接相邻的白色区域。也可以使用cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)进行闭运算先膨胀后腐蚀这对填充物体内部的小黑洞和连接邻近物体特别有效。调整高斯模糊在转换到 HSV 之前对原图进行轻微的高斯模糊cv2.GaussianBlur(frame, (5,5), 0)可以平滑图像噪声使颜色区域更连续。但模糊过度会损失边缘信息需要权衡。轮廓面积过滤确保你已经设置了合理的area 500这样的过滤条件这能直接滤除噪声点。个人心得调试是王道不要指望一次写对代码、一次调好参数。准备好滑杆调试工具耐心地、反复地在实际环境中调试阈值和形态学参数这是项目成功的保证。理解原理比记住代码更重要清楚 HSV 每个通道代表什么知道腐蚀膨胀做了什么明白轮廓查找的原理。这样当遇到新问题时你才能自己分析原因并找到解决方案而不是盲目搜索代码片段。从简单场景开始先用一个颜色鲜艳、背景单一的物体在稳定光照下测试确保基础流程跑通。然后再逐步增加复杂度如更换背景、改变光照、检测多颜色、追踪移动物体。reTerminal 的屏幕是优势它的集成屏幕使得现场调试和演示非常方便。你可以把调试信息如当前帧率、检测到的颜色、目标坐标直接显示在图像上一目了然。这个项目就像一个乐高积木的基础模块掌握了它你就拥有了为各种实体项目添加“视觉”能力的基础。无论是颜色分拣机、视觉巡线小车还是简单的互动艺术装置其核心都离不开这套“捕获-转换-阈值-定位”的流程。希望这份详细的梳理能帮你少走弯路更快地享受到嵌入式视觉开发的乐趣。