600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > python绘制黑白棋盘_生成黑白棋盘标定图和单目相机标定(python+opencv实现)

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

时间:2019-11-10 11:21:15

相关推荐

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

学习记录。

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

相机成像

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

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

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

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

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

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

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

f:相机的焦距

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

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

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

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

生成棋盘标定图

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

#生成想要的标定图,大小自定义import cv2import sys#读入一张空白图片,该图片最好和你想要标定的相机分辨率一致image = cv2.imread("C:\\Users\\wlx\\Documents\\py_study\\camera calibration\\white.jpg")#设置图片上黑白方格dpi = 96 #dpi自己电脑上一英寸显示的像素个数cm_to_inch = 0.3937 #1cm = 0.3937inchsquare_length = 1.5 #黑白方格边长1.5cmx_nums = 10 #x方向画10个方格y_nums = 8 #y方向画8个方格square_pixel = int(square_length * cm_to_inch * dpi) #方格边长的像素#为了把方格图像放在纸张的中间,设定起始座标x0 = 40y0 = 16#画方格def DrawSquare(): flag = -1 #颜色转变标志 #一行一行的画 for i in range(y_nums): #每画一行先换一次颜色 flag = 0 - flag for 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 cv2import 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 True else: return False#获取不同角度的标定图像def gain_photo(photo_path): # 检查输入路径是否存在——不存在就创建 CreateFolder(photo_path) #开启摄像头 video = cv2.VideoCapture(0) #显示窗口名称 photo_window = "calibration" #保存的标定图像名称以数量命名 photo_num = 0 while video.isOpened(): ok,frame = video.read() #读一帧的图像 if not ok: break else: cv2.imshow(photo_window,frame) key = cv2.waitKey(10) #按键盘‘A’保存图像 if key & 0xFF == ord("a"): photo_num += 1 photo_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 cv2import sysimport numpy as npimport 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,(y_nums,x_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,(y_nums,x_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) print(mtx, dist) #计算偏差 mean_error = 0 for 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 += error print("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张图像

相机内参:

[[1.24956824e+03 0.00000000e+00 2.16230694e+02] [0.00000000e+00 2.92154313e+03 3.87901459e+02] [0.00000000e+00 0.00000000e+00 1.00000000e+00]]

相机外参:

[[-2.80875093e+02 8.92572104e+03 -2.80196846e+00 8.90336346e+00 -1.46134126e+05]]

偏差值:

error: 6.968280883027417

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。