StitchingCodes/stitching-test-yuan.py
2025-06-08 20:21:47 +08:00

200 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import cv2
import numpy as np
from matplotlib import pyplot as plt
from tqdm import tqdm
import time
def lr_match(left_path, right_path):
left_img = cv2.imread(left_path)
right_img = cv2.imread(right_path)
# 配准
left_gray = cv2.cvtColor(left_img, cv2.COLOR_BGR2GRAY)
right_gray = cv2.cvtColor(right_img, cv2.COLOR_BGR2GRAY)
h, w = left_gray.shape
print(f"图像尺寸: 宽度={w}像素, 高度={h}像素")
template = left_gray[100:h - 100, w - 100:w]
print(f"模板区域: 上边界=100, 下边界={h - 100}, 左边界={w - 100}, 右边界={w}")
search_area = right_gray[:, :200]
print(f"搜索区域: 宽度={200}, 高度={h}")
res = cv2.matchTemplate(search_area, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(f"匹配质量: {max_val:.4f} (1.0=完美匹配)")
match_x, match_y = max_loc
print(f"匹配位置: x={match_x}, y={match_y} (在搜索区域内)")
dx = w - 100 - match_x
dy = 100 - match_y
print(f"计算平移量: dx={dx}, dy={dy}")
return dx, dy
def tb_match(top_path, bottom_path):
top_img = cv2.imread(top_path)
bottom_img = cv2.imread(bottom_path)
# 配准
top_gray = cv2.cvtColor(top_img, cv2.COLOR_BGR2GRAY)
bottom_gray = cv2.cvtColor(bottom_img, cv2.COLOR_BGR2GRAY)
h, w = top_gray.shape
print(f"图像尺寸: 宽度={w}像素, 高度={h}像素")
template = top_gray[h - 100:h, 100:w - 100]
print(f"模板区域: 上边界={h - 100}, 下边界={h}, 左边界={100}, 右边界={w - 100}")
search_area = bottom_gray[:200, :]
print(f"搜索区域: 宽度={w}, 高度={200}")
res = cv2.matchTemplate(search_area, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(f"匹配质量: {max_val:.4f} (1.0=完美匹配)")
match_x, match_y = max_loc
print(f"匹配位置: x={match_x}, y={match_y} (在搜索区域内)")
dx = 100 - match_x
dy = h - 100 - match_y
print(f"计算平移量: dx={dx}, dy={dy}")
return dx, dy
if __name__ == "__main__":
start_time = time.time()
# ====== 1. 计算相对配准关系 ======
max_x, max_y = 9, 9
# 假设图像范围x 从 0 到 max_x, y 从 0 到 max_y
right_disp = [[None] * (max_y+1) for _ in range(max_x)] # 大小为 [max_x][max_y+1]
down_disp = [[None] * max_y for _ in range(max_x+1)] # 大小为 [max_x+1][max_y]
# 计算左右相邻位移(横向关系)
for x in range(max_x): # x 从 0 到 max_x-1
for y in range(max_y + 1): # y 从 0 到 max_y
img_left = f"cell/{x}-{y}.jpg"
img_right = f"cell/{x+1}-{y}.jpg"
print(f"Matching: {img_left} and {img_right}")
dx, dy = lr_match(img_left, img_right) # 右图相对于左图的位移
right_disp[x][y] = (dx, dy) # 存储结果
# 计算上下相邻位移(纵向关系)
for x in range(max_x + 1): # x 从 0 到 max_x
for y in range(max_y): # y 从 0 到 max_y-1
img_top = f"cell/{x}-{y}.jpg"
img_bottom = f"cell/{x}-{y+1}.jpg"
dx, dy = tb_match(img_top, img_bottom) # 下图相对于上图的位移
down_disp[x][y] = (dx, dy) # 存储结果
# ====== 2. 计算绝对配准关系,即相对于 0-0 的配准关系 ======
global_disp = [[(0, 0)] * (max_y + 1) for _ in range(max_x + 1)] # 初始化
# 初始化第一行 (y=0)
for x in range(1, max_x + 1):
dx_prev, dy_prev = global_disp[x-1][0] # 左邻居 (x-1,0) 的位移
dx_right, dy_right = right_disp[x-1][0] # (x-1,0) 到 (x,0) 的位移
global_disp[x][0] = (dx_prev + dx_right, dy_prev + dy_right)
# 初始化第一列 (x=0)
for y in range(1, max_y + 1):
dx_prev, dy_prev = global_disp[0][y-1] # 上邻居 (0,y-1) 的位移
dx_down, dy_down = down_disp[0][y-1] # (0,y-1) 到 (0,y) 的位移
global_disp[0][y] = (dx_prev + dx_down, dy_prev + dy_down)
# 计算内部点 (x≥1, y≥1)
for x in range(1, max_x + 1):
for y in range(1, max_y + 1):
# 通过左侧邻居 (x-1,y) 计算
dx_left, dy_left = global_disp[x-1][y]
dx_r, dy_r = right_disp[x-1][y] # (x-1,y) 到 (x,y) 的位移
from_left = (dx_left + dx_r, dy_left + dy_r)
# 通过上方邻居 (x,y-1) 计算
dx_top, dy_top = global_disp[x][y-1]
dx_d, dy_d = down_disp[x][y-1] # (x,y-1) 到 (x,y) 的位移
from_top = (dx_top + dx_d, dy_top + dy_d)
# 取平均值(整数四舍五入)
global_disp[x][y] = (
round((from_left[0] + from_top[0]) / 2),
round((from_left[1] + from_top[1]) / 2)
)
print(global_disp)
# ====== 3. 正数化全局坐标 ======
min_dx = 0
min_dy = 0
# 遍历所有位移值,找到最小偏移量
for x in range(len(global_disp)):
for y in range(len(global_disp[0])):
dx, dy = global_disp[x][y]
min_dx = min(min_dx, dx)
min_dy = min(min_dy, dy)
# 计算偏移量(将所有位移变为非负)
offset_x = -min_dx # 当 min_dx 为负时offset_x 为正
offset_y = -min_dy # 当 min_dy 为负时offset_y 为正
# 创建新矩阵存储非负位移
global_disp_abs = []
for x in range(len(global_disp)):
row = []
for y in range(len(global_disp[0])):
dx, dy = global_disp[x][y]
# 应用偏移使所有值非负
abs_dx = dx + offset_x
abs_dy = dy + offset_y
row.append((abs_dx, abs_dy))
global_disp_abs.append(row)
print(global_disp_abs)
# ====== 4. 根据全局坐标进行拼接 ======
# 计算画布尺寸,创建空白画布
sample_img = cv2.imread("cell/0-0.jpg")
h, w = sample_img.shape[:2]
max_dx = max(dx for row in global_disp_abs for dx, dy in row)
max_dy = max(dy for row in global_disp_abs for dx, dy in row)
canvas_width = max_dx + w
canvas_height = max_dy + h
canvas = np.zeros((canvas_height, canvas_width, 3), dtype=np.uint8)
total_images = len(global_disp_abs) * len(global_disp_abs[0])
with tqdm(total=total_images, desc="拼接图像") as pbar:
for x in range(len(global_disp_abs)):
for y in range(len(global_disp_abs[0])):
img = cv2.imread(f"cell/{x}-{y}.jpg")
# 获取该图像的位移
dx, dy = global_disp_abs[x][y]
# 将图像放置到画布上
try:
# 将图像复制到画布对应位置
canvas[dy:dy+h, dx:dx+w] = img
except ValueError:
# 处理可能的尺寸不匹配问题
print(f"错误: 无法放置图像 cell/{x}-{y}.jpg 在位置({dx},{dy})")
continue
pbar.update(1)
# 保存拼接结果
cv2.imwrite("result.jpg", canvas)
print(f"拼接完成!结果保存至: result.jpg")
end_time = time.time()
print(f"总耗时:{end_time - start_time}s")