当前位置: 首页 > news >正文

图像进行拼接-后进行ocr检测识别

一、两张图像拼接

import cv2
import numpy as npdef stitch_images(img1, img2):"""将两张图像拼接在一起:param img1: 第一张图像:param img2: 第二张图像:return: 拼接后的图像"""# 转换为灰度图gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 使用SIFT特征检测器sift = cv2.SIFT_create()# 检测关键点和计算描述符kp1, des1 = sift.detectAndCompute(gray1, None)kp2, des2 = sift.detectAndCompute(gray2, None)# 使用FLANN匹配器进行特征匹配FLANN_INDEX_KDTREE = 1index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)search_params = dict(checks=50)flann = cv2.FlannBasedMatcher(index_params, search_params)matches = flann.knnMatch(des1, des2, k=2)# 筛选好的匹配点good_matches = []for m, n in matches:if m.distance < 0.7 * n.distance:good_matches.append(m)# 提取匹配点的坐标src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)# 计算单应性矩阵H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)# 获取图像尺寸h1, w1 = img1.shape[:2]h2, w2 = img2.shape[:2]# 获取变换后的图像角点corners1 = np.float32([[0, 0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)corners2 = np.float32([[0, 0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2)transformed_corners = cv2.perspectiveTransform(corners1, H)# 计算拼接后图像的尺寸all_corners = np.concatenate((corners2, transformed_corners), axis=0)[x_min, y_min] = np.int32(all_corners.min(axis=0).ravel() - 0.5)[x_max, y_max] = np.int32(all_corners.max(axis=0).ravel() + 0.5)# 计算平移变换矩阵translation_dist = [-x_min, -y_min]H_translation = np.array([[1, 0, translation_dist[0]], [0, 1, translation_dist[1]], [0, 0, 1]])# 应用透视变换和平移result = cv2.warpPerspective(img1, H_translation.dot(H), (x_max - x_min, y_max - y_min))# 将第二张图像拼接到变换后的图像上result[translation_dist[1]:translation_dist[1] + h2, translation_dist[0]:translation_dist[0] + w2] = img2return resultdef blend_images(result, img2, translation_dist):"""对拼接后的图像进行融合处理,使过渡更自然:param result: 拼接后的图像:param img2: 第二张原始图像:param translation_dist: 平移距离:return: 融合后的图像"""h2, w2 = img2.shape[:2]# 创建掩码mask = np.zeros(result.shape[:2], dtype=np.uint8)mask[translation_dist[1]:translation_dist[1] + h2, translation_dist[0]:translation_dist[0] + w2] = 255# 使用泊松融合使过渡更自然center = (translation_dist[0] + w2 // 2, translation_dist[1] + h2 // 2)blended_result = cv2.seamlessClone(img2, result, mask, center, cv2.NORMAL_CLONE)return blended_result# 主程序
if __name__ == "__main__":# 读取两张图像img1 = cv2.imread('01.png')  # 请替换为你的第一张图像路径img2 = cv2.imread('02.png')  # 请替换为你的第二张图像路径if img1 is None or img2 is None:print("错误:无法读取图像文件,请检查路径是否正确")exit()# 调整图像大小(可选,如果图像太大可以调整)img1 = cv2.resize(img1, (0, 0), fx=0.5, fy=0.5)img2 = cv2.resize(img2, (0, 0), fx=0.5, fy=0.5)# 拼接图像result = stitch_images(img1, img2)# 显示结果cv2.imshow('fusion Image', result)cv2.waitKey(0)cv2.destroyAllWindows()# 保存结果cv2.imwrite('fusion.jpg', result)print("拼接完成,结果已保存为 fusion.jpg")

二、多张图像拼接

import cv2
import numpy as npdef correct_curvature(img, curvature_strength=0.3):"""校正图像的曲率,使其更接近平面图像:param img: 输入图像:param curvature_strength: 曲率校正强度 (0-1):return: 校正后的图像"""h, w = img.shape[:2]# 创建映射矩阵map_x = np.zeros((h, w), dtype=np.float32)map_y = np.zeros((h, w), dtype=np.float32)# 中心点坐标center_x, center_y = w // 2, h // 2# 曲率校正参数max_dist = np.sqrt(center_x**2 + center_y**2)for y in range(h):for x in range(w):# 计算当前点到中心的距离dx = x - center_xdy = y - center_ydist = np.sqrt(dx**2 + dy**2)# 曲率校正:将弯曲的点映射到平面上if dist > 0:# 计算校正因子correction = 1 + curvature_strength * (dist / max_dist)**2# 新的坐标new_x = center_x + dx / correctionnew_y = center_y + dy / correction# 确保坐标在图像范围内if 0 <= new_x < w and 0 <= new_y < h:map_x[y, x] = new_xmap_y[y, x] = new_yelse:map_x[y, x] = xmap_y[y, x] = yelse:map_x[y, x] = xmap_y[y, x] = y# 应用重映射进行曲率校正corrected_img = cv2.remap(img, map_x, map_y, cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT)return corrected_imgdef preprocess_images(images, target_width=1536, target_height=2048):"""预处理图像:曲率校正和尺寸调整:param images: 输入图像列表:param target_width: 目标宽度:param target_height: 目标高度:return: 预处理后的图像列表"""processed_images = []for i, img in enumerate(images):if img is None:continueprint(f"预处理图像 {i+1}...")# 1. 曲率校正corrected_img = correct_curvature(img, curvature_strength=0.4)# 2. 调整尺寸(保持宽高比)h, w = corrected_img.shape[:2]# 计算缩放比例,使图像高度接近目标高度scale_factor = target_height / hnew_width = int(w * scale_factor)new_height = target_height# 调整尺寸resized_img = cv2.resize(corrected_img, (new_width, new_height))processed_images.append(resized_img)print(f"图像 {i+1} 预处理完成: {w}x{h} -> {new_width}x{new_height}")return processed_imagesdef find_homography_robust(img1, img2):"""鲁棒的单应性矩阵计算:param img1: 第一张图像:param img2: 第二张图像:return: 单应性矩阵, 匹配点数量"""# 转换为灰度图gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 使用SIFT特征检测器sift = cv2.SIFT_create(nfeatures=5000)# 检测关键点和计算描述符kp1, des1 = sift.detectAndCompute(gray1, None)kp2, des2 = sift.detectAndCompute(gray2, None)if des1 is None or des2 is None or len(des1) < 10 or len(des2) < 10:print("SIFT特征点不足,尝试使用ORB")orb = cv2.ORB_create(3000)kp1, des1 = orb.detectAndCompute(gray1, None)kp2, des2 = orb.detectAndCompute(gray2, None)if des1 is None or des2 is None or len(des1) < 10 or len(des2) < 10:return None, 0# 确保描述符数据类型正确if des1.dtype != np.float32:des1 = des1.astype(np.float32)if des2.dtype != np.float32:des2 = des2.astype(np.float32)# 使用FLANN匹配器FLANN_INDEX_KDTREE = 1index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)search_params = dict(checks=100)flann = cv2.FlannBasedMatcher(index_params, search_params)matches = flann.knnMatch(des1, des2, k=2)# 筛选好的匹配点good_matches = []for match_pair in matches:if len(match_pair) == 2:m, n = match_pairif m.distance < 0.6 * n.distance:good_matches.append(m)if len(good_matches) < 10:return None, len(good_matches)# 提取匹配点坐标src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)# 使用RANSAC计算单应性矩阵H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)return H, len(good_matches)def stitch_two_images_left_right(img1, img2, direction):"""拼接两张图像(修复版):param img1: 新图像:param img2: 基准图像:param direction: 拼接方向 ('left' 或 'right'):return: 拼接结果"""H, num_matches = find_homography_robust(img1, img2)if H is None:print(f"拼接失败,匹配点数量: {num_matches}")return img2# 获取图像尺寸h1, w1 = img1.shape[:2]h2, w2 = img2.shape[:2]try:if direction == 'left':# 将img1拼接到img2的左侧H_inv = np.linalg.inv(H)# 计算变换后的图像尺寸corners1 = np.float32([[0, 0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)transformed_corners = cv2.perspectiveTransform(corners1, H_inv)all_corners = np.concatenate((np.float32([[0, 0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2), transformed_corners), axis=0)[x_min, y_min] = np.int32(all_corners.min(axis=0).ravel() - 0.5)[x_max, y_max] = np.int32(all_corners.max(axis=0).ravel() + 0.5)# 计算平移变换矩阵translation_dist = [-x_min, -y_min]H_translation = np.array([[1, 0, translation_dist[0]], [0, 1, translation_dist[1]], [0, 0, 1]])# 应用透视变换和平移warped_img1 = cv2.warpPerspective(img1, H_translation.dot(H_inv), (x_max - x_min, y_max - y_min))# 创建结果图像result = np.zeros_like(warped_img1)result[:] = warped_img1[:]# 将第二张图像拼接到右侧y_start = translation_dist[1]y_end = translation_dist[1] + h2x_start = translation_dist[0]x_end = translation_dist[0] + w2# 确保不越界y_start = max(0, y_start)x_start = max(0, x_start)y_end = min(result.shape[0], y_end)x_end = min(result.shape[1], x_end)if y_end > y_start and x_end > x_start:result[y_start:y_end, x_start:x_end] = img2[0:y_end-y_start, 0:x_end-x_start]else:  # direction == 'right'# 将img1拼接到img2的右侧# 计算变换后的图像尺寸corners1 = np.float32([[0, 0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)transformed_corners = cv2.perspectiveTransform(corners1, H)all_corners = np.concatenate((np.float32([[0, 0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2), transformed_corners), axis=0)[x_min, y_min] = np.int32(all_corners.min(axis=0).ravel() - 0.5)[x_max, y_max] = np.int32(all_corners.max(axis=0).ravel() + 0.5)# 计算平移变换矩阵translation_dist = [-x_min, -y_min]H_translation = np.array([[1, 0, translation_dist[0]], [0, 1, translation_dist[1]], [0, 0, 1]])# 应用透视变换和平移warped_img1 = cv2.warpPerspective(img1, H_translation.dot(H), (x_max - x_min, y_max - y_min))# 创建结果图像result = np.zeros_like(warped_img1)# 先放置第二张图像(基准图像)y_start = translation_dist[1]y_end = translation_dist[1] + h2x_start = translation_dist[0]x_end = translation_dist[0] + w2# 确保不越界y_start = max(0, y_start)x_start = max(0, x_start)y_end = min(result.shape[0], y_end)x_end = min(result.shape[1], x_end)if y_end > y_start and x_end > x_start:result[y_start:y_end, x_start:x_end] = img2[0:y_end-y_start, 0:x_end-x_start]# 然后叠加变换后的第一张图像result = blend_images_simple(result, warped_img1)return resultexcept Exception as e:print(f"拼接过程中出错: {str(e)}")return img2def blend_images_simple(base_img, overlay_img):"""简单的图像融合:param base_img: 基础图像:param overlay_img: 叠加图像:return: 融合后的图像"""# 确保两张图像尺寸相同if base_img.shape != overlay_img.shape:h, w = base_img.shape[:2]overlay_img = cv2.resize(overlay_img, (w, h))# 创建掩码:叠加图像中非黑色的区域gray_overlay = cv2.cvtColor(overlay_img, cv2.COLOR_BGR2GRAY)mask = gray_overlay > 10# 创建结果图像result = base_img.copy()# 只在叠加图像有内容的地方进行融合for c in range(3):  # 对每个颜色通道result_channel = result[:, :, c]overlay_channel = overlay_img[:, :, c]result_channel[mask] = overlay_channel[mask]return resultdef stitch_images_optimized(images, target_width=1536, target_height=2048):"""优化的多图像拼接算法,专门处理曲率图像:param images: 预处理后的图像列表:param target_width: 目标宽度:param target_height: 目标高度:return: 拼接后的图像"""if len(images) < 2:raise ValueError("至少需要两张图像进行拼接")print("开始图像拼接...")# 如果只有两张图像,直接拼接if len(images) == 2:print("直接拼接两张图像...")result = stitch_two_images_left_right(images[0], images[1], 'right')return resize_to_target(result, target_width, target_height)# 从中间图像开始拼接mid_index = len(images) // 2base_img = images[mid_index]print(f"以第 {mid_index+1} 张图像为基准")# 向左拼接left_result = base_imgfor i in range(mid_index-1, -1, -1):print(f"向左拼接第 {i+1} 张图像...")left_result = stitch_two_images_left_right(images[i], left_result, 'left')if left_result is None:print("向左拼接失败,使用基准图像")left_result = base_img# 向右拼接right_result = base_imgfor i in range(mid_index+1, len(images)):print(f"向右拼接第 {i+1} 张图像...")right_result = stitch_two_images_left_right(images[i], right_result, 'right')if right_result is None:print("向右拼接失败,使用基准图像")right_result = base_img# 合并左右两部分print("合并左右部分...")try:# 简单的左右合并:将右部分拼接到左部分的右侧h_left, w_left = left_result.shape[:2]h_right, w_right = right_result.shape[:2]# 计算总宽度(减去重叠部分估计值)overlap_estimate = w_left // 3  # 估计重叠部分为左图宽度的1/3total_width = w_left + w_right - overlap_estimatetotal_height = max(h_left, h_right)# 创建结果画布result = np.zeros((total_height, total_width, 3), dtype=np.uint8)# 放置左侧部分result[0:h_left, 0:w_left] = left_result# 放置右侧部分(避免重叠)right_start_x = w_left - overlap_estimateresult[0:h_right, right_start_x:right_start_x + w_right] = right_resultfinal_result = resultexcept Exception as e:print(f"合并左右部分失败: {str(e)}")# 如果合并失败,返回较大的那个结果if left_result.shape[1] > right_result.shape[1]:final_result = left_resultelse:final_result = right_result# 最终尺寸调整final_result = resize_to_target(final_result, target_width, target_height)return final_resultdef resize_to_target(img, target_width=1536, target_height=2048):"""调整图像到目标尺寸:param img: 输入图像:param target_width: 目标宽度:param target_height: 目标高度:return: 调整后的图像"""if img is None:return Noneh, w = img.shape[:2]# 如果图像尺寸已经接近目标尺寸,直接返回if abs(w - target_width) < 100 and abs(h - target_height) < 100:return img# 计算缩放比例scale_x = target_width / wscale_y = target_height / hscale = min(scale_x, scale_y)# 计算新尺寸new_width = int(w * scale)new_height = int(h * scale)# 调整尺寸resized = cv2.resize(img, (new_width, new_height))# 创建目标尺寸的画布result = np.zeros((target_height, target_width, 3), dtype=np.uint8)# 计算居中位置y_start = (target_height - new_height) // 2x_start = (target_width - new_width) // 2# 将图像放置在画布中央result[y_start:y_start+new_height, x_start:x_start+new_width] = resizedreturn resultdef post_process(result):"""后处理:增强图像质量:param result: 拼接结果:return: 处理后的图像"""if result is None:return None# 1. 直方图均衡化(分别对每个通道)b, g, r = cv2.split(result)b_eq = cv2.equalizeHist(b)g_eq = cv2.equalizeHist(g)r_eq = cv2.equalizeHist(r)result_eq = cv2.merge([b_eq, g_eq, r_eq])# 2. 锐化处理kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])sharpened = cv2.filter2D(result_eq, -1, kernel)# 3. 去除黑边gray = cv2.cvtColor(sharpened, cv2.COLOR_BGR2GRAY)coords = np.column_stack(np.where(gray > 10))if len(coords) > 0:y_min, x_min = coords.min(axis=0)y_max, x_max = coords.max(axis=0)cropped = sharpened[y_min:y_max+1, x_min:x_max+1]return croppedreturn sharpeneddef main():"""主程序"""# 图像文件列表(修改为你的图像路径)image_paths = ['06.jpeg', '07.jpeg', '08.jpeg']  # 修改为你的图像路径# 读取图像images = []for i, path in enumerate(image_paths):img = cv2.imread(path)if img is None:print(f"错误:无法读取图像文件 {path}")continueimages.append(img)print(f"成功加载图像 {i+1}: {path} - 尺寸: {img.shape[1]}x{img.shape[0]}")if len(images) < 2:print("错误:至少需要两张有效图像")return# 目标尺寸TARGET_WIDTH = 1536TARGET_HEIGHT = 2048print(f"目标尺寸: {TARGET_WIDTH}x{TARGET_HEIGHT}")print(f"开始处理 {len(images)} 张图像...")try:# 1. 预处理:曲率校正和尺寸调整processed_images = preprocess_images(images, TARGET_WIDTH, TARGET_HEIGHT)if len(processed_images) < 2:print("预处理后有效图像不足")return# 2. 拼接图像result = stitch_images_optimized(processed_images, TARGET_WIDTH, TARGET_HEIGHT)if result is None:print("拼接失败")return# 3. 后处理result = post_process(result)# 4. 最终尺寸调整result = resize_to_target(result, TARGET_WIDTH, TARGET_HEIGHT)# 显示结果cv2.imshow('Curvature Corrected Panorama', result)print("按任意键关闭窗口...")cv2.waitKey(0)cv2.destroyAllWindows()# 保存结果output_path = 'curvature_panorama.jpg'cv2.imwrite(output_path, result)print(f"拼接完成!最终尺寸: {result.shape[1]}x{result.shape[0]}")print(f"结果已保存为 {output_path}")except Exception as e:print(f"处理过程中出现错误: {str(e)}")import tracebacktraceback.print_exc()if __name__ == "__main__":main()

http://www.dtcms.com/a/520240.html

相关文章:

  • 登封网站设计wordpress终极简码
  • 网站服务器关闭建设网站需要的安全设备
  • STM32 RS422异步UART通信测试全方案C++软件开发,嵌入式软件开发,Linux
  • Qt笔记:的初次使用Qt-Advanced-Docking-System
  • 基于PyTorch和CuPy的GPU并行化遗传算法实现
  • Apollo Canbus模块技术深度解析
  • DeepSeek-OCR 嵌入dify工作流
  • Linux小课堂: Vim与Emacs之Linux文本编辑器的双雄格局及Vim安装启动详解
  • 江宁外贸网站建设国内付费代理ip哪个好
  • 多种大连网站建设景观设计公司理念
  • KP201FLGA电机驱动电源方案SOT23-6恒压恒流恒功率电路原理图分析
  • Hadoop报错 Couldn‘t find datanode to read file from. Forbidden
  • 【案例实战】HarmonyOS分布式购物车:多设备无缝协同的电商体验
  • OpenCV工程中直接包含调用vs2022
  • 怎么看一个网站用什么做的北京建设公司有哪些
  • 上海交大刘鹏飞:智能不在于数据堆砌,78个样本训练出超强Agent,数据效率提升128倍
  • SpringAI1-快速⼊⻔
  • 本地局域网邮件管理系统:从原理到实现的完整指南
  • 面向小样本蜂窝网络故障诊断的模型与知识互增强方法
  • 上海网站推广方法河北石家庄属于几线城市
  • 专业购物网站建设哪家好免费找客户网站
  • 受欢迎的网站开发php源码搭建网站流程
  • 第八章 排序——课后习题解练【数据结构(c语言版 第2版)】
  • 如果有大量的key需要设置同一时间过期,一般需要注意什么?
  • 【nvidia-GB200】(2) 18 台 GB200 服务器集群 NCCL All-to-All 性能深度测评:72 张 GPU 多对多通信的效率与潜力
  • MYSQL数据库--基本练习
  • Harbor VS Hadess,开源制品管理工具一文详细对比分析
  • 查找企业信息的网站哪个好广州网站外包
  • 基于3D激光点云的障碍物检测与跟踪---(3)基于匈牙利算法的障碍物跟踪
  • 虚拟化技术实践指南:KVM 与 VMware ESXi 部署全流程