2013-03-27 50 views
2

我正在尝试使用python中的opencv cv2标定我的单个摄像头。我正在使用cv2.findChessboardCorners和cv2.calibrateCamera函数。但是,从calibrateCamera函数返回的根均方根似乎非常高。无论使用多少个找到的电路板,总是在50左右。我读到的值很好,范围从0-1。我在一张贴在木板上的纸上使用了一个5x8的黑色和白色格子图案。任何人都可以帮我解决这个问题吗?奇怪的是,我使用了三维建模软件Blender渲染的图像,其中没有镜头失真,板子的坐标已知,我能够得到0.22的RMS,这很好。虽然我无法用我的网络摄像头复制这些结果,但使用了类似的代码。也许我错过了一些东西。非常感谢每个看过这个的人。下面是完整的代码:OpenCV摄像机标定的均方根值太高

import sys 
import os 
import numpy as np 
import cv2 
import time 

''' 
This module finds the intrinsic parameters of the camera. These parameters include 
the focal length, pixel aspect ratio, image center, and lens distortion (see wiki 
entry for "camera resectioning" for more detail). It is important to note that the 
parameters found by this class are independent of location and rotation of the camera. 
Thus, it only needs to be calculated once assuming the lens and focus of the camera is 
unaltered. The location and rotation matrix are defined by the extrinsic parameters. 
''' 

class Find_Intrinsics: 
    '''Finds the intrinsic parameters of the camera.''' 
    def __init__(self): 
     #Import user input from Blender in the form of argv's 
     self.rows = int(sys.argv[1]) 
     self.cols = int(sys.argv[2]) 
     self.board_width_pxls = float(sys.argv[3]) 
     self.pxls_per_sq_unit = float(sys.argv[4]) 
     self.printer_scale = float(sys.argv[5]) 


    def find_calib_grid_points(self,cols,rows,board_width_pxls,pxls_per_sq_unit,printer_scale): 
     '''Defines the distance of the board squares from each other and scale them. 

      The scaling is to correct for the scaling of the printer. Most printers 
      cannot print all the way to the end of the page and thus scale images to 
      fit the entire image. If the user does not desire to maintain real world 
      scaling, then an arbitrary distance is set. The 3rd value appended to 
      calib_points signifies the depth of the points and is always zero because 
      they are planar. 
     ''' 
     #should be dist for each square 
     point_dist = (((board_width_pxls)/(pxls_per_sq_unit))*printer_scale)/(cols+2) 
     calib_points = [] 
     for i in range(0,cols): 
      for j in range(0,rows): 
       pointX = 0 + (point_dist*j) 
       pointY = 0 - (point_dist*i) 
       calib_points.append((pointX,pointY,0))  
     np_calib_points = np.array(calib_points,np.float32) 
     return np_calib_points 


    def main(self): 
     print '---------------------------Finding Intrinsics----------------------------------'  
     np_calib_points = self.find_calib_grid_points(self.cols,self.rows,self.board_width_pxls, 
               self.pxls_per_sq_unit,self.printer_scale) 
     pattern_size = (self.cols,self.rows) 
     obj_points = [] 
     img_points = []   

     camera = cv2.VideoCapture(0) 
     found_count = 0 
     while True: 
      found_cam,img = camera.read()    
      h, w = img.shape[:2] 
      print h,w 
      gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
      found, corners = cv2.findChessboardCorners(img, pattern_size)    

      if found:    
       term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1) 
       cv2.cornerSubPix(gray_img, corners, (5, 5), (-1, -1), term) 

       cv2.drawChessboardCorners(img, pattern_size, corners, found) 
       found_count+=1 

       img_points.append(corners.reshape(-1, 2)) 
       obj_points.append(np_calib_points) 

      cv2.putText(img,'Boards found: '+str(found_count),(30,30), 
       cv2.FONT_HERSHEY_DUPLEX, 0.8,(0,0,255,1)) 
      cv2.putText(img,'Press any key when finished',(30,h-30), 
       cv2.FONT_HERSHEY_DUPLEX, 0.8,(0,0,255,1)) 
      cv2.imshow("webcam",img) 

      if (cv2.waitKey (1000) != -1): 
       cv2.destroyAllWindows() 
       del(camera) 
       np_obj_points = np.array(obj_points) 
       print "Calibrating.Please be patient" 
       start = time.clock() 

       #OpenCV function to solve for camera matrix 
       try: 
        print obj_points[0:10] 
        rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (w, h)) 
        print "RMS:", rms 
        print "camera matrix:\n", camera_matrix 
        print "distortion coefficients: ", dist_coefs 

        #Save the camera matrix and the distortion coefficients to the hard drive to use 
        #to find the extrinsics 
        #want to use same file directory as this file 
        #directory = os.path.dirname(os.path.realpath('Find_Intrinsics.py')) 
        np.save('C:\\Users\\Owner\\Desktop\\3D_Scanning\\Blender_3d_Scanning\\camera_matrix.npy',camera_matrix) 
        np.save('C:\\Users\\Owner\\Desktop\\3D_Scanning\\Blender_3d_Scanning\\dist_coefs.npy',dist_coefs)  

        elapsed = (time.clock() - start) 
        print("Elapsed time: ", elapsed, " seconds") 

        img_undistort = cv2.undistort(img,camera_matrix,dist_coefs) 
        cv2.namedWindow('Undistorted Image',cv2.WINDOW_NORMAL)#WINDOW_NORMAL used bc WINDOW_AUTOSIZE does not let you resize 
        cv2.resizeWindow('Undistorted Image',w,h) 
        cv2.imshow('Undistorted Image',img_undistort) 
        cv2.waitKey(0) 
        cv2.destroyAllWindows() 

        break 

       except: 
        print "\nSorry, an error has occurred. Make sure more than zero boards are found." 
        break 

if __name__ == '__main__' and len(sys.argv)== 6: 
    Intrinsics = Find_Intrinsics() 
    Intrinsics_main = Intrinsics.main() 
else: 
    print "Incorrect number of args found. Make sure that the python27 filepath is entered correctly." 
print '--------------------------------------------------------------------------------' 

回答

1

哇,我不知道它是什么有AHA时刻(或卫生署的时刻,如果你看辛普森!)计算器上张贴哈哈之后。这是一个骨头错误。我设法搞定了calibrateCamera函数的obj_points参数的构造。 OpenCV将第一个点作为左上角,并从左到右遍历每个,直到它到达最后一个点(右下角)。因此,我的find_calib_grid_points函数是错误的。这是以防万一别人大干快上绊倒了正确的代码,虽然这可能是不可能的:

for j in range(0,rows): 
      for i in range(0,cols): 
       pointX = 0 + (point_dist*i) 
       pointY = 0 - (point_dist*j) 
       calib_points.append((pointX,pointY,0))  
     np_calib_points = np.array(calib_points,np.float32) 

谢谢大家谁看了这个,送我心灵的消息,所以我能想出这一个正确的哈哈。他们工作!我的RMS是0.33!