OpenCV、Python:航拍图像拼接中的透视变形问题

问题描述

目前,我正在对航拍素材进行图像拼接。我正在使用数据集,从 OrchardDataset 获取。首先,感谢 stackoverflow 上的一些很棒的答案,尤其是来自 @alkasm(HereHere)的答案。但是我遇到了一个问题,您可以在下面的 Gap within the stitched image 部分看到。

我使用了 H21H31H41 等来包装图像。使用 H21 的拼接图像非常好,但是当使用 img3current stitched image 包裹到 H31 时,结果显示 img3current stitched image 之间的对齐很糟糕.随着我包裹的图像越多,间隙变得越大,图像完全没有对齐。

优秀的 stackoverflow 社区是否有关于如何解决这个问题的想法?

这些是我用来拼接图像的步骤:

  1. 每秒从素材中提取帧,并使用提供的相机校准矩阵不失真图像以消除鱼眼效应。
  2. 计算SIFT 特征描述符。使用 FLANN kd-tree 设置 macther 并查找图像之间的匹配项。找到 HomographyH21H32H43 等,其中 H21 指的是扭曲的单应性imag2 转换为 img1) 的坐标
  3. 使用 Here 中建议的方法将单应性与之前的单应性组合以获得净单应性。 (计算 H31H41H51 等)
  4. 使用 Here 中提供的答案包装图像。

拼接图像内的间隙

我使用的是从 OrchardDataSet 获取的前 10 张图片。

Stitched Image with Gaps

这是我的脚本部分:

main.py

ref_img 是第一帧 (img1)。 AdjHomoSet 包含要包装的图像(img2img3img4 等)。 AccHomoSet 包含净单应性(H31H41H51 等)

temp_mosaic = ref_img
h,w = temp_mosaic.shape[:2]
# Wrap the Images 
for x in range(1,(len(AccHomoSet)+1)):
    query_img = AdjHomoSet['H%d%d'%(x+1,(x))][1]
    M_homo = AccHomoSet['H%d1'%(x+1)]

    M_homo_inv = np.linalg.inv(M_homo)

    (shifted_transf,dst_padded) = warpPerspectivePadded(query_img,temp_mosaic,M_homo_inv)
    dst_pad_h,dst_pad_w = dst_padded.shape[:2]

    next_img_warp = cv2.warpPerspective(query_img,shifted_transf,(dst_pad_w,dst_pad_h),flags=cv2.INTER_NEAREST)

    # Put the base image on an enlarged palette
    enlarged_base_img = np.zeros((dst_pad_h,dst_pad_w,3),np.uint8)

    # Create masked composite
    (ret,data_map) = cv2.threshold(cv2.cvtColor(next_img_warp,cv2.COLOR_BGR2GRAY),255,cv2.THRESH_BINARY)

    # add base image
    enlarged_base_img = cv2.add(enlarged_base_img,dst_padded,mask=np.bitwise_not(data_map),dtype=cv2.CV_8U)

    final_img = cv2.add(enlarged_base_img,next_img_warp,dtype=cv2.CV_8U)

    temp_mosaic = final_img

warpPerspectivePadded.py

def warpPerspectivePadded(image,homography):
    src_h,src_w = image.shape[:2]
    lin_homg_pts = np.array([[0,src_w,0],[0,src_h,src_h],[1,1,1]])

    trans_lin_homg_pts = homography.dot(lin_homg_pts)
    trans_lin_homg_pts /= trans_lin_homg_pts[2,:]

    minX = np.floor(np.min(trans_lin_homg_pts[0])).astype(int)
    minY = np.floor(np.min(trans_lin_homg_pts[1])).astype(int)
    maxX = np.ceil(np.max(trans_lin_homg_pts[0])).astype(int)
    maxY = np.ceil(np.max(trans_lin_homg_pts[1])).astype(int)

    # add translation to the transformation matrix to shift to positive values
    anchorX,anchorY = 0,0
    transl_transf = np.eye(3,3)
    if minX < 0: 
        anchorX = -minX
        transl_transf[0,2] += anchorX
    if minY < 0:
        anchorY = -minY
        transl_transf[1,2] += anchorY
    shifted_transf = transl_transf.dot(homography)
    shifted_transf /= shifted_transf[2,2]

    # create padded destination image
    temp_mosaic_h,temp_mosaic_w = temp_mosaic.shape[:2]

    pad_widths = [anchorY,max(maxY,temp_mosaic_h) - temp_mosaic_h,anchorX,max(maxX,temp_mosaic_w) - temp_mosaic_w]

    dst_padded = cv2.copyMakeBorder(temp_mosaic,pad_widths[0],pad_widths[1],pad_widths[2],pad_widths[3],cv2.BORDER_CONSTANT)

    return (shifted_transf,dst_padded)

解决方法

最终我使用 Jahaniam Real Time Video Mosaic 提供的方法改变了扭曲图像的方式。他将参考图像定位在空白图像预设尺寸的中间位置,计算后续单应性并将相邻图像扭曲到参考图像。

Example of stitched image

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...