
##1.适用于红外热成像相机、rgb相机、红外相机只要能拍摄出多张棋盘格图像即可##2. 代码输出的RMSRoot Mean Square是一个统计学上的术语表示均方根误差。在相机标定的上下文中RMS误差是衡量标定质量的一个指标。它表示的是重投影误差的均方根值即计算出的相机参数用于将三维世界坐标点投影到图像平面上时这些投影点与实际检测到的图像点之间的误差的均方根值。具体来说RMS值越小表示相机标定的精度越高计算出的相机参数越接近真实值。反之如果RMS值较大则可能意味着标定过程中存在较多的误差可能是由于图像质量不佳、棋盘格角点检测不准确或其他原因造成的。##3. 注意pattern_size指定了棋盘格的角点尺寸square_size指定了格子的实际尺寸单位为厘米当棋盘格更换时就需要重新改动这些参数以符合当前标定的棋盘格参数。##4. 操作步骤用相机拍摄多张棋盘格图片后新建文件夹data并将拍摄得到的棋盘格图像放入以下代码运行可以遍历data中所有的棋盘格图像之后代码会综合所有棋盘格图像的处理结果输出相机内参、RMS值、畸变参数与畸变校正前后的图像角点检测结果。其余操作可查看代码中的注释已经很详细了。##5. 对于相机内参、畸变参数的解释与原理可参考网站https://blog.csdn.net/MobooV/article/details/128730417# Python 2/3 compatibility from __future__ import print_function import numpy as np import cv2 as cv # local modules def splitfn(fn): path, fn os.path.split(fn) name, ext os.path.splitext(fn) return path, name, ext # built-in modules import os def main(): import sys import getopt from glob import glob args, img_mask getopt.getopt(sys.argv[1:], , [debug, square_size, threads]) args dict(args) args.setdefault(--debug, C:/Users/zhao/Desktop/realsense/test/output)##填入输入图像角点检测与畸变校正前后的图像输出路径 args.setdefault(--square_size, 2.5)##棋盘格单个格子的实际尺寸单位为厘米 args.setdefault(--threads, 4)##cpu线程数设置用于并行处理多个图像 if not img_mask: img_mask C:/Users/zhao/Desktop/realsense/test/data/??.jpg # default ##填入输入图像的路径采用??.jpg形式可以遍历并处理所有文件夹1中的所有图像从而综合给出相机标定结果与相机畸变参数 else: img_mask img_mask[0] img_names glob(img_mask) debug_dir args.get(--debug) if debug_dir and not os.path.isdir(debug_dir): os.mkdir(debug_dir) square_size float(args.get(--square_size)) pattern_size (11, 8)##pattern_size 是一个元组指定了棋盘格的尺寸即棋盘格的角点数宽度和高度。这里棋盘格的尺寸被设置为 11x8这意味着棋盘格有 11 个角点宽和 8 个角点高。 pattern_points np.zeros((np.prod(pattern_size), 3), np.float32) pattern_points[:, :2] np.indices(pattern_size).T.reshape(-1, 2) pattern_points * square_size obj_points [] img_points [] h, w cv.imread(img_names[0], cv.IMREAD_GRAYSCALE).shape[:2] # TODO: use imquery call to retrieve results def processImage(fn): print(processing %s... % fn) img cv.imread(fn, 0) if img is None: print(Failed to load, fn) return None assert w img.shape[1] and h img.shape[0], (size: %d x %d ... % (img.shape[1], img.shape[0])) found, corners cv.findChessboardCorners(img, pattern_size) if found: term (cv.TERM_CRITERIA_EPS cv.TERM_CRITERIA_COUNT, 30, 0.1) cv.cornerSubPix(img, corners, (5, 5), (-1, -1), term) if debug_dir: vis cv.cvtColor(img, cv.COLOR_GRAY2BGR) cv.drawChessboardCorners(vis, pattern_size, corners, found) _path, name, _ext splitfn(fn) outfile os.path.join(debug_dir, name _chess.png) cv.imwrite(outfile, vis) if not found: print(chessboard not found) return None print( %s... OK % fn) return (corners.reshape(-1, 2), pattern_points) threads_num int(args.get(--threads)) if threads_num 1: chessboards [processImage(fn) for fn in img_names] else: print(Run with %d threads... % threads_num) from multiprocessing.dummy import Pool as ThreadPool pool ThreadPool(threads_num) chessboards pool.map(processImage, img_names) chessboards [x for x in chessboards if x is not None] for (corners, pattern_points) in chessboards: img_points.append(corners) obj_points.append(pattern_points) # calculate camera distortion rms, camera_matrix, dist_coefs, _rvecs, _tvecs cv.calibrateCamera(obj_points, img_points, (w, h), None, None) print(\nRMS:, rms) print(camera matrix:\n, camera_matrix) print(distortion coefficients: , dist_coefs.ravel()) print((rvecs:\n), _rvecs) # 相机坐标系与标定板间的旋转向量 # 外参数 print((tvecs:\n), _tvecs) # 相机坐标系与标定板间的平移向量 # 外参数 # Save results to a text file if debug_dir: result_file os.path.join(debug_dir, calibration_results.txt) with open(result_file, w) as f: f.write(RMS: {}\n.format(rms)) f.write(Camera Matrix:\n) f.write(str(camera_matrix) \n) f.write(Distortion Coefficients: {}\n.format(dist_coefs.ravel())) # undistort the image with the calibration print() for fn in img_names if debug_dir else []: _path, name, _ext splitfn(fn) img_found os.path.join(debug_dir, name _chess.png)##output文件夹中保存得到的_chess.png为畸变校正前的角点检测图像 outfile os.path.join(debug_dir, name _undistorted.png)##output文件夹中保存得到的_undistorted.png为畸变校正后的角点检测图像 img cv.imread(img_found) if img is None: continue h, w img.shape[:2] newcameramtx, roi cv.getOptimalNewCameraMatrix(camera_matrix, dist_coefs, (w, h), 1, (w, h)) dst cv.undistort(img, camera_matrix, dist_coefs, None, newcameramtx) # crop and save the image x, y, w, h roi dst dst[y:yh, x:xw] print(Undistorted image written to: %s % outfile) cv.imwrite(outfile, dst) print(Done) if __name__ __main__: print(__doc__) main() cv.destroyAllWindows()