首页 > 编程问答 >使用 warpPerspective 生成​​全景图像并使用 python 进行单应拼接

使用 warpPerspective 生成​​全景图像并使用 python 进行单应拼接

时间:2024-07-29 10:19:00浏览次数:13  
标签:python image opencv image-processing image-stitching

我没有获得正确的全景图像,并且图像质量随着图像的缝合而降低。我期待获得正确的 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 度图像,而不会因为正确的拼接而失去质量。当我使用网络摄像头图像时。它应该得到没有不匹配的拼接图像


好的,我可以帮助理解代码并改进它,以便获得更好的全景拼接结果。

代码概述

提供的代码实现了一个使用特征点检测和单应性变换的图像拼接流水线。以下是逐步分解:

  1. 加载图像: 从指定文件夹加载多个图像。
  2. 特征提取:
  3. 使用 SIFT、SURF、BRISK 或 ORB 等选定算法从图像中提取特征点(关键点和描述符)。
  4. 关键点表示图像中的重要点(如角点),而描述符是这些点的数学表示,用于将它们与其他点区分开来。
  5. 特征匹配:
  6. 使用暴力匹配器 (BFMatcher) 或基于 k 最近邻 (KNN) 的匹配器在图像对之间找到匹配的特征点。
  7. 这确定了图像之间的对应关系。
  8. 单应性估计:
  9. 使用找到的匹配特征点计算图像对之间的单应性矩阵。
  10. 单应性矩阵是一个 3x3 矩阵,它描述了两个图像平面之间的几何变换(假设它们位于同一平面上)。
  11. 图像扭曲和拼接:
  12. 使用计算出的单应性矩阵对其中一个图像进行扭曲(投影)。
  13. 然后将扭曲的图像与参考图像融合在一起,创建更大的全景图。
  14. 裁剪黑色区域:
  15. 从拼接后的全景图中删除不需要的黑色边界,这些边界可能是图像对齐和扭曲造成的。

改进拼接质量的技巧

  1. 图像对齐:
  2. 最佳匹配: 虽然代码包括暴力匹配器和 KNN 匹配器,但探索更强大的匹配技术(如具有比率检验的第二近邻匹配)以减少错误匹配至关重要。错误匹配会导致对齐不准确。
  3. RANSAC 优化: 代码使用 RANSAC 来估计单应性,这是一个强大的技术,但调整其参数(例如, reprojThresh 值)会影响结果。尝试使用不同的值来找到最佳设置。
  4. 图像融合:
  5. 多分辨率融合: 考虑使用多分辨率融合技术,例如拉普拉斯金字塔融合或梯度融合。这些技术可以最大限度地减少接缝伪影,尤其是在曝光或颜色差异很大的图像中。
  6. 失真校正:
  7. 柱面或球面投影: 对于较宽的全景图(接近 360 度或更大),使用柱面或球面投影可以帮助最大限度地减少失真。这些投影提供了更逼真的表示。
  8. 曝光补偿和颜色校正:
  9. 在拼接之前均衡输入图像的曝光和颜色可以显着提高最终全景图的视觉质量。

解决黑色区域

代码中已经包含了用于裁剪黑色区域的函数 crop_black_area() 。此函数识别并删除由对齐和扭曲的图像引起的任何黑色边界。

360 度全景图

要创建完整的 360 度全景图,需要捕获一组重叠的图像,这些图像覆盖整个 360 度视图。捕获图像时要保持一致的朝向和高度,这一点很重要。

针对网络摄像头图像进行优化

  • 实时拼接: 对于网络摄像头流,需要优化代码以实现实时性能。这可能涉及使用高效的特征提取和匹配算法,以及降低图像分辨率。
  • 循环拼接: 要创建 360 度全景图,需要检测到第一张图像和最后一张图像之间的循环,并相应地拼接它们。

其他提示

  • 为了提高准确性,请在特征点丰富的区域(例如,具有高对比度或纹理的区域)中捕获具有足够重叠(大约 30-50%)的图像。
  • 尝试不同的特征提取和匹配算法,以找到最适合的图像集的算法。
  • 使用高质量的图像捕获设备,以最大限度地减少噪点和模糊。

通过实施这些改进和优化,可以显着提高全景图像拼接的结果并创建令人惊叹的 360 度全景图。

标签:python,image,opencv,image-processing,image-stitching
From: 78805201

相关文章

  • 通过 python 获取 android.view.ViewGroup 中的子项
    是否可以使用python、adb或任何库从android.view.ViewGroup获取子元素或文本,但不需要java和kotlin?我正在尝试使用python自动化android模拟器。与模拟器的交互通过adb进行。当我得到屏幕转储时,我看到我需要的元素是android.view.ViewGroup,并且text和content-......
  • Python反编译失败。 (不支持的操作码:JUMP_IF_NOT_EXC_MATCH)
    我尝试使用“pycdc.exe”反编译使用pycdc.exe失败。因为错误“不支持的操作码:JUMP_IF_NOT_EXC_MATCH”在此处输入图像描述使用pycdc.exe失败。因为错误“不支持的操作码:JUMP_IF_NOT_EXC_MATCH”你知道我为什么失败吗?(我试图编译的.pyc似乎是3.10版本)......
  • 计算机毕业设计项目推荐,基于Echarts的高校就业数据可视化管理系统 81461(开题答辩+程序
    摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对高校就业管理等问题,对高校就业管理进行研究分析,然后开发设计出高校就业数据可视化管理系统......
  • Python逆向总结(Python反编译)
    目录第一种:直接反编译型第二种:打包成exe的py文件第三种: 给pyc字节码(类汇编形式)第四种:加花的pyc内容参考第一种:直接反编译型除了直接获得题目内容的python文件外,出题人也可以稍微加工一点点,给出题目python文件所对应的pyc文件,即python的字节码。PYC文件的定义pyc......
  • 【Python学习手册(第四版)】学习笔记06-Python动态类型-赋值模型详解
    个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。主要介绍Python的动态类型(也就是Python自动为跟踪对象的类型,不需要在脚本中编写声明语句),Python中变量和对象是如何通过引用关联,垃圾收集的概念,对象共享引用是如何影响多个变量......
  • Python学习手册(第四版)】学习笔记09.3-Python对象类型-分类、引用VS拷贝VS深拷贝、比较
    个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。这部分稍杂,视需要选择目录读取。主要讲的是对之前的所有对象类型作复习,以通俗易懂、由浅入深的方式进行介绍,所有对象类型共有的特性(例如,共享引用),引用、拷贝、深拷贝,以及比较、......
  • 同时运行多个Python文件
    如何同时运行python的多个文件我有三个文件pop.pypop1.pypop2.py我想同时运行这个文件这些文件正在被一一运行python代码运行所有文件可以使用以下几种方法同时运行多个Python文件:1.使用多线程/多进程:多线程(threading):如果的Pytho......
  • 《最新出炉》系列入门篇-Python+Playwright自动化测试-56- 多文件上传 - 下篇
    1.简介前边的两篇文章中,宏哥分别对input控件上传文件和非input控件上传文件进行了从理论到实践地讲解和介绍,但是后来又有人提出疑问,前边讲解和介绍的都是上传一个文件,如果上传多个文件,Playwright是如何实现的呢?宏哥看了一下官方的API也有上传多个文件的API,那么今天就来讲解和介绍......
  • 如何使用python模块捕获用户的文本输入
    我正在开发一个项目,它会检测到如果您按“(”,它会自动关闭它“[”和“{”的情况相同,但重点是它检测键盘按钮“{”或“[”不是字符,这意味着如果朋友有不同的方式输入“[”,它将无法工作,因为该程序用于检测“altgr+(”序列,这可能会影响不同语言的键盘因为您不想在按下......
  • 如何更新 numpy 2 的 python 模块?
    在带有pip的Linux上,新的numpy2似乎可以很好地与pandas配合使用:$python3-c'importnumpyasnp;print(np.__version__);importpandasaspd;print(pd.__version__)'2.0.12.2.2但是,在带有miniconda的Windows上,我得到$${localappdata}/miniconda3/en......