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)