我没有获得正确的全景图像,并且图像质量随着图像的缝合而降低。我期待获得正确的 360 度图像,并且不会因正确拼接而降低质量。当我使用网络摄像头图像时。它应该得到没有不匹配的拼接图像。我正在研究匹配 FCFS 中的图像或最佳匹配的方法。创建并添加一个输入图像以及 image1 和 image2 的函数,并使用homography_stitching 和 warpPerspective() 组合该图片,组合两个图像后将创建一个黑色区域,但您必须使用此代码删除它并将新图像另存为在一个文件夹中。然后将image3和新保存的图像合并,并将新生成的图像保存在一个文件夹中。让这个过程继续下去,直到所有图像都加载完毕,依此类推
import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
cv2.ocl.setUseOpenCL(False)
import warnings
warnings.filterwarnings("ignore")
feature_extraction_algo = 'sift'
feature_to_match = 'bf'
# Load images from folder
def load_images_from_folder(folder):
images = []
for filename in os.listdir(folder):
img = cv2.imread(os.path.join(folder, filename))
if img is not None:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
images.append(img)
return images
# Initialize feature detector
def select_descriptor_methods(image, method=None):
assert method is not None, "Please define a feature descriptor method. Accepted values are: 'sift', 'surf'"
if method == 'sift':
descriptor = cv2.SIFT_create()
elif method == 'surf':
descriptor = cv2.SURF_create()
elif method == 'brisk':
descriptor = cv2.BRISK_create()
elif method == 'orb':
descriptor = cv2.ORB_create()
keypoints, features = descriptor.detectAndCompute(image, None)
return keypoints, features
# Create matching object
def create_matching_object(method, crossCheck):
if method in ['sift', 'surf']:
return cv2.BFMatcher(cv2.NORM_L2, crossCheck=crossCheck)
elif method in ['orb', 'brisk']:
return cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=crossCheck)
# Keypoints matching
def key_points_matching(features_train_img, features_query_img, method):
bf = create_matching_object(method, crossCheck=True)
best_matches = bf.match(features_train_img, features_query_img)
return sorted(best_matches, key=lambda x: x.distance)
def key_points_matching_KNN(features_train_img, features_query_img, ratio, method):
bf = create_matching_object(method, crossCheck=False)
rawMatches = bf.knnMatch(features_train_img, features_query_img, k=2)
matches = [m for m, n in rawMatches if m.distance < n.distance * ratio]
return matches
def homography_stitching(keypoints_train_img, keypoints_query_img, matches, reprojThresh):
keypoints_train_img = np.float32([keypoint.pt for keypoint in keypoints_train_img])
keypoints_query_img = np.float32([keypoint.pt for keypoint in keypoints_query_img])
if len(matches) > 4:
points_train = np.float32([keypoints_train_img[m.queryIdx] for m in matches]).reshape(-1, 1, 2)
points_query = np.float32([keypoints_query_img[m.trainIdx] for m in matches]).reshape(-1, 1, 2)
H, status = cv2.findHomography(points_train, points_query, cv2.RANSAC, reprojThresh)
return matches, H, status
else:
return None
# Crop the black areas from the panorama
def crop_black_area(image):
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
_, thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 0:
return image
x, y, w, h = cv2.boundingRect(contours[0])
return image[y:y+h, x:x+w]
# Initialize with the first two images
def stitch_images(images, method, feature_to_match):
panorama = images[0]
panorama_gray = cv2.cvtColor(panorama, cv2.COLOR_RGB2GRAY)
for i in range(1, len(images)):
train_photo = images[i]
train_photo_gray = cv2.cvtColor(train_photo, cv2.COLOR_RGB2GRAY)
keypoints_train_img, features_train_img = select_descriptor_methods(train_photo_gray, method=method)
keypoints_panorama_img, features_panorama_img = select_descriptor_methods(panorama_gray, method=method)
if feature_to_match == 'bf':
matches = key_points_matching(features_train_img, features_panorama_img, method=method)
elif feature_to_match == 'knn':
matches = key_points_matching_KNN(features_train_img, features_panorama_img, ratio=0.75, method=method)
M = homography_stitching(keypoints_train_img, keypoints_panorama_img, matches, reprojThresh=4)
if M is None:
print(f"Homography stitching failed for image {i}")
continue
matches, homography_matrix, status = M
width = panorama.shape[1] + train_photo.shape[1]
height = max(panorama.shape[0], train_photo.shape[0])
result = cv2.warpPerspective(train_photo, homography_matrix, (width, height))
result[0:panorama.shape[0], 0:panorama.shape[1]] = panorama
panorama = crop_black_area(result)
panorama_gray = cv2.cvtColor(panorama, cv2.COLOR_RGB2GRAY)
plt.figure(figsize=(40, 20))
plt.axis('off')
plt.imshow(panorama)
plt.savefig(f'./output/panorama_{i}.jpeg', bbox_inches='tight', dpi=300, format='jpeg')
plt.show()
return panorama
# Load the images
images = load_images_from_folder(r'C:\Users\Varad Naik\Downloads\image-stitching-main\image-stitching-main\samples\mountain')
if len(images) < 2:
print("Need at least two images to create a panorama")
else:
result_panorama = stitch_images(images, method=feature_extraction_algo, feature_to_match=feature_to_match)
plt.figure(figsize=(80, 40))
plt.axis('off')
plt.imshow(result_panorama)
plt.savefig('./output/final_panorama.jpg', bbox_inches='tight', dpi=300, format='jpeg')
cv2.imshow("Final Panorama", cv2.cvtColor(result_panorama, cv2.COLOR_RGB2BGR))
cv2.waitKey(0)
cv2.destroyAllWindows()
我期待一个正确的 360 度图像,而不会因为正确的拼接而失去质量。当我使用网络摄像头图像时。它应该得到没有不匹配的拼接图像
好的,我可以帮助理解代码并改进它,以便获得更好的全景拼接结果。
代码概述
提供的代码实现了一个使用特征点检测和单应性变换的图像拼接流水线。以下是逐步分解:
- 加载图像: 从指定文件夹加载多个图像。
- 特征提取:
- 使用 SIFT、SURF、BRISK 或 ORB 等选定算法从图像中提取特征点(关键点和描述符)。
- 关键点表示图像中的重要点(如角点),而描述符是这些点的数学表示,用于将它们与其他点区分开来。
- 特征匹配:
- 使用暴力匹配器 (BFMatcher) 或基于 k 最近邻 (KNN) 的匹配器在图像对之间找到匹配的特征点。
- 这确定了图像之间的对应关系。
- 单应性估计:
- 使用找到的匹配特征点计算图像对之间的单应性矩阵。
- 单应性矩阵是一个 3x3 矩阵,它描述了两个图像平面之间的几何变换(假设它们位于同一平面上)。
- 图像扭曲和拼接:
- 使用计算出的单应性矩阵对其中一个图像进行扭曲(投影)。
- 然后将扭曲的图像与参考图像融合在一起,创建更大的全景图。
- 裁剪黑色区域:
- 从拼接后的全景图中删除不需要的黑色边界,这些边界可能是图像对齐和扭曲造成的。
改进拼接质量的技巧
- 图像对齐:
- 最佳匹配: 虽然代码包括暴力匹配器和 KNN 匹配器,但探索更强大的匹配技术(如具有比率检验的第二近邻匹配)以减少错误匹配至关重要。错误匹配会导致对齐不准确。
-
RANSAC 优化:
代码使用 RANSAC 来估计单应性,这是一个强大的技术,但调整其参数(例如,
reprojThresh
值)会影响结果。尝试使用不同的值来找到最佳设置。 - 图像融合:
- 多分辨率融合: 考虑使用多分辨率融合技术,例如拉普拉斯金字塔融合或梯度融合。这些技术可以最大限度地减少接缝伪影,尤其是在曝光或颜色差异很大的图像中。
- 失真校正:
- 柱面或球面投影: 对于较宽的全景图(接近 360 度或更大),使用柱面或球面投影可以帮助最大限度地减少失真。这些投影提供了更逼真的表示。
- 曝光补偿和颜色校正:
- 在拼接之前均衡输入图像的曝光和颜色可以显着提高最终全景图的视觉质量。
解决黑色区域
代码中已经包含了用于裁剪黑色区域的函数
crop_black_area()
。此函数识别并删除由对齐和扭曲的图像引起的任何黑色边界。
360 度全景图
要创建完整的 360 度全景图,需要捕获一组重叠的图像,这些图像覆盖整个 360 度视图。捕获图像时要保持一致的朝向和高度,这一点很重要。
针对网络摄像头图像进行优化
- 实时拼接: 对于网络摄像头流,需要优化代码以实现实时性能。这可能涉及使用高效的特征提取和匹配算法,以及降低图像分辨率。
- 循环拼接: 要创建 360 度全景图,需要检测到第一张图像和最后一张图像之间的循环,并相应地拼接它们。
其他提示
- 为了提高准确性,请在特征点丰富的区域(例如,具有高对比度或纹理的区域)中捕获具有足够重叠(大约 30-50%)的图像。
- 尝试不同的特征提取和匹配算法,以找到最适合的图像集的算法。
- 使用高质量的图像捕获设备,以最大限度地减少噪点和模糊。
通过实施这些改进和优化,可以显着提高全景图像拼接的结果并创建令人惊叹的 360 度全景图。
标签:python,image,opencv,image-processing,image-stitching From: 78805201