import numpy as np from PIL import Image from skimage import color from scipy.optimize import minimize import os import time from concurrent.futures import ProcessPoolExecutor, as_completed # ================= 配置区域 ================= max_workers = 8 # 【并行】 并行处理的进程数 (建议设为 CPU 核心数,如 4, 8, 16) # 图片后缀 prefix = "_AOD-Net" # "_10_0.2_result" # "_result" # 输入文件夹 (带 prefix 后缀的图片) src_dir = "AOD-Net" # 参考文件夹 (GT/Ground Truth,无 prefix 后缀) ref_dir = "去雾图像-北航合作-雾图" # 输出文件夹 out_dir = "AOD-Net+后处理" # =========================================== # 尝试导入 tqdm,如果没安装则定义一个简单的占位符 try: from tqdm import tqdm except ImportError: def tqdm(iterable, **kwargs): return iterable def process_single_image(filename, src_folder, ref_folder, output_folder, prefix=prefix): """ 处理单张图片的函数,用于并行调用 """ source_path = os.path.join(src_folder, filename) try: # --- 寻找对应的参考图 --- # 逻辑:去除文件名后缀 "prefix" name_no_ext, ext = os.path.splitext(filename) if name_no_ext.endswith(prefix): ref_name_no_ext = name_no_ext[:-len(prefix)] # 去掉最后n个字符 (prefix) else: ref_name_no_ext = name_no_ext ref_filename = ref_name_no_ext + ext ref_path = os.path.join(ref_folder, ref_filename) # 检查参考图是否存在 if not os.path.exists(ref_path): return f"[跳过] 找不到参考图: {ref_filename} (对应: {filename})" # --- 读取图片并归一化 --- img_src_pil = Image.open(source_path).convert('RGB') img_src = np.array(img_src_pil) / 255.0 img_ref_pil = Image.open(ref_path).convert('RGB') # 确保参考图尺寸和源图一致 if img_src_pil.size != img_ref_pil.size: img_ref_pil = img_ref_pil.resize(img_src_pil.size, Image.BILINEAR) img_ref = np.array(img_ref_pil) / 255.0 # --- 转换到 HSV --- hsv_src = color.rgb2hsv(img_src) hsv_ref = color.rgb2hsv(img_ref) # --- 定义损失函数 --- # 注意:在多进程中,loss_function 必须定义在 worker 内部才能访问到 hsv_src/ref def loss_function(params): ks, kv = params adj_s = np.clip(hsv_src[:,:,1] * ks, 0, 1) adj_v = np.clip(hsv_src[:,:,2] * kv, 0, 1) loss_s = np.mean((adj_s - hsv_ref[:,:,1])**2) loss_v = np.mean((adj_v - hsv_ref[:,:,2])**2) return loss_s + loss_v # --- 开始优化 --- res = minimize(loss_function, [1.0, 1.0], method='Nelder-Mead', tol=1e-4) best_s, best_v = res.x s_percent = int(best_s * 100) v_percent = int(best_v * 100) # --- 应用最佳参数 --- hsv_new = hsv_src.copy() hsv_new[:, :, 1] = np.clip(hsv_new[:, :, 1] * best_s, 0, 1) hsv_new[:, :, 2] = np.clip(hsv_new[:, :, 2] * best_v, 0, 1) # --- 转回 RGB 并保存 --- img_result_rgb = color.hsv2rgb(hsv_new) img_save = Image.fromarray((img_result_rgb * 255).astype(np.uint8)) new_filename = f"{name_no_ext}_S_{s_percent}_V_{v_percent}{ext}" save_path = os.path.join(output_folder, new_filename) img_save.save(save_path) return f"OK: {filename} -> S={s_percent}%, V={v_percent}%" except Exception as e: return f"[错误] 处理文件 {filename} 时出错: {str(e)}" def calculate_and_process_batch_parallel(src_folder, ref_folder, output_folder, max_workers=None): # 1. 确保输出目录存在 if not os.path.exists(output_folder): os.makedirs(output_folder) print(f"已创建输出目录: {output_folder}") # 2. 获取源文件夹内所有图片文件 valid_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.tif') file_list = [f for f in os.listdir(src_folder) if f.lower().endswith(valid_extensions)] total_files = len(file_list) print(f"共发现 {total_files} 张图片,准备开始并行处理 (进程数: {max_workers if max_workers else '自动'})...\n") # 3. 并行处理 results = [] # ProcessPoolExecutor 自动管理进程池 # max_workers=None 意味着使用 CPU 核心数 with ProcessPoolExecutor(max_workers=max_workers) as executor: # 提交所有任务 future_to_file = { executor.submit(process_single_image, filename, src_folder, ref_folder, output_folder): filename for filename in file_list } # 使用 tqdm 显示进度条,as_completed 会在任何一个任务完成时yield pbar = tqdm(total=total_files, unit="img") for future in as_completed(future_to_file): result_msg = future.result() pbar.update(1) # 如果是错误或跳过信息,打印出来;如果是OK,只更新进度条不刷屏(可选) if not result_msg.startswith("OK"): tqdm.write(result_msg) # 使用 tqdm.write 防止打断进度条 # else: # tqdm.write(result_msg) # 如果想看每张图的详细结果,取消注释这行 pbar.close() print("\n" + "="*30) print("所有处理已完成。") # 执行 if __name__ == "__main__": # Windows 下使用多进程必须放在 if __name__ == "__main__": 之下 if os.path.exists(src_dir) and os.path.exists(ref_dir): # max_workers 可以手动指定,例如 max_workers=4。如果不填则默认跑满 CPU。 calculate_and_process_batch_parallel(src_dir, ref_dir, out_dir, max_workers = max_workers) else: print("错误: 找不到输入文件夹或参考文件夹,请检查路径。")