3

Pythonでopencv cv2を使用して、単一のWebカメラを調整しようとしています。私は cv2.findChessboardCorners と cv2. calibrationCamera 関数を使用しています。ただし、キャリブレーションカメラ関数から返された二乗平均平方根は非常に高いようです。ボードが見つかったフレームをいくつ使用しても、常に 50 前後です。適切な値の範囲は 0 ~ 1 です。木の板にテープで貼り付けた一枚の紙に、5x8 の白黒の市松模様を使用しています。これを下げるのを手伝ってくれる人はいますか?奇妙なことに、3D モデリング ソフトウェアである Blender からレンダリングした画像を使用しました。これには、レンズの歪みがなく、ボードの座標が確実にわかっており、0.22 の RMS を取得できました。これは良好です。同様のコードを使用しても、ウェブカメラでこれらの結果を複製することはできません。おそらく私は何かが欠けています。これを見てくださっている皆様、本当にありがとうございます。完全なコードは次のとおりです。

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 '--------------------------------------------------------------------------------'
4

1 に答える 1

2

うわー、スタックオーバーフローに投稿した直後にアハの瞬間(またはザ・シンプソンズを見ているならああ!の瞬間)を持つことについて私はそれが何であるかわかりません。これは骨の頭の間違いでした。調整カメラ関数の 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でした!

于 2013-03-27T23:38:03.843 に答える