当前位置: 首页 > news >正文

【python】Printable ChArUco Board

文章目录

  • 用 A4 纸打印一张「尺寸准确、远处也能识别」的 ChArUco 标定板
  • 一、先搞清楚:ChArUco 是什么,两个尺寸参数指什么
  • 二、最简单的生成(OpenCV)
  • 三、三个打印大坑
    • 坑 1:打印机自动缩放
    • 坑 2:PDF 的物理页面尺寸在生成时就被写错
    • 坑 3:分辨率太高,页面比纸大,选 100% 只印出中心一小块
  • 四、稳妥解法:让物理尺寸和像素分辨率彻底解耦
  • 五、关键一步:按相机内参反推「多远能识别到」
  • 六、按需定尺寸:把板子放大到铺满 A4
  • 七、两个必须记住的一致性要点
  • 八、小结

用 A4 纸打印一张「尺寸准确、远处也能识别」的 ChArUco 标定板

做相机标定时,很多人第一步就翻车:随手生成一张 ChArUco 板、丢给打印机、拿尺子一量——方格既不是设定的尺寸,摆远一点相机还识别不到。本文把从「生成」到「打印物理尺寸准确」再到「按相机内参反推识别距离」的完整方法整理出来,附可直接运行的脚本。整体路线如下:

距离处太小则回头放大板子

① 生成 ChArUco 图像
OpenCV cv2.aruco

② 打印物理尺寸准确
reportlab 锁毫米 + 实际大小 100%

③ 按相机内参反推识别距离
像素 = f × M / D


一、先搞清楚:ChArUco 是什么,两个尺寸参数指什么

ChArUco 板是棋盘格(Chessboard)+ ArUco 标记的组合:棋盘格的黑白角点提供亚像素级的精确定位,嵌在白格里的 ArUco 标记则用来识别板子朝向、定位当前可见的是哪些棋盘格角点,从而给每个角点一个全局唯一编号。即使标定板被部分遮挡,靠编号也能识别出剩余角点,比纯棋盘格鲁棒得多。

生成时有两个关键尺寸:

  • Square Length(方格边长):棋盘格一个方格的边长。
  • Marker Length(标记边长):嵌在白格里的 ArUco 标记的边长,必须小于Square Length,四周留出白边,检测才稳。

两者常见比例约为Marker ≈ 0.7 ~ 0.75 × Square


二、最简单的生成(OpenCV)

OpenCV 的cv2.aruco模块直接能生成。注意CharucoBoard的尺寸参数在生成图像阶段是像素,物理尺寸由打印环节决定:

importcv2fromcv2importaruco# (cols, rows) = (5, 7),即 5 列 7 行aruco_dict=aruco.getPredefinedDictionary(aruco.DICT_6X6_250)board=aruco.CharucoBoard((5,7),squareLength=200,markerLength=150,dictionary=aruco_dict)img=board.generateImage((1000,1400))# 输出像素尺寸cv2.imwrite('charuco.png',img)

到这里你会拿到一张图。但真正的坑在打印


三、三个打印大坑

坑 1:打印机自动缩放

直接把图片丢进打印预览,默认往往是「适应纸张」——它会把图按纸张大小缩放,你设定的 25mm 方格印出来可能变成 40mm。打印时必须选「实际大小 / 100%」,关掉任何「适应纸张 / 自动缩放」。

坑 2:PDF 的物理页面尺寸在生成时就被写错

先厘清一个常见误解:PDF 的页面物理尺寸是绝对写死在文件里的(MediaBox,单位是 point = 1/72 英寸),阅读器不会、也无需用 DPI 去"猜"页面多大。所以如果打印对话框里显示的尺寸不对,错误不是阅读器"解读"出来的,而是生成阶段就烤进了文件

实测就踩了这个坑:我用 PIL 把图存成 PDF 并写了dpi=(96,96),本以为得到一张 A4(21×29.7cm),结果打印对话框显示成了 28×39.6cm。原因是Pillow 的 PDF 导出在不少版本里并不真正采用这个dpi参数、而是回落到 72 DPI:于是 793px 的图被当作793 ÷ 72 × 25.4 = 279.7mm ≈ 28cm写进了页面宽度(高度 1122px →1122 ÷ 72 × 25.4 ≈ 39.6cm,两个维度都指向 72 DPI 生成)。阅读器只是忠实显示了这个被写错的尺寸。

根因:把「物理尺寸」隐式地绑定在「图像像素 + DPI 元数据」上,而这条 DPI 通路(尤其 PIL 存 PDF)不可靠——它悄悄回落到 72 时,物理尺寸就整个错位。

坑 3:分辨率太高,页面比纸大,选 100% 只印出中心一小块

如果直接用 300 DPI 生成整页图(2480×3508px),有些阅读器会把它当成一张超大纸,选「实际大小」时只印出页面中心的一小块。


四、稳妥解法:让物理尺寸和像素分辨率彻底解耦

三个坑各自对应的解法,可以先看这张对应关系图——坑 1 靠打印设置,坑 2/坑 3 靠 reportlab,两者合起来才拿到正确的物理尺寸:

坑1 打印机自动缩放

打印选「实际大小 / 100%」

坑2 PDF 物理尺寸生成时写错
PIL 回落 72 DPI

reportlab 按物理毫米摆到 A4
物理尺寸与像素解耦

坑3 分辨率过高
100% 只印中心一小块

尺子量方格 = 40mm ✓

思路:不要靠 DPI 元数据传递物理尺寸。改用reportlab建一张真正的 A4 画布,把棋盘图像按物理毫米精确摆放上去。这样图像分辨率只决定清晰度,物理尺寸由「毫米坐标」直接锁死,打印选「实际大小」就一定准。

importcv2fromcv2importarucofromreportlab.lib.pagesizesimportA4fromreportlab.lib.unitsimportmmfromreportlab.pdfgenimportcanvasfromreportlab.lib.utilsimportImageReaderfromPILimportImage# ===== 目标物理尺寸 =====COLS,ROWS=5,7SQUARE_MM=40.0MARKER_MM=30.0# ===== 生成高分辨率棋盘图像(分辨率只影响清晰度)=====render_dpi=300px_per_mm=render_dpi/25.4square_px=round(SQUARE_MM*px_per_mm)marker_px=round(MARKER_MM*px_per_mm)aruco_dict=aruco.getPredefinedDictionary(aruco.DICT_6X6_250)board=aruco.CharucoBoard((COLS,ROWS),squareLength=square_px,markerLength=marker_px,dictionary=aruco_dict)img=board.generateImage((COLS*square_px,ROWS*square_px),marginSize=0)img_pil=Image.fromarray(img)# ===== reportlab 在 A4 上按物理毫米精确放置、居中 =====board_w_mm=COLS*SQUARE_MM# 200 mmboard_h_mm=ROWS*SQUARE_MM# 280 mmpage_w,page_h=A4# 210 x 297 mm(单位 point)x=(page_w-board_w_mm*mm)/2y=(page_h-board_h_mm*mm)/2c=canvas.Canvas('charuco_A4.pdf',pagesize=A4)c.drawImage(ImageReader(img_pil),x,y,width=board_w_mm*mm,height=board_h_mm*mm)c.showPage()c.save()

打印这张charuco_A4.pdf,选「实际大小 / 100%」,拿尺子量方格——就是 40mm。之所以能根治,正是因为 reportlab 绕开了 PIL 那条不可靠的 DPI 通路,直接把正确的物理尺寸写进 A4 页面的 MediaBox。

这里generateImage(..., marginSize=0)让棋盘外不留白边是安全的,因为 reportlab 把它居中放在整张白色 A4 上、四周自然留出了空白(ArUco 检测所需的静默区 quiet zone 就来自这片空白)。但如果你改成贴边打印、或把图裁到刚好只剩棋盘,就会丢掉这圈静默区导致检测变差——那种场景要显式保留 margin。

五、关键一步:按相机内参反推「多远能识别到」

尺寸准了还不够。我遇到的真实问题是:25mm/18mm 的小板子,摆到 50cm 处相机就识别不到了。要不要放大、放多大,不能凭感觉,要用相机内参算

针孔模型下,一个物理尺寸为M(米)的物体,在距离D(米)处成像的像素大小为:

像素 = f × M / D

其中f是相机焦距(像素)。这是物体正对相机、且fx ≈ fy前提下的量级估算(用于判断"够不够大"足矣,不必当作图像边缘、大畸变区的精确值)。以我的相机为例(一组双目标定得到 f = 1459 px,单目分辨率 1520×1520):

物理尺寸50cm 处成像
Square 25mm1459 × 0.025 / 0.5 ≈ 73 px
Marker 18mm1459 × 0.018 / 0.5 ≈ 52 px

一个 DICT_6X6 的 ArUco,加上四周边框共8 个模块。52px 的 marker 意味着每个模块只有52 / 8 ≈ 6.5 px——稍有离焦、运动模糊或斜视角,检测就崩了。这正是「50cm 看不见」的原因。

经验上,ArUco marker 的成像至少要几十像素、每模块 ≥ 3~4px 才比较稳;越大越好。

六、按需定尺寸:把板子放大到铺满 A4

要让 marker 在 50cm 处翻倍到 ~88px,反推物理尺寸并考虑 A4 上限。A4 竖版放 5×7,单格上限是min(210/5, 297/7) ≈ 42mm。取Square 40mm / Marker 30mm(留边距),重新算各距离:

距离Square (40mm)Marker (30mm)
0.3m195 px146 px
0.5m117 px88 px
0.8m73 px55 px
1.0m58 px44 px

50cm 处 marker 从 52px 提到 88px,检测就稳了。这也是单张 A4 的物理极限

如果还需要更大(比如要在 1m 处稳),单张 A4 已到头,只能:

  • 减少格数(如 4×6),单格可到 ~48mm;
  • 换 A3 纸,单格可到 ~57mm;
  • 换更粗的字典(DICT_5X5 或 DICT_4X4):同样的 marker 物理尺寸下模块更少、每模块更大,更抗距离和模糊。代价是可编码的 marker 数量更少、码间汉明距离更小、抗误检能力略降——对 5×7 这种小板无妨,但大板或多板场景要留意;另外检测代码里的字典也要同步改。

七、两个必须记住的一致性要点

  1. 打印务必选「实际大小 / 100%」,否则前面所有物理尺寸的努力全白费。打印后用尺子实测方格边长核对。
  2. 改了标定板的物理尺寸,标定代码里的squareLength/markerLength必须同步改成对应的米数(如 0.040 / 0.030)。这两个值决定了标定出来的尺度——它们错了,相机外参的平移量、以及基于视差换算的深度都会整体缩放错。注意区分:标定板的物理尺寸不影响相机内参(内参是像素单位、与标定板实际多大无关,写错也照样能标出正确的 fx/fy/畸变);它只影响外参平移量和度量深度。正因为内参不受影响,这个错误特别隐蔽——重投影误差看起来正常,只有最终的距离/尺度整体偏了。

八、小结

  • ChArUco = 棋盘格 + ArUco,Marker 要小于 Square 并留白边。
  • 打印翻车三连:自动缩放、PDF 生成时物理页面尺寸被写错(PIL 回落 72 DPI)、分辨率过高只印中心。
  • 稳妥解法:用 reportlab 把图按物理毫米摆到 A4 画布上,物理尺寸与像素解耦,打印选「实际大小」。
  • 尺寸够不够,用像素 = f × M / D按相机内参算,别凭感觉。
  • 物理尺寸、打印缩放、标定代码里的参数,三处必须一致。
http://www.jsqmd.com/news/1105643/

相关文章:

  • Burp Suite自定义SQL注入扫描插件开发实战指南
  • 团队代码规范落地难?用Inspect Code自动拦截87%低级缺陷——附可即插即用的Enterprise Rule Set
  • 基于OpenVAS构建企业级自动化漏洞扫描体系:从架构设计到安全运营
  • 终极指南:如何用Resynthesizer插件实现GIMP智能图像修复与纹理合成
  • 终极指南:掌握Juicebox进行Hi-C数据可视化与三维基因组分析
  • HackBar插件实战指南:Web安全手工测试利器详解
  • 基于Si4732与PIC18F86J16的数字收音机硬件设计
  • 从AES到国密:加密算法实战实现、性能对比与安全避坑指南
  • [论文学习]LLM 代理的隐私黑洞:外部存储个人数据的提示注入攻击基准测试深度解读
  • TVBoxOSC电视盒子全能播放器:3步打造家庭影院级观影体验
  • Sunshine游戏串流主机:打造你的终极跨平台游戏云端
  • JSP页面HTML注释泄露敏感信息:原理、危害与修复方案
  • 分布式事务反直觉坑:两阶段提交也不是银弹
  • 错过这6个SonarLint高级技巧,你在IDEA里写的每行代码都可能成为生产事故源头——资深架构师20年代码治理血泪总结
  • WechatAPI 高并发自动化系统的性能边界究竟在哪?
  • 合规发票管理系统·商业应用(28)—东方仙盟练气期
  • 英雄联盟回放分析神器:ROFLPlayer完整指南与实战技巧
  • 如何快速配置XUnity.AutoTranslator:Unity游戏自动翻译工具的完整使用指南
  • GPT-4 Turbo技术解析与工程调优实战指南
  • 3分钟彻底解决NCM音乐格式限制:NcmpGui极速转换工具完整指南
  • 【案例】角色智能体“小真”3D重建:张雪摩托车(由一张图重建成3D模型)
  • 从零开始:5步掌握ComfyUI-WanVideoWrapper AI视频生成
  • GPT-4稀疏激活真相:2%参数背后的硬件约束与工程实践
  • Topit:告别窗口切换烦恼,让你的Mac窗口永远在最前面
  • SRC漏洞挖掘实战指南:从零入门到独立提交安全漏洞
  • Deepseek V4实测:长上下文推理与中文逻辑严谨性深度解析
  • 不锈钢防火玻璃门现行全套新国标(2026强制执行版)
  • 构建高效移动端调试流程:以WebDebugX为核心的工具链与实战
  • 仿生学赋能结构热设计:从莲藕到叶脉,自然智慧如何重塑散热科技
  • Appium自动化测试从入门到精通:环境搭建、元素定位与框架构建实战指南