| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- import cv2
- import numpy as np
- import py360convert
- import requests
- import json
- import os
- import argparse
- from pathlib import Path
- def imread_url(url):
- """从 URL 读取图片并转换为 OpenCV 格式"""
- try:
- response = requests.get(url, timeout=10)
- response.raise_for_status()
- image_array = np.asarray(bytearray(response.content), dtype="uint8")
- img = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
- return img
- except Exception as e:
- print(f"❌ 无法从 URL 下载图片: {url}, 错误: {e}")
- return None
- def generate_pinhole_from_array(img, points, output_size=(600, 800)):
- """处理图像数组,根据给定的四个点生成 Pinhole 图像"""
- h, w = img.shape[:2]
- pts = np.array(points, dtype=np.float32)
- # 处理全景图跨界逻辑
- if pts[1][0] < pts[0][0]:
- pts[1][0] += w
- if pts[2][0] < pts[3][0]:
- pts[2][0] += w
- center_x = np.mean(pts[:, 0]) % w
- center_y = np.mean(pts[:, 1])
- u_deg = (center_x / w) * 360 - 180
- v_deg = 90 - (center_y / h) * 180
- span_x = np.max(pts[:, 0]) - np.min(pts[:, 0])
- span_y = np.max(pts[:, 1]) - np.min(pts[:, 1])
- fov_h = (span_x / w) * 360 * 1.2
- fov_v = (span_y / h) * 180 * 1.2
- fov_h = min(fov_h, 110)
- fov_v = min(fov_v, 110)
- pinhole_img = py360convert.e2p(
- img,
- fov_deg=(fov_h, fov_v),
- u_deg=u_deg,
- v_deg=v_deg,
- out_hw=output_size,
- )
- return pinhole_img
- def main():
- # 1. 定义参数解析器
- parser = argparse.ArgumentParser(description="全景图区域批量切图工具")
- parser.add_argument("--json", type=str, required=True, help="输入的 JSON 文件路径")
- parser.add_argument("--output", type=str, default="cropped_results", help="输出根目录 (默认: cropped_results)")
- parser.add_argument("--width", type=int, default=5671, help="输出图片的宽度 (默认: 800)")
- parser.add_argument("--height", type=int, default=3186, help="输出图片的高度 (默认: 600)")
- args = parser.parse_args()
- # 2. 读取 JSON
- if not os.path.exists(args.json):
- print(f"❌ 找不到文件: {args.json}")
- return
- with open(args.json, 'r', encoding='utf-8') as f:
- data = json.load(f)
- scene_code = data.get("sceneCode", "unknown_scene")
- image_cache = {}
- output_size = (args.height, args.width) # 注意 opencv 是 (h, w)
- # 3. 循环处理
- for item in data.get("list", []):
- sid = item.get("tag", {}).get("sid", "unknown_sid")
- snaps = item.get("snap", [])
- for idx, snap in enumerate(snaps):
- img_url = snap.get("imageUrl")
- pano_id = snap.get("panoId", "0")
- corners = snap.get("corners", [])
- if not img_url or len(corners) < 4:
- continue
- if img_url not in image_cache:
- print(f"🌐 正在下载全景图: {img_url}")
- image_cache[img_url] = imread_url(img_url)
- origin_img = image_cache[img_url]
- if origin_img is None: continue
- pts_list = [(c['x'], c['y']) for c in corners]
- try:
- print(f"🎨 处理 [SID: {sid}] [Pano: {pano_id}] - 区域 {idx}")
- result_img = generate_pinhole_from_array(origin_img, pts_list, output_size=output_size)
- # 创建保存目录
- save_dir = Path(args.output) / scene_code / sid
- save_dir.mkdir(parents=True, exist_ok=True)
- save_path = save_dir / f"pano_{pano_id}_snap_{idx}.jpg"
- cv2.imwrite(str(save_path), result_img)
- except Exception as e:
- print(f"⚠️ 处理失败: {e}")
- print("\n✨ 处理完成!")
- if __name__ == "__main__":
- main()
|