相机标定的原理及实现

相机标定的原理及实现本文参考文档:原理部分:https://blog.csdn.net/honyniu/article/details/51004397代码部分:https://www.cnblogs.com/wildbloom/p/8320351.html;https://blog.csdn.net/firemicrocosm/article/details/48594897#1、相机标定的原理摄像…

大家好,又见面了,我是你们的朋友全栈君。

本文参考文档:
原理部分:https://blog.csdn.net/honyniu/article/details/51004397
代码部分:https://www.cnblogs.com/wildbloom/p/8320351.html ;https://blog.csdn.net/firemicrocosm/article/details/48594897#

1、相机标定的原理

摄像机标定(Camera calibration)简单来说是从世界坐标系转换为相机坐标系,再由相机坐标系转换为图像坐标系的过程,也就是求最终的投影矩阵P的过程。

世界坐标系(world coordinate system):用户定义的三维世界的坐标系,为了描述目标物在真实世界里的位置而被引入。单位为m。

相机坐标系(camera coordinate system):在相机上建立的坐标系,为了从相机的角度描述物体位置而定义,作为沟通世界坐标系和图像/像素坐标系的中间一环。单位为m。

图像坐标系(image coordinate system):为了描述成像过程中物体从相机坐标系到图像坐标系的投影透射关系而引入,方便进一步得到像素坐标系下的坐标。 单位为m。

从世界坐标系到相机坐标系:

这一步是三维点到三维点的转换,包括R,t(相机外参)等参数;
在这里插入图片描述

相机坐标系转换为图像坐标系:

这一步是三维点到二维点的转换,包括K(相机内参)等参数;在这里插入图片描述
在这里插入图片描述
根据上述的关系图可以推导出下面的变换公式:
在这里插入图片描述在这里插入图片描述

像主点的偏移:

在这里插入图片描述
可以推出:
在这里插入图片描述

内参矩阵K:

在这里插入图片描述

外参矩阵[R丨t]:

表示三个方向的偏转:
在这里插入图片描述

投影矩阵P

(在这里可以认为旋转矩阵 R 为单位矩阵 I,平移矩阵 t 都为0):
在这里插入图片描述
根据上述变换最终可以得到一个投影矩阵P的公式为:
在这里插入图片描述
总结一下公式大致如下:
在这里插入图片描述

畸变参数

在几何光学和阴极射线管显示中,畸变是对直线投影的一种偏移。简单来说直线投影是场景内的一条直线投影到图片上也保持为一条直线。那畸变简单来说就是一条直线投影到图片上不能保持为一条直线了,这是一种光学畸变。畸变一般可以分为两大类,包括径向畸变和切向畸变。主要的一般径向畸变有时也会有轻微的切向畸变。

2、相机标定的实现

相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。

相机标定的输入:标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下假定图像位于Z=0平面上)。

相机标定的输出:摄像机的内参、外参系数。

这三个基础的问题就决定了使用Opencv实现张正友法标定相机的标定流程、标定结果评价以及使用标定结果矫正原始图像的完整流程:

  1. 准备标定图片
  2. 对每一张标定图片,提取角点信息
  3. 对每一张标定图片,进一步提取亚像素角点信息
  4. 在棋盘标定图上绘制找到的内角点(非必须,仅为了显示)
  5. 相机标定
  6. 对标定结果进行评价
  7. 查看标定效果——利用标定结果对棋盘图进行矫正

我准备的是下图这种格子数为7×5,内角点为6×4的棋盘格图片,手机型号为荣耀PLAY。
在这里插入图片描述
将它放在一个平面上从不同角度拍摄10张照片作为实验素材。
代码如下:

import cv2
import numpy as np
import glob

# 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)

# 获取标定板角点的位置
objp = np.zeros((4 * 6, 3), np.float32)
objp[:, :2] = np.mgrid[0:6, 0:4].T.reshape(-1, 2)  # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y

obj_points = []  # 存储3D点
img_points = []  # 存储2D点

images = glob.glob("image4/*.jpg")
i=0;
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    size = gray.shape[::-1]
    ret, corners = cv2.findChessboardCorners(gray, (6, 4), None)
    #print(corners)

    if ret:

        obj_points.append(objp)

        corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)  # 在原角点的基础上寻找亚像素角点
        #print(corners2)
        if [corners2]:
            img_points.append(corners2)
        else:
            img_points.append(corners)

        cv2.drawChessboardCorners(img, (6, 4), corners, ret)  # 记住,OpenCV的绘制函数一般无返回值
        i+=1;
        cv2.imwrite('conimg'+str(i)+'.jpg', img)
        cv2.waitKey(1500)

print(len(img_points))
cv2.destroyAllWindows()

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)

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 ) # 平移向量  # 外参数

print("-----------------------------------------------------")

img = cv2.imread(images[2])
h, w = img.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))#显示更大范围的图片(正常重映射之后会删掉一部分图像)
print (newcameramtx)
print("------------------使用undistort函数-------------------")
dst = cv2.undistort(img,mtx,dist,None,newcameramtx)
x,y,w,h = roi
dst1 = dst[y:y+h,x:x+w]
cv2.imwrite('calibresult3.jpg', dst1)
print ("方法一:dst的大小为:", dst1.shape)

代码中的9、10、21、35行中的角点数根据自己的棋盘格大小进行更改。
实验分为两步,第一步主要是对每张图片进行角点的提取,结果如下:
在这里插入图片描述
第二步就是实现相机的标定,运行结果如下:

mtx为内参数矩阵,dist为畸变系数:
在这里插入图片描述
rvecs为旋转向量:
其中mtx为内参数矩阵,dist为畸变系数
tvecs为平移向量:
在这里插入图片描述
畸变矫正:
在这里插入图片描述
矫正前后的图片
在这里插入图片描述
在这里插入图片描述

总结

通过标定得到荣耀PLAY的后置摄像头的内置参数矩阵为:
在这里插入图片描述
矫正后的图和原图通过对比发现差距并不大,只是在宽度上有一点拉伸(肉眼能看出的差距只有图片右上角的白字因为图片的拉伸而消失了),原因应该是原图基本上没有出现明显的畸变。(应该是现在的手机相机比较厉害吧…)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/140209.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 十大it博客_中国it名人

    十大it博客_中国it名人IT名人博客推荐(15个)1.李彦宏百度公司总裁博客地址:http://hi.baidu.com/liyanhong2.张朝阳搜狐董事局主席兼CEO博客地址:http://charles.blog.sohu.com/3.马云阿里巴巴集团主席兼首席执行官博客地址:http://yunma.blog.china.alibaba.com/4.雷军曾任金山…

    2022年8月30日
  • Django(67)drf搜索过滤和排序过滤「建议收藏」

    Django(67)drf搜索过滤和排序过滤「建议收藏」前言当我们需要对后台的数据进行过滤的时候,drf有两种,搜索过滤和排序过滤。搜索过滤:比如我们想返回sex=1的,那么我们就可以从所有数据中进行筛选排序过滤:比如我们想对价格进行升序排列,就可以

    2022年7月29日
  • APK签名原理

    APK签名原理网上已有多篇分析签名的类似文章,但是都有一个共同的问题,就是概念混乱,混乱的一塌糊涂。在了解APK签名原理之前,首先澄清几个概念:消息摘要-MessageDigest简称摘要,请看英文翻译,是摘要,不是签名,网上几乎所有android签名分析的文章都对这两个概念乱用摘要的链接http://en.wikipedia.org/wiki/Message_digest简

    2022年6月12日
  • codeforces 437C The Child and Toy

    codeforces 437C The Child and Toy

    2022年1月25日
  • 基于C#的WinForm窗体美化(无须美工功底)「建议收藏」

    基于C#的WinForm窗体美化(无须美工功底)「建议收藏」基于C#的WinForm窗体美化(无须美工功底)在近期的实训中,学习到了许多精髓的小知识。接下来我会发布几篇博客,分享我的开发经验。在设计面向对象的UI层界面时,常常因为WinForm自身的窗体界面不够美观而去反复修改各种控件的位置。当然在不同的Windos中,WinForm所具有的主题也是不同的,但对于颜控的我们,这些也是无法满足的。所以今天我分享一个关于简单的对窗体进行美化的一个小技巧。

    2022年5月28日
  • jvm字符串常量池_java 常量池

    jvm字符串常量池_java 常量池字符串字符串字面量:就是指这个字符串本身,比如”Java”,”Hello”。字符串对象:比如newString(“abc”),或者直接Strings=”str”,后面的”str”也是一个字符串对象。字符串引用:引用就是一个变量,指向对应的字符串对象。常量池class常量池Java源文件编译之后得到的class文件,其中有项信息就是常量池,保存有字面量和符号引用,比如publicclassJ…

    2022年7月28日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号