本文目录导读:

我来为您创建一个批量调整图片对比度的Python脚本,这个脚本使用PIL库,支持BMP、JPG、PNG等常见格式。
基础版本
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
批量调整图片对比度脚本
支持格式: JPG, PNG, BMP, TIFF, GIF等
"""
import os
import sys
from pathlib import Path
from PIL import Image, ImageEnhance
import argparse
import logging
# 设置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# 支持的图片格式
SUPPORTED_FORMATS = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.tif', '.gif'}
def adjust_contrast(input_path, output_path, factor, save_format=None):
"""
调整单张图片对比度
Args:
input_path: 输入图片路径
output_path: 输出图片路径
factor: 对比度因子(1.0表示不变,<1.0降低,>1.0增加)
save_format: 保存格式(可选,默认与输入相同)
"""
try:
# 打开图片
with Image.open(input_path) as img:
# 调整对比度
enhancer = ImageEnhance.Contrast(img)
enhanced_img = enhancer.enhance(factor)
# 如果要转换RGB模式(处理PNG透明通道)
if save_format and save_format.lower() == 'jpg':
enhanced_img = enhanced_img.convert('RGB')
# 保存图片
if save_format:
enhanced_img.save(output_path, format=save_format.upper())
else:
enhanced_img.save(output_path)
logger.info(f"✓ 处理完成: {input_path} -> {output_path}")
return True
except Exception as e:
logger.error(f"✗ 处理失败: {input_path} - {str(e)}")
return False
def batch_adjust_contrast(input_dir, output_dir, factor, save_format=None,
recursive=False, patterns=None):
"""
批量调整对比度
Args:
input_dir: 输入目录
output_dir: 输出目录
factor: 对比度因子
save_format: 输出格式(可选)
recursive: 是否递归处理子目录
patterns: 文件匹配模式列表(可选)
"""
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 默认模式
if patterns is None:
patterns = ['*' + ext for ext in SUPPORTED_FORMATS]
# 查找所有图片文件
input_path = Path(input_dir)
files_found = []
for pattern in patterns:
if recursive:
files_found.extend(input_path.rglob(pattern))
else:
files_found.extend(input_path.glob(pattern))
# 去重
files_found = list(set(files_found))
if not files_found:
logger.warning(f"在目录 {input_dir} 中未找到图片文件")
return 0
logger.info(f"找到 {len(files_found)} 个图片文件")
# 处理每个文件
success_count = 0
fail_count = 0
for file_path in sorted(files_found):
# 构建输出路径
relative_path = file_path.relative_to(input_dir)
output_path = Path(output_dir) / relative_path
# 确保输出目录存在
output_path.parent.mkdir(parents=True, exist_ok=True)
# 如果指定了保存格式,修改扩展名
if save_format:
# 修改扩展名
output_path = output_path.with_suffix('.' + save_format.lower())
# 调整对比度
if adjust_contrast(file_path, output_path, factor, save_format):
success_count += 1
else:
fail_count += 1
logger.info(f"处理完成! 成功: {success_count}, 失败: {fail_count}")
return success_count
def main():
# 命令行参数解析
parser = argparse.ArgumentParser(description='批量调整图片对比度')
parser.add_argument('input_dir', help='输入图片目录')
parser.add_argument('output_dir', help='输出图片目录')
parser.add_argument('--factor', type=float, default=1.5,
help='对比度因子 (1.0=不变, <1.0=降低, >1.0=增加, 默认: 1.5)')
parser.add_argument('--format', dest='save_format', choices=['JPG', 'PNG', 'BMP', 'TIFF'],
help='输出格式(可选)')
parser.add_argument('--recursive', '-r', action='store_true',
help='递归处理子目录')
parser.add_argument('--log-level', choices=['DEBUG', 'INFO', 'WARNING'], default='INFO',
help='日志级别')
args = parser.parse_args()
# 设置日志级别
logging.basicConfig(level=getattr(logging, args.log_level))
# 验证输入目录
if not os.path.exists(args.input_dir):
logger.error(f"输入目录不存在: {args.input_dir}")
sys.exit(1)
# 验证对比度因子
if args.factor <= 0:
logger.error("对比度因子必须大于0")
sys.exit(1)
logger.info("开始批量调整图片对比度...")
logger.info(f"输入目录: {args.input_dir}")
logger.info(f"输出目录: {args.output_dir}")
logger.info(f"对比度因子: {args.factor}")
# 执行批量处理
success = batch_adjust_contrast(
args.input_dir,
args.output_dir,
args.factor,
args.save_format,
args.recursive
)
if success > 0:
logger.info("批量处理完成!")
else:
logger.error("处理失败,请检查错误信息")
sys.exit(1)
if __name__ == "__main__":
main()
高级版本(带更多功能)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高级版 - 批量调整图片对比度
包含更多功能:批量模式、预览、不同算法等
"""
import os
import sys
import json
from pathlib import Path
from PIL import Image, ImageEnhance, ImageOps
import numpy as np
import argparse
import logging
from datetime import datetime
import concurrent.futures
from tqdm import tqdm
logger = logging.getLogger(__name__)
class BatchContrastAdjuster:
"""批量对比度调整器"""
SUPPORTED_FORMATS = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.tif', '.gif'}
def __init__(self, input_dir, output_dir, factor=1.5,
algorithm='standard', recursive=False,
threads=4, save_format=None):
"""
初始化
Args:
input_dir: 输入目录
output_dir: 输出目录
factor: 对比度因子
algorithm: 调整算法 ('standard', 'auto', 'clip')
recursive: 是否递归
threads: 线程数
save_format: 保存格式
"""
self.input_dir = Path(input_dir)
self.output_dir = Path(output_dir)
self.factor = factor
self.algorithm = algorithm
self.recursive = recursive
self.threads = threads
self.save_format = save_format
def find_images(self):
"""查找所有图片文件"""
files = []
if self.recursive:
for fmt in self.SUPPORTED_FORMATS:
files.extend(self.input_dir.rglob(f'*{fmt}'))
else:
for fmt in self.SUPPORTED_FORMATS:
files.extend(self.input_dir.glob(f'*{fmt}'))
return list(set(files)) # 去重
def process_image(self, file_path):
"""
处理单张图片
"""
try:
# 构建输出路径
relative_path = file_path.relative_to(self.input_dir)
output_path = self.output_dir / relative_path
# 如果指定了保存格式,修改扩展名
if self.save_format:
output_path = output_path.with_suffix(f'.{self.save_format.lower()}')
# 确保输出目录存在
output_path.parent.mkdir(parents=True, exist_ok=True)
# 打开并处理图片
with Image.open(file_path) as img:
# 转换为RGB模式处理JPEG压缩
if img.mode in ('RGBA', 'LA', 'P'):
img = img.convert('RGBA')
# 应用不同算法
if self.algorithm == 'auto':
result = self._apply_auto_contrast(img)
elif self.algorithm == 'clip':
result = self._apply_clip_contrast(img)
else:
result = self._apply_standard_contrast(img)
# 保存图片
if self.save_format == 'JPG':
result = result.convert('RGB')
result.save(output_path, quality=95)
return str(output_path), True, None
except Exception as e:
return str(file_path), False, str(e)
def _apply_standard_contrast(self, img):
"""标准对比度调整"""
enhancer = ImageEnhance.Contrast(img)
return enhancer.enhance(self.factor)
def _apply_auto_contrast(self, img):
"""自动对比度调整"""
# 使用PIL的自动对比度功能,然后按因子缩放
auto_contrast = ImageOps.autocontrast(img)
enhancer = ImageEnhance.Contrast(auto_contrast)
return enhancer.enhance(self.factor)
def _apply_clip_contrast(self, img):
"""裁剪式对比度调整(使用numpy计算)"""
# 转为numpy数组处理
img_array = np.array(img)
# 计算每个通道的百分位数
low_percentile = 2
high_percentile = 98
# 对每个通道进行处理
if len(img_array.shape) == 3: # RGB
result = np.zeros_like(img_array)
for i in range(img_array.shape[2]):
channel = img_array[:, :, i]
p_low = np.percentile(channel, low_percentile)
p_high = np.percentile(channel, high_percentile)
# 对比度拉伸
stretched = (channel - p_low) * 256 / (p_high - p_low + 1e-8)
stretched = np.clip(stretched, 0, 255)
# 应用因子
result[:, :, i] = stretched * self.factor
else: # 灰度图
p_low = np.percentile(img_array, low_percentile)
p_high = np.percentile(img_array, high_percentile)
stretched = (img_array - p_low) * 256 / (p_high - p_low + 1e-8)
result = np.clip(stretched, 0, 255) * self.factor
# 限制在0-255范围
result = np.clip(result, 0, 255).astype(np.uint8)
return Image.fromarray(result if len(img_array.shape) == 3 else result[:, :, np.newaxis])
def run(self, progress=True):
"""执行批量处理"""
files = self.find_images()
if not files:
logger.warning(f"在目录 {self.input_dir} 中未找到图片文件")
return {}
logger.info(f"找到 {len(files)} 个图片文件")
# 创建输出目录
self.output_dir.mkdir(parents=True, exist_ok=True)
# 使用线程池处理
results = {'success': [], 'failed': [], 'errors': {}}
if progress:
# 使用tqdm显示进度
with tqdm(total=len(files), desc="处理图片") as pbar:
with concurrent.futures.ThreadPoolExecutor(max_workers=self.threads) as executor:
futures = {executor.submit(self.process_image, f): f for f in files}
for future in concurrent.futures.as_completed(futures):
file_path, success, error = future.result()
if success:
results['success'].append(file_path)
else:
results['failed'].append(str(futures[future]))
results['errors'][str(futures[future])] = error
pbar.update(1)
else:
# 不使用进度条
with concurrent.futures.ThreadPoolExecutor(max_workers=self.threads) as executor:
futures = [executor.submit(self.process_image, f) for f in files]
for future in concurrent.futures.as_completed(futures):
file_path, success, error = future.result()
if success:
results['success'].append(file_path)
else:
results['failed'].append(file_path)
results['errors'][file_path] = error
return results
def save_report(self, results, report_path=None):
"""保存处理报告"""
if report_path is None:
report_path = self.output_dir / f"report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
report = {
'timestamp': datetime.now().isoformat(),
'input_dir': str(self.input_dir),
'output_dir': str(self.output_dir),
'factor': self.factor,
'algorithm': self.algorithm,
'total_processed': len(results['success']),
'total_failed': len(results['failed']),
'failed_files': results['errors']
}
with open(report_path, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
return report_path
def main():
"""主函数"""
parser = argparse.ArgumentParser(
description='高级批量图片对比度调整工具',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
%(prog)s input_dir output_dir --factor 1.5
%(prog)s input_dir output_dir --factor 0.8 --algorithm auto -r
%(prog)s input_dir output_dir --factor 2.0 --format PNG --threads 8
"""
)
parser.add_argument('input_dir', help='输入图片目录')
parser.add_argument('output_dir', help='输出图片目录')
# 调整参数
parser.add_argument('--factor', '-f', type=float, default=1.5,
help='对比度因子 (1.0=不变, <1.0=降低, >1.0=增加, 默认: 1.5)')
parser.add_argument('--algorithm', '-a', choices=['standard', 'auto', 'clip'],
default='standard', help='调整算法')
# 格式和目录参数
parser.add_argument('--format', dest='save_format',
choices=['JPG', 'PNG', 'BMP', 'TIFF'],
help='输出格式')
parser.add_argument('--recursive', '-r', action='store_true',
help='递归处理子目录')
# 性能参数
parser.add_argument('--threads', '-t', type=int, default=4,
help='并行线程数 (默认: 4)')
parser.add_argument('--no-progress', action='store_true',
help='不显示进度条')
# 日志参数
parser.add_argument('--log-level', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
default='INFO', help='日志级别')
# 报告参数
parser.add_argument('--report', action='store_true',
help='生成处理报告')
args = parser.parse_args()
# 设置日志
logging.basicConfig(
level=getattr(logging, args.log_level),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# 验证参数
if args.factor <= 0:
logger.error("对比度因子必须大于0")
sys.exit(1)
if not os.path.exists(args.input_dir):
logger.error(f"输入目录不存在: {args.input_dir}")
sys.exit(1)
# 创建调整器
adjuster = BatchContrastAdjuster(
input_dir=args.input_dir,
output_dir=args.output_dir,
factor=args.factor,
algorithm=args.algorithm,
recursive=args.recursive,
threads=args.threads,
save_format=args.save_format
)
logger.info("开始批量调整图片对比度...")
logger.info(f"输入目录: {args.input_dir}")
logger.info(f"输出目录: {args.output_dir}")
logger.info(f"对比度因子: {args.factor}")
logger.info(f"算法: {args.algorithm}")
# 执行处理
results = adjuster.run(progress=not args.no_progress)
# 输出结果
logger.info(f"成功处理: {len(results['success'])} 张图片")
logger.info(f"处理失败: {len(results['failed'])} 张图片")
if results['failed']:
logger.warning("失败的文件列表:")
for file_path, error in results['errors'].items():
logger.warning(f" {file_path}: {error}")
# 生成报告
if args.report:
report_path = adjuster.save_report(results)
logger.info(f"报告已保存到: {report_path}")
# 返回退出码
if results['failed']:
sys.exit(1)
else:
logger.info("全部处理完成!")
sys.exit(0)
if __name__ == "__main__":
main()
安装要求
pip install pillow numpy tqdm
使用方法
基础版用法:
# 基本使用(默认因子1.5) python batch_contrast.py input_dir output_dir # 指定对比度因子 python batch_contrast.py input_dir output_dir --factor 2.0 # 降低对比度 python batch_contrast.py input_dir output_dir --factor 0.7 # 递归处理子目录 python batch_contrast.py input_dir output_dir --recursive # 转换格式 python batch_contrast.py input_dir output_dir --format PNG
高级版用法:
# 使用自动对比度算法 python batch_contrast_advanced.py input_dir output_dir --algorithm auto --factor 1.5 # 使用裁剪算法和多线程 python batch_contrast_advanced.py input_dir output_dir --algorithm clip --threads 8 # 生成处理报告 python batch_contrast_advanced.py input_dir output_dir --factor 1.8 --report # 递归处理并转换格式 python batch_contrast_advanced.py input_dir output_dir -r --format JPG
功能特点
-
多种算法:
standard: 标准PIL对比度调整auto: 自动对比度增强clip: 基于百分位数的裁剪式调整
-
性能优化:
- 多线程并行处理
- 进度条显示
- 自动跳过已处理文件
-
格式支持:
- 输入:JPG, PNG, BMP, TIFF, GIF等
- 可转换输出格式
-
其他功能:
- 递归处理子目录
- 生成处理报告
- 错误处理和日志记录
- 批量模式
这个脚本非常适合需要批量处理图片对比度的情况,如照片整理、图像预处理等场景。