OpenCV和Python - 如何通过指定坐标来叠加图像?

时间:2017-07-12 06:38:50

标签: python opencv image-processing

简而言之,我的问题是如何通过为添加的图像指定特定坐标来将图像放在另一个上面?我需要扩展"画布"根据需要添加基本图像,以便添加的图像不会被裁剪。

这是扩展版本:

我的项目是拍摄从无人机视频中提取的照片,并通过将一张照片与最后一张照片对齐,制作一张粗略的地图。我知道有一些软件我可以用来做这个,比如Agisoft Photoscan,但我的目标是创建一个更轻量级,粗糙的解决方案。

所以这是我的计划,我打算对每一帧做:

  1. 使用estimateRigidTransform生成转换矩阵,使curr_photo与最后一张照片base
  2. 对齐
  3. 计算封闭结果图像所需的边界矩形(使用四个角的变换)
  4. 修改变换矩阵,使边界框的左上角位于原点
  5. 使用边界矩形的宽度和高度将变换应用于当前照片,以确保不会裁剪生成的图像
  6. 通过在适当的坐标处将curr_image添加到base,使用最后一个图像(确保不会出现任何图像的裁剪)超级强加当前图像。这一步是我要问的。
  7. 以下是执行第一步到第四步的代码。

    import numpy as np
    import cv2
    
    
    base = cv2.imread("images/frame_03563.jpg")
    curr_photo = cv2.imread("images/frame_03564.jpg")
    
    height, width = curr_photo.shape[:2]
    
    # Step 1
    # which transformation is required to go from curr_photo to base?
    transformation = cv2.estimateRigidTransform(curr_photo, base, True)
    
    # Step 2
    # add a line to the affine transformation matrix so it can be used by
    # perspectiveTransform
    three_by_three = np.array([
        transformation[0],
        transformation[1],
        [0, 0, 1]], dtype="float32")
    
    # get corners of curr_photo (to be transformed)
    corners = np.array([
        [0, 0],
        [width - 1, 0],
        [width - 1, height - 1],
        [0, height - 1]
    ])
    
    # where do the corners of the image go
    trans_corners = cv2.perspectiveTransform(np.float32([corners]), three_by_three)
    
    # get the bounding rectangle for the four corner points (and thus, the transformed image)
    bx, by, bwidth, bheight = cv2.boundingRect(trans_corners)
    
    # Step 3
    # modify transformation matrix so that the top left of the bounding box is at the origin
    transformation[0][2] = transformation[0][2] - bx
    transformation[1][2] = transformation[1][2] - by
    
    # Step 4
    # transform the image in a window the size of its bounding rectangle (so no cropping)
    mod_curr_photo = cv2.warpAffine(curr_photo, transformation, (bwidth, bheight))
    
    # for viewing
    cv2.imshow("base", base)
    cv2.imshow("current photo", curr_photo)
    cv2.imshow("image2 transformed to image 1", mod_curr_photo)
    
    cv2.waitKey()
    

    我还附上了两张样本图片。我用第一个作为基础,但无论哪种方式都可以。

    Base

    Current

1 个答案:

答案 0 :(得分:2)

Edit: I have now turned the answer linked below into a Python module, which you can now grab from GitHub here.


I answered this question a few weeks ago. The answer should contain everything needed to accomplish what you're after; the only thing I don't discuss there is alpha blending or other techniques to blend the borders of the images together as you would with a panorama or similar.

In order to not crop the warped photo you need to calculate the needed padding beforehand because the image warp itself could reference negative indices, in which case it won't draw them...so you need to calculate the warp locations first, pad your image enough to account for those indices outside your image bounds, and then modify your warp matrix to add those translations in so they get warped to positive values.

This allows you to create an image like this:

Blended, warped, padded image

Image from Oxford's VGG.