CV2 Python - 基于单应性矩阵的图像合并 - 合并错误

0 投票
0 回答
28 浏览
提问于 2025-04-12 06:23

我正在做一个项目,需要合并一些(超过1000张)正射影像。首先,我想知道我有哪些选择,因为我觉得我还没有找到所有的解决方案。

其次,我遇到了一个具体的问题。我的问题是,当我想把第二张图片添加到第一张图片上时,背景(原本是透明的)把第三张图片遮住了。我觉得我的错误在于放置方法。

我的最终目标是使用QGIS把这张图片放到地图上,但一个一个地处理并不是最好的方法,合并成更少的部分会更好。

这段代码生成的图片像第一张:

import cv2
import numpy as np

# Load the images
img1 = cv2.imread('out1-163.png')
img2 = cv2.imread('out1-160.png')

# Load the images
image2 = img1
image1 = img2

# Define the size of the border
top, bottom, left, right = [100]*4  # Adjust these values as needed

# Convert image1 to 4-channel RGBA
image1_rgba = cv2.cvtColor(image1, cv2.COLOR_BGR2BGRA)

# Create a transparent border around image1
image1_bordered = image1_rgba
# Convert image2 to 4-channel RGBA
image2_rgba = cv2.cvtColor(image2, cv2.COLOR_BGR2BGRA)

# Create a transparent border around image2
image2_bordered = image2_rgba

# Convert images to grayscale
gray1 = cv2.cvtColor(image1_bordered, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2_bordered, cv2.COLOR_BGR2GRAY)
# Initialize the feature detector and extractor (e.g., SIFT)
sift = cv2.SIFT_create()

# Detect keypoints and compute descriptors for both images
keypoints1, descriptors1 = sift.detectAndCompute(gray1, None)
keypoints2, descriptors2 = sift.detectAndCompute(gray2, None)

# Initialize the feature matcher using brute-force matching
bf = cv2.BFMatcher()

# Match the descriptors using brute-force matching
matches = bf.match(descriptors1, descriptors2)

# Select the top N matches
num_matches = 50
matches = sorted(matches, key=lambda x: x.distance)[:num_matches]

# Extract matching keypoints
src_points = np.float32([keypoints1[match.queryIdx].pt for match in matches]).reshape(-1, 1, 2)
dst_points = np.float32([keypoints2[match.trainIdx].pt for match in matches]).reshape(-1, 1, 2)

# Estimate the homography matrix
homography, _ = cv2.findHomography(src_points, dst_points, cv2.RANSAC, 5.0)

# Calculate the size of the new image
corners = np.array([
    [0, 0],
    [0, image1_bordered.shape[0]],
    [image1_bordered.shape[1], 0],
    [image1_bordered.shape[1], image1_bordered.shape[0]]
], dtype=np.float32)
corners = cv2.perspectiveTransform(corners.reshape(-1, 1, 2), homography).reshape(-1, 2)
min_x, min_y = corners.min(axis=0).astype(int)
max_x, max_y = corners.max(axis=0).astype(int)

width = max(max_x, image2_bordered.shape[1]) - min_x
height = max(max_y, image2_bordered.shape[0]) - min_y

# Adjust the homography matrix to shift the image to the right place
homography[0, 2] -= min_x
homography[1, 2] -= min_y

# Warp image1 to image2 using the adjusted homography matrix
result = cv2.warpPerspective(image1_bordered, homography, (width, height))

# Overlay image2 on the warped image1
startY = max(-min_y, 0)
startX = max(-min_x, 0)
endY = startY + image2_bordered.shape[0]
endX = startX + image2_bordered.shape[1]

# Replace the corresponding pixels in the first image with the pixels from the second image
result[startY:endY, startX:endX] = image2_bordered[:endY-startY, :endX-startX]

# Save the result
cv2.imwrite('merged.png', result)

这是第三张图片合并的代码:

import cv2
import numpy as np

# Load the images    
img1 = cv2.imread('merged.png', cv2.IMREAD_UNCHANGED)
img2 = cv2.imread('out1-164.png')

# Load the images
image2 = img1
image1 = img2

# Define the size of the border
top, bottom, left, right = [100]*4  # Adjust these values as needed

# Convert image1 to 4-channel RGBA
image1_rgba = cv2.cvtColor(image1, cv2.COLOR_BGR2BGRA)

# Create a transparent border around image1
image1_bordered = image1_rgba
# Convert image2 to 4-channel RGBA
image2_rgba = cv2.cvtColor(image2, cv2.COLOR_BGR2BGRA)

# Create a transparent border around image2
image2_bordered = image2_rgba

# Convert images to grayscale
gray1 = cv2.cvtColor(image1_bordered, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2_bordered, cv2.COLOR_BGR2GRAY)
# Initialize the feature detector and extractor (e.g., SIFT)
sift = cv2.SIFT_create()

# Detect keypoints and compute descriptors for both images
keypoints1, descriptors1 = sift.detectAndCompute(gray1, None)
keypoints2, descriptors2 = sift.detectAndCompute(gray2, None)

# Initialize the feature matcher using brute-force matching
bf = cv2.BFMatcher()

# Match the descriptors using brute-force matching
matches = bf.match(descriptors1, descriptors2)

# Select the top N matches
num_matches = 50
matches = sorted(matches, key=lambda x: x.distance)[:num_matches]

# Extract matching keypoints
src_points = np.float32([keypoints1[match.queryIdx].pt for match in matches]).reshape(-1, 1, 2)
dst_points = np.float32([keypoints2[match.trainIdx].pt for match in matches]).reshape(-1, 1, 2)

# Estimate the homography matrix
homography, _ = cv2.findHomography(src_points, dst_points, cv2.RANSAC, 5.0)

# Calculate the size of the new image
corners = np.array([
    [0, 0],
    [0, image1_bordered.shape[0]],
    [image1_bordered.shape[1], 0],
    [image1_bordered.shape[1], image1_bordered.shape[0]]
], dtype=np.float32)
corners = cv2.perspectiveTransform(corners.reshape(-1, 1, 2), homography).reshape(-1, 2)
min_x, min_y = corners.min(axis=0).astype(int)
max_x, max_y = corners.max(axis=0).astype(int)

width = max(max_x, image2_bordered.shape[1]) - min_x
height = max(max_y, image2_bordered.shape[0]) - min_y

# Adjust the homography matrix to shift the image to the right place
homography[0, 2] -= min_x
homography[1, 2] -= min_y

# Warp image1 to image2 using the adjusted homography matrix
result = cv2.warpPerspective(image1_bordered, homography, (width, height))

# Overlay image2 on the warped image1
startY = max(-min_y, 0)
startX = max(-min_x, 0)
endY = startY + image2_bordered.shape[0]
endX = startX + image2_bordered.shape[1]

# Ensure endY and endX do not exceed the size of the result image
endY = min(endY, result.shape[0])
endX = min(endX, result.shape[1])

# Replace the corresponding pixels in the first image with the pixels from the second image
result[startY:endY, startX:endX] = image2_bordered[:(endY-startY), :(endX-startX)]
# Create a mask of image2_bordered
mask = image2_bordered[..., 3] > 0

# Create a mask of non-transparent pixels in image2_bordered
mask = image2_bordered[..., 3] > 0

# Replace the non-transparent pixels in the first image with the pixels from the second image
for c in range(0, 3):
    result[startY:endY, startX:endX, c] = np.where(mask[:(endY-startY), :(endX-startX)], 
                                                   image2_bordered[:(endY-startY), :(endX-startX), c], 
                                                   result[startY:endY, startX:endX, c])

# Save the result
cv2.imwrite('merged2_image.png', result)

我创建的第一张图片:

合并的图片(质量更好,但上传大小有限)

第二张创建的图片: 第三张合并的图片,黑色边框下的图片没有显示(官方透明)

提前谢谢你们!

0 个回答

暂无回答

撰写回答