如何用Python案例实现批量图片裁剪?

wen python案例 2

本文目录导读:

如何用Python案例实现批量图片裁剪?

  1. 方案一:使用PIL/Pillow库(最常用)
  2. 方案二:使用OpenCV(处理速度更快)
  3. 方案三:高级功能实现
  4. 使用建议

我来为您提供一个完整的Python批量图片裁剪方案。

使用PIL/Pillow库(最常用)

基本实现

import os
from PIL import Image
import glob
def batch_crop_images(input_dir, output_dir, crop_box):
    """
    批量裁剪图片
    参数:
    input_dir: 输入图片文件夹路径
    output_dir: 输出图片文件夹路径
    crop_box: 裁剪区域 (left, top, right, bottom)
    """
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    # 支持的图片格式
    extensions = ['*.jpg', '*.jpeg', '*.png', '*.bmp', '*.tiff']
    # 统计处理数量
    processed = 0
    failed = 0
    for ext in extensions:
        for img_path in glob.glob(os.path.join(input_dir, ext)):
            try:
                # 打开图片
                img = Image.open(img_path)
                # 执行裁剪
                cropped_img = img.crop(crop_box)
                # 获取文件名
                filename = os.path.basename(img_path)
                name, ext = os.path.splitext(filename)
                output_path = os.path.join(output_dir, f"{name}_cropped{ext}")
                # 保存裁剪后的图片
                cropped_img.save(output_path, quality=95)
                processed += 1
                print(f"✓ 已处理: {filename}")
            except Exception as e:
                failed += 1
                print(f"✗ 处理失败 {img_path}: {e}")
    print(f"\n处理完成! 成功: {processed}, 失败: {failed}")
# 使用示例
if __name__ == "__main__":
    # 裁剪区域 (左, 上, 右, 下)
    crop_box = (100, 50, 500, 400)  # 从(100,50)到(500,400)
    # 执行批量裁剪
    batch_crop_images(
        input_dir="./input_images",
        output_dir="./output_images",
        crop_box=crop_box
    )

中心裁剪(获取正方形图片)

def center_crop_images(input_dir, output_dir, target_size=256):
    """
    中心裁剪为正方形
    """
    os.makedirs(output_dir, exist_ok=True)
    for img_path in glob.glob(os.path.join(input_dir, '*')):
        try:
            img = Image.open(img_path)
            # 获取图片尺寸
            width, height = img.size
            # 计算裁剪区域
            if width > height:
                left = (width - height) // 2
                top = 0
                right = left + height
                bottom = height
            else:
                left = 0
                top = (height - width) // 2
                right = width
                bottom = top + width
            # 执行中心裁剪
            cropped_img = img.crop((left, top, right, bottom))
            # 调整到目标尺寸
            if target_size:
                resized_img = cropped_img.resize((target_size, target_size), 
                                               Image.Resampling.LANCZOS)
            else:
                resized_img = cropped_img
            # 保存
            filename = os.path.basename(img_path)
            output_path = os.path.join(output_dir, filename)
            resized_img.save(output_path, quality=95)
            print(f"✓ {filename} -> {cropped_img.size}")
        except Exception as e:
            print(f"✗ 处理失败 {img_path}: {e}")

按百分比裁剪

def percentage_crop_images(input_dir, output_dir, crop_percent):
    """
    按百分比裁剪图片
    参数:
    crop_percent: 裁剪比例 [left%, top%, right%, bottom%]
    """
    os.makedirs(output_dir, exist_ok=True)
    for img_path in glob.glob(os.path.join(input_dir, '*')):
        try:
            img = Image.open(img_path)
            width, height = img.size
            # 将百分比转换为像素
            left = int(width * crop_percent[0] / 100)
            top = int(height * crop_percent[1] / 100)
            right = int(width * crop_percent[2] / 100)
            bottom = int(height * crop_percent[3] / 100)
            # 裁剪
            cropped_img = img.crop((left, top, right, bottom))
            # 保存
            filename = os.path.basename(img_path)
            output_path = os.path.join(output_dir, filename)
            cropped_img.save(output_path)
        except Exception as e:
            print(f"错误: {e}")

使用OpenCV(处理速度更快)

import cv2
import os
import glob
def batch_crop_opencv(input_dir, output_dir, crop_region):
    """
    使用OpenCV批量裁剪图片
    参数:
    crop_region: (x, y, width, height)
    """
    os.makedirs(output_dir, exist_ok=True)
    x, y, w, h = crop_region
    for img_path in glob.glob(os.path.join(input_dir, '*')):
        try:
            # 读取图片
            img = cv2.imread(img_path)
            if img is None:
                continue
            # 裁剪图片
            cropped_img = img[y:y+h, x:x+w]
            # 保存图片
            filename = os.path.basename(img_path)
            output_path = os.path.join(output_dir, f"cropped_{filename}")
            cv2.imwrite(output_path, cropped_img)
            print(f"✓ 裁剪完成: {filename}")
        except Exception as e:
            print(f"✗ 处理失败: {e}")
# 使用示例
batch_crop_opencv(
    input_dir="./images",
    output_dir="./cropped_images",
    crop_region=(100, 50, 300, 400)  # x=100, y=50, width=300, height=400
)

高级功能实现

交互式裁剪

def interactive_crop():
    """选择裁剪区域的交互式工具"""
    import tkinter as tk
    from tkinter import filedialog
    # 选择输入文件夹
    root = tk.Tk()
    root.withdraw()
    input_dir = filedialog.askdirectory(title="选择图片文件夹")
    if not input_dir:
        return
    # 处理所有图片
    for img_path in glob.glob(os.path.join(input_dir, '*.*')):
        try:
            img = Image.open(img_path)
            img.show()
            # 用户输入裁剪坐标
            print(f"\n当前图片: {os.path.basename(img_path)}")
            print(f"图片尺寸: {img.size}")
            left = int(input("左坐标: "))
            top = int(input("上坐标: "))
            right = int(input("右坐标: "))
            bottom = int(input("下坐标: "))
            batch_crop_images(input_dir, "interactive_output", 
                            (left, top, right, bottom))
        except Exception as e:
            print(f"错误: {e}")
# 启动交互式裁剪
# interactive_crop()

批量裁剪并添加水印

def crop_with_watermark(input_dir, output_dir, crop_box, watermark_text="Sample"):
    """裁剪并添加水印"""
    from PIL import ImageDraw, ImageFont
    os.makedirs(output_dir, exist_ok=True)
    for img_path in glob.glob(os.path.join(input_dir, '*')):
        try:
            # 打开并裁剪
            img = Image.open(img_path)
            cropped_img = img.crop(crop_box)
            # 添加水印
            draw = ImageDraw.Draw(cropped_img)
            font = ImageFont.truetype("arial.ttf", 30)
            # 在右下角添加水印
            text_width = draw.textlength(watermark_text, font=font)
            text_height = 30
            x = cropped_img.width - text_width - 10
            y = cropped_img.height - text_height - 10
            # 绘制水印
            draw.text((x, y), watermark_text, font=font, 
                     fill=(255, 255, 255, 128))
            # 保存
            filename = os.path.basename(img_path)
            output_path = os.path.join(output_dir, filename)
            cropped_img.save(output_path)
        except Exception as e:
            print(f"处理失败: {e}")

使用建议

安装依赖

pip install pillow opencv-python

选择建议

  1. 简单场景:使用Pillow库,易于理解和使用
  2. 高性能需求:使用OpenCV,处理速度快
  3. 批量处理:加入多线程或多进程提高效率

多线程优化

from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
def process_single_image(img_path, output_dir, crop_box, lock):
    """处理单张图片"""
    try:
        img = Image.open(img_path)
        cropped_img = img.crop(crop_box)
        filename = os.path.basename(img_path)
        output_path = os.path.join(output_dir, filename)
        with lock:
            cropped_img.save(output_path)
            return True, filename
    except Exception as e:
        return False, str(e)
def batch_crop_multithreaded(input_dir, output_dir, crop_box, max_workers=4):
    """多线程批量裁剪"""
    os.makedirs(output_dir, exist_ok=True)
    lock = threading.Lock()
    image_paths = glob.glob(os.path.join(input_dir, '*'))
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = []
        for img_path in image_paths:
            future = executor.submit(process_single_image, 
                                   img_path, output_dir, crop_box, lock)
            futures.append(future)
        # 处理结果
        success = 0
        failed = 0
        for future in as_completed(futures):
            result, info = future.result()
            if result:
                success += 1
                print(f"✓ 成功: {info}")
            else:
                failed += 1
                print(f"✗ 失败: {info}")
    print(f"\n总处理: {len(image_paths)}, 成功: {success}, 失败: {failed}")

这个方案涵盖了从基础到高级的批量图片裁剪需求,您可以根据具体场景选择合适的实现方式。

抱歉,评论功能暂时关闭!