2013-03-27 75 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!