opencv 中如何通过欧式距离估算实际距离(厘米)

发布于:2024-07-11 ⋅ 阅读:(18) ⋅ 点赞:(0)

1:这个方法个人测试觉得是正确的,误差较小,目前满足我当前的需求,如果方法不对,请大家评论,完善。

2:确保拍摄的参照物是垂直的,如果不垂直,就会有误差,不垂直的角度越大,误差越大。

实际中主要是利用无人机拍摄的俯视图,计算边缘到特定点的距离。

3:使用棋盘格作为物理参照物,如下

4:代码

import cv2
import numpy as np
import glob
def get_K_and_D(checkerboard, imgsPath):

    CHECKERBOARD = checkerboard
    subpix_criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01)
    calibration_flags = cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC+cv2.fisheye.CALIB_CHECK_COND+cv2.fisheye.CALIB_FIX_SKEW
    objp = np.zeros((1, CHECKERBOARD[0]*CHECKERBOARD[1], 3), np.float32)
    objp[0,:,:2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)*50
    
    _img_shape = None
    #print(objp)
    #objp+=200
    objpoints = []
    imgpoints = []
    images = glob.glob(imgsPath + '/*.jpg')
    for fname in images:
        img = cv2.imread(fname)
        
        if _img_shape == None:
            _img_shape = img.shape[:2]
        else:
            assert _img_shape == img.shape[:2], "All images must share the same size."

        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD,cv2.CALIB_CB_ADAPTIVE_THRESH) #+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)
        if ret == True:
            objpoints.append(objp)
            cv2.cornerSubPix(gray,corners,(5,5),(-1,-1),subpix_criteria)
            imgpoints.append(corners)
            #print(images)
    N_OK = len(objpoints)
    #print(objpoints)
    K = np.zeros((3, 3))
    D = np.zeros((4, 1))
    rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
    tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
    rms, _, _, _, _ = cv2.fisheye.calibrate(
        objpoints,
        imgpoints,
        gray.shape[::-1],
        K,
        D,
        rvecs,
        tvecs,
        calibration_flags,
        (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6)
    )



            
    DIM = _img_shape[::-1]
    print("Found " + str(N_OK) + " valid images for calibration")
    print("DIM=" + str(_img_shape[::-1]))
    print("K=np.array(" + str(K.tolist()) + ")")
    print("D=np.array(" + str(D.tolist()) + ")")
    print("rms",rms)
    return DIM, K, D,corners



if __name__ == '__main__':
    
    BORAD_HEIGHT=3
    BORAD_WIDTH=3
    radius = 1
    color = (0, 0, 255)  # BGR格式,红色
    thickness = 2

    DIM, K, D,corners = get_K_and_D((BORAD_HEIGHT, BORAD_WIDTH), './distance')   
    dst_img=cv2.imread("./distance/img_dst_distance.jpg")
    
    cnt=0
    print(corners)
    for index in range(len(corners)): 
        x, y = corners[index][0]
        color = (0, 0, 255)  # BGR格式,红色
        cv2.putText(dst_img, str(cnt), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 1,color, thickness)
        color = (0, 255, 255)  # BGR格式,红色
        cv2.circle(dst_img,(int(x),int(y)), radius, color, thickness)
        cnt+=1

    dist_total=0
    for i in range(BORAD_HEIGHT):
        print(i * BORAD_WIDTH,(i+1) * BORAD_WIDTH-1)
        print(corners[i * BORAD_WIDTH,:])
        dist = cv2.norm(corners[i * BORAD_WIDTH,:], corners[(i+1) * BORAD_WIDTH-1,:], cv2.NORM_L2)
        dist_total += dist / (BORAD_WIDTH - 1)

   
    dist_square = dist_total / BORAD_HEIGHT
    print("dst_img.shape:",dst_img.shape)
    print("dist_square:",dist_square)
    realy_board_length=13.5/2 #厘米,13.5是从尺子测量出来2个正方形边长的长度,所以单个要除以2
    realy_H=dst_img.shape[0]*realy_board_length/dist_square
    realy_W=dst_img.shape[1]*realy_board_length/dist_square
    print("realy_H",realy_H)
    print("realy_W",realy_W)
    ret=1
    cv2.drawChessboardCorners(dst_img, (BORAD_HEIGHT,BORAD_WIDTH), corners, ret)
    cv2.imshow("org_img", dst_img)
    cv2.waitKey(0)