template_match_test.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import cv2
  2. import os
  3. import time
  4. from pathlib import Path
  5. import re
  6. from tqdm import tqdm
  7. import cv2
  8. # 导入您提供的拼接器类和拼接顺序生成器
  9. from fry_project_classes.stitch_img_template_match import ImageStitcherTemplateMatch
  10. from fry_project_classes.get_full_stitch_order import get_full_stitch_order
  11. # 导入您提供的拼接器类
  12. from fry_project_classes.stitch_img_template_match import ImageStitcherTemplateMatch
  13. def natural_sort_key(s):
  14. """
  15. 提供自然排序的键,例如 '2.jpg' 会排在 '10.jpg' 之前。
  16. """
  17. return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', str(s))]
  18. def stitch_img(IMAGE_DIR, OUTPUT_DIR, NUM_COLS: int, NUM_ROWS: int,
  19. ESTIMATE_OVERLAP_HORIZONTAL_PIXELS: int, ESTIMATE_OVERLAP_VERTICAL_PIXELS: int,
  20. BLEND_TYPE: str, LIGHT_COMPENSATION: bool,
  21. DEBUG_MODE: bool, BLEND_RATIO: float, LIGHT_COMPENSATION_WIDTH: int):
  22. OUTPUT_DIR.mkdir(exist_ok=True)
  23. print("--- 图像拼接开始 ---")
  24. print(f"配置: {NUM_ROWS}行 x {NUM_COLS}列")
  25. print(f"图片目录: {IMAGE_DIR}")
  26. print(f"输出目录: {OUTPUT_DIR}")
  27. print(f"水平重叠预估: {ESTIMATE_OVERLAP_HORIZONTAL_PIXELS}px, 垂直重叠预估: {ESTIMATE_OVERLAP_VERTICAL_PIXELS}px")
  28. print(f"融合模式: {BLEND_TYPE}, 权重: {BLEND_RATIO}")
  29. print(f"光照补偿: {'启用' if LIGHT_COMPENSATION else '禁用'}, 补偿宽度: {LIGHT_COMPENSATION_WIDTH}px")
  30. # --- 1. 加载并排序所有图片 ---
  31. image_paths = sorted(list(IMAGE_DIR.glob("*.jpg")), key=natural_sort_key)
  32. if len(image_paths) != NUM_COLS * NUM_ROWS:
  33. print(f"错误: 找到 {len(image_paths)} 张图片, 但预期需要 {NUM_COLS * NUM_ROWS} 张。")
  34. return
  35. # 将所有图片读入内存,并用一个字典存储
  36. images_dict = {}
  37. for i, path in enumerate(image_paths):
  38. img = cv2.imread(str(path))
  39. if img is None:
  40. print(f"错误: 无法读取图片 {path}")
  41. return
  42. # 使用从 '1' 开始的字符串作为键,模仿 stitch_worker.py 的行为
  43. images_dict[str(i + 1)] = img
  44. # --- 2. 获取拼接顺序 ---
  45. full_stitch_order_dict = get_full_stitch_order(NUM_ROWS, NUM_COLS)
  46. print(f"\n--- 获取到 {len(full_stitch_order_dict)} 步拼接指令 ---")
  47. # --- 3. 按照指令集执行拼接 ---
  48. final_image = None
  49. progress_bar = tqdm(full_stitch_order_dict.items(), desc="执行拼接")
  50. for step, (round_num, img1_name, img2_name, direction, result_name) in progress_bar:
  51. progress_bar.set_description(f"步骤 {step}: {img1_name} + {img2_name} -> {result_name}")
  52. img1 = images_dict[img1_name]
  53. img2 = images_dict[img2_name]
  54. # 根据方向选择重叠像素
  55. overlap_pixels = 0
  56. if direction == 'horizontal':
  57. overlap_pixels = ESTIMATE_OVERLAP_HORIZONTAL_PIXELS
  58. elif direction == 'vertical':
  59. overlap_pixels = ESTIMATE_OVERLAP_VERTICAL_PIXELS
  60. else:
  61. raise ValueError(f"未知的拼接方向: {direction}")
  62. # 每次都创建一个新的拼接器实例
  63. stitcher = ImageStitcherTemplateMatch(
  64. estimate_overlap_pixels=overlap_pixels,
  65. stitch_type=direction,
  66. blend_type=BLEND_TYPE,
  67. blend_ratio=BLEND_RATIO,
  68. light_uniformity_compensation_enabled=LIGHT_COMPENSATION,
  69. light_uniformity_compensation_width=LIGHT_COMPENSATION_WIDTH,
  70. debug=DEBUG_MODE,
  71. debug_dir=str(OUTPUT_DIR / f'debug_{result_name}')
  72. )
  73. # 执行拼接
  74. stitched_image = stitcher.stitch_main(img1, img2)
  75. # 将新生成的图片存入字典,用于下一步拼接
  76. images_dict[result_name] = stitched_image
  77. final_image = stitched_image # 始终保留最新的拼接结果
  78. if DEBUG_MODE:
  79. # 保存每一步的中间结果
  80. intermediate_path = OUTPUT_DIR / f"intermediate_{result_name}.jpg"
  81. cv2.imwrite(str(intermediate_path), stitched_image)
  82. # --- 4. 保存最终结果 ---
  83. if final_image is not None:
  84. final_output_path = OUTPUT_DIR / "final_stitched_image.jpg"
  85. cv2.imwrite(str(final_output_path), final_image)
  86. print("\n--- 所有拼接任务完成!---")
  87. print(f"最终的全景图已保存至: {final_output_path}")
  88. else:
  89. print("\n--- 拼接失败,没有生成最终图像 ---")
  90. def main():
  91. """
  92. 主执行函数
  93. """
  94. # --- 1. 配置参数 ---
  95. # 图片和输出目录设置
  96. IMAGE_DIR = Path(r"C:\Code\ML\Project\StitchImageServer\temp\input\front_0_1")
  97. # OUTPUT_DIR = Path(r"C:\Code\ML\Project\StitchImageServer\temp\output")
  98. # 拼图网格设置
  99. NUM_COLS = 4
  100. NUM_ROWS = 6
  101. # !!!关键拼接参数,您可能需要根据实际图片进行调整!!!
  102. # 预估水平方向重叠的像素数。如果您的图片宽1920像素,重叠25%,则该值为 1920 * 0.25 ≈ 480
  103. # 预估垂直方向重叠的像素数。如果您的图片高1080像素,重叠25%,则该值为 1080 * 0.25 ≈ 270
  104. # estimate_overlap_ratio = 0.45
  105. ESTIMATE_OVERLAP_HORIZONTAL_PIXELS = 405
  106. ESTIMATE_OVERLAP_VERTICAL_PIXELS = 440
  107. # 选择融合模式。'blend_half_importance_partial_HSV' 是效果最好但最慢的模式之一
  108. '''
  109. 前五个都不行
  110. half_importance,right_first,left_first 0星
  111. ⭐half_importance_add_weight 2星, 49秒
  112. half_importance_global_brightness 0星, 49秒
  113. half_importance_partial_brightness 还行, 4星, 速度适中 ,99秒
  114. blend_half_importance_partial_HV 不错 5星, 慢, 107秒
  115. blend_half_importance_partial_SV 不错, 5星, 慢, 108秒
  116. blend_half_importance_partial_HSV 很不错, 5星, 很慢, 120秒
  117. ⭐blend_half_importance_partial_brightness_add_weight: 5星, 106秒
  118. '''
  119. blend_type_list = ["half_importance_add_weight",
  120. # "half_importance_global_brightness", "half_importance_partial_brightness",
  121. # "blend_half_importance_partial_HV", "blend_half_importance_partial_SV",
  122. # "blend_half_importance_partial_HSV", "blend_half_importance_partial_brightness_add_weight"
  123. ]
  124. # BLEND_TYPE = 'blend_half_importance_partial_HSV'
  125. # 是否开启光照补偿(推荐开启以获得更好效果)
  126. LIGHT_COMPENSATION = True
  127. # 是否开启调试模式(会生成大量中间过程图片,用于分析问题)
  128. DEBUG_MODE = False
  129. for i, BLEND_TYPE in enumerate(blend_type_list):
  130. base_dir_path = r"C:\Code\ML\Project\StitchImageServer\temp\output"
  131. img_dir_name = f"{i}_{BLEND_TYPE}"
  132. OUTPUT_DIR = Path(os.path.join(base_dir_path, img_dir_name))
  133. one_img_time = time.time()
  134. stitch_img(IMAGE_DIR=IMAGE_DIR, OUTPUT_DIR=OUTPUT_DIR, NUM_COLS=NUM_COLS, NUM_ROWS=NUM_ROWS,
  135. ESTIMATE_OVERLAP_HORIZONTAL_PIXELS=ESTIMATE_OVERLAP_HORIZONTAL_PIXELS,
  136. ESTIMATE_OVERLAP_VERTICAL_PIXELS=ESTIMATE_OVERLAP_VERTICAL_PIXELS,
  137. BLEND_TYPE=BLEND_TYPE, BLEND_RATIO=0.5,
  138. LIGHT_COMPENSATION=LIGHT_COMPENSATION, LIGHT_COMPENSATION_WIDTH=15,
  139. DEBUG_MODE=DEBUG_MODE)
  140. print()
  141. print("_" * 20)
  142. print(f"单个用时: {BLEND_TYPE}: {time.time() - one_img_time}")
  143. print("_" * 20)
  144. if __name__ == '__main__':
  145. start_time = time.time()
  146. main()
  147. end_time = time.time()
  148. print(f"\n总耗时: {end_time - start_time:.2f} 秒")