学习记录。

事实上很早就接触过视觉定位这东西,但是到现在才返回头学习一下相机的标定,真是可耻啊!我把想法和过程记录一下。

相机成像

相机的成像原理——小孔成像

然而,在实际由于设计工艺问题、相机安装环境或物体摆放位置等影响,会照成成像与实际图像不一样的现象。

由于设计工艺照成的影响是无法改变的事实,所以这将是相机的内参;

由环境或安装方式照成的影响是可以改变的,这就是相机的外参。

在https://blog.csdn.net/aoulun/article/details/78768570中详细介绍了相机成像原理,相机内、外参数是什么。这里为了保证记录的完整型,把成像平面的像素坐标与实际物体的世界坐标公式写下来。

1.红框就是相机外参,R为旋转矩阵,T为平移向量;如果相机镜头和物体平面平行(室内定位中,有一种基于视觉的室内定位,定位方式就是在移动的小车上安装单目相机,在屋顶安装各种可识别的标签,相机的光轴一直与屋顶是垂直的),在这种情况下,旋转矩阵可以看作是单位向量及R=E,而平移向量T=0。

2.蓝框就是相机的内参,相机的内参从出厂后就被固定了。

f:相机的焦距

(u0,v0):像平面的投影中心点

dx,dy:就是单位像素对应实际距离

Zc:可以认为相机镜头到成像物体的垂直距离

对这部分我就不赘述了,在麻呱智能 的文章中介绍的特别详细,我就不班门弄斧了。

生成棋盘标定图

创建自定义的棋盘标定图,这个没啥要说的,就是调用了opencv的画矩形框的函数,代码如下:

#生成想要的标定图,大小自定义
import cv2
import sys#读入一张空白图片,该图片最好和你想要标定的相机分辨率一致
image = cv2.imread('C:\\Users\\wlx\\Documents\\py_study\\camera calibration\\white.jpg')
#设置图片上黑白方格
dpi = 96                                                #dpi自己电脑上一英寸显示的像素个数
cm_to_inch = 0.3937                                     #1cm = 0.3937inch
square_length = 1.5                                     #黑白方格边长1.5cm
x_nums = 10                                             #x方向画10个方格
y_nums = 8                                              #y方向画8个方格
square_pixel = int(square_length * cm_to_inch * dpi)    #方格边长的像素
#为了把方格图像放在纸张的中间,设定起始坐标
x0 = 40
y0 = 16#画方格
def DrawSquare():flag = -1                                            #颜色转变标志#一行一行的画for i in range(y_nums):#每画一行先换一次颜色flag = 0 - flagfor j in range(x_nums):if flag > 0:color = [0,0,0]                          #黑色方格else:color = [255,255,255]#调用opencv中的画方框函数cv2.rectangle(image,(x0 + j*square_pixel,y0 + i*square_pixel),(x0 + j*square_pixel+square_pixel,y0 + i*square_pixel+square_pixel),color,-1)flag = 0 - flag#保存图像cv2.imwrite('chess_map.jpg',image)#判断本程序是独立运行还是被调用
if __name__ == '__main__':DrawSquare()

上面的代码可以生成自己想要的棋盘标定图,修改x_nums和y_nums参数的值,就能获得任意数量的黑白格子。实现原理就是在图像的某一点开始,先画一个黑色方格(或者白色),画完后将起点坐标和终点坐标都向右移动方格边长的距离,然后改变颜色再画一个方格,依次类推,画完一行后,就转战到第二行,直到全部完成。

注意:在图像上坐标是这样的

cv2.rectangle(img,pt1,pt2,color,thickness=None,line_type=None,shift=None)

img:图像,要画图的图像

pt1:方格的起点坐标(x0,y0)

pt2:方格的终点坐标(x1,y1)

color:方框的颜色

thickness:方框线的宽度(像素),当值为负数时,填充方框

line_type:方框线的样式

采集标定图

我采用离线标定,先把不同角度的标定图采集保存下来,然后再开始标定。下面是采集的代码

import cv2
import os#标定图像保存路径
photo_path = "C:\\Users\\wlx\\Documents\\py_study\\camera calibration\\image"
#创建路径
def CreateFolder(path):#去除首位空格del_path_space = path.strip()#去除尾部'\'del_path_tail = del_path_space.rstrip('\\')#判读输入路径是否已存在isexists = os.path.exists(del_path_tail)if not isexists:os.makedirs(del_path_tail)return Trueelse:return False
#获取不同角度的标定图像
def gain_photo(photo_path):# 检查输入路径是否存在——不存在就创建CreateFolder(photo_path)#开启摄像头video = cv2.VideoCapture(0)#显示窗口名称photo_window = 'calibration'#保存的标定图像名称以数量命名photo_num = 0while video.isOpened():ok,frame = video.read()                                 #读一帧的图像if not ok:breakelse:cv2.imshow(photo_window,frame)key = cv2.waitKey(10)#按键盘‘A’保存图像if key & 0xFF == ord('a'):photo_num += 1photo_name = photo_path + '\\' + str(photo_num) + '.jpg'cv2.imwrite(photo_name,frame)print('create photo is :',photo_name)#按键盘‘Q’中断采集if key & 0xFF == ord('q'):breakif __name__ == '__main__':gain_photo(photo_path)
video = cv2.VideoCapture(0)中的0代表的是我的USB相机在我电脑上的驱动位置
if __name__ == '__main__':就是判断这些代码是不是要当作单独的代码执行,如果是就执行if中的内容。

标定

我先上代码吧

import cv2
import sys
import numpy as np
import glob#标定图像保存路径
photo_path = "C:\\Users\\wlx\\Documents\\py_study\\camera calibration\\image"
#标定图像
def calibration_photo(photo_path):#设置要标定的角点个数x_nums = 9                                                          #x方向上的角点个数y_nums = 7# 设置(生成)标定图在世界坐标中的坐标world_point = np.zeros((x_nums * y_nums,3),np.float32)            #生成x_nums*y_nums个坐标,每个坐标包含x,y,z三个元素world_point[:,:2] = np.mgrid[:x_nums,:y_nums].T.reshape(-1, 2)    #mgrid[]生成包含两个二维矩阵的矩阵,每个矩阵都有x_nums列,y_nums行#.T矩阵的转置#reshape()重新规划矩阵,但不改变矩阵元素#保存角点坐标world_position = []image_position = []#设置角点查找限制criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,30,0.001)#获取所有标定图images = glob.glob(photo_path+'\\*.jpg')#print(images)for image_path in images:image = cv2.imread(image_path)gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)#查找角点ok,corners = cv2.findChessboardCorners(gray,(x_nums,y_nums),None)if ok:#把每一幅图像的世界坐标放到world_position中world_position.append(world_point)#获取更精确的角点位置exact_corners = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)#把获取的角点坐标放到image_position中image_position.append(exact_corners)#可视化角点# image = cv2.drawChessboardCorners(image,(x_nums,y_nums),exact_corners,ok)# cv2.imshow('image_corner',image)# cv2.waitKey(5000)#计算内参数ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(world_position, image_position, gray.shape[::-1], None,None)#将内参保存起来np.savez('C:\\Users\\wlx\\Documents\\py_study\\camera calibration\\data\\intrinsic_parameters',mtx=mtx,dist=dist)print(mtx, dist)#计算偏差mean_error = 0for i in range(len(world_position)):image_position2, _ = cv2.projectPoints(world_position[i], rvecs[i], tvecs[i], mtx, dist)error = cv2.norm(image_position[i], image_position2, cv2.NORM_L2) / len(image_position2)mean_error += errorprint("total error: ", mean_error / len(image_position))if __name__ == '__main__':calibration_photo(photo_path)

使用opencv标定这些图像,步骤大致就是:

1、设置想标定角点的个数

2、创建对应角点个数的世界坐标

3、将采集到的标定图读入缓存

4、灰度处理

5、使用findChessboardCorners(img,patternSize,corners,flags=None)函数,查找图像中的内点

  • image:输入的棋盘图像,必须是8位的灰度或者彩色图像
  • patternSize:棋盘中每行每列的角点个数
  • corners:检测到的角点
  • flags:各种操作标准

6、使用cornerSubPix(image,corners,winSize,zeroZone,criteria)函数,精确查找图像上的角点

  • image:输入图像,,必须是8位的灰度或者彩色图像

  • corners:输入角点的初始化坐标,也存储精确的输出角点坐标

  • winSize:搜索窗口的一半尺度,如winSize=(5,5),则使用(2x5+1, 2x5+1)=(11,11)的搜索窗

  • zeroZone:死区的一半尺寸,死区为不对搜索区做求和运算的区域,当值为(-1,-1)时,表示没有死区

  • criteria:搜索角点停止的标志

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,30,0.001)就是一个标志,TERM_CRITERIA_EPS 代表误差也就是精度,TERM_CRITERIA_MAX_ITER代表迭代次数,它两之和就是指两个因素同时作用,这里当迭代次数超过30或误差大于0.001都会停止运算。

7、将图像的世界坐标保存到数组world_position中,将找到的角点坐标保存到数组image_position中

8、使用cv2.calibrateCamera(world_position, image_position, gray.shape[::-1], None,None)计算内外参数

9、计算一下准确度,也就是通过你算出来的内参数,逆运算出角点坐标,然后将这个坐标和识别出来的角点坐标进行误差运算,得到偏差值。

最后,可以将得到的内参数保存到一个文件中,以后在用相机采集图像时,就可以用内参数去矫正图像了,这里我没做图像的矫正,过几天做了再写上来。

另外,用来标定的图像不要太少,我做了实验随着标定图像的增加,最后计算出的偏差会减小;而且拍摄标定图像时,角度要合理,相机固定位置不要发生变化。

下面是我实验,就是为了验证代码是否能运行,所以没有打印标定图纸,而是直接用摄像头拍摄电脑显示器上的图像,摄像头也没固定牢靠,所以结果不是很好。拍摄了20张图像

相机内参:

相机的基础矩阵
M1=[[889.02484885   0.         305.16086021][  0.         874.05128244 296.97147721][  0.           0.           1.        ]]
相机的畸变矩阵
D1=[[-1.19429590e-01  1.62553701e+00 -1.23085637e-02 -9.56110534e-03-9.61452725e+00]]

偏差值:

error:  0.022833192243376606

生成黑白棋盘标定图和单目相机标定(一)(python+opencv实现)相关推荐

  1. python绘制黑白棋盘_生成黑白棋盘标定图和单目相机标定(python+opencv实现)

    学习记录. 事实上很早就接触过视觉定位这东西,但是到现在才返回头学习一下相机的标定,真是可耻啊!我把想法和过程记录一下. 相机成像 相机的成像原理--小孔成像 然而,在实际由于设计工艺问题.相机安装环 ...

  2. Halcon例程(基于多个标定图的单目相机标定)详解—— Camera_calibration_multi_image.hdev

    一.前言 在我的工业相机专栏里已经将相机标定涉及到的理论部分讲解完毕,为什么要标定以及标定要求出什么参数呢,用一个Halcon 例程来帮助理解. 这个例程是比较经典的标定程序,基本将标定过程讲的比较清 ...

  3. 【计算机视觉】OpenCV实现单目相机标定

    文章目录 单目相机标定(基于Python OpenCV) 1.上期填坑 2.单目相机标定 2.1 数据采集 2.2 角点提取 2.3 参数求解 2.4 参数评估(重投影误差) 2.5 相机位姿(棋盘位 ...

  4. 一文图解单目相机标定算法

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 有一天,蟹老板找底下的员工川建国同学: 等蟹老板走后,然后转头问旁边的学霸李雷同学: 李雷同学整理了下 ...

  5. matlab单目相机标定

    文章目录 1.标定图片 2.标定 3.获取标定结果 使用matlab进行相机参数标定非常方便,相机畸变模型请参考另一篇文章相机内参与畸变模型,单目相机标定的结果就是得到相机内参与畸变系数. 1.标定图 ...

  6. SLAM学习 | 单目相机标定(附代码实测可用)

    SLAM学习 | 单目相机标定(附代码实测可用) 1 针孔相机模型 2 张正友标定法 3 VS2013下配置openCV 4 标定过程与结果 5 经验总结与注意事项 概要: 这篇文章介绍如何解决做SL ...

  7. matlab单目相机标定步骤,matlab相机标定

    本文是一篇关于相机标定意义和原理的个人总结,包含了 OpenCV 和 Matlab 中常用的相机 标定函数的注解. 相机标定是机器视觉的基础, 标定结果的好坏直接决定了机器...... 图片数量一定程 ...

  8. 单目相机标定(使用OpenCV)

    关于相机标定的理论知识和使用Matlab软件进行相机标定请看这篇博文:单目相机标定(使用Matlab) 这次因为项目原因需要给海康工业相机进行标定了,下载Matlab软件有些麻烦(主要是我电脑内存小. ...

  9. 单目相机标定实现--张正友标定法

    文章目录 一:相机坐标系,像素平面坐标系,世界坐标系,归一化坐标系介绍 1:概述 公式 二:实现 1:整体流程 4:求出每张图像的单应性矩阵并用LMA优化 5:求解理想无畸变情况下的摄像机的内参数和外 ...

最新文章

  1. 2018牛客暑期ACM多校训练营第二场 - A题
  2. python 提高文件查询效率_Python 大量小文件存储提高效率的简单示例
  3. BugKuCTF WEB 你必须让他停下
  4. IDEA使用技巧整理
  5. Android 6.0以上运行权限及RxPermissions的使用
  6. 模板变量,过滤器和静态文件引用
  7. iOS里面MVC模式详解
  8. javascirpt如何模仿块级作用域(js高程笔记)
  9. [CF1073E]Segment Sum
  10. RUP---统一软件开发过程
  11. 恐龙机器人钢索恐龙形态_恐龙有的四脚行走有的两脚行走,有的会飞有的会游,差别咋这么大...
  12. win7 64位如何安装sql2005
  13. spss分析方法-因子分析(转载)
  14. 全球及中国城市规划行业十四五建设方向与运营动态分析报告2022版
  15. 计算机配置的详细信息,如何查看电脑的配置参数,看电脑详细配置的方法
  16. 未来办公利器-无影云超级桌面体验
  17. 京东7天无理由退货换货运费应该谁来出是商家支付还是买家支付?
  18. 基于android平台的条码扫描软件的设计与实现,基于android平台的条码扫描软件的设计与实现...
  19. 阿里巴巴2014年校园招聘试题解答
  20. Flash 实验 遮罩层

热门文章

  1. 网页FLASH幻灯片播放带链接源代码 pixviewer.swf使用(转)
  2. 桌面记事本软件测试培训,记事本程序测试用例及编写.doc
  3. MATLAB发票识别系统
  4. 厦门工学院计算机管理,厦门工学院
  5. Atitit 人的面相 脸型分类 编码与识别 attilax总结
  6. 基于windows子系统WSL2搭建openharmony开发环境(图文详解)
  7. 我发现陌生人社交赛道最大的秘密,就是它根本不存在
  8. 【Ubuntu 修改盘符名称】
  9. 如何在模拟器上调用RealPlayer播放流媒体(转)
  10. 做小程序平台比开网店更挣钱吗?