【计算机视觉】OpenCV实现单目相机标定

文章目录

单目相机标定(基于Python OpenCV)

1.上期填坑

在开始本篇博客之前,先填一下上一篇博客【计算机视觉】基于ORB角点+RANSAC算法实现图像全景拼接的坑(不算填吧,算做一个记录,因为并没有解决问题,留着看以后有没有空解决??),不想看的可以直接跳到下一节。

首先解决如何拼接多张图像(上篇博客只能拼接两张图像,多张图像需要保存两张图像的匹配结果,再重新读取计算角点)

改进的方法的基本思路是,仅计算当前两张图像的单应变换M_current,通过先前的单应矩阵M_before再计算一个累积变换,最终通过矩阵乘法得到的M的变换就延续了当前变换的累积变换矩阵:

    # 一开始无先前变换,因此设置为单位阵
    M_before = np.eye(3,3)
    result = cv2.imread('datas/1.jpg')
    # result = CalcUndistort(result, mtx, dist)
    result,_,_ = utils.auto_reshape(result, 1080)
    img2 = result
    cors2, desc2= extraORBfromImg(orb, img2)

    for i in range(1,6):
        print(i)
        img1 = cv2.imread('datas/'+str(i+1)+'.jpg')
        # img1 = CalcUndistort(img1, mtx, dist)
        img1,_,_ = utils.auto_reshape(img1, 1080)
        cors1, desc1= extraORBfromImg(orb, img1)
        
        match_dist, match_idx = ORBMatch(match, desc1, desc2)
        # 得到匹配点对的坐标
        match_pts = findMatchCord(match_idx, cors1, cors2)
        # 可视化匹配点
        # utils.drawMatches(img1, img2, cors1, cors2, match_idx)
        # RANSAC迭代去除异常点对
        update_match_pts = RANSAC(match_pts)
        # 最小二乘方法计算单应矩阵
        M = calc_homography(update_match_pts)
        # 图像拼接结果可视化, 并传递累积单应变换矩阵M ,返回先前累积拼接结果result
        result, M = homography_trans(M, M_before, img1, result)
        M_before = M
        # 不用再提取一遍:
        img2 = img1
        cors2, desc2 = cors1, desc1

值得注意的是,代码采用的匹配顺序是从右至左,为了保证每次只提取最左侧图像的角点,img1对于图像的拍摄时序应该要在img2的左侧

相应的,函数homography_trans也要做修改:

# 可视化图像对映射效果
def homography_trans(M, M_before, img1, img2):
    M = M_before @ M
    # out_img 第一张图像映射到第二张
    x_min, x_max, y_min, y_max, M2 = calc_border(M, img1.shape)
    # 透视变换+平移变换(使得图像在正中央)
    M = M2 @ M
    w, h = int(round(x_max)-round(x_min)), int(round(y_max)-round(y_min))
    out_img = cv2.warpPerspective(img1, M, (w, h))
    # print(out_img.shape)
    # cv2.imshow('ww',out_img)
    # cv2.waitKey(0)
    # 调整两张图像位姿一致:
    # x方向
    out_img_blank_x = np.zeros((out_img.shape[0], abs(round(x_min)), 3)).astype(np.uint8)
    img2_blank_x = np.zeros((img2.shape[0], abs(round(x_min)), 3)).astype(np.uint8)
    if(x_min>0):
        # print(1)
        out_img = cv2.hconcat((out_img_blank_x, out_img))
    if(x_min<0):
        # print(2)
        img2 = cv2.hconcat((img2_blank_x, img2))
    # y方向
    out_img_blank_y = np.zeros((abs(round(y_min)), out_img.shape[1], 3)).astype(np.uint8)
    img2_blank_y = np.zeros((abs(round(y_min)), img2.shape[1], 3)).astype(np.uint8)
    if(y_min>0):
        # print(3)
        out_img = cv2.vconcat((out_img, out_img_blank_y))
    if(y_min<0):
        # print(4)
        img2 = cv2.vconcat((img2_blank_y, img2))
    # 调整两张图像尺度一致(边缘填充):
    if(img2.shape[0]<out_img.shape[0]):
        blank_y = np.zeros((out_img.shape[0]-img2.shape[0], img2.shape[1], 3)).astype(np.uint8)
        img2 = cv2.vconcat((img2, blank_y)) 
    else:
        blank_y = np.zeros((img2.shape[0]-out_img.shape[0], out_img.shape[1], 3)).astype(np.uint8)
        out_img = cv2.vconcat((out_img, blank_y)) 
    if(img2.shape[1]<out_img.shape[1]):
        blank_x = np.zeros((img2.shape[0], out_img.shape[1]-img2.shape[1], 3)).astype(np.uint8)
        img2 = cv2.hconcat((img2, blank_x)) 
    else:
        blank_x = np.zeros((out_img.shape[0], img2.shape[1]-out_img.shape[1], 3)).astype(np.uint8)
        out_img = cv2.hconcat((out_img, blank_x))        

    # cv2.imwrite('out_img.jpg',out_img)
    # 叠加
    result = addMatches(out_img, img2)

    # 图像背景白
    mask = 255*np.ones(result.shape).astype(np.uint8)
    gray_res = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
    mask[gray_res==0]=0
    cv2.imwrite('mask.jpg',mask)
    # result[result==0]=255
    cv2.imwrite('result.jpg',result)
    return result, M

重点是改了这里(实现单应变换的传递):

... ...
M = M_before @ M
... ...
M = M2 @ M

(Ps:如果从左至右拼接,好像有点问题…)

然后另一个问题是:往后的拼接图像计算出的单应矩阵就会越扭曲:整一个视觉效果就会像

  • 9
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值