第二章 相机选型与标定:工业相机分类与选型、镜头参数与选型、相机标定原理与实战(张正友标定法)

各位同学,咱们今天聊点硬核的。相机选型与标定,说白了就是给贴片机装上一双「看得准」的眼睛。我做了这么多年自动化设备,见过太多因为相机没选好、标定没做对,导致整条产线报废的案例。嗯,咱们一步步来。

2.1 工业相机分类与选型

工业相机,不是咱们手机上的摄像头。它要扛得住产线上的震动、灰尘、温度变化。我个人习惯把工业相机分成三大类:

  • CCD相机:成像质量高,噪声低,适合高精度视觉引导。缺点是贵,帧率一般。
  • CMOS相机:功耗低,帧率高,现在技术成熟了,很多贴片机都在用。性价比不错。
  • 线阵相机:适合检测连续移动的物体,比如PCB板在传送带上跑,线阵相机一行一行扫过去。

选型时,我建议你重点关注这几个参数:

参数 说明 贴片机场景建议
分辨率 像素数量,比如500万、1200万 贴片机一般500万~1200万够用,太高了数据量大,处理慢
帧率 每秒采集多少帧图像 高速贴片机需要30fps以上,低速的15fps也行
靶面尺寸 感光芯片的物理大小,常见1/1.8英寸、2/3英寸 靶面越大,视野越大,但镜头也要匹配
接口 USB3.0、GigE、Camera Link等 GigE最常用,传输距离远,抗干扰好
我的经验: 选相机时别只看分辨率。我在一个项目里吃过亏,选了1200万像素的相机,结果帧率只有10fps,贴片机一加速就丢帧。后来换了500万像素、60fps的CMOS相机,反而更稳。记住:贴片机要的是「快」和「准」,不是「大」。

2.2 镜头参数与选型

镜头是相机的「眼镜」。选错了镜头,再好的相机也白搭。你想想看,镜头决定了两件事:看得多宽看得多清楚

核心参数有这些:

  • 焦距:比如8mm、12mm、25mm。焦距越短,视野越宽;焦距越长,看得越远越清楚。
  • 光圈:用F值表示,F值越小光圈越大,进光量越多。但光圈太大,景深会变浅。
  • 景深:能清晰成像的深度范围。贴片机里,元件高度不一,景深太浅会导致边缘模糊。
  • 畸变:镜头带来的图像变形。普通镜头有桶形畸变或枕形畸变,高精度场景要用远心镜头。
选型口诀(我自己总结的):
视野决定焦距,精度决定分辨率,景深决定光圈,畸变决定镜头类型。

举个例子:你要检测一个20mm×20mm的PCB区域,精度要求0.01mm。那相机分辨率至少需要2000像素×2000像素,也就是400万像素。镜头焦距怎么算?用公式:焦距 = 工作距离 × 靶面尺寸 / 视野。假设工作距离100mm,靶面尺寸6.4mm(1/1.8英寸),视野20mm,那焦距就是32mm。嗯,选个35mm的镜头就差不多。

避坑指南: 我曾经在一个项目里用了普通CCTV镜头做高精度定位,结果边缘畸变达到0.5%,定位误差直接超了。后来换了远心镜头,畸变控制在0.02%以内,问题才解决。所以,精度要求高的场景,别省镜头的钱。

2.3 相机标定原理与实战(张正友标定法)

相机标定,说白了就是告诉电脑:「你看到的图像和真实世界之间,差了多少?」。没有标定,你测出来的坐标全是错的。

张正友标定法是目前最主流的标定方法。它的核心思想是:拍一张棋盘格,然后算。为什么用棋盘格?因为棋盘格的角点(黑白格子交界处)很容易被算法检测到,而且位置关系是已知的。

2.3.1 标定的数学原理(简单版)

相机成像可以简化成三步:

  1. 世界坐标系相机坐标系(旋转+平移,这叫外参)
  2. 相机坐标系图像坐标系(透视投影,这叫内参)
  3. 图像坐标系像素坐标系(缩放+偏移)

标定要算的就是:内参矩阵(焦距、主点坐标、畸变系数)和外参矩阵(相机相对于标定板的位置)。

张正友标定法的巧妙之处在于:它只需要你从不同角度拍几张棋盘格照片,然后通过数学推导,把内参和外参一起解出来。不需要知道标定板的精确三维位置,省事很多。

2.3.2 实战步骤

我带你走一遍完整的标定流程。这是我做过的项目里最常用的方法:

  1. 准备标定板:打印一张棋盘格,格子大小要精确测量(比如每个格子5mm×5mm)。贴在平整的板上。
  2. 采集图像:从不同角度拍10~20张照片。注意:角度要多样,有倾斜、有旋转、有远近。我习惯拍15张左右,太少精度不够,太多浪费时间。
  3. 检测角点:用OpenCV的cv2.findChessboardCorners()找到所有角点。
  4. 标定计算:调用cv2.calibrateCamera(),输入角点坐标和真实世界坐标,得到内参和畸变系数。
  5. 评估结果:看重投影误差,一般小于0.5像素就算合格。

代码示例(Python + OpenCV):

import cv2
import numpy as np
import glob

# 棋盘格参数
chessboard_size = (9, 6)  # 内角点数量
square_size = 5.0  # 格子大小,单位mm

# 准备真实世界坐标
objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)
objp *= square_size

# 存储所有图片的角点
objpoints = []  # 真实世界坐标
imgpoints = []  # 图像坐标

images = glob.glob('calib_images/*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 检测角点
    ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
    
    if ret:
        objpoints.append(objp)
        imgpoints.append(corners)
        
        # 可视化角点
        cv2.drawChessboardCorners(img, chessboard_size, corners, ret)
        cv2.imshow('img', img)
        cv2.waitKey(500)

cv2.destroyAllWindows()

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
    objpoints, imgpoints, gray.shape[::-1], None, None
)

print("内参矩阵:\n", mtx)
print("畸变系数:\n", dist)
print("重投影误差:", ret)
我的实战经验: 标定的时候,记得把标定板放平。我遇到过新手把标定板贴在弯曲的纸板上,结果标定出来的畸变系数全是错的。还有,拍照时不要只拍正对着的,多拍一些倾斜角度,这样标定出来的结果更鲁棒。

2.3.3 标定结果怎么用?

标定完,你得到了内参矩阵和畸变系数。接下来要做两件事:

  • 畸变校正:用cv2.undistort()把每帧图像校正,消除镜头畸变。
  • 坐标转换:把图像上的像素坐标,通过内参和外参,转换成真实世界的物理坐标。这样贴片机才知道元件该往哪里放。

举个例子:你在图像上检测到一个元件的中心在(320, 240)像素位置,经过标定转换后,得到它在世界坐标系中的位置是(12.5mm, 8.3mm)。贴片机的吸嘴就根据这个坐标去抓取和放置。

注意: 标定不是一劳永逸的。相机如果被碰过、镜头重新调过焦距、或者温度变化太大,都需要重新标定。我建议每次设备维护后都做一次标定,花不了几分钟,但能避免很多定位问题。

2.4 知识体系总览

下面这张图,是我自己画的相机选型与标定的知识体系。你看一眼,心里就有数了:

相机选型与标定知识体系 工业相机选型 CCD / CMOS 线阵相机 分辨率 帧率 靶面尺寸 接口类型 镜头选型 焦距 光圈/景深 畸变控制 远心镜头 相机标定 张正友法 棋盘格 内参矩阵 畸变系数 外参矩阵 重投影误差 核心目标:让贴片机「看得准、放得稳」

嗯,这张图把咱们今天讲的内容串起来了。相机选型、镜头选型、相机标定,这三件事是环环相扣的。选错了相机,标定再准也没用;标定没做好,再好的相机也是白搭。

最后说一句:做视觉引导定位,别怕花时间在标定上。我见过太多工程师急着调算法,结果定位不准,回头才发现是标定没做对。磨刀不误砍柴工,标定这一步,值得你认真对待。


公众号:蓝海资料掘金营,微信deep3321