当前位置:网站首页>Opencv camera calibration (1): internal and external parameters, distortion coefficient calibration and 3D point to 2D image projection

Opencv camera calibration (1): internal and external parameters, distortion coefficient calibration and 3D point to 2D image projection

2022-06-13 01:46:00 No change of name

0. Content

It can be used for camera calibration picture filtering

Camera calibration

3-D point re projection will affect 2-D image

draw Z Plane and connecting line

Be careful : This calibration method is suitable for ordinary cameras with small distortion , The calibration of the fish eye camera is as follows :Opencv Camera calibration (2): Fish eye camera calibration _m0_58772523 The blog of -CSDN Blog ...

1. Picture screening

utilize opencv in findChessboardCorners Determine whether the corresponding corner can be detected in the picture , If a corner is detected ret The value is True, Delete the corresponding picture when no corner is detected .

import os
import cv2
import glob


def delete_pic(inter_corner_shape, img_dir, img_type):
    images = glob.glob(img_dir + os.sep + '**.' + img_type)
    for fname in images:
        img = cv2.imread(fname)
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        ret, cp_img = cv2.findChessboardCorners(gray_img,
            (inter_corner_shape[0], inter_corner_shape[1]), None)
        if not ret:
            os.remove(fname)


if __name__ == '__main__':
    inter_corner_shape = (9, 6)
    img_dir = "./data"
    img_type = "jpg"
    delete_pic(inter_corner_shape, img_dir, img_type)

2. Line and plane drawing auxiliary functions ( With detailed notes )

#  Two dimensional pictures ,  Picture corner coordinates ,  The coordinates of the projection points of the 3D points to be projected in the image 
def draw(img, corners, imgpts):
    #  Get the first image corner information 
    corner = tuple(corners[0].ravel().astype(np.int64))
    #  Use the coordinates of the first image corner and projection point to draw the desired line and plane 
    # np.ravel() The function reduces the dimension of a multidimensional array to one dimension 
    #  The new version of the opencv When drawing lines and planes, it is necessary to manually convert the coordinate information to integer , In the old version, you don't need to ( The test found )
    img = cv2.drawContours(img, [np.array([list(corners[0].ravel()), list(imgpts[1].ravel()),
                                           list(imgpts[2].ravel()), list(imgpts[3].ravel())]).astype(np.int64)], -1,
                           (175, 0, 175), -3)
    img = cv2.line(img, corner, tuple(imgpts[0].ravel().astype(np.int64)), (255, 0, 0), 5)
    img = cv2.line(img, corner, tuple(imgpts[1].ravel().astype(np.int64)), (0, 255, 0), 5)
    # img = cv2.line(img, corner, tuple(imgpts[2].ravel().astype(np.int64)), (0, 0, 255), 5)
    img = cv2.line(img, corner, tuple(imgpts[3].ravel().astype(np.int64)), (0, 0, 255), 5)
    return img

3. The main function ( Camera calibration : Get internal parameters 、 Distortion coefficient , External reference < The calibration phase is not very useful >)

#  Define number of corners ,  Chessboard size ( It should be possible to write at will , It does not affect the parameter calibration ), Image path ,  Image type 
def calib(inter_corner_shape, size_per_grid, img_dir, img_type):
    #  Generate the world coordinate system coordinates of the corner 
    # np.mgrid()  Return to multidimensional structure , It is recommended to try the specific functions by yourself 
    w, h = inter_corner_shape
    cp_int = np.zeros((w * h, 3), np.float32)
    cp_int[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)
    cp_world = cp_int * size_per_grid
    obj_points = []
    img_points = []
    #  Corner extraction 
    images = glob.glob(img_dir + os.sep + '**.' + img_type)
    for fname in images:
        img = cv2.imread(fname)
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        #  Get whether there are corners and corners 
        ret, cp_img = cv2.findChessboardCorners(gray_img, (w, h), None)
        if ret:
            #  Get the optimized corner 
            cp_img = cv2.cornerSubPix(gray_img, cp_img, (11, 11), (-1, -1), criteria)
            obj_points.append(cp_world)
            img_points.append(cp_img)
            #  Draw corners , You can check whether corner extraction is accurate 
            cv2.drawChessboardCorners(img, (w, h), cp_img, ret)
            cv2.imshow('FoundCorners', img)
            cv2.waitKey(100)
    cv2.destroyAllWindows()
    #  Camera calibration 
    #  Parameters : World coordinate system coordinates , Corner coordinates , Images ,None,None( Calibration method , Default )
    #  We need to pay attention to :opencv The middle image is wide 、 high , And numpy Is read differently 
    #  Parameters shall be transmitted in sequence numpy Of 1, 0 Two dimensions 
    _, mat_inter, coff_dis, v_rot, v_trans = cv2.calibrateCamera(obj_points,
                    img_points, gray_img.shape[::-1], None, None)
    #  Internal reference 
    print("internal matrix:\n", mat_inter)
    #  Distortion coefficient 
    print("distortion cofficients:\n", coff_dis)
    #  Rotating vector 
    # print("rotation vectors:\n", v_rot)
    #  Translation vector 
    # print("translation vectors:\n", v_trans)
    #  Project the points of the world coordinate system back to the 2D plane , Calculate the distance error between the projection point and the corner point 
    total_error = 0
    for i in range(len(obj_points)):
        img_points_repro, _ = cv2.projectPoints(obj_points[i], v_rot[i], v_trans[i], mat_inter, coff_dis)
        error = cv2.norm(img_points[i], img_points_repro, cv2.NORM_L2) / len(img_points_repro)
        total_error += error
    print(("Average Error of Reproject: "), total_error / len(obj_points))
    return mat_inter, coff_dis, cp_world

4. Realization ( With detailed notes )

if __name__ == '__main__':
    #  Define number of corners 
    inter_corner_shape = (9, 6)
    #  Define the size of the checkerboard 
    size_per_grid = 0.02
    #  Define image path 
    img_dir = "./data"
    #  Define picture format 
    img_type = "jpg"
    #  Camera calibration 
    mat_inter, coff_dis, cp_world = calib(inter_corner_shape, size_per_grid, img_dir, img_type)
    #  Read the picture to test the calibration effect 
    img = cv2.imread("./data/test01.jpg")
    h, w = img.shape[:2]
    # new To optimize the parameter matrix ,roi by opencv Areas of interest considered , It can be used to cut the black edge after distortion removal 
    #  When parameters 1 Change it to 0 when ,opencv Will automatically crop the image 
    #  Be careful w and h
    new, roi = cv2.getOptimalNewCameraMatrix(mat_inter, coff_dis, (w, h), 1, (w, h))
    x, y, w, h = roi
    print(roi)
    #  Image de distortion , Method 1 
    dst = cv2.undistort(img, mat_inter, coff_dis, None, new)
    #  Image de distortion , Method 2 , There is a little problem , You can try it yourself 
    # mapx, mapy = cv2.initUndistortRectifyMap(mat_inter, coff_dis, None, new, (w, h), 5)
    # dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
    cv2.namedWindow('origin', cv2.WINDOW_NORMAL)
    cv2.namedWindow('no_cut', cv2.WINDOW_NORMAL)
    cv2.namedWindow('cut', cv2.WINDOW_NORMAL)
    cv2.namedWindow('img_with_line', cv2.WINDOW_NORMAL)
    cv2.imshow('origin', img)
    cv2.imshow('cut', dst[y: y+h, x: x+w])
    cv2.imshow('no_cut', dst)
    #  Visual wiring , The process is as follows 
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    #  Corner finding  ->  Optimize corner  ->  Get external parameters  ->  Transformation of external parameter matrix  ->  Select the world coordinate system points to draw  ->  Get the projection point of the world coordinate system point on the image  ->  Draw a line 
    ok, corners = cv2.findChessboardCorners(gray, (inter_corner_shape[0], inter_corner_shape[1]), )
    if ok:
        exact_corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        _, rvec, tvec, inliers = cv2.solvePnPRansac(cp_world, exact_corners, mat_inter, coff_dis)
        axis = 0.02 * np.float32([[0, 0, -8], [8, 0, 0], [8, 5, 0], [0, 5, 0]]).reshape(-1, 3)
        imgpts, _ = cv2.projectPoints(axis, rvec, tvec, mat_inter, coff_dis)
        img = draw(img, corners, imgpts)
        cv2.imshow('img_with_line', img)
    cv2.waitKey(0)

5. Result display

 6. Code link

360sorround/calibration at main · liuweixue001/360sorround (github.com)

7. Subsequent updates

1. Image de distortion 、 Aerial view generation 、 Image mosaic 、 Image fusion :liuweixue001/360sorround: 360 Look around -- Camera calibration -> Distortion treatment -> Overhead transformation -> Image mosaic (github.com)

2. C++ Version related work :

liuweixue001/360surround-2.0-: A simple case , contain : Image de distortion 、 Overhead transformation 、 Image mosaic and fusion (github.com)

原网站

版权声明
本文为[No change of name]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202280550191455.html