刘虾 2025-11-03 09:23 采纳率: 49.4%
浏览 12
已结题

python+opencv读取两张图像进行拼接图像

python+opencv读取两张图像进行拼接图像
图像一左边(200x5000)和图像二(4800x
5000)右边有重叠区域,大概占图像的五分之一,两张图像的像素比较大(5000x5000),将图像一左边大概固定区域(200x5000)和图像二右边大概固定区域(4800x5000)计算一个刚性变换的矩阵,将图像二向图像一往右移动(消除重叠),使用一张空白(10000x10000)的图像将这两张图像进行拼接

  • 写回答

3条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-11-03 09:56
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:你现在的努力,是为了以后能有更多的自由。
    .

    Python + OpenCV 图像拼接方案

    针对您的大尺寸图像拼接需求,以下是完整的解决方案:

    思路分析

    1. 两张图像有重叠区域(约1/5宽度)
    2. 需要计算刚性变换矩阵(旋转+平移)
    3. 使用大画布(10000×10000)进行最终拼接

    完整代码实现

    import cv2
    import numpy as np
    
    
    def stitch_images(image1_path, image2_path, output_path):
        """
        拼接两张有重叠区域的大尺寸图像
        
        Args:
            image1_path: 左侧图像路径 (200x5000)
            image2_path: 右侧图像路径 (4800x5000)
            output_path: 输出图像路径
        """
        
        # 读取图像
        img1 = cv2.imread(image1_path)  # 左侧图像
        img2 = cv2.imread(image2_path)  # 右侧图像
        
        if img1 is None or img2 is None:
            print("错误:无法读取图像文件")
            return
        
        print(f"图像1尺寸: {img1.shape}")
        print(f"图像2尺寸: {img2.shape}")
        
        # 定义重叠区域(假设重叠区域占图像2宽度的1/5)
        overlap_ratio = 0.2
        overlap_width = int(img2.shape[1] * overlap_ratio)
        
        # 从图像1提取右侧特征区域(用于匹配)
        img1_features = img1[:, -overlap_width:] if img1.shape[1] > overlap_width else img1
        
        # 从图像2提取左侧特征区域(用于匹配)
        img2_features = img2[:, :overlap_width]
        
        # 转换为灰度图进行特征检测
        gray1 = cv2.cvtColor(img1_features, cv2.COLOR_BGR2GRAY)
        gray2 = cv2.cvtColor(img2_features, cv2.COLOR_BGR2GRAY)
        
        # 使用SIFT特征检测器
        sift = cv2.SIFT_create()
        keypoints1, descriptors1 = sift.detectAndCompute(gray1, None)
        keypoints2, descriptors2 = sift.detectAndCompute(gray2, None)
        
        # 特征匹配
        bf = cv2.BFMatcher()
        matches = bf.knnMatch(descriptors1, descriptors2, k=2)
        
        # 应用Lowe's比率测试筛选好的匹配点
        good_matches = []
        for match_pair in matches:
            if len(match_pair) == 2:
                m, n = match_pair
                if m.distance < 0.7 * n.distance:
                    good_matches.append(m)
        
        print(f"找到 {len(good_matches)} 个好的匹配点")
        
        if len(good_matches) < 4:
            print("错误:匹配点不足,无法计算变换矩阵")
            return
        
        # 提取匹配点的坐标
        src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
        dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
        
        # 注意:由于我们提取的是局部区域,需要调整坐标到完整图像坐标系
        src_pts[:, 0, 0] += img1.shape[1] - overlap_width  # 图像1的特征区域在右侧
        dst_pts[:, 0, 0] += 0  # 图像2的特征区域在左侧
        
        # 计算刚性变换矩阵(只包含旋转和平移)
        M, mask = cv2.estimateAffinePartial2D(dst_pts, src_pts, method=cv2.RANSAC, ransacReprojThreshold=5.0)
        
        if M is None:
            print("错误:无法计算变换矩阵")
            return
        
        print(f"变换矩阵:\n{M}")
        
        # 创建大画布 (10000x10000)
        canvas = np.zeros((10000, 10000, 3), dtype=np.uint8)
        
        # 计算图像2变换后的位置
        height2, width2 = img2.shape[:2]
        corners = np.array([[0, 0], [width2, 0], [width2, height2], [0, height2]], dtype=np.float32)
        transformed_corners = cv2.transform(corners.reshape(1, -1, 2), M).reshape(-1, 2)
        
        # 计算画布中的偏移量,确保两张图像都能完整显示
        min_x = min(0, transformed_corners[:, 0].min())
        min_y = min(0, transformed_corners[:, 1].min())
        
        offset_x = int(abs(min_x)) + 100  # 添加边距
        offset_y = int(abs(min_y)) + 100
        
        # 将图像1放置到画布上
        h1, w1 = img1.shape[:2]
        canvas[offset_y:offset_y+h1, offset_x:offset_x+w1] = img1
        
        # 变换图像2并放置到画布上
        # 调整变换矩阵以包含偏移
        M_adjusted = M.copy()
        M_adjusted[0, 2] += offset_x
        M_adjusted[1, 2] += offset_y
        
        # 应用变换
        warped_img2 = cv2.warpAffine(img2, M_adjusted, (canvas.shape[1], canvas.shape[0]), 
                                    flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_TRANSPARENT)
        
        # 创建掩码并融合图像
        mask1 = np.zeros((canvas.shape[0], canvas.shape[1]), dtype=np.uint8)
        mask1[offset_y:offset_y+h1, offset_x:offset_x+w1] = 255
        
        mask2 = (warped_img2.sum(axis=2) > 0).astype(np.uint8) * 255
        
        # 简单融合:直接覆盖(对于刚性变换通常效果很好)
        result = canvas.copy()
        result[warped_img2 > 0] = warped_img2[warped_img2 > 0]
        
        # 裁剪掉多余的黑色区域
        non_black_mask = (result.sum(axis=2) > 0)
        coords = np.argwhere(non_black_mask)
        if len(coords) > 0:
            y_min, x_min = coords.min(axis=0)
            y_max, x_max = coords.max(axis=0)
            result = result[y_min:y_max+1, x_min:x_max+1]
        
        # 保存结果
        cv2.imwrite(output_path, result)
        print(f"拼接完成,结果保存至: {output_path}")
        print(f"最终图像尺寸: {result.shape}")
    
    
    # 使用示例
    if __name__ == "__main__":
        # 替换为您的实际图像路径
        image1_path = "left_image.jpg"  # 左侧图像 (200x5000)
        image2_path = "right_image.jpg" # 右侧图像 (4800x5000)
        output_path = "stitched_result.jpg"
        
        stitch_images(image1_path, image2_path, output_path)
    

    关键步骤说明

    1. 特征提取与匹配

    • 使用SIFT算法检测特征点
    • 通过BFMatcher进行特征匹配
    • 应用Lowe's比率测试筛选优质匹配点

    2. 刚性变换计算

    • 使用estimateAffinePartial2D计算只包含旋转和平移的变换矩阵
    • RANSAC算法提高变换矩阵的鲁棒性

    3. 图像拼接

    • 创建10000×10000的大画布
    • 将变换后的图像2与图像1进行融合
    • 自动裁剪黑色边界区域

    优化建议

    1. 内存优化:对于5000×5000的大图像,可以考虑分块处理
    2. 特征检测参数:根据图像特性调整SIFT参数
    3. 融合方式:可以尝试多频段融合以获得更平滑的过渡

    这个方案应该能够很好地处理您的大尺寸图像拼接需求。如果遇到具体问题,可以进一步调整参数。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 11月16日
  • 已采纳回答 11月8日
  • 修改了问题 11月3日
  • 修改了问题 11月3日
  • 展开全部