相机标定python、cpp--关于标定板一奇一偶--深度图与RGB对齐

相机标定:

https://docs.opencv.org/3.4/d9/d47/samples_2cpp_2tutorial_code_2features2D_2Homography_2homography_from_camera_displacement_8cpp-example.html

教程:

https://docs.opencv.org/3.4/d9/dab/tutorial_homography.html

https://docs.opencv.org/3.4/examples.html

https://docs.opencv.org/3.4/d3/d81/tutorial_contrib_root.html

 

http://www.technolabsz.com/2012/07/camera-calibration-using-opencv.html

https://github.com/warp1337/opencv_cam_calibration/blob/master/src/camera_calibration.cpp

https://github.com/warp1337/opencv_cam_calibration

https://docs.opencv.org/2.4/doc/tutorials/calib3d/camera_calibration/camera_calibration.html

 

相机校准和3D重建
相机校准
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html
姿态估计
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_pose/py_pose.html
对极几何
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.html
立体图像的深度图
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_depthmap/py_depthmap.html

 

彩色图对齐深度图:::

深度图像配准(Registration)原理

https://www.cnblogs.com/cv-pr/p/5769617.html

 

intel realsense SR300 深度图像和彩色图像对齐

https://blog.csdn.net/jay463261929/article/details/53582800

 

Kinect深度图与RGB摄像头的标定与配准

https://blog.csdn.net/aichipmunk/article/details/9264703

补充我写的一些:

# coding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
import json
import os

#为深度图像中的每一个像素附上对应的RGB颜色: 深度图坐标系转换到RGB坐标系

#为RGB图像中的每一个像素附上对应的深度: RGB坐标系转换到深度图坐标系

'''
-0.991604  -0.126243  -0.027989  214.997275
-0.122135  0.985481  -0.117944  133.474350
0.042472  -0.113535  -0.992626  407.073850
0.000000  0.000000  0.000000  1.000000
'''
R_dep = np.array([[-0.991604,  -0.126243,  -0.027989],
                  [-0.122135,  0.985481,  -0.117944],
                  [0.042472,  -0.113535,  -0.992626]])
t_dep = np.array([[214.997275,133.474350,407.073850]]).T

'''
-0.990949  -0.125081  -0.048724  189.587175
-0.118729  0.986054  -0.116626  194.357782
0.062633  -0.109786  -0.991980  383.686418
0.000000  0.000000  0.000000  1.000000
'''
R_rgb = np.array([[-0.990949,  -0.125081,  -0.048724],
                  [-0.118729,  0.986054,  -0.116626],
                  [0.062633,  -0.109786,  -0.991980]])
t_rgb = np.array([[189.587175,194.357782,383.686418]]).T


R_dep = np.matrix(R_dep)
t_dep = np.matrix(t_dep)
R_rgb = np.matrix(R_rgb)
t_rgb = np.matrix(t_rgb)

print("R_dep\n", R_dep, "\n")
print("t_dep\n", t_dep, "\n")
print("R_rgb\n", R_rgb, "\n")
print("t_rgb\n", t_rgb, "\n")

#为深度图像中的每一个像素附上对应的RGB颜色: 深度图坐标系转换到RGB坐标系
#所有旋转矩阵都是正交阵,因此可用转置运算代替求逆运算
#R_rgb2dep = R_rgb * R_dep.I
R_dep2rgb = R_rgb * R_dep.T
T_dep2rgb = t_rgb - (R_dep2rgb * t_dep)
print("R_rgb2dep\n", R_dep2rgb, "\n")
print("T_rgb2dep\n", T_dep2rgb, "\n")

#XYZ = K_rgb * R_dep2rgb * K_dep.T * Z_dep * Point_dep + K_rgb * T_dep2rgb
'''
void computeC2MC1(const Mat &R1, const Mat &tvec1, const Mat &R2, const Mat &tvec2,
                  Mat &R_1to2, Mat &tvec_1to2)
{
    //c2Mc1 = c2Mo * oMc1 = c2Mo * c1Mo.inv()
    R_1to2 = R2 * R1.t();
    tvec_1to2 = R2 * (-R1.t()*tvec1) + tvec2;
}
Mat R_1to2, t_1to2;
computeC2MC1(R1, tvec1, R2, tvec2, R_1to2, t_1to2);
'''

# R2 = R_rgb
# R1 = R_dep
# tvec2 = t_rgb
# tvec1= t_dep
#
# R_dep2rgb = R2 * R1.T;
# T_dep2rgb = R2 * (-R1.T*tvec1) + tvec2;
#
# print("R_rgb2dep\n", R_dep2rgb, "\n")
# print("T_rgb2dep\n", T_dep2rgb, "\n")





#结果
''' 
 [[ 0.99978415  0.00351069  0.02047798]
 [-0.00348663  0.99999324 -0.00122868]
 [-0.02048311  0.00115602  0.9997894 ]] 

T_rgb2dep
 [[-34.16833064]
 [ 62.1341124 ]
 [-19.05218977]] 
'''

import pcl
import pcl.pcl_visualization

def depth2cloud(depth, intrinsics):
    # https://blog.csdn.net/renyuanxingxing/article/details/89846404
    cloud = pcl.PointCloud()
    rows = len(depth)
    cols = len(depth[0])
    pointcloud = []
    for m in range(0, rows):
        for n in range(0, cols):
            d = depth[m][n]
            if d == 0:
                pass
            else:
                z = float(d) / intrinsics[2][2]
                x = (n - intrinsics[0][2]) * z / intrinsics[0][0]
                y = (m - intrinsics[1][2]) * z / intrinsics[1][1]
                points = [x, y, z]
                pointcloud.append(points)
    pointcloud = np.array(pointcloud, dtype=np.float32)
    cloud.from_array(pointcloud)
    return cloud

'''
'''
        //相机1
        Mat rvec1, tvec1;
        solvePnP(objectPoints, corners1, leftcameraMatrix, leftdistCoeffs, rvec1, tvec1);


        //相机2
        Mat rvec2, tvec2;
        solvePnP(objectPoints, corners2, rightcameraMatrix, rightdistCoeffs, rvec2, tvec2);


        //利用罗德里格斯公式,将旋转向量转为旋转矩阵
        Mat R1, R2;
        Rodrigues(rvec1, R1);
        Rodrigues(rvec2, R2);



        //同一场景下,计算两个相机之间的RT
        //相机1到相机2的Rt
        Mat R_1to2, tvec_1to2;
        R_1to2 = R2 * R1.t();
        tvec_1to2 = R2 * (-R1.t()*tvec1) + tvec2;

        std::cout<<"1to2_rgb2dep"<<std::endl;
        cout << fixed << setprecision(0) << R_1to2 << endl;
        cout << fixed << setprecision(0) << t_1to2 << endl;











        //相反求是否也对????
        //相机2到相机1的Rt
        Mat R_2to1, tvec_2to1;
        R_2to1 = R1 * R2.t();
        tvec_2to1 = R1 * (-R2.t()*tvec2) + tvec1;

        std::cout<<"2to1_dep2rgb"<<std::endl;
        cout << fixed << setprecision(0) << R_2to1 << endl;
        cout << fixed << setprecision(0) << t_2to1 << endl;

 

Kinect深度图与摄像头RGB的标定与配准(转载文章)有很多新东西

https://blog.csdn.net/aidem_brown/article/details/83713961

 

kinect 2.0 SDK学习笔记(四)--深度图与彩色图对齐

https://blog.csdn.net/jiaojialulu/article/details/53154045

 

kinect深度图与彩图匹配

https://blog.csdn.net/cocoaqin/article/details/77428100?fps=1&locationNum=3

 

深度摄像头与彩色摄像头的对齐

https://www.cnblogs.com/rogerjin/p/7845866.html

 

请教关于Kinect深度和彩色图融合的问题?

https://www.zhihu.com/question/29631310

https://devblogs.microsoft.com/cppblog/kinect-for-windows-c-samples/

国外的标定:

http://rgbdemo.org/index.php/Documentation/Calibration

http://burrus.name/index.php/Research/KinectCalibration#tocLink5

 

Kinect彩色图深度图配准(分辨率不一样时的处理方式):

http://blog.csdn.net/shihz_fy/article/details/43602393

 

ROS下的驱动与图像序列保存及opencv显示深度坐标:

http://blog.csdn.net/sunbibei/article/details/51594824

 

SDK获取出厂内参数代码,MATLAB 标定Kinect v2等

http://blog.csdn.net/jiaojialulu/article/details/77430563

 

https://blog.csdn.net/h532600610/article/details/51800488

Corners中的角点坐标顺序排列规律不一定是以行从左上到右下。

使用坐标计算映射关系时应提高警惕,对坐标进行重新排列

 

标定板横纵方向点数一奇一偶,检测到的点顺序就是固定的。板不标准,无法判断起始坐标点。

 

总结:该函数的功能就是判断图像内是否包含完整的棋盘图,如果能够检测完全,就把他们的角点坐标按顺序(逐行,从左到右)记录下来,并返回非0数,否则返回0。这里对size参数要求非常严格,函数必须检测到相同的size才会返回非0,否则返回0,这里一定要注意。角点检测不完全时,可能画不出图像,或者画出红色角点;正确的图像后面有参考。 
该函数检测的角点的坐标是不精确的,要想精确结果,需要使用cornerSubPix()函数,进行亚像素精度的调整。

 

recoverPose求Rt

https://python.hotexamples.com/examples/cv2/-/recoverPose/python-recoverpose-function-examples.html

https://github.com/CarlosHVMoraes/py3DRec

c++版本:https://blog.csdn.net/AIchipmunk/article/details/48157369

# coding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
import json
import os

def mkdir(path):
    import os
    isExists = os.path.exists(path)
    if not isExists:
        os.makedirs(path)

def searchCheckerboardDirFile(rootDir, garyimglist, rgbimglist, namelist, bboxflag):
    for dir_or_file in os.listdir(rootDir):
        filePath = os.path.join(rootDir, dir_or_file)
        # 判断是否为文件
        if os.path.isfile(filePath):
            # 如果是文件再判断是否以.jpg结尾,不是则跳过本次循环
            if bboxflag in filePath:
                if os.path.basename(filePath).endswith('.png'):
                    if os.path.exists(filePath.replace("_IMG_Texture_8Bit.png", "_IMG_DepthMap.tif")):
                        nameTemp = filePath.split('/')[-1]
                        tempPath = filePath.split(nameTemp)[0]
                        tempName = tempPath.split('/')[-2]
                        garyimglist.append(os.path.join(tempPath, "OtherSampleFrame_IMG_Texture_8Bit.png"))
                        rgbimglist.append(os.path.join(tempPath, "OtherSampleFrame_IMG_Rgb.jpg"))
                        namelist.append(tempName)
            else:
                continue
        # 如果是个dir,则再次调用此函数,传入当前目录,递归处理。
        elif os.path.isdir(filePath):
            searchCheckerboardDirFile(filePath, garyimglist, rgbimglist, namelist, bboxflag)
        else:
            print('not file and dir '+os.path.basename(filePath))
    return garyimglist,rgbimglist, namelist

R1path = "./R2"
R1undistort = "./R2_undistort"
R1draw = "./R2_draw"
flagTemp = "-R2-"
mkdir(R1undistort)
mkdir(R1draw)

R1garyimglist = []
R1rgbimglist = []
R1namelist = []
R1garyimglist, rgbimglist, R1namelist = searchCheckerboardDirFile(R1path, R1garyimglist, R1rgbimglist, R1namelist, flagTemp)


patternSize = (9, 9)
patternH = 9
patternW = 9
# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵,认为在棋盘格这个平面上Z=0
objp = np.zeros((patternW*patternH,3), np.float32) #构造0矩阵,81行3列,用于存放角点的世界坐标
objp[:,:2] = np.mgrid[0:patternW,0:patternH].T.reshape(-1,2)# 三维网格坐标划
#棋盘格在真实世界的大小 20mm
patternDistance = 20
objp = objp * patternDistance
# 储存棋盘格角点的世界坐标和图像坐标对
objpoints = [] # 在世界坐标系中的三维点
imgpoints = [] # 在图像平面的二维点


cornersSubPix1 = []
cornersSubPix2 = []
for exR1 in range(len(R1garyimglist)):
    print(exR1, "/", len(R1garyimglist), "\n")
    grayTemp = cv2.imread(R1garyimglist[exR1], -1)
    GRAYH, GRAYW = grayTemp.shape[:2]

    rgb = cv2.imread(rgbimglist[exR1], -1)
    fliprgb = np.flip(rgb).copy()
    # flip 会把读入的bgr图像,转换乘rgb图像,那么等会儿的cvtColor,其实是rgb去做这个函数了,为了统一,我们把他弄回BGR
    fliprgb = cv2.cvtColor(fliprgb, cv2.COLOR_RGB2BGR)

    LeftImgNewgray = cv2.cvtColor(fliprgb, cv2.COLOR_BGR2GRAY)
    RightImggray = cv2.cvtColor(grayTemp, cv2.COLOR_BGR2GRAY)

    patternSize = (9, 9)
    cornersLeft = None
    cornersRight = None

    test = 0
    if test == 0:
        retLeft, cornersLeft = cv2.findChessboardCorners(LeftImgNewgray, patternSize, cornersLeft,
                                                         cv2.CALIB_CB_ADAPTIVE_THRESH)
        retRight, cornersRight = cv2.findChessboardCorners(RightImggray, patternSize, cornersRight,
                                                           cv2.CALIB_CB_ADAPTIVE_THRESH)
    else:
        retLeft, cornersLeft = cv2.findChessboardCorners(LeftImgNewgray, patternSize, cornersLeft,
                                                        cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FILTER_QUADS)
        retRight, cornersRight = cv2.findChessboardCorners(RightImggray, patternSize, cornersRight,
                                                        cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FILTER_QUADS)

    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    if (retLeft and retRight):
        SubPix = 1
        if SubPix:
            img1 = cv2.drawChessboardCorners(LeftImgNewgray.copy(), patternSize, cornersLeft, retLeft)
            #cv2.imwrite("./R1/"+R1namelist[exR1]+"LeftResult.png", img1)
            cornersSubPix1 = cv2.cornerSubPix(LeftImgNewgray, cornersLeft, (11, 11), (-1, -1), criteria)
            img1_ = cv2.drawChessboardCorners(LeftImgNewgray.copy(), patternSize, cornersSubPix1, retLeft)
            cv2.imwrite(R1draw + "/"+R1namelist[exR1]+"LeftSubPixResult.png", img1_)


            # img2 = cv2.drawChessboardCorners(RightImggray.copy(), patternSize, cornersRight, retLeft)
            # #cv2.imwrite("./R1/"+R1namelist[exR1]+"RightResult.png", img2)
            # cornersSubPix2 = cv2.cornerSubPix(RightImggray, cornersRight, (11, 11), (-1, -1), criteria)
            # img2_ = cv2.drawChessboardCorners(RightImggray.copy(), patternSize, cornersSubPix2, retRight)
            # #cv2.imwrite(R1draw + "/"+R1namelist[exR1]+"RightSubPixResult.png", img2_)

            #求彩色相机内参畸变
            objpoints.append(objp)
            imgpoints.append(cornersSubPix1)

        else:
            cornersSubPix1.extend(cornersLeft)
            cornersSubPix2.extend(cornersRight)
    else:
        print("棋盘格检测有问题")
        print(R1namelist[exR1])
        continue

rgbTemp = cv2.imread(rgbimglist[0], -1)
fliprgbTemp = np.flip(rgbTemp).copy()
fliprgbTemp = cv2.cvtColor(fliprgbTemp, cv2.COLOR_RGB2BGR)
gary = cv2.cvtColor(fliprgbTemp, cv2.COLOR_BGR2GRAY)


# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gary.shape[::-1], None, None)

print("mtx\n", mtx, "\n")
print("dist\n", dist, "\n")

for exR1 in range(len(rgbimglist)):
    print("去畸变:",exR1, "/", len(rgbimglist), "\n")

    rgb = cv2.imread(rgbimglist[exR1], -1)
    fliprgb = np.flip(rgb).copy()
    fliprgb = cv2.cvtColor(fliprgb, cv2.COLOR_RGB2BGR)

    h,  w = LeftImgNewgray.shape[:2]
    newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),0,(w,h)) # 自由比例参数
    dst = cv2.undistort(fliprgb, mtx, dist, None, newcameramtx)
    cv2.imwrite(R1undistort + '/'+R1namelist[exR1] + ".jpg", dst)

# 反投影误差
total_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)
    total_error += error
print("total error: ", total_error/len(objpoints))


 

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值