基于ArUco标签的OpenCV视觉定位与单目测距实战指南
2026/9/16 1:34:04 网站建设 项目流程

做机器人的朋友应该都有过这种经历:想测个距离,拿起超声波及红外一量,方向稍稍偏一点就偏得离谱;想定位吧,好一点的激光雷达价格劝退,普通摄像头又不知道怎么从图像里把“物体在哪儿、离我多远”给算出来。

这篇文章想分享的是一套我用了很长时间、在多个小项目里反复打磨过的方案——基于 ArUco 标签的视觉定位、测距与三维位置估算,核心工具就是 OpenCV。它可以做到:识别画面里贴好的 ArUco 码,输出它的 ID、中心坐标、相对相机的距离,甚至给出标签在相机坐标系下的完整 6 自由度位姿(X、Y、Z 位置以及绕三个轴的旋转角)。整套方法不需要昂贵的硬件,一个普通 USB 摄像头、一张打印出来的标签纸、再加一段不算复杂的 Python 代码就能跑起来。

适合谁来参考?如果你在做小车避障、机械臂抓取、无人机定点降落、AR 叠加渲染,或者只是想给大学课程设计、毕业设计找一个靠谱的视觉定位方案,这篇文章的内容基本可以照抄。就算你之前没接触过相机标定和位姿解算,我也会点差布,尽量讲清楚背后的原理和每一步的要坑。

1. 为什么选 ArUco 做视觉定位:原理与方案选型

1.1 ArUco 标签的构成与识别逻辑

ArUco 标签本质上是二进制方形标记,跟二维码有点像,但结构简单得多。它的内部是一个由黑白小块组成的网格,不同的网格图案对应不同的 ID;外圈围着一圈黑色边框,这个边框不是为了好看,而是为了让检测算法能快速通过“黑色方块”找到候选区域。

OpenCV 的 aruco 模块检测标签时,大致走的是这样一条链路:先把图像转成灰度图再做自适应阈值处理,把图像变成黑白分明的二值图;接着用轮廓提取找出所有闭合的黑白区域,再用四边形逼近筛选出那些“看起来像正方形”的候选块;然后对候选块的内部网格进行透视校正和采样,得到一个二进制矩阵;最后拿这个矩阵去和当前使用的字典做匹配,匹配上就返回 ID,匹配不上就丢弃。整个过程在普通 CPU 上处理一帧 640x480 的图像,耗时基本在 10 毫秒以内,性能完全不是问题。

这里有个容易理解错的地方:ArUco 标签本身不携带任何实际物理尺寸信息。它能告诉你“我检测到了 ID 为 3 的标签”,但如果你不告诉程序这张标签实际打印出来有多宽,程序是无法算出距离的。所以使用 ArUco 做测距,有一个必要的前置条件——你要知道自己打印的标签纸的边长是多少,以米为单位,这个参数叫 marker length。

1.2 为什么不用二维码、棋盘格或特征点匹配

有人会问:直接用 OpenCV 的二维码检测不也能定位吗?确实能,但二维码的检测模块设计上更偏重信息量(存储大量的字符串),内部结构复杂,在光照变化剧烈、视角倾斜严重时识别率明显下降。ArUco 字典更稀疏、容错更好、抗遮挡能力更强,对实时定位场景更友好。

棋盘格常用于相机标定,但它必须整块可见才能解算出有效的角点,部分遮挡时就无从下手。ArUco 只要有一个角点被遮住,靠另外三个角点仍然能解算出位姿。至于传统 ORB、SIFT 特征点匹配,在没有先验纹理特征的场景下几乎无法工作,更不用说 ArUco 的 ID 天然自带“身份识别”能力,这是普通特征点完全做不到的。

如果项目需要更高精度和更强的抗遮挡能力,可以考虑 AprilTag,它与 ArUco 类似但编码和检错机制不太一样,在特定机器人和无人机领域用得很多。不过 AprilTag 在 OpenCV 主仓库里没有直接集成,需要额外编译或安装第三方库,而对于绝大多数需求来说,OpenCV 内置的 ArUco 已经足够,这也是我选择它作为主方案的原因。

1.3 字典概念:为什么是 DICT_6X6_250

ArUco 提供了很多种预定义字典,常见的包括 DICT_4X4_50、DICT_5X5_100、DICT_6X6_250、DICT_ARUCO_ORIGINAL 等。命名里的第一个数字表示内部网格尺寸,比如 6x6 表示内部是 6 乘 6 的格子,第二个数字表示该字典最多可以表示的 ID 数量(如 250 表示可以编码 0 到 249 共 250 个不同标签)。

我默认会选择 DICT_6X6_250,原因是它在识别稳定性、视觉特征丰富度和 ID 容量之间找到了一个比较好的平衡点。4x4 的标签内部信息太少,稍微模糊一点就很容易误判;7x7 或更大的标签识别率确实高,但打印出来占用的面积也大,而且近距离观看时占据的像素更多,给画面中的其他目标留出的空间就少了。6x6 的标签在 1 米外、旋转 30 度的条件下,用普通 720p 摄像头实测依然能保持较高的识别成功率。

2. 环境准备与相机标定

2.1 OpenCV 的版本选择和 aruco 模块的坑

很多人在环境搭建这一步就卡住了。ArUco 模块在主 OpenCV 仓库里不存在,它在 opencv-contrib-python 这个扩展包里。也就是说,如果只安装普通的 opencv-python,你会得到一个“module ‘cv2’ has no attribute ‘aruco’”的报错。正确做法是卸载掉原来的 opencv-python,然后安装 opencv-contrib-python。

要注意的一点是,opencv-contrib-python 和 opencv-python 不能同时安装,否则会因为命名空间冲突导致各种诡异问题。安装命令很简单:

pip uninstall opencv-python opencv-contrib-python pip install opencv-contrib-python

如果你用的是 4.x 以上版本,直接import cv2然后cv2.aruco就能用了。还有一个小坑:不同版本的 aruco API 有些变化。比如 OpenCV 4.7 之前获取字典的写法是cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250),但在 OpenCV 4.7 之后推荐改成cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250)。两个写法在新版本里都能用,但老写法会有一条 DeprecationWarning。本文后面展示的代码我会用兼容性更好的写法,方便直接复制运行。

2.2 相机内参与畸变系数的标定方法

前面说过,ArUco 测距的前提是知道标签实际物理尺寸,还有一个同样重要的前提是相机的内参矩阵和畸变系数。内参矩阵主要包含焦距和光心坐标,畸变系数描述镜头成像时产生的桶形或枕形畸变。

如果你不做标定,直接用默认内参去解算位姿,结果会像戴着一副度数不对的眼镜看世界——距离和角度都会存在不可忽略的系统误差。实验室里最好用的方案是打印一张棋盘格标定板,用 OpenCV 自带的样例脚本去标定。你可以把这个过程理解成:让相机从不同角度拍下几十张棋盘格照片,程序通过已知的棋盘格角点世界坐标和图像坐标之间的对应关系,反向解算出相机内参。

这里给出一个最简化的相机标定流程:

  1. 用打印机输出一张棋盘格,推荐 9x6 的格子数量,贴在一个平整硬纸板上。
  2. 用待标定的相机从多个角度、多个距离拍摄 20 到 30 张照片,保证棋盘格在画面中清晰完整。
  3. 用 OpenCV 的 findChessboardCorners 提取每张图中的角点坐标。
  4. 调用 calibrateCamera 计算内参矩阵和畸变系数。
  5. 把结果保存到一个 numpy 文件里,后续程序直接加载。

代码方面我在第 3 部分里会再细化。如果你觉得标定麻烦,也可以用 OpenCV 提供的网络摄像头标定交互工具,但那个工具我在实际使用中感觉容易漏帧,还是自己写脚本更可控。

2.3 标定过程中的几个要点

标定棋盘格时有一个经常踩的坑:不要把标定板放在画面正中间拍一堆照片就结束了。因为照片如果都是同样的角度、同样的位置,解算出来的内参矩阵会很“偏科”,对靠近画面边缘的区域误差极大。正确做法是让标定板尽量出现在相机的各个角落,并且倾斜角度要有变化。距离也要拉开,从近到远都拍一些。

另一个要点是粘贴标定板的底板要绝对平整,稍微凹凸不平都会导致角点位置和理想坐标模型有偏差。我试过把棋盘格贴在快递纸箱上,结果标定出来焦距值偏得离谱,换了玻璃板和双面胶之后才恢复正常。

最后保存内参时建议单独存成文件,不要每次跑代码都重新标定一次。相机出厂后内参在相当长时间内是稳定的,除非拧过镜头焦距,否则一次标定可以用很久。

3. 核心代码实现:检测、测距、三维位置估算

3.1 单目测距和三维定位的几何原理

单目测距的本质是根据“已知物体尺寸 + 物体在图像中的像素尺寸”来反推深度,这是针孔相机模型下的一个经典计算。设标签真实边长为 L 米,在图像中检测到的像素边长是 p 像素,相机焦距为 f 像素,那么标签中心到相机的垂直深度 Z 约等于:

Z = f * L / p

这里得到的 Z 其实是沿相机光轴方向的距离,而不是“标签到相机镜头中心的直线距离”。如果标签正对着相机,两个值差不多;如果标签偏到了画面边缘,或者与相机光轴有大角度倾斜,直接用这个方法算出来的距离就会有偏差。更严谨的做法是用 solvePnP 解出完整位姿后,直接取平移向量的长度作为直线距离。

solvePnP 的中文是“解算 n 点透视问题”。它干的事情是:已知标签上四个角点在标签自身坐标系里的三维坐标(比如左上角为原点,(0,0,0)、(L,0,0)、(L,L,0)、(0,L,0)),再已知这四个角点在图像上的二维像素坐标,就能求出相机相对标签的平移向量 tvec 和旋转向量 rvec。平移向量 tvec 就是标签在相机坐标系下的三维位置,这正是我们要的“三维位置估算”。

3.2 图像采集与 ArUco 标签检测

接下来直接上代码。先写一个最基础的 ArUco 检测与 ID 识别脚本:

import cv2 import numpy as np # 兼容 OpenCV 4.7 前后版本 try: dictionary = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250) except AttributeError: dictionary = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) # 打开摄像头,0 表示默认摄像头 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) corners, ids, rejected = cv2.aruco.detectMarkers(gray, dictionary) if ids is not None: # 可视化标签边框和 ID cv2.aruco.drawDetectedMarkers(frame, corners, ids) cv2.putText(frame, f"Markers: {len(ids)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow("ArUco Detection", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

detectMarkers 函数的返回结构是:corners 里是每个检测到的标签的四个角点坐标,排序顺序是左上、右上、右下、左下;ids 是与 corners 一一对应的 ID 数组。实际开发时不需要自己写角点排序,这个顺序 OpenCV 已经固定了。

3.3 姿态估计与三维坐标计算

上面的代码只完成了“检测”,还没有做“位姿”。要输出三维位置和测距结果,需要把内参矩阵和畸变系数加载进来,然后调用 estimatePoseSingleMarkers。完整的示例代码如下:

import cv2 import numpy as np # 1. 加载标定结果 camera_data = np.load('camera_params.npz') camera_matrix = camera_data['mtx'] dist_coeffs = camera_data['dist'] # 2. 定义字典和真实边长 try: dictionary = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250) except AttributeError: dictionary = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) marker_length = 0.05 # 标签边长,单位:米 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) corners, ids, rejected = cv2.aruco.detectMarkers(gray, dictionary) if ids is not None: # 位姿估计 rvecs, tvecs, _ = cv2.aruco.estimatePoseSingleMarkers( corners, marker_length, camera_matrix, dist_coeffs) for i in range(len(ids)): rvec = rvecs[i] tvec = tvecs[i].flatten() # 画坐标轴,长度0.03表示画3厘米的轴 cv2.drawFrameAxes(frame, camera_matrix, dist_coeffs, rvec, tvec, 0.03) # 三维位置 x, y, z = tvec distance_m = np.linalg.norm(tvec) # 计算旋转角 rmat, _ = cv2.Rodrigues(rvec) euler = cv2.RQDecomp3x3(rmat)[0] yaw, pitch, roll = euler info = f"ID:{ids[i][0]} X:{x:.2f} Y:{y:.2f} Z:{z:.2f} dist:{distance_m:.2f}m" cv2.putText(frame, info, (10, 30 + i * 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow("ArUco Pose Estimation", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

这段代码输出的是 tvec 的三个分量和距离。tvec 的含义是“标签坐标系原点在相机坐标系下的三维坐标”,具体说就是以相机光心为原点,X 轴朝右,Y 轴朝下,Z 轴朝向相机正前方。所以如果我们把标签贴在物体正前方,tvec 的 Z 分量就是标签相对于相机的深度距离,dist 则是包含 XY 偏移在内的直线距离。

3.4 距离计算时该取 Z 还是取欧氏距离

这里有一个在实际工程里需要想清楚的问题:到底拿 tvec 的 Z 值当作距离,还是用 sqrt(X^2 + Y^2 + Z^2) 的欧氏距离?

如果标签基本在画面中央,两个值差距不大;如果标签跑到画面边缘,欧氏距离会比 Z 值大几个百分点。在机器人避障场景里,通常关心的是相机坐标系下 Z 轴的“前向距离”,此时取 Z 更合理,因为真正影响碰撞的是物体在运动方向上的投影距离。在机械臂抓取场景里,需要的是标签相对于机械臂末端的完整空间坐标,那就直接用 tvec 的 XYZ,不做降维处理。在需要做“两点间空间距离”判断时,才应该用欧氏距离。

所以在使用上不用死板,先想清楚应用场景要什么,再决定取哪个值。

3.5 批量生成 ArUco 标签

ArUco 标签必须打印出来贴在物体上。写一个批量生成标签的脚本很实用:

import cv2 import os try: dictionary = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250) except AttributeError: dictionary = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250) os.makedirs("aruco_tags", exist_ok=True) tag_size_px = 300 margin_size_px = 20 for tag_id in range(20): tag_image = cv2.aruco.generateImageMarker(dictionary, tag_id, tag_size_px, marginSize=margin_size_px) cv2.imwrite(f"aruco_tags/tag_{tag_id}.png", tag_image) print(f"Generated tag_{tag_id}.png")

实际打印时要注意把图片设置为“实际大小”不要缩放,否则打印出来的物理尺寸与 marker_length 不一致,测距结果就会偏。我一般会在打印后用尺子量一下黑色边框的外边缘,以实际测量值为准填入 marker_length,这一步能消除很多不必要的误差。

4. 实测效果与精度提升手段

4.1 一台普通摄像头能跑到什么程度

我用一个普通 720p 办公摄像头做过一组简单实验。标签打印成 5cm 宽,贴在纸箱上,相机从 0.5 米到 2.5 米每隔 0.1 米测一次。结果是这样的:1 米以内,距离误差基本在 1 到 2 厘米,相当准;1 到 2 米,误差在 3 到 5 厘米,还可以接受;2.5 米以上时,标签在画面里只占 30 到 40 个像素宽,角点检测精度开始下降,误差偶尔到 10 厘米以上。

这个结果说明 ArUco 单目测距的精度取决于标签在图像中的像素占比。如果想让 3 米外的目标也有较高测距精度,有三条路:一是换更高分辨率的摄像头,二是用更大尺寸的标签,三是让相机靠近目标。标签在图像中的像素宽度越大,角点定位的亚像素精度对最终位姿的影响就越小。

还测过标签旋转对结果的影响。标签正对相机时误差最小,倾斜超过 45 度后,识别率明显下降,解算出来的角度误差也会变大。这和 ArUco 的采样网格有关,标签越倾斜,透视变形越严重,内部格子的二值化结果就越容易出问题。如果项目需要大角度检测,建议多个标签配合使用,或者尽量保证相机视角与标签平面夹角不要太大。

4.2 提高精度的五个具体方向

单目视觉的精度上限不低,但能不能达到上限,取决于你有没有处理下面这五件事。

第一,亚像素角点优化。ArUco 检测到的角点是整数像素级别的,直接用这个结果做 solvePnP,精度还有提升空间。可以用 cornerSubPix 对角点坐标做亚像素精细化,输入检测到的原始角点,再加上终止条件,让角点位置收敛到亚像素精度。这个操作在近距离测距时能明显减小抖动。

第二,多帧滤波。单帧解算出来的距离会有些抖动,这在手持摄像头场景很常见。工程上最简单的办法是滑动窗口平均,或者用卡尔曼滤波做平滑。如果你的应用是机器人,后面接一个扩展卡尔曼滤波是非常自然的做法,能把距离波动控制在很小的范围。

第三,多标签融合。一个物体上贴多个 ArUco 标签,同时检测到多个标签后,把各自算出的位姿求平均,或者做加权融合,可以抵消单个标签因为角度偏差带来的系统性误差。这个在运动平台上的效果尤其明显。

第四,高分辨率图像与镜头选择。如果项目允许的话,尽量用 1280x720 甚至 1920x1080 的采集分辨率,同时在检测前做一次适当的图像预处理,比如高斯模糊去掉噪点、对比度增强让边缘更锐利。

第五,精确测量标签尺寸。这一步看似简单,但很多人随手在打印设置里填了个数字就开始用。正确的做法是打印后用游标卡尺量标签黑色边框的外边距,因为不同打印机的缩放比例不同,设置和实际尺寸常有零点几毫米的偏差,这几毫米的偏差在远距离测距时会被放大很多倍。

4.3 结合 RGB-D 相机做一个补充

如果手上只有普通单目相机,上面的方案就够用了。但如果项目有深度相机,比如 Intel RealSense 或奥比中光,可以把 ArUco 检测的结果和深度图对齐。具体做法是先用 ArUco 求出标签中心的像素坐标,然后在深度图对应位置取深度值,这样能拿到更稳的绝对距离。这种方案的好处是可以用深度传感器修正 ArUco 解算的 Z 值,同时又用 ArUco 给深度图一个语义身份标签,两者形成互补。

不过这里有个需要注意的地方:彩色图和深度图之间存在视差,必须先用 SDK 做对齐,否则从彩色图上得到的像素坐标直接去索引深度图,位置会偏差几十个像素。这一步在不同相机 SDK 里的叫法不一样,有的叫 align,有的叫 registration,本质是同一回事。

5. 踩坑记录:ArUco 使用中的常见问题与排查

5.1 检测不到标签或者识别率极低

遇到这种情况,先不要怀疑代码,按下面的顺序逐一排查:

  • 标签打印模糊、墨迹扩散导致黑白边界不清晰。解决方案是换打印机或把标签尺寸调大。
  • 标签在画面里太小。经验值是标签宽度至少占图像宽度的 3% 到 5%,比如 1280 像素宽的图像里,标签至少要有 40 到 60 像素宽。
  • 光线太强或太暗。ArUco 依赖二值化阈值,强反光或阴影都会破坏内部网格结构。这不意味着要在无影灯下使用,但需要注意让标签表面受光均匀。
  • 摄像头自动曝光和自动白平衡造成画面过曝。在固定光照环境下,建议手动固定相机的曝光和增益参数。

另外一个容易忽略的问题:误用了不匹配的字典。用 DICT_4X4_50 生成的标签,用 DICT_5X5_100 的字典去检测,肯定识别不出来。代码里生成和检测必须用同一个字典。

5.2 距离和位置数据一直抖动

如果标签静止不动,但屏幕上的距离数据一直在小幅跳动,这通常是角点检测的亚像素噪声导致的。可以先做滑窗平均:

from collections import deque import numpy as np distance_history = deque(maxlen=10) # 每次得到新的 distance 后 distance_history.append(distance_m) smoothed_distance = np.mean(distance_history)

注意滑窗大小不要过大,否则系统响应会变得很迟钝。对运动速度较快的目标,建议滑窗长度 5 到 10;对静止目标,可以放到 20 到 30。另一个思路是用卡尔曼滤波,代码会稍微复杂一点,但效果更好。它的核心思想是把上一帧的预测值和当前帧的观测值做一个权衡,权重由系统噪声和测量噪声决定,这样既平滑又不会过度滞后。

5.3 多个标签同时出现在画面里怎么处理

detectMarkers 天然支持一帧里检测多个标签,ids 数组的长度就是检测到标签的数量。工程上可以建立一个字典,把 ID 映射到具体的物理含义。比如 ID 0 表示“充电桩”,ID 1 表示“货架”,ID 2 表示“目标抓取点”。需要在代码里建立一个映射关系:

marker_map = { 0: "charging_station", 1: "shelf", 2: "grasp_point", }

这样程序里每个标签检测结果都能直接对应到业务语义,后续做路径规划或者决策处理就直观多了。当画面中同时出现多个标签时,可以加上去重逻辑,同一个 ID 在一帧里只处理一次。实际使用中很少发生一个 ID 被检测成另一个的情况,因为 ArUco 的字典带有校验能力,但如果标签太模糊,偶尔会出现误检,通过限制最小角点距离或使用更高精度字典可以减少这个问题。

5.4 标签 ID 混乱或者读错

读错 ID 的情况比较少见,但一旦出现就要警惕字典的纠错能力。ArUco 字典采用了类似汉明码的机制,允许一定数量的比特错误纠正。但如果标签本身模糊到内部网格都看不清,纠错也救不回来。此时建议:降低检测距离、增大标签尺寸、优化光照,并且可以在代码里统计每个 ID 的检测频率,对连续多帧出现且稳定的 ID 才认为有效,单帧偶发出现的 ID 直接丢弃。

5.5 运行环境下无法安装 OpenCV 的替代思路

这个坑主要出现在离线环境或特殊嵌入式平台上。如果没法安装 opencv-contrib-python,可以考虑用 ROS 环境下现成的 aruco 功能包,或者编译 OpenCV 时手动勾选 contrib 模块。不过无论哪种方式,本质上用的都是同一套底层算法。对于 Jetson Nano 这类 ARM 设备,pip 直接安装 opencv-contrib-python 通常也是可行的,只是需要注意选择匹配 Python 版本和系统架构的 wheel 包。

6. 延伸方向:从单站定位到更广的应用场景

走到这一步,你已经能拿到标签在相机坐标系下的三维位置和姿态了。这个信息可以直接用于很多有意思的项目:

如果你在做小车或无人机定位,可以把标签贴在固定位置作为“着陆点”或“充电桩”,相机识别之后通过 tvec 引导运动控制,实现自动对准和降落。此时要注意位姿解算的坐标系定义:tvec 是相机相对标签的位姿,如果要控制机器人移动,需要转换成机器人基座坐标系,中间通常还要做一次坐标变换。

如果你在做增强现实,ArUco 标签可以作为虚拟物体锚点,用 rvec 和 tvec 作为 OpenGL 或 Unity 的外参,直接在标签位置渲染 3D 模型。很多 AR 入门教程用二维码做,但其实 ArUco 更适合,因为它识别更快,姿态解算也更稳定。

如果你在做多传感器融合,可以把 ArUco 位姿作为视觉观测,配合轮式里程计或 IMU 做卡尔曼滤波融合。这样既解决了里程计漂移问题,又不会被视觉单帧遮挡彻底打断。这是我在实际项目里觉得最有价值的一个方向——视觉不是万能的,但当一个低成本的绝对定位源,它的性价比非常高。

我个人在实际操作中的体会是:ArUco 方案的学习曲线不算陡峭,真正花时间的反而是相机标定、坐标系转换和参数调试这些细节。这篇文章里给出的代码和参数我都在真实环境里跑过,如果你照着执行仍然遇到问题,不要犹豫,先从打印标签尺寸和相机内参入手检查,因为九成以上的异常最终都出在这两个地方。希望这套方案能帮你少走几步弯路。

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

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

立即咨询