| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- #!/usr/bin/env python3
- """
- 本地分析 zoom=1 校准扫描结果,用多尺度模板匹配 + 中心 ROI 重新定位。
- """
- import json
- from pathlib import Path
- import cv2
- import numpy as np
- def match_center_roi(ptz_img: np.ndarray, panorama_img: np.ndarray,
- roi_ratio=0.5, scales=(0.10, 0.12, 0.15, 0.18, 0.20, 0.25)):
- """用 PTZ 中心 ROI 在全景图中做模板匹配"""
- ph, pw = ptz_img.shape[:2]
- # 提取中心 ROI
- rw, rh = int(pw * roi_ratio), int(ph * roi_ratio)
- x0, y0 = (pw - rw) // 2, (ph - rh) // 2
- roi = ptz_img[y0:y0+rh, x0:x0+rw]
- roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
- pano_gray = cv2.cvtColor(panorama_img, cv2.COLOR_BGR2GRAY)
- pano_h, pano_w = pano_gray.shape
- best = None
- best_score = -1
- for scale in scales:
- sw, sh = int(rw * scale), int(rh * scale)
- if sw > pano_w or sh > pano_h:
- continue
- resized = cv2.resize(roi_gray, (sw, sh), interpolation=cv2.INTER_AREA)
- result = cv2.matchTemplate(pano_gray, resized, cv2.TM_CCOEFF_NORMED)
- _, max_val, _, max_loc = cv2.minMaxLoc(result)
- if max_val > best_score:
- best_score = max_val
- center_x = max_loc[0] + sw / 2
- center_y = max_loc[1] + sh / 2
- best = (center_x / pano_w, center_y / pano_h, scale, float(max_val))
- return best
- def main():
- base = Path('/Users/wenhongquan/Desktop/阿里云同步/项目/dnn/德胜河 AI/dsh/calibration_scan_180_360_z1')
- ptz_dir = base / 'ptz_images'
- pano_path = base / 'panorama.jpg'
- raw_path = base / 'mapping_raw.json'
- panorama = cv2.imread(str(pano_path))
- pano_h, pano_w = panorama.shape[:2]
- print(f'Panorama: {pano_w}x{pano_h}')
- with open(raw_path, 'r', encoding='utf-8') as f:
- raw_data = json.load(f)
- results = []
- for r in raw_data['records']:
- filename = r['filename']
- ptz = cv2.imread(str(ptz_dir / filename))
- if ptz is None:
- continue
- res = match_center_roi(ptz, panorama)
- record = dict(r)
- if res:
- x_ratio, y_ratio, scale, score = res
- record['tm_x_ratio'] = round(x_ratio, 4)
- record['tm_y_ratio'] = round(y_ratio, 4)
- record['tm_panorama_x'] = int(x_ratio * pano_w)
- record['tm_panorama_y'] = int(y_ratio * pano_h)
- record['tm_scale'] = round(scale, 3)
- record['tm_score'] = round(score, 3)
- print(f"{filename}: pan={r['pan']:3d} tilt={r['tilt']:+3d} -> x={x_ratio:.3f} y={y_ratio:.3f} scale={scale:.2f} score={score:.3f}")
- results.append(record)
- # 保存结果
- out_path = base / 'mapping_tm_center.json'
- with open(out_path, 'w', encoding='utf-8') as f:
- json.dump({
- 'records': results,
- 'panorama_size': {'width': pano_w, 'height': pano_h},
- }, f, indent=2, ensure_ascii=False)
- print(f'\nSaved: {out_path}')
- # 生成 lookup table
- valid = [r for r in results if 'tm_x_ratio' in r and r['tm_score'] > 0.3]
- pan_lookup = sorted([[r['tm_x_ratio'], float(r['pan'])] for r in valid], key=lambda x: x[0])
- tilt_lookup = sorted([[r['tm_y_ratio'], float(r['tilt'])] for r in valid], key=lambda x: x[0])
- lookup = {
- 'pan_lookup': pan_lookup,
- 'tilt_lookup': tilt_lookup,
- 'valid_count': len(valid),
- }
- with open(base / 'lookup_table_tm_center.json', 'w', encoding='utf-8') as f:
- json.dump(lookup, f, indent=2, ensure_ascii=False)
- print(f'Lookup table: {len(valid)} valid records')
- if __name__ == '__main__':
- main()
|