基于MATLAB和python的简易相机标定

准备工具:MATLAB2021A,python,opencv3.4.2.16

图像处理一系列工作往往都需要用到不同、特殊的相机,这些相机不同于日常生活中的普通相机,我们往往需要对其进行标定,以及利用标定参数对所得到的图片进行矫正。

目前业界已有成熟的标定方法——张正友棋盘标定法,这也是我们所常用的。相机标定原理和畸变来源在此就不过多赘述,此篇文章只给出相关软件在相机标定中的使用。

原理部分请自行阅读《视觉SLAM十四讲从理论到实践 第二版》118页至128页 

MATLAB部分

提前准备一块标定板,或者使用命令行生成棋盘格

close all;
clear all;
clc;
width=1024  ;      %pattern的宽
height=768     ;          %pattern的高
img_final=zeros(height,width);
reinforceconner=0       ;%是否加强角点 
row=8;                 %pattern中棋盘格的行数
col=12 ;              %pattern中棋盘格的列数
length=60;           %pattern中棋盘格的大小
org_X=(height-row*length)/2;        %pattern关于纵轴方向的位置,默认放在中间
org_Y=(width-col*length)/2;             %pattern关于横轴方向的位置,默认放在中间
  color1=1;
     color2=color1;
img=zeros(row*length,col*length);
for i=0:(row-1)
    color2=color1;
    for j=0:(col-1)
        if color2==1
        img(i*length+1:(i+1)*length-1,j*length+1:(j+1)*length-1)=color2;
        end
        %不加的话,可以注释掉
        %
        color2=~color2;
    end
    color1=~color1;
end
img_final(org_X:org_X+row*length-1,org_Y:org_Y+col*length-1)=img;
   img_final=~img_final;
     figure;imshow(img_final);   
     imwrite(img_final, 'cheesBoard.bmp','bmp');

 如果使用标定版则如下:

 此标定板是12格*9格*40mm的标定板

接下来在不同位姿和角度拍摄完整的标定板图片,图片数量最好在15至20张

打开matlab,顶部工具栏APP部分,找到Camera Calibrator点击进入 

 进入新的页面后,Add Images 

 顶部栏选择Options,可选择标定参数个数,以及是否测量切向畸变,完成后点击Calibrate进行标定,成功后界面如下,可点击绿色对勾键将数据表示在命令行窗口方便查看各种具体参数

以下参数依次为:

K值,标定时选择三参数则此时有三个值,否则默认两个(径向畸变参数)

P值,两个 (切向畸变参数)

世界坐标

平移矩阵T

相机内参(矩阵)

旋转矩阵R

python opencv部分


import numpy as np
import cv2
import glob

'''
  在这里,我的棋盘格是8*8的,所以角点个数为7*7,当然棋盘格的行列个数可以不一样;
  如果想方便代码改变棋盘格数,是以定义两个变量w(列角点数)和h(行角点数),注意如果角点维数超出的话,标定的时候会报错。
'''

# 终止标准
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# w = 7
# h = 7
# 准备对象点,如(0,0,0),(1,0,0),(2,0,0)......,(6,5,0)
# objp = np.zeros((w*h,3), np.float32)
objp = np.zeros((6 * 6, 3), np.float32)
objp[:, :2] = np.mgrid[0:6, 0:6].T.reshape(-1, 2)

# 用于存储所有图像中的对象点和图像点的数组。
objpoints = []  # 在现实世界空间的3d点
imgpoints = []  # 图像平面中的2d点。
# glob是个文件名管理工具
images = glob.glob(r"C:/Users/ZJH/Desktop/image/*.png")
print('...loading')
for fname in images:
    # 对每张图片,识别出角点,记录世界物体坐标和图像坐标
    print(f'processing img:{fname}')
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转灰度
    print('grayed')
    # 寻找角点,存入corners,ret是找到角点的flag
    # ret, corners = cv2.findChessboardCorners(gray, (w, h),None)
    ret, corners = cv2.findChessboardCorners(gray, (6, 6), None)

    # 如果找到,添加对象点,图像点(精炼后)
    if ret == True:
        print('chessboard detected')
        objpoints.append(objp)
        # 执行亚像素级角点检测
        corners2 = cv2.cornerSubPix(gray, corners, (9, 9), (-1, -1), criteria)
        imgpoints.append(corners2)

        # 绘制并显示角点
       # img = cv2.drawChessboardCorners(img, (w,h), corners2,ret)
        img = cv2.drawChessboardCorners(img, (6, 6), corners2, ret)
        cv2.namedWindow('img', 0)
        cv2.resizeWindow('img', 500, 500)
        cv2.imshow('img', img)
        cv2.waitKey(5000)
        cv2.destroyAllWindows()
'''
传入所有图片各自角点的三维、二维坐标,相机标定。
每张图片都有自己的旋转和平移矩阵,但是相机内参和畸变系数只有一组。
mtx,相机内参;dist,畸变系数;revcs,旋转矩阵;tvecs,平移矩阵。
'''

img2 = cv2.imread(r"C:/Users/ZJH/Desktop/image/Image_20220802101955958.png")
#print(f"type objpoints:{objpoints[0].shape}")
#print(f"type imgpoints:{imgpoints[0].shape}")

ret,mtx,dist,rvecs,tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
h, w = img2.shape[:2]

'''
优化相机内参(camera matrix),这一步可选。
参数1表示保留所有像素点,同时可能引入黑色像素,
设为0表示尽可能裁剪不想要的像素,这是个scale,0-1都可以取。
'''
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
# 纠正畸变
dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)

# 裁剪图像,输出纠正畸变以后的图片
x, y, w, h = roi
dst = dst[y:y + h, x:x + w]
cv2.imwrite('calibresult.png', dst)

# 打印我们要求的两个矩阵参数
print("newcameramtx内参:\n", newcameramtx)
print("dist畸变值:\n", dist)
print("newcameramtx旋转(向量)外参:\n", rvecs)
print("dist平移(向量)外参:\n", tvecs)
print("roi:",roi)
# 计算误差
tot_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    tot_error += error

print("total error: ", tot_error / len(objpoints))

使用时角点检测、存储3D和2D点等部分若图片质量不够高时可将7*7的区域下调为6*6、5*5,此时标定效果会下降,若使用图片质量足够好且标定板大小足够可上调至9*9,效果精度上升。

接下来提供批量矫正代码

import os

import cv2
import numpy as np
import glob


def Correct(path, outpath):
    mtx = [[1.469676421803936e+04,0.00000000e+00 ,2.037223864686618e+03],
           [0.00000000e+00 ,1.469588493956052e+04,1.378055336391949e+03],
           [0.00000000e+00 ,0.00000000e+00 ,1.00000000e+00]]#内参
    dist = [[-0.011893710738358, 4.904839042705877 ,-0.002652573042541,-2.067947202844048e-04
                      ,-1.154190361442721e+02]]#畸变参数--顺序很重要!!!:k1,k2,p1,p2,k3
    image_path = path
    img = cv2.imread(image_path)

    img_distort = cv2.undistort(img, np.array(mtx), np.array(dist))

    # ---------------------------------------------------------------------------------

    cv2.imwrite(outpath, img_distort)

    return img_distort


if __name__ == "__main__":
    count=os.listdir(r"C:/Users/ZJH/Desktop/image")
    countt=os.listdir(r"C:/Users/ZJH/Desktop/image_1")
    for i in range(0,len(count)):
        path=os.path.join("C:/Users/ZJH/Desktop/image",count[i])

        outpath=os.path.join("C:/Users/ZJH/Desktop/image_1/"+count[i].split(".")[0]+".png")

        Correct(path, outpath)
        print(path)
        print(outpath+"\n")
    # path = "C:/Users/ZJH/Desktop/image/31.png"
    # outpath = "C:/Users/ZJH/Desktop/image_1/31.png"
    # Correct(path, outpath)

修改路径,导入参数,参数可使用MATLAB进行标定,快捷且精度较高

参考   计算机视觉——python3实现张正友棋盘相机标定图像

Matlab相机标定方法及主要参数含义,坐标变换过程

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想要头发QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值