前言

图片有点多,想做个以分辨率为主的分类。

代码

import os
import shutil
import argparse
from PIL import Image, ImageOps

def classify_images(source_dir, desktop_dir, mobile_dir, avatar_dir, ratio_threshold=0.9):
    """
    根据图片方向比例分类到桌面、移动和头像目录
    :param source_dir: 源图片目录
    :param desktop_dir: 横屏图片目录
    :param mobile_dir: 竖屏图片目录
    :param avatar_dir: 头像图片目录
    :param ratio_threshold: 视为头像的最小宽高比(默认0.9)
    """
    # 创建所有目标目录
    for d in [desktop_dir, mobile_dir, avatar_dir]:
        os.makedirs(d, exist_ok=True)

    valid_exts = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'}

    for filename in os.listdir(source_dir):
        file_path = os.path.join(source_dir, filename)
        
        if not os.path.isfile(file_path):
            continue
        ext = os.path.splitext(filename)[1].lower()
        if ext not in valid_exts:
            continue

        try:
            with Image.open(file_path) as img:
                img = ImageOps.exif_transpose(img)  # 校正方向
                width, height = img.size
                # 计算宽高比(总在0-1之间)
                ratio = min(width, height) / max(width, height)
        except Exception as e:
            print(f"错误:无法处理文件 {filename} ({e})")
            continue

        # 分类优先级:先判断头像
        if ratio >= ratio_threshold:
            target_dir = avatar_dir
        else:
            target_dir = desktop_dir if width > height else mobile_dir

        # 处理重名文件
        dest_path = os.path.join(target_dir, filename)
        if os.path.exists(dest_path):
            base, ext = os.path.splitext(filename)
            counter = 1
            while os.path.exists(dest_path):
                new_name = f"{base}_{counter}{ext}"
                dest_path = os.path.join(target_dir, new_name)
                counter += 1

        try:
            shutil.move(file_path, dest_path)
            print(f"已分类:{filename} -> {os.path.basename(target_dir)}")
        except Exception as e:
            print(f"移动失败:{filename} ({e})")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='智能图片分类工具')
    parser.add_argument('source_dir', help='源目录路径')
    parser.add_argument('--desktop', help='横屏目录(默认:源目录/desktop)')
    parser.add_argument('--mobile', help='竖屏目录(默认:源目录/mobile)')
    parser.add_argument('--avatar', help='头像目录(默认:源目录/avatar)')
    parser.add_argument('--ratio', type=float, default=0.9,
                      help='头像宽高比阈值(0-1,默认0.9)')

    args = parser.parse_args()

    source_dir = os.path.abspath(args.source_dir)
    desktop_dir = args.desktop or os.path.join(source_dir, 'desktop')
    mobile_dir = args.mobile or os.path.join(source_dir, 'mobile')
    avatar_dir = args.avatar or os.path.join(source_dir, 'avatar')

    classify_images(
        source_dir=source_dir,
        desktop_dir=desktop_dir,
        mobile_dir=mobile_dir,
        avatar_dir=avatar_dir,
        ratio_threshold=args.ratio
    )