|
2 | 2 | from pathlib import Path |
3 | 3 | from typing import Literal |
4 | 4 | from collections.abc import Sequence |
| 5 | +from PIL import Image |
| 6 | +import imageio |
5 | 7 |
|
6 | 8 | import numpy as np |
7 | 9 | import numpy.typing as npt |
|
19 | 21 | __all__ = [ |
20 | 22 | "plot_brain_connection_figure", |
21 | 23 | "save_brain_connection_frames", |
| 24 | + "batch_crop_images", |
| 25 | + "create_gif_from_images", |
22 | 26 | ] |
23 | 27 |
|
24 | 28 |
|
@@ -314,3 +318,99 @@ def save_brain_connection_frames( |
314 | 318 | fig.update_layout(scene_camera=camera) |
315 | 319 | pio.write_image(fig, f"{output_dir}/frame_{i:03d}.png", width=800, height=800) |
316 | 320 | logger.info(f"保存了 {n_frames} 张图片在 {output_dir}") |
| 321 | + |
| 322 | + |
| 323 | +def batch_crop_images( |
| 324 | + directory_path: Path, |
| 325 | + suffix: str = "_cropped", |
| 326 | + left_frac: float = 0.25, |
| 327 | + top_frac: float = 0.25, |
| 328 | + right_frac: float = 0.25, |
| 329 | + bottom_frac: float = 0.25, |
| 330 | +): |
| 331 | + """ |
| 332 | + 批量裁剪指定目录下的图像文件。 |
| 333 | +
|
| 334 | + Args: |
| 335 | + directory_path (Path): 图像文件所在的目录路径。 |
| 336 | + suffix (str, optional): 新文件名后缀。默认为 "_cropped"。 |
| 337 | + left_frac (float, optional): 左侧裁剪比例(0-1)。默认为 0.2。 |
| 338 | + top_frac (float, optional): 上侧裁剪比例(0-1)。默认为 0.15。 |
| 339 | + right_frac (float, optional): 右侧裁剪比例(0-1)。默认为 0.2。 |
| 340 | + bottom_frac (float, optional): 下侧裁剪比例(0-1)。默认为 0.15。 |
| 341 | +
|
| 342 | + Notes: |
| 343 | + 支持常见图像格式 (PNG, JPG, JPEG, BMP, TIFF)。 |
| 344 | + 裁剪后的图像将保存在原目录中,并添加指定后缀,原图像保持不变。 |
| 345 | + 所有裁剪均基于图像尺寸的百分比计算,无绝对像素值。 |
| 346 | + """ |
| 347 | + supported_extensions = {".png", ".jpg", ".jpeg", ".bmp", ".tiff", ".tif"} |
| 348 | + |
| 349 | + for image_path in directory_path.rglob("*"): |
| 350 | + if ( |
| 351 | + not image_path.is_file() |
| 352 | + or image_path.suffix.lower() not in supported_extensions |
| 353 | + ): |
| 354 | + continue |
| 355 | + |
| 356 | + new_file_name = image_path.stem + suffix + image_path.suffix |
| 357 | + |
| 358 | + try: |
| 359 | + figure = Image.open(image_path) |
| 360 | + width, height = figure.size |
| 361 | + print(f"图像宽度:{width},高度:{height}") |
| 362 | + |
| 363 | + left = int(width * left_frac) |
| 364 | + right = int(width * (1 - right_frac)) |
| 365 | + top = int(height * top_frac) |
| 366 | + bottom = int(height * (1 - bottom_frac)) |
| 367 | + |
| 368 | + # 裁切图像 |
| 369 | + cropped_fig = figure.crop((left, top, right, bottom)) |
| 370 | + # 保存裁切后的图像 |
| 371 | + cropped_fig.save(image_path.parent / new_file_name) |
| 372 | + |
| 373 | + figure.close() |
| 374 | + cropped_fig.close() |
| 375 | + except Exception as e: |
| 376 | + print(f"处理文件 {image_path.name} 时出错: {e}") |
| 377 | + |
| 378 | + |
| 379 | +def create_gif_from_images( |
| 380 | + folder_path: str | Path, |
| 381 | + output_name: str = "output.gif", |
| 382 | + fps: int = 10, |
| 383 | + extensions: Sequence[str] = (".png", ".jpg", ".jpeg"), |
| 384 | +) -> None: |
| 385 | + """ |
| 386 | + 从指定文件夹中的图片生成 GIF 文件。 |
| 387 | +
|
| 388 | + Args: |
| 389 | + folder_path (str | Path): 图片所在文件夹路径 |
| 390 | + output_name (str, optional): 输出 GIF 文件名,默认为 "output.gif" |
| 391 | + fps (int, optional): GIF 帧率,默认为 10 |
| 392 | + extensions (Sequence[str], optional): 图片文件扩展名过滤,默认为 ('.png', '.jpg', '.jpeg') |
| 393 | + """ |
| 394 | + folder = Path(folder_path) |
| 395 | + if not folder.exists() or not folder.is_dir(): |
| 396 | + raise ValueError(f"{folder} 不是有效的文件夹路径。") |
| 397 | + |
| 398 | + # 获取文件夹下指定扩展名的文件,并排序 |
| 399 | + figures_path = sorted( |
| 400 | + [f for f in folder.iterdir() if f.suffix.lower() in extensions] |
| 401 | + ) |
| 402 | + |
| 403 | + if not figures_path: |
| 404 | + raise ValueError(f"文件夹 {folder} 中没有找到符合 {extensions} 的图片文件。") |
| 405 | + |
| 406 | + figures = [Image.open(f) for f in figures_path] |
| 407 | + |
| 408 | + # 输出 GIF 路径 |
| 409 | + output_path = folder / output_name |
| 410 | + |
| 411 | + # 创建 GIF |
| 412 | + with imageio.get_writer(output_path, mode='I', fps=fps, loop=0) as writer: |
| 413 | + for figure in figures: |
| 414 | + writer.append_data(figure.convert('RGB')) |
| 415 | + |
| 416 | + print(f"GIF 已保存到: {output_path}") |
0 commit comments