OpenCV和Python - 如何通过指定坐标来叠加图像? [英] OpenCV and Python -- How to superimpose images by specifying coordinates?

查看:2557
本文介绍了OpenCV和Python - 如何通过指定坐标来叠加图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这是扩展版本:



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



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


  1. 使用 estimateRigidTransform 来生成转换矩阵与最后一张照片对齐 curr_photo base

  2. 计算边界

  3. 修改转换矩阵,使边界框的左上角位于原点

  4. 使用边界矩形的宽度和高度将变换应用于当前照片,以确保不会裁剪生成的图像

  5. 使用最后一个图像超级强加当前图像(通过在适当的坐标处将 curr_image 添加到 base ,确保不会出现任何图像的裁剪。这一步是我要问的。

以下是执行第1步到第4步的代码。

  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]

#步骤1
#需要从curr_photo转换到base?
transformation = cv2.estimateRigidTransform(curr_photo,base,True)

#步骤2
#在仿射变换矩阵中添加一行,以便
使用它#perspectiveTransform
three_by_three = np.array([
transformation [0],
transformation [1],
[0,0,1]],dtype =float32)

#获取curr_photo的角落(待转换)
corner = np.array([
[0,0],
[width - 1,0] ,
[宽度 - 1,高度 - 1],
[0,高度 - 1]
])

#图像的角落去哪里
trans_corners = cv2.perspectiveTransform(np.float32([corner]),three_by_three)

#获取四个角点的边界矩形(因此,转换后的图像)
bx,by,bwidth,bheight = cv2.boundingRect(trans_corners)

#步骤3
#修改变换矩阵,使边界框的左上角位于原点
转换[0] [2] =转换[0] [2] - bx
转换格式ion [1] [2] = transformation [1] [2] -

#步骤4
#在窗口中转换图像边界矩形的大小(所以没有裁剪)
mod_curr_photo = cv2.warpAffine(curr_photo,transformation,(bwidth,bheight))

#用于查看
cv2.imshow(base,base)
cv2 .imshow(当前照片,curr_photo)
cv2.imshow(image2变换为图像1,mod_curr_photo)

cv2.waitKey()

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





解决方案

编辑:我现在有了将下面链接的答案转换为Python模块,您现在可以从GitHub中获取



图片来自牛津大学的VGG


In short, my question is how do I put an image on top of another by specifying specific coordinates for the added image? I would need to extend the "canvas" of the base image as needed so that the added image doesn't get cropped.

Here's the extended version:

My project is to take pictures extracted from a drone video and make a rough map with them, by aligning one photo with the last. I know there is software I can use to do this, like Agisoft Photoscan, but my goal is to create a more lightweight, rough solution.

So here's my plan, which I intend to do with each frame:

  1. Use estimateRigidTransform, to generate the transformation matrix to align curr_photo with the last photo, base
  2. Calculate the bounding rectangle needed to enclose the resulting image (using transformations of the four corners)
  3. Modify the transformation matrix so that the top left of the bounding box is at the origin
  4. Apply the transformation to the current photo, using the bounding rectangle's width and height to ensure none of the resulting image gets cropped
  5. Super-impose the current image with the last image (making sure no cropping of either image occurs), by adding curr_image to base at the proper coordinates. This step is what I am asking about.

Here is the code that does steps one to four.

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()

I've also attached two sample images. I used the first one as the base, but it works either way.

解决方案

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:

Image from Oxford's VGG.

这篇关于OpenCV和Python - 如何通过指定坐标来叠加图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆