Python之OpenCV相机标定

这篇具有很好参考价值的文章主要介绍了Python之OpenCV相机标定。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文结合OpenCV官方样例,对官方样例中的代码进行修改,使其能够正常运行,并对自己采集的数据进行实验和讲解。

一、准备

OpenCV使用棋盘格板进行标定,如下图所示。为了标定相机,我们需要输入一系列三维点和它们对应的二维图像点。在黑白相间的棋盘格上,二维图像点很容易通过角点检测找到。而对于真实世界中的三维点呢?由于我们采集中,是将相机放在一个地方,而将棋盘格定标板进行移动变换不同的位置,然后对其进行拍摄。所以我们需要知道(X,Y,Z)的值。但是简单来说,我们定义棋盘格所在平面为XY平面,即Z=0。对于定标板来说,我们可以知道棋盘格的方块尺寸,例如30mm,这样我们就可以把棋盘格上的角点坐标定义为(0,0,0),(30,0,0),(60,0,0),···,这个结果的单位是mm。

3D点称为object points,2D图像点称为image points。

getoptimalnewcameramatrix python,ML/CV,cv,opencv,python,Powered by 金山文档

棋盘格生成方法:《Python图像拼接之自定义生成棋盘格》

二、检测棋盘格角点

为了找到棋盘格模板,我们使用openCV中的函数cv2.findChessboardCorners()。我们也需要告诉程序我们使用的模板是什么规格的,例如8*8的棋盘格或者5*5棋盘格等,建议使用x方向和y方向个数不相等的棋盘格模板。下面实验中,我们使用的是10*7的棋盘格,每个方格边长是20mm,即含有9*6的内部角点。这个函数如果检测到模板,会返回对应的角点,并返回true。当然不一定所有的图像都能找到需要的模板,所以我们可以使用多幅图像进行定标。除了使用棋盘格,我们还可以使用圆点阵,对应的函数为cv2.findCirclesGrid()。

找到角点后,我们可以使用cv2.cornerSubPix()可以得到更为准确的角点像素坐标。我们也可以使用cv2.drawChessboardCorners()将角点绘制到图像上显示。如下图所示:

getoptimalnewcameramatrix python,ML/CV,cv,opencv,python,Powered by 金山文档

三、标定

通过上面的步骤,我们得到了用于标定的三维点和与其对应的图像上的二维点对。我们使用cv2.calibrateCamera()进行标定,这个函数会返回标定结果、相机的内参数矩阵、畸变系数、旋转矩阵和平移向量。

四、去畸变

第三步我们已经得到了相机内参和畸变系数,在将图像去畸变之前,我们还可以使用cv.getOptimalNewCameraMatrix()优化内参数和畸变系数,通过设定自由自由比例因子alpha。当alpha设为0的时候,将会返回一个剪裁过的将去畸变后不想要的像素去掉的内参数和畸变系数;当alpha设为1的时候,将会返回一个包含额外黑色像素点的内参数和畸变系数,并返回一个ROI用于将其剪裁掉。

然后我们就可以使用新得到的内参数矩阵和畸变系数对图像进行去畸变了。有两种方法进行去畸变:

(1)使用cv2.undistort()

这是一个最直接的办法,只用直接调用函数就可以得到去畸变的图像,使用上面的ROI可以对其进行剪裁。代码如下

# undistort
dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
 
# crop the image
x,y,w,h = roi
dst = dst[y:y+h, x:x+w]
cv2.imwrite('calibresult.png',dst)

下图显示将一张图片去畸变后,保留黑色像素的结果:

getoptimalnewcameramatrix python,ML/CV,cv,opencv,python,Powered by 金山文档

(2)使用remmaping

这是一个分两步的方法,首先计算一个从畸变图像到非畸变图像的映射,然后使用这个映射关系对图像进行去畸变。代码如下:

# undistort
mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
 
# crop the image
x,y,w,h = roi
dst = dst[y:y+h, x:x+w]
cv2.imwrite('calibresult.png',dst)

五、反投影误差

通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。

代码

所有步骤的代码如下所示:

#coding:utf-8
import cv2
import numpy as np
import glob
 
# 找棋盘格角点
# 阈值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
#棋盘格模板规格
w = 9
h = 6
# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵
objp = np.zeros((w*h,3), np.float32)
objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2)
# 储存棋盘格角点的世界坐标和图像坐标对
objpoints = [] # 在世界坐标系中的三维点
imgpoints = [] # 在图像平面的二维点
 
images = glob.glob('calib/*.png')
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 找到棋盘格角点
    ret, corners = cv2.findChessboardCorners(gray, (w,h),None)
    # 如果找到足够点对,将其存储起来
    if ret == True:
        cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        objpoints.append(objp)
        imgpoints.append(corners)
        # 将角点在图像上显示
        cv2.drawChessboardCorners(img, (w,h), corners, ret)
        cv2.imshow('findCorners',img)
        cv2.waitKey(1)
cv2.destroyAllWindows()
 
# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
 
# 去畸变
img2 = cv2.imread('calib/00169.png')
h,  w = img2.shape[:2]
newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),0,(w,h)) # 自由比例参数
dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)
# 根据前面ROI区域裁剪图片
#x,y,w,h = roi
#dst = dst[y:y+h, x:x+w]
cv2.imwrite('calibresult.png',dst)
 
# 反投影误差
total_error = 0
for i in xrange(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
    total_error += error
print "total error: ", total_error/len(objpoints)

自标定所有步骤连起来,标定自动化就完成了。

在这个过程中,你是否发现不经意又收到了平坦区域合并的算法,他实质是穿越点的界定的变化,这样,在二维平面上,当行列被自动界定(分割),则另一个好处是,平面任意平坦区域(高斯区域,变化不大区域,模糊区域)尽在掌握,这便开启了模糊匹配的想法。

在这个过程中,你还收获了行列list(序列)是如何归一化的算法,因为你可能收不到harris角点,某行某列,以及多收和干扰。

当你通透了SIFT(scale-invariant feature transform,还未代码实现),你会发现,这个实质是利用了hariss角点的分布为特征在做文章(实现匹配),SIFT只不过是把二维的harris角点映射到了三维空间。learning opencv的光流跟踪算法也就不在话下了,他除了可以跟踪光流,还可以求harris角点,这种二维矩阵运算的推导,实质是最小二乘法变化(换了个面孔),我们也推导和证明了结果相同。补充一句,SIFT的三维矩阵运算推导实质是光流二维矩阵运算的推导的扩展(算法已经证明),而一维则是泰勒展开多项式逼近。(在此,你就会知道吴恩达在机器学习(斯坦福大学课程)中为什么会那么重视矩阵形式的运算推导了)

在你回顾了这些数学知识后,你忽然发现learning opencv的光流推导有一个符号错误,在一维时,偏导数(不存在这种叫法)与微分相同,二维时,即隐函数微分法求出的结果是微分而不是偏导数,而learning opencv却写成了偏导符号。

以上说明,你就可以看到标定求harris角点在人工智能(AI)天空所喷薄而出的光芒,而你不去发觉这机器视觉中已经慢慢隐藏于硬件的标定,你如何能激活人工智能(AI)时代的自己。

————————————————

完整的

import cv2
import numpy as np
import glob

# 找棋盘格角点
# 阈值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 棋盘格模板规格
# 内角点个数,内角点是和其他格子连着的点
w = 9
h = 6
# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵
objp = np.zeros((w * h, 3), np.float32)
objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)
# 储存棋盘格角点的世界坐标和图像坐标对
objpoints = []  # 在世界坐标系中的三维点
imgpoints = []  # 在图像平面的二维点

images = glob.glob('image/*.jpg')
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 找到棋盘格角点
    # 棋盘图像(8位灰度或彩色图像)  棋盘尺寸  存放角点的位置
    ret, corners = cv2.findChessboardCorners(gray, (w, h), None)
    # 如果找到足够点对,将其存储起来
    if ret == True:
        # 角点精确检测
        # 输入图像 角点初始坐标 搜索窗口为2*winsize+1 死区 求角点的迭代终止条件
        cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        objpoints.append(objp)
        imgpoints.append(corners)
        # 将角点在图像上显示
        cv2.drawChessboardCorners(img, (w, h), corners, ret)
        cv2.imshow('findCorners', img)
        cv2.waitKey(1000)
cv2.destroyAllWindows()
# 标定、去畸变
# 输入:世界坐标系里的位置 像素坐标 图像的像素尺寸大小 3*3矩阵,相机内参数矩阵 畸变矩阵
# 输出:标定结果 相机的内参数矩阵 畸变系数 旋转矩阵 平移向量
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
# mtx:内参数矩阵
# dist:畸变系数
# rvecs:旋转向量 (外参数)
# tvecs :平移向量 (外参数)
print(("ret:"), ret)
print(("mtx:\n"), mtx)  # 内参数矩阵
print(("dist:\n"), dist)  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print(("rvecs:\n"), rvecs)  # 旋转向量  # 外参数
print(("tvecs:\n"), tvecs)  # 平移向量  # 外参数
# 去畸变
img2 = cv2.imread('image/6.jpg')
h, w = img2.shape[:2]
# 我们已经得到了相机内参和畸变系数,在将图像去畸变之前,
# 我们还可以使用cv.getOptimalNewCameraMatrix()优化内参数和畸变系数,
# 通过设定自由自由比例因子alpha。当alpha设为0的时候,
# 将会返回一个剪裁过的将去畸变后不想要的像素去掉的内参数和畸变系数;
# 当alpha设为1的时候,将会返回一个包含额外黑色像素点的内参数和畸变系数,并返回一个ROI用于将其剪裁掉
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 0, (w, h))  # 自由比例参数

dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)
# 根据前面ROI区域裁剪图片
x, y, w, h = roi
dst = dst[y:y + h, x:x + w]
cv2.imwrite('image/6_calibresult.jpg', dst)

# 反投影误差
# 通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。
# 通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,
# 然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。
total_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    total_error += error
print(("total error: "), total_error / len(objpoints))

矫正后图像的缩放ROI

https://blog.csdn.net/yghjkliikk/article/details/110070315文章来源地址https://www.toymoban.com/news/detail-770504.html

到了这里,关于Python之OpenCV相机标定的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python OpenCV 单目相机标定、坐标转换相关代码(包括鱼眼相机)

      本文不讲原理,只关注代码,有很多博客是讲原理的,但是代码最多到畸变矫正就结束了,实际上就是到 OpenCV 官方示例涉及的部分。   在官方示例中使用黑白棋盘格求解了相机的内外参和畸变系数,并对图像做了畸变矫正,但在实际使用时还缺少很多功能,以下是本

    2024年02月02日
    浏览(33)
  • OpenCV-Python相机标定:Camera Calibration

    在使用相机拍照片时,大多数人会考虑拍的好不好看,关注相机中物体坐标的并不多,但是对于地信学科来说,如果能从照片中获取物体的真实位置,对地理信息获取大有帮助,在这里面,十分关键的一步就是相机标定。 相机标定的基本原理也是相对简单的,看官网中的一个

    2024年02月09日
    浏览(58)
  • 使用opencv-python(cv2)库进行相机标定

    2023年09月11日
    浏览(53)
  • python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)

    今天的低价单孔摄像机(照相机)会给图像带来很多畸变。畸变主要有两 种:径向畸变和切想畸变。如下图所示,用红色直线将棋盘的两个边标注出来, 但是你会发现棋盘的边界并不和红线重合。所有我们认为应该是直线的也都凸 出来了。 在 3D 相关应用中,必须要先校正这些畸变

    2024年02月06日
    浏览(49)
  • 机械臂手眼标定ZED相机——眼在手外python、matlab

    目录 1.眼在手外原理 2.附上眼在手外求得手眼矩阵的python代码 3.眼在手外标定步骤 1)打印棋盘格 2)得到hand数据 3)得到camera数据 4.运行python得到手眼矩阵   眼在手外所求的手眼矩阵是基坐标到相机的转换矩阵 其中:         hand为基坐标系下抓夹的位姿,一般从示教器

    2024年02月11日
    浏览(31)
  • 相机标定-机器视觉基础(理论推导、Halcon和OpenCV相机标定)

             相机标定是获得目标工件精准坐标信息的基础。首先,必须进行相机内参标定,构建一个模型消除图像畸变;其次,需要对相机和机器人的映射关系进行手眼标定,构建一个模型将图像坐标系上的点映射到世界坐标系。主要分为背景知识、相机内外参模型推导、

    2023年04月21日
    浏览(46)
  • python 手眼标定OpenCV手眼标定(calibrateHandeye())二

    这一章我们来根据上一章的分析,为手眼标定函数calibrateHandEye 准备他那些麻烦的参数 更详细的参数参考链接 即R_all_end_to_base_1,T_all_end_to_base_1, 我们可用通过输入的机械臂提供的6组参数得到,3个位姿与3个欧拉角 示例代码 这里是关系是 通过 cv2.findChessboardCorners 角点查找函数

    2024年02月01日
    浏览(35)
  • python 手眼标定OpenCV手眼标定(calibrateHandeye())一

    以下代码来源 本篇博客通过该代码,附上记录的公式与查找连接,方面以后调用能弄懂各个参数的意思 本篇看完看第二篇代码踩坑部分python 手眼标定OpenCV手眼标定(calibrateHandeye())二 相机标定原理视频介绍 calibrateHandeye() 参数描述如下:R_gripper2base,t_gripper2base是机械臂抓手

    2024年02月15日
    浏览(41)
  • 用OpenCV进行相机标定(张正友标定,有代码)

    理论部分可以参考其他博客或者视觉slam十四讲 相机标定主要是为了获得相机的内参矩阵K和畸变参数 内参矩阵K 畸变系数:径向畸变(k1,k2,k3), 切向畸变(p1,p2) 径向畸变公式 切向畸变公式 张正友标定方法能够提供一个比较好的初始解,用于后序的最优化. 这里用棋盘格进行标定,如

    2024年02月07日
    浏览(39)
  • OpenCV中的相机标定

          之前在https://blog.csdn.net/fengbingchun/article/details/130039337 中介绍了相机的内参和外参,这里通过OpenCV中的接口实现对内参和外参的求解。       估计相机参数的过程称为相机标定(camera calibration)。相机标定是使用已知的真实世界模式(例如棋盘)来估计相机镜头和传感器的外

    2023年04月19日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包