import torch import cv2 import os import glob import numpy as np import onnxruntime as ort from tqdm import tqdm from concurrent.futures import ThreadPoolExecutor import threading def preview_frame(video_path, frame_number): """预览指定帧的图像""" cap = cv2.VideoCapture(video_path) cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number) ret, frame = cap.read() cap.release() if ret: cv2.imwrite(f'frame_{frame_number}.jpg', frame) print(f"已保存第 {frame_number} 帧的预览图像") else: print(f"无法读取第 {frame_number} 帧") def extract_specific_frames(video_path, frame_numbers): """从视频中提取指定帧号的图像""" cap = cv2.VideoCapture(video_path) # 获取视频基本信息 frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) print(f"视频信息:\n分辨率: {frame_width}x{frame_height}\n总帧数: {total_frames}") # 创建画布 - 宽度为单帧宽度乘以要提取的帧数 canvas_width = frame_width * len(frame_numbers) canvas = np.zeros((frame_height, canvas_width, 3), dtype=np.uint8) current_frame = 0 canvas_position = 0 # 按顺序处理指定的帧 for target_frame in sorted(frame_numbers): print(f"正在处理第 {target_frame} 帧...") # 快进到目标帧 while current_frame < target_frame: ret = cap.grab() # 使用grab()而不是read()来快速跳过帧 if not ret: print(f"无法读取到第 {target_frame} 帧") break current_frame += 1 # 读取目标帧 ret, frame = cap.retrieve() # 获取当前帧的图像数据 if ret: # 将帧放入画布 canvas[:, canvas_position:canvas_position+frame_width] = frame canvas_position += frame_width # 保存每个提取的帧(可选) cv2.imwrite(f'frame_{target_frame}.jpg', frame) else: print(f"无法读取第 {target_frame} 帧的图像数据") cap.release() # 如果canvas_position小于预期的canvas_width,裁剪未使用的部分 if canvas_position < canvas_width: canvas = canvas[:, :canvas_position] return canvas def preview_all_frames(video_path, interval=10): """每隔一定间隔预览并保存帧,用于选择合适的帧""" cap = cv2.VideoCapture(video_path) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) frame_count = 0 while True: ret, frame = cap.read() if not ret: break if frame_count % interval == 0: cv2.imwrite(f'preview_frame_{frame_count}.jpg', frame) print(f"已保存第 {frame_count} 帧的预览图像") frame_count += 1 cap.release() print(f"总共处理了 {frame_count} 帧") def get_longimage(video_path2,output_path): video_path = video_path2 # 是否需要预览帧 need_preview = False if need_preview: # 预览特定帧 preview_frames = [13, 82, 196, 290, 381] for frame_num in preview_frames: preview_frame(video_path, frame_num) # 或者每隔10帧预览一次 # preview_all_frames(video_path, interval=10) return # 指定要提取的帧号 frame_numbers = [13, 82, 196, 290, 381, 483, 697, 798, 893, 1047] # 提取帧并拼接 panorama = extract_specific_frames(video_path, frame_numbers) # 保存结果 cv2.imwrite(os.path.join(output_path,'panorama.jpg'), panorama) print(f"全景图已保存,尺寸: {panorama.shape[1]}x{panorama.shape[0]}") def init_onnx(): """Initialize ONNX Runtime session""" test_weights = "/data1/Hatcher/model/PopulationCounting/Bayesian_project_ours/sim-CAS-base-test.onnx" if 'CUDAExecutionProvider' in ort.get_available_providers(): print("CUDA is available. Using GPU.") providers = ["CUDAExecutionProvider"] if ort.get_device() == "GPU" else ["CPUExecutionProvider"] else: print("CUDA not available. Using CPU.") providers = ["CPUExecutionProvider"] ort_session = ort.InferenceSession(test_weights, providers=providers) return ort_session def split_image(image): """Split large image into 800x800 patches""" h, w = image.shape[:2] # Calculate optimal width for resizing n_segments = max(1, w // 800) target_w = n_segments * 800 scale = target_w / w # Resize image to make width divisible by 800 new_w = target_w new_h = int(h * scale) resized_img = cv2.resize(image, (new_w, new_h)) # Split into patches patches = [] positions = [] # Store original positions for reconstruction for i in range(0, new_w, 800): patch = resized_img[:, i:i+800] if patch.shape[1] < 800: # Handle last patch if smaller than 800 continue patches.append(patch) positions.append((i, i+800)) return patches, positions, scale, (new_h, new_w) def process_patch(patch, ort_session): """Process a single 800x800 patch""" # Preprocess patch img = cv2.resize(patch, (800, 800))/255.0 img = img[np.newaxis, :, :].transpose(0,3,1,2) input_blob = np.array(img, dtype=np.float32) # Run inference onnx_input_name = ort_session.get_inputs()[0].name onnx_outputs_names = ort_session.get_outputs()[0].name onnx_result = ort_session.run([onnx_outputs_names], input_feed={onnx_input_name: input_blob}) # Get density map density_map = onnx_result[0][0][0] density_map[density_map<1e-6] = 0 return density_map def process_single_image(image_path, save_root, ort_session, file_lock): """Process a single large image""" try: # Get image name image_name = os.path.basename(image_path) result_name = f"result_{image_name}" # Read image img_or = cv2.imread(image_path) if img_or is None: print(f"Failed to read image: {image_path}") return False # Split image into patches patches, positions, scale, (new_h, new_w) = split_image(img_or) # Process each patch density_maps = [] total_count = 0 for patch in patches: density_map = process_patch(patch, ort_session) density_maps.append(density_map) total_count += np.sum(density_map) # Combine density maps combined_density = np.zeros((new_h, new_w)) for density_map, (start_x, end_x) in zip(density_maps, positions): resized_density = cv2.resize(density_map, (800, new_h)) combined_density[:, start_x:end_x] = resized_density # Resize combined density map back to original size combined_density = cv2.resize(combined_density, (img_or.shape[1], img_or.shape[0])) # Create heatmap heatmap = combined_density/np.max(combined_density) heatmap = np.power(heatmap, 0.7) # 降低gamma值会使颜色更深 heatmap = np.uint8(heatmap*255) heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) # Create visualization imgheatmap_W = int(img_or.shape[1]/3) imgheatmap_H = int(img_or.shape[0]/3) density_result = cv2.resize(heatmap,(imgheatmap_W,imgheatmap_H)) # Add density map to top-left corner img_or[0:imgheatmap_H, 0:imgheatmap_W] = density_result # Add count text cv2.putText(img_or, f"Count: {int(total_count)}", (50,200), cv2.FONT_HERSHEY_SIMPLEX, 4, (0,0,255), 8) # Save result save_path = os.path.join(save_root, result_name) with file_lock: cv2.imwrite(save_path, img_or) print(save_path) return True except Exception as e: print(f"Error processing {image_path}: {str(e)}") return False def process_images_batch(input_folder, num_threads=4): """Process images in parallel""" # Initialize ONNX session ort_session = init_onnx() # Create output directory save_root = os.path.join(input_folder, "results") os.makedirs(save_root, exist_ok=True) # Get image paths image_paths = glob.glob(os.path.join(input_folder, "*.jpg")) + \ glob.glob(os.path.join(input_folder, "*.png")) print(f"Found {len(image_paths)} images to process") # Initialize counters and locks success_count = 0 counter_lock = threading.Lock() file_lock = threading.Lock() # Create progress bar pbar = tqdm(total=len(image_paths), desc="Processing images") def process_with_progress(image_path): nonlocal success_count result = process_single_image(image_path, save_root, ort_session, file_lock) with counter_lock: if result: success_count += 1 pbar.update(1) pbar.set_postfix({'succeeded': success_count}) # Process images in parallel with ThreadPoolExecutor(max_workers=num_threads) as executor: executor.map(process_with_progress, image_paths) pbar.close() print(f"Processing complete. Successfully processed {success_count} images") if __name__ == "__main__": video_path = "/data1/Hatcher/model/project/MPKFNet/mmexport1733810879708.mp4" out_put_path = "./20251105001" if not os.path.exists(out_put_path): os.makedirs(out_put_path) get_longimage(video_path,out_put_path) # Start processing process_images_batch(out_put_path)