我正在尝试创建地毯的高分辨率合成图像,所有部分都清晰可见。为此,我想到的最好方法是对地毯的不同部分拍摄几张照片,然后将它们缝合在一起。
我最初是使用 Photoshop API 来完成此操作,但最近(在过去 30 天内)Adobe 将 Photoshop API 捆绑到了 Firefly 中,目前仅适用于企业版。所以现在我正在尝试为此创建一个 OpenCV 函数。
我的原始图像是:-
从上到下(图5、3、1) | 从上到下(图6、4、2) |
---|---|
图5 |
图6 |
图3 |
图4 |
图片 1 |
图 2 |
这些图像的高分辨率版本可在此处
获得我尝试使用 Open CV 的缝合器类来执行此操作,甚至使用了多个参数,但它们似乎适用于某些图像集,而不是所有图像集。所以目前正在采用这种手动方法。
我正在做成对缝合。 所以在第一次迭代中我会将行缝合在一起
1 与 2 缝合
3 与 4 缝合
5 与 6 缝合
结果还不错 |
---|
第 1 行 |
第 2 行 |
第 3 行 |
我能够进行混合和曝光补偿以获得无缝结果,因此我们可以在这些测试图像中忽略它们。
下一步是将第 1 行与第 2 行缝合,得到结果,然后将这些结果与第 3 行缝合以获得最终的合成结果。结果是:-
最终结果 |
---|
第 1 行和第 2 行 |
上面与第 3 行缝合 |
我没有裁剪图像以保持真实性,所以请原谅拼接图像中额外的白色部分。
如果您查看最终图像,会发现地毯边缘有轻微的错位。这是我无法删除的。
我的代码是
import cv2
from loader import load_images
from stitcher import stitch_images_manual
def main():
corrected_images_dir = "out"
num_images = 6 # Adjust this to the number of images you have
rows = 3 # Number of rows in your grid
columns = 2 # Number of columns in your grid
# Load images
images = load_images(corrected_images_dir, num_images)
if len(images) == 0:
print("No images loaded.")
return
# Stitch images in pairs for each row
row_images = []
for i in range(rows):
start_idx = i * columns
pair = [images[start_idx], images[start_idx + 1]]
print(f'Stitching row {i + 1} with images {start_idx + 1} and {start_idx + 2}')
stitched_row = stitch_images_manual(pair[0], pair[1])
if stitched_row is not None:
row_images.append(stitched_row)
cv2.imwrite(f'out/stitched_row_{i + 1}.png', stitched_row)
print(f'Saved stitched row {i + 1} as stitched_row_{i + 1}.png')
else:
print(f'Stitching failed for row {i + 1}')
return
if __name__ == "__main__":
main()
import cv2
import numpy as np
from features import detect_and_compute_features
from homography import compute_homography
from warp import warp_image
from resize import resize_image
from camera_params import estimate_initial_camera_params, refine_camera_params
def stitch_images_manual(image1, image2, scale_percent=50):
print(f"Stitching images of shapes: {image1.shape} and {image2.shape}")
# # Resize images to medium resolution
# image1_resized = resize_image(image1, scale_percent)
# image2_resized = resize_image(image2, scale_percent)
# Convert images to grayscale
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGRA2GRAY)
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGRA2GRAY)
# Detect SIFT features and compute descriptors
keypoints1, descriptors1 = detect_and_compute_features(gray1)
keypoints2, descriptors2 = detect_and_compute_features(gray2)
# Match features using FLANN matcher
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=10)
search_params = dict(checks=500)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(descriptors1, descriptors2, k=2)
# Apply ratio test
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
if len(good_matches) < 4:
print("Not enough good matches to compute homography.")
return None
# Extract location of good matches
points1 = np.zeros((len(good_matches), 2), dtype=np.float32)
points2 = np.zeros((len(good_matches), 2), dtype=np.float32)
for i, match in enumerate(good_matches):
points1[i, :] = keypoints1[match.queryIdx].pt
points2[i, :] = keypoints2[match.trainIdx].pt
# Compute homography
h = compute_homography(points1, points2)
if h is None:
return None
# Get dimensions of input images
height1, width1 = image1.shape[:2]
height2, width2 = image2.shape[:2]
# Determine canvas size based on stitching direction
if height1 > height2:
canvas_width = max(width1, width2)
canvas_height = height1 + height2
else:
canvas_width = width1 + width2
canvas_height = max(height1, height2)
# Warp the second image to the first image's plane
warped_image2 = warp_image(image2, h, (canvas_width, canvas_height))
# Create the stitched image canvas
result = np.zeros((canvas_height, canvas_width, 4), dtype=np.uint8)
result[0:height1, 0:width1] = image1
# Create a mask of where the warped image has valid pixels
mask = np.any(warped_image2 != 0, axis=2)
# Paste the warped image pixels into the result image
result[mask] = warped_image2[mask]
return result
import cv2
import numpy as np
def warp_image(image, homography, canvas_size):
warped_image = cv2.warpPerspective(image, homography, canvas_size)
# cv2.imshow("warped",warped_image)
# cv2.waitKey(0)
# cv2.destroyAllWindows
return warped_image
import os
import cv2
def load_images(image_dir, num_images):
images = []
for i in range(1, num_images + 1):
image_path = os.path.join(image_dir, f'{i}.png')
if os.path.exists(image_path):
img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
if img.shape[2] == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
images.append(img)
print(f'Loaded image {i} with shape {img.shape}')
else:
print(f'Image {image_path} not found.')
return images
import cv2
import numpy as np
def compute_homography(points1, points2):
h, mask = cv2.findHomography(points2, points1, cv2.RANSAC)
if h is None:
print("Homography computation failed.")
return h
import cv2
def detect_and_compute_features(image):
sift = cv2.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(image, None)
return keypoints, descriptors
目前,我首先手动缝合行,然后旋转结果并通过更改行参数再次输入它们。这只是我的懒惰工作并且很容易解决,所以也请忽略它。
对于如何改善结果有什么想法吗?我尝试在删除背景后拼接图像,但即使这样也不起作用。
任何可以引导我走向正确方向的提示或指示将不胜感激。
我已经尝试了几个来自 github 的缝合包,但都给出了类似的未对齐结果。
作为评论中讨论的总结:OpenCVs拼接模块支持至少两种获取图像的方式
全景(球体,无平移,透视)
平板扫描(平面、平移、无透视)
您的用例不适合两者之一。然而,正如 Christoph Rackwitz 指出的那样:
如果地毯平放在地面上,则要纹理化的表面是 飞机。它不是一个球体。单应性适合组合 将地毯的图片融入到它的一大纹理中。
事实上,OpenCV 能够估计图像的单应性。
OpenCV 提供不同的单应性变形器(请参阅 stitching_detailed.py 或 stitching 包)。使用
plane
整经机 可能会获得更好的结果