Python+OpenCV学习(17)---摄像机标定

时间:2024-04-08 20:09:07

Python+OpenCV学习(17)---摄像机标定

原文:http://blog.csdn.net/firemicrocosm/article/details/48594897

利用python学习OpenCV,个人感觉比较方便。函数的形式与C++基本相同,所以切换过来还是比较好的,对于像我这种对python不太熟练的人,使用python的集成开发环境PyCharm进行学习,可以设置断点调试,有助于我这类初学者理解掌握。

摄像机标定是机器人视觉进行目标定位跟踪的首要环节,通过标定板标定好摄像机的内外参数,然后进行后续的定位识别工作。本次介绍的摄像机标定的实验测试图像是OpenCV安装目录文件夹cpp\samples中的left0-left14.jpg图像。

下面是利用python语言结合OpenCV进行摄像机标定的代码:

[python] view plain copy
  1. # -*- coding:utf-8 -*-  
  2. __author__ = 'Microcosm'  
  3.   
  4. import cv2  
  5. import numpy as np  
  6. import glob  
  7.   
  8. # 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001  
  9. criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 300.001)  
  10.   
  11. # 获取标定板角点的位置  
  12. objp = np.zeros((6*7,3), np.float32)  
  13. objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)  # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y  
  14.   
  15. obj_points = []    # 存储3D点  
  16. img_points = []    # 存储2D点  
  17.   
  18. images = glob.glob("E:\python\Python Project\opencv_showimage\images\calibrateImages\*.jpg")  
  19. for fname in images:  
  20.     img = cv2.imread(fname)  
  21.     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  22.     size = gray.shape[::-1]  
  23.     ret, corners = cv2.findChessboardCorners(gray, (7,6), None)  
  24.   
  25.     if ret:  
  26.         obj_points.append(objp)  
  27.   
  28.         corners2 = cv2.cornerSubPix(gray, corners, (5,5), (-1,-1), criteria)  # 在原角点的基础上寻找亚像素角点  
  29.         if corners2:  
  30.             img_points.append(corners2)  
  31.         else:  
  32.             img_points.append(corners)  
  33.   
  34.         cv2.drawChessboardCorners(img, (7,6), corners, ret)   # 记住,OpenCV的绘制函数一般无返回值  
  35.         cv2.imshow('img', img)  
  36.         cv2.waitKey(50)  
  37.   
  38. print len(img_points)  
  39. cv2.destroyAllWindows()  
  40.   
  41. # 标定  
  42. ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points,size, NoneNone)  
  43.   
  44. print "ret:",ret  
  45. print "mtx:\n",mtx        # 内参数矩阵  
  46. print "dist:\n",dist      # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)  
  47. print "rvecs:\n",rvecs    # 旋转向量  # 外参数  
  48. print "tvecs:\n",tvecs    # 平移向量  # 外参数  
  49.   
  50. print("-----------------------------------------------------")  
  51. # 畸变校正  
  52. img = cv2.imread(images[12])  
  53. h, w = img.shape[:2]  
  54. newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))  
  55. print newcameramtx  
  56. print("------------------使用undistort函数-------------------")  
  57. dst = cv2.undistort(img,mtx,dist,None,newcameramtx)  
  58. x,y,w,h = roi  
  59. dst1 = dst[y:y+h,x:x+w]  
  60. cv2.imwrite('calibresult11.jpg', dst1)  
  61. print "方法一:dst的大小为:", dst1.shape  
  62.   
  63. # undistort方法二  
  64. print("-------------------使用重映射的方式-----------------------")  
  65. mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)  # 获取映射方程  
  66. #dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)      # 重映射  
  67. dst = cv2.remap(img,mapx,mapy,cv2.INTER_CUBIC)        # 重映射后,图像变小了  
  68. x,y,w,h = roi  
  69. dst2 = dst[y:y+h,x:x+w]  
  70. cv2.imwrite('calibresult11_2.jpg', dst2)  
  71. print "方法二:dst的大小为:", dst2.shape        # 图像比方法一的小  
  72.   
  73. print("-------------------计算反向投影误差-----------------------")  
  74. tot_error = 0  
  75. for i in xrange(len(obj_points)):  
  76.     img_points2, _ = cv2.projectPoints(obj_points[i],rvecs[i],tvecs[i],mtx,dist)  
  77.     error = cv2.norm(img_points[i],img_points2, cv2.NORM_L2)/len(img_points2)  
  78.     tot_error += error  
  79.   
  80. mean_error = tot_error/len(obj_points)  
  81. print "total error: ", tot_error  
  82. print "mean error: ", mean_error  

下图是畸变校正前的图片:

Python+OpenCV学习(17)---摄像机标定

通过标定获取摄像机内外参数以及畸变校正系数后对其进行校正:

方法一:

Python+OpenCV学习(17)---摄像机标定

方法二:

Python+OpenCV学习(17)---摄像机标定