You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将相机校准结果用于实时场景?remap实现与帧率疑问

实现实时相机畸变校正(基于预计算映射表)

核心优化思路

原代码的问题是在校准过程中仅处理单张图片,实时场景下不能每次帧都重新计算映射表——映射表只需根据校准参数计算一次,之后每帧直接复用即可大幅提升速度。

步骤1:保存校准后的关键参数

修改你的校准函数,将计算好的映射表、新相机矩阵、ROI区域等参数保存下来,避免重复计算:

def calibrateCamera(self, chessboardRows=9, chessboardCols=6, imshow=False):
    self.chessboardRows = chessboardRows
    self.chessboardCols = chessboardCols
    self.imshow = imshow
    chessboardSize = (self.chessboardRows, self.chessboardCols)
    criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    
    objp = np.zeros((self.chessboardCols*self.chessboardRows,3), np.float32)
    objp[:,:2] = np.mgrid[0:self.chessboardRows,0:self.chessboardCols].T.reshape(-1,2)
    
    objpoints = [] 
    imgpoints = [] 

    for path, index in zip(self.paths, self.indices):
        images = glob.glob(path + "*.png")

        for img in images:
            frame = cv.imread(img)
            gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
            ret, corners = cv.findChessboardCorners(gray, chessboardSize, None)

            if ret == True:
                objpoints.append(objp)
                corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
                imgpoints.append(corners2)
                cv.drawChessboardCorners(frame, chessboardSize, corners2, ret)
                if self.imshow == True:
                    cv.imshow(f"Calibrated images, Camera{index}", frame)
                    cv.waitKey(0)
            
            if ret == False:
                print("No pattern detected")
                break

        ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
        h,  w = frame.shape[:2]
        newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))

        # 计算映射表,使用CV_16SC2类型提升remap速度
        mapx, mapy = cv.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w,h), cv.CV_16SC2)
        
        # 保存参数到本地文件
        np.savez(f"camera{index}_calib_params.npz", 
                 mapx=mapx, mapy=mapy, roi=roi)
        
        # 原有的单张图校正显示逻辑可保留,不影响实时功能
        dst = cv.remap(frame, mapx, mapy, cv.INTER_LINEAR)
        x, y, w_roi, h_roi = roi
        dst = dst[y:y+h_roi, x:x+w_roi]
        cv.imshow('calibresult.png', dst)
        k = cv.waitKey(0)

步骤2:实时畸变校正实现

加载预保存的参数,在相机实时读取循环中仅执行remap操作,这是最耗时的部分,但因为映射表已预计算,速度会大幅提升:

def realtime_undistort(camera_index=0):
    # 加载校准参数
    params = np.load(f"camera{camera_index}_calib_params.npz")
    mapx = params['mapx']
    mapy = params['mapy']
    x, y, w_roi, h_roi = params['roi']
    
    # 打开相机
    cap = cv.VideoCapture(camera_index)
    if not cap.isOpened():
        print("无法打开相机")
        return
    
    while True:
        ret, frame = cap.read()
        if not ret:
            print("无法获取帧")
            break
        
        # 实时畸变校正:仅执行预计算好的映射
        undistorted_frame = cv.remap(frame, mapx, mapy, cv.INTER_LINEAR)
        
        # 裁剪ROI区域(可选,根据校准需求)
        undistorted_frame = undistorted_frame[y:y+h_roi, x:x+w_roi]
        
        # 显示结果
        cv.imshow(f"Real-time Undistorted Camera{camera_index}", undistorted_frame)
        
        # 按ESC退出循环
        if cv.waitKey(1) == 27:
            break
    
    cap.release()
    cv.destroyAllWindows()

帧率限制说明

实时校正的帧率受以下因素影响:

  • 相机硬件:相机本身的最大输出帧率(比如USB相机常见30fps,工业相机可到60/120fps)
  • 图像分辨率:分辨率越高,remap计算量越大,帧率越低;1080p比720p帧率下降明显
  • 映射表类型:使用CV_16SC2类型的映射表比CV_32FC1快20%-30%,因为整数运算更高效
  • 插值方式:INTER_NEAREST(最近邻插值)速度最快,但边缘有锯齿;INTER_LINEAR(双线性插值)速度稍慢但画质更好;INTER_CUBIC最慢,实时场景不推荐
  • 硬件性能:CPU核心数、主频越高帧率越高;若有NVIDIA GPU,可使用OpenCV的CUDA模块(cv.cuda.remap),帧率能提升数倍
  • 额外处理:如果实时帧还要叠加其他算法(比如目标检测),会进一步占用资源降低帧率

普通PC上,1080p分辨率下用INTER_LINEAR+CV_16SC2映射表,帧率可稳定在25-30fps;用CUDA加速能轻松达到60fps以上。

内容的提问来源于stack exchange,提问作者cou7inho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 07:20:35