欢迎光临武汉雪聪网
详情描述
Python使用Pillow库批量处理图片的示例详解
Python 使用 Pillow 库批量处理图片的完整示例

Pillow 是 Python 中功能强大的图像处理库,下面我将展示如何使用它进行批量图片处理。

1. 安装 Pillow

首先确保已安装 Pillow:

pip install Pillow

2. 基本批量处理示例

2.1 批量调整图片尺寸

from PIL import Image
import os

def batch_resize_images(input_folder, output_folder, target_size=(800, 600)):
    """
    批量调整图片尺寸

    参数:
    input_folder: 输入文件夹路径
    output_folder: 输出文件夹路径
    target_size: 目标尺寸 (宽, 高)
    """

    # 确保输出文件夹存在
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 支持的图片格式
    supported_formats = ('.jpg', '.jpeg', '.png', '.bmp', '.gif')

    # 遍历输入文件夹
    for filename in os.listdir(input_folder):
        # 检查文件格式
        if filename.lower().endswith(supported_formats):
            try:
                # 打开图片
                img_path = os.path.join(input_folder, filename)
                img = Image.open(img_path)

                # 调整尺寸(保持宽高比)
                img.thumbnail(target_size, Image.Resampling.LANCZOS)

                # 保存图片
                output_path = os.path.join(output_folder, filename)
                img.save(output_path)

                print(f"已处理: {filename}")

            except Exception as e:
                print(f"处理 {filename} 时出错: {e}")

    print("批量调整尺寸完成!")

# 使用示例
if __name__ == "__main__":
    input_dir = "./input_images"  # 输入图片文件夹
    output_dir = "./output_resized"  # 输出图片文件夹
    batch_resize_images(input_dir, output_dir, (800, 600))

2.2 批量转换图片格式

from PIL import Image
import os

def batch_convert_format(input_folder, output_folder, target_format='JPEG', quality=95):
    """
    批量转换图片格式

    参数:
    input_folder: 输入文件夹路径
    output_folder: 输出文件夹路径
    target_format: 目标格式 ('JPEG', 'PNG', 'BMP', 'GIF'等)
    quality: 图片质量(仅对JPEG有效,1-100)
    """

    # 确保输出文件夹存在
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 遍历输入文件夹
    for filename in os.listdir(input_folder):
        try:
            # 打开图片
            img_path = os.path.join(input_folder, filename)
            img = Image.open(img_path)

            # 生成输出文件名(修改扩展名)
            name, ext = os.path.splitext(filename)
            output_filename = f"{name}.{target_format.lower()}"
            output_path = os.path.join(output_folder, output_filename)

            # 转换并保存
            if target_format.upper() == 'JPEG':
                # JPEG格式需要转换RGBA模式
                if img.mode in ('RGBA', 'LA', 'P'):
                    # 创建白色背景
                    rgb_img = Image.new('RGB', img.size, (255, 255, 255))
                    rgb_img.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
                    img = rgb_img
                img.save(output_path, target_format, quality=quality)
            else:
                img.save(output_path, target_format)

            print(f"已转换: {filename} -> {output_filename}")

        except Exception as e:
            print(f"处理 {filename} 时出错: {e}")

    print("批量格式转换完成!")

# 使用示例
if __name__ == "__main__":
    input_dir = "./input_images"
    output_dir = "./output_converted"
    batch_convert_format(input_dir, output_dir, 'PNG')

3. 高级批量处理功能

3.1 批量添加水印

from PIL import Image, ImageDraw, ImageFont
import os

def batch_add_watermark(input_folder, output_folder, watermark_text="Copyright", 
                        position='bottom-right', opacity=0.5):
    """
    批量添加文字水印

    参数:
    input_folder: 输入文件夹路径
    output_folder: 输出文件夹路径
    watermark_text: 水印文字
    position: 水印位置 ('top-left', 'top-right', 'bottom-left', 'bottom-right', 'center')
    opacity: 水印透明度 (0.0-1.0)
    """

    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 支持的图片格式
    supported_formats = ('.jpg', '.jpeg', '.png', '.bmp')

    for filename in os.listdir(input_folder):
        if filename.lower().endswith(supported_formats):
            try:
                # 打开图片
                img_path = os.path.join(input_folder, filename)
                img = Image.open(img_path).convert('RGBA')

                # 创建水印图层
                watermark = Image.new('RGBA', img.size, (255, 255, 255, 0))
                draw = ImageDraw.Draw(watermark)

                # 设置字体(注意:需要字体文件,这里使用默认字体)
                try:
                    font = ImageFont.truetype("arial.ttf", 40)
                except:
                    font = ImageFont.load_default()

                # 计算水印位置
                text_bbox = draw.textbbox((0, 0), watermark_text, font=font)
                text_width = text_bbox[2] - text_bbox[0]
                text_height = text_bbox[3] - text_bbox[1]

                if position == 'top-left':
                    position_coords = (10, 10)
                elif position == 'top-right':
                    position_coords = (img.width - text_width - 10, 10)
                elif position == 'bottom-left':
                    position_coords = (10, img.height - text_height - 10)
                elif position == 'bottom-right':
                    position_coords = (img.width - text_width - 10, img.height - text_height - 10)
                else:  # center
                    position_coords = ((img.width - text_width) // 2, (img.height - text_height) // 2)

                # 绘制半透明水印
                draw.text(position_coords, watermark_text, font=font, 
                         fill=(255, 255, 255, int(255 * opacity)))

                # 合并图片和水印
                watermarked = Image.alpha_composite(img, watermark)

                # 保存图片
                output_path = os.path.join(output_folder, filename)
                watermarked.convert('RGB').save(output_path)

                print(f"已添加水印: {filename}")

            except Exception as e:
                print(f"处理 {filename} 时出错: {e}")

    print("批量添加水印完成!")

# 使用示例
if __name__ == "__main__":
    input_dir = "./input_images"
    output_dir = "./output_watermarked"
    batch_add_watermark(input_dir, output_dir, "© 2023 MyCompany", 'bottom-right', 0.7)

3.2 批量调整亮度和对比度

from PIL import Image, ImageEnhance
import os

def batch_adjust_images(input_folder, output_folder, brightness=1.0, 
                        contrast=1.0, saturation=1.0, sharpness=1.0):
    """
    批量调整图片的亮度、对比度、饱和度和锐度

    参数:
    input_folder: 输入文件夹路径
    output_folder: 输出文件夹路径
    brightness: 亮度因子 (1.0为原始)
    contrast: 对比度因子 (1.0为原始)
    saturation: 饱和度因子 (1.0为原始)
    sharpness: 锐度因子 (1.0为原始)
    """

    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    supported_formats = ('.jpg', '.jpeg', '.png', '.bmp')

    for filename in os.listdir(input_folder):
        if filename.lower().endswith(supported_formats):
            try:
                img_path = os.path.join(input_folder, filename)
                img = Image.open(img_path)

                # 调整亮度
                if brightness != 1.0:
                    enhancer = ImageEnhance.Brightness(img)
                    img = enhancer.enhance(brightness)

                # 调整对比度
                if contrast != 1.0:
                    enhancer = ImageEnhance.Contrast(img)
                    img = enhancer.enhance(contrast)

                # 调整饱和度
                if saturation != 1.0:
                    enhancer = ImageEnhance.Color(img)
                    img = enhancer.enhance(saturation)

                # 调整锐度
                if sharpness != 1.0:
                    enhancer = ImageEnhance.Sharpness(img)
                    img = enhancer.enhance(sharpness)

                # 保存图片
                output_path = os.path.join(output_folder, filename)
                img.save(output_path)

                print(f"已调整: {filename}")

            except Exception as e:
                print(f"处理 {filename} 时出错: {e}")

    print("批量调整完成!")

# 使用示例
if __name__ == "__main__":
    input_dir = "./input_images"
    output_dir = "./output_adjusted"
    # 增加亮度,增强对比度
    batch_adjust_images(input_dir, output_dir, brightness=1.2, contrast=1.3)

4. 综合批量处理类

下面是一个更完整的批量处理类,包含多种功能:

from PIL import Image, ImageOps, ImageFilter, ImageEnhance, ImageDraw, ImageFont
import os
import time

class BatchImageProcessor:
    """批量图片处理器"""

    def __init__(self, input_folder, output_folder):
        self.input_folder = input_folder
        self.output_folder = output_folder
        self.supported_formats = ('.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff')

        # 确保输出文件夹存在
        if not os.path.exists(output_folder):
            os.makedirs(output_folder)

    def get_image_files(self):
        """获取所有图片文件"""
        image_files = []
        for filename in os.listdir(self.input_folder):
            if filename.lower().endswith(self.supported_formats):
                image_files.append(filename)
        return image_files

    def batch_resize(self, target_size=(800, 600), keep_aspect=True):
        """批量调整尺寸"""
        image_files = self.get_image_files()

        for filename in image_files:
            try:
                img_path = os.path.join(self.input_folder, filename)
                img = Image.open(img_path)

                if keep_aspect:
                    # 保持宽高比
                    img.thumbnail(target_size, Image.Resampling.LANCZOS)
                else:
                    # 强制调整到指定尺寸
                    img = img.resize(target_size, Image.Resampling.LANCZOS)

                output_path = os.path.join(self.output_folder, filename)
                img.save(output_path)
                print(f"✓ 调整尺寸: {filename}")

            except Exception as e:
                print(f"✗ 处理 {filename} 时出错: {e}")

        print(f"完成!共处理 {len(image_files)} 张图片")

    def batch_convert(self, target_format='JPEG', quality=95):
        """批量转换格式"""
        image_files = self.get_image_files()

        for filename in image_files:
            try:
                img_path = os.path.join(self.input_folder, filename)
                img = Image.open(img_path)

                # 生成新文件名
                name, ext = os.path.splitext(filename)
                new_filename = f"{name}.{target_format.lower()}"
                output_path = os.path.join(self.output_folder, new_filename)

                # 保存为指定格式
                img.save(output_path, target_format, quality=quality)
                print(f"✓ 转换格式: {filename} -> {new_filename}")

            except Exception as e:
                print(f"✗ 处理 {filename} 时出错: {e}")

        print(f"完成!共处理 {len(image_files)} 张图片")

    def batch_rotate(self, angle=90):
        """批量旋转图片"""
        image_files = self.get_image_files()

        for filename in image_files:
            try:
                img_path = os.path.join(self.input_folder, filename)
                img = Image.open(img_path)

                # 旋转图片
                rotated = img.rotate(angle, expand=True)

                output_path = os.path.join(self.output_folder, filename)
                rotated.save(output_path)
                print(f"✓ 旋转图片: {filename} ({angle}度)")

            except Exception as e:
                print(f"✗ 处理 {filename} 时出错: {e}")

        print(f"完成!共处理 {len(image_files)} 张图片")

    def batch_grayscale(self):
        """批量转换为灰度图"""
        image_files = self.get_image_files()

        for filename in image_files:
            try:
                img_path = os.path.join(self.input_folder, filename)
                img = Image.open(img_path)

                # 转换为灰度
                grayscale = ImageOps.grayscale(img)

                output_path = os.path.join(self.output_folder, filename)
                grayscale.save(output_path)
                print(f"✓ 转换为灰度: {filename}")

            except Exception as e:
                print(f"✗ 处理 {filename} 时出错: {e}")

        print(f"完成!共处理 {len(image_files)} 张图片")

    def batch_apply_filter(self, filter_type='blur'):
        """批量应用滤镜"""
        image_files = self.get_image_files()

        filter_map = {
            'blur': ImageFilter.BLUR,
            'contour': ImageFilter.CONTOUR,
            'detail': ImageFilter.DETAIL,
            'edge_enhance': ImageFilter.EDGE_ENHANCE,
            'emboss': ImageFilter.EMBOSS,
            'sharpen': ImageFilter.SHARPEN,
            'smooth': ImageFilter.SMOOTH,
        }

        if filter_type not in filter_map:
            print(f"错误: 不支持的滤镜类型 '{filter_type}'")
            return

        for filename in image_files:
            try:
                img_path = os.path.join(self.input_folder, filename)
                img = Image.open(img_path)

                # 应用滤镜
                filtered = img.filter(filter_map[filter_type])

                output_path = os.path.join(self.output_folder, filename)
                filtered.save(output_path)
                print(f"✓ 应用滤镜: {filename} ({filter_type})")

            except Exception as e:
                print(f"✗ 处理 {filename} 时出错: {e}")

        print(f"完成!共处理 {len(image_files)} 张图片")

    def batch_add_border(self, border_size=10, border_color='white'):
        """批量添加边框"""
        image_files = self.get_image_files()

        # 将颜色名称转换为RGB值
        color_map = {
            'white': (255, 255, 255),
            'black': (0, 0, 0),
            'red': (255, 0, 0),
            'green': (0, 255, 0),
            'blue': (0, 0, 255),
            'gray': (128, 128, 128),
        }

        if border_color in color_map:
            border_rgb = color_map[border_color]
        else:
            # 如果不是预定义颜色,尝试解析
            try:
                border_rgb = tuple(int(border_color[i:i+2], 16) for i in (0, 2, 4))
            except:
                border_rgb = (255, 255, 255)  # 默认白色

        for filename in image_files:
            try:
                img_path = os.path.join(self.input_folder, filename)
                img = Image.open(img_path)

                # 添加边框
                bordered = ImageOps.expand(img, border=border_size, fill=border_rgb)

                output_path = os.path.join(self.output_folder, filename)
                bordered.save(output_path)
                print(f"✓ 添加边框: {filename}")

            except Exception as e:
                print(f"✗ 处理 {filename} 时出错: {e}")

        print(f"完成!共处理 {len(image_files)} 张图片")

# 使用示例
if __name__ == "__main__":
    # 创建处理器实例
    processor = BatchImageProcessor(
        input_folder="./input_images",
        output_folder="./output_processed"
    )

    # 执行各种批量操作
    print("=== 批量图片处理开始 ===")

    # 1. 调整尺寸
    print("\n1. 调整图片尺寸...")
    processor.batch_resize(target_size=(1024, 768))

    # 2. 转换为灰度图
    print("\n2. 转换为灰度图...")
    processor = BatchImageProcessor("./output_processed", "./output_grayscale")
    processor.batch_grayscale()

    # 3. 添加边框
    print("\n3. 添加边框...")
    processor = BatchImageProcessor("./output_grayscale", "./output_bordered")
    processor.batch_add_border(border_size=20, border_color='black')

    print("\n=== 批量图片处理完成 ===")

5. 使用示例脚本

创建一个完整的使用示例:

#!/usr/bin/env python3
"""
批量图片处理工具
使用: python batch_image_processor.py [操作] [输入文件夹] [输出文件夹] [参数...]
"""

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

def process_images(args):
    """根据参数处理图片"""

    if not os.path.exists(args.input):
        print(f"错误: 输入文件夹 '{args.input}' 不存在")
        return

    if not os.path.exists(args.output):
        os.makedirs(args.output)

    # 获取图片文件
    image_files = []
    supported_formats = ('.jpg', '.jpeg', '.png', '.bmp', '.gif')

    for filename in os.listdir(args.input):
        if filename.lower().endswith(supported_formats):
            image_files.append(filename)

    if not image_files:
        print("警告: 输入文件夹中没有支持的图片文件")
        return

    processed_count = 0

    for filename in image_files:
        try:
            input_path = os.path.join(args.input, filename)
            output_path = os.path.join(args.output, filename)

            img = Image.open(input_path)

            # 根据操作类型处理图片
            if args.operation == 'resize':
                img.thumbnail((args.width, args.height), Image.Resampling.LANCZOS)

            elif args.operation == 'rotate':
                img = img.rotate(args.angle, expand=True)

            elif args.operation == 'grayscale':
                img = ImageOps.grayscale(img)

            elif args.operation == 'mirror':
                if args.direction == 'horizontal':
                    img = ImageOps.mirror(img)
                else:  # vertical
                    img = ImageOps.flip(img)

            elif args.operation == 'crop':
                # 假设居中裁剪
                width, height = img.size
                left = (width - args.crop_width) // 2
                top = (height - args.crop_height) // 2
                right = left + args.crop_width
                bottom = top + args.crop_height
                img = img.crop((left, top, right, bottom))

            # 保存图片
            img.save(output_path)
            processed_count += 1
            print(f"已处理: {filename}")

        except Exception as e:
            print(f"处理 {filename} 时出错: {e}")

    print(f"\n完成!成功处理 {processed_count}/{len(image_files)} 张图片")

def main():
    parser = argparse.ArgumentParser(description='批量图片处理工具')
    parser.add_argument('operation', choices=['resize', 'rotate', 'grayscale', 'mirror', 'crop'],
                       help='要执行的操作')
    parser.add_argument('input', help='输入文件夹路径')
    parser.add_argument('output', help='输出文件夹路径')

    # 操作特定参数
    parser.add_argument('--width', type=int, default=800, help='调整宽度 (用于resize操作)')
    parser.add_argument('--height', type=int, default=600, help='调整高度 (用于resize操作)')
    parser.add_argument('--angle', type=int, default=90, help='旋转角度 (用于rotate操作)')
    parser.add_argument('--direction', choices=['horizontal', 'vertical'], default='horizontal',
                       help='镜像方向 (用于mirror操作)')
    parser.add_argument('--crop-width', type=int, default=400, help='裁剪宽度 (用于crop操作)')
    parser.add_argument('--crop-height', type=int, default=300, help='裁剪高度 (用于crop操作)')

    args = parser.parse_args()
    process_images(args)

if __name__ == "__main__":
    main()

总结

Pillow 库为 Python 提供了强大的图像处理能力,通过上述示例,您可以:

批量调整图片尺寸 - 保持宽高比或强制调整 批量转换图片格式 - 在不同格式间转换 批量添加水印 - 添加文字或图片水印 批量调整图像属性 - 亮度、对比度、饱和度、锐度 批量应用滤镜 - 模糊、锐化、边缘检测等 批量执行其他操作 - 旋转、镜像、裁剪、添加边框等

这些示例可以根据您的具体需求进行调整和扩展,构建适合自己项目的批量图片处理工具。