259 lines
9.9 KiB
Python
259 lines
9.9 KiB
Python
"""
|
||
图片去背景工具
|
||
使用rembg库自动去除图片背景
|
||
"""
|
||
import os
|
||
import argparse
|
||
from pathlib import Path
|
||
from rembg import remove, new_session
|
||
from PIL import Image
|
||
|
||
# 支持HEIC格式
|
||
try:
|
||
from pillow_heif import register_heif_opener
|
||
register_heif_opener()
|
||
HEIC_SUPPORTED = True
|
||
except ImportError:
|
||
HEIC_SUPPORTED = False
|
||
|
||
def str2bool(v):
|
||
"""将字符串转换为布尔值"""
|
||
if isinstance(v, bool):
|
||
return v
|
||
if v.lower() in ('yes', 'true', 't', 'y', '1'):
|
||
return True
|
||
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
|
||
return False
|
||
else:
|
||
raise argparse.ArgumentTypeError('布尔值应为true或false')
|
||
|
||
def remove_background(input_path, output_path, session=None, **kwargs):
|
||
"""
|
||
去除图片背景
|
||
|
||
Args:
|
||
input_path: 输入图片路径
|
||
output_path: 输出图片路径
|
||
session: rembg会话对象(可选)
|
||
**kwargs: 其他参数,如alpha_matting相关参数
|
||
"""
|
||
print(f"正在处理: {input_path}")
|
||
|
||
# 读取输入图片
|
||
input_image = Image.open(input_path)
|
||
|
||
# 去除背景
|
||
output_image = remove(input_image, session=session, **kwargs)
|
||
|
||
# 保存输出图片
|
||
output_image.save(output_path)
|
||
|
||
print(f"已保存: {output_path}")
|
||
|
||
def process_images_folder(input_folder, output_folder, model_name="u2net",
|
||
alpha_matting=False, alpha_matting_foreground_threshold=240,
|
||
alpha_matting_background_threshold=10, alpha_matting_erode_size=10,
|
||
post_process_mask=False):
|
||
"""
|
||
批量处理文件夹中的所有图片
|
||
|
||
Args:
|
||
input_folder: 输入文件夹路径
|
||
output_folder: 输出文件夹路径
|
||
model_name: 模型名称,可选值:
|
||
- u2net (默认): 通用模型
|
||
- u2netp: 轻量版u2net
|
||
- u2net_human_seg: 人物分割
|
||
- silueta: 精简版u2net (43MB)
|
||
- isnet-general-use: 新的通用模型
|
||
- isnet-anime: 动漫角色高精度分割
|
||
- birefnet-general: 通用模型
|
||
- birefnet-portrait: 人像模型
|
||
alpha_matting: 是否启用alpha matting后处理(改善边缘质量)
|
||
alpha_matting_foreground_threshold: 前景阈值 (0-255),值越大保留越多前景
|
||
alpha_matting_background_threshold: 背景阈值 (0-255),值越大去除越多背景
|
||
alpha_matting_erode_size: 侵蚀大小,用于平滑边缘
|
||
post_process_mask: 是否启用mask后处理
|
||
"""
|
||
# 创建输出文件夹
|
||
Path(output_folder).mkdir(parents=True, exist_ok=True)
|
||
|
||
# 创建会话(重用会话可以提高性能)
|
||
print(f"使用模型: {model_name}")
|
||
session = new_session(model_name)
|
||
|
||
# 支持的图片格式
|
||
image_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.webp'}
|
||
if HEIC_SUPPORTED:
|
||
image_extensions.update({'.heic', '.heif'})
|
||
else:
|
||
print("提示: 未安装pillow-heif,HEIC格式不可用。安装方法: pip install pillow-heif")
|
||
|
||
# 获取所有图片文件
|
||
input_path = Path(input_folder)
|
||
image_files = [f for f in input_path.iterdir()
|
||
if f.is_file() and f.suffix.lower() in image_extensions]
|
||
|
||
if not image_files:
|
||
print(f"在 {input_folder} 中没有找到图片文件")
|
||
return
|
||
|
||
print(f"找到 {len(image_files)} 张图片,开始处理...")
|
||
print(f"Alpha Matting: {'启用' if alpha_matting else '禁用'}")
|
||
if alpha_matting:
|
||
print(f" - 前景阈值: {alpha_matting_foreground_threshold}")
|
||
print(f" - 背景阈值: {alpha_matting_background_threshold}")
|
||
print(f" - 侵蚀大小: {alpha_matting_erode_size}")
|
||
print(f"Mask后处理: {'启用' if post_process_mask else '禁用'}")
|
||
print("-" * 50)
|
||
|
||
# 处理每张图片
|
||
for i, image_file in enumerate(image_files, 1):
|
||
try:
|
||
# 输出文件名(保持原始名称,改为PNG格式以支持透明背景)
|
||
output_filename = image_file.stem + '_nobg.png'
|
||
output_path = Path(output_folder) / output_filename
|
||
|
||
print(f"[{i}/{len(image_files)}] ", end="")
|
||
remove_background(
|
||
str(image_file),
|
||
str(output_path),
|
||
session=session,
|
||
alpha_matting=alpha_matting,
|
||
alpha_matting_foreground_threshold=alpha_matting_foreground_threshold,
|
||
alpha_matting_background_threshold=alpha_matting_background_threshold,
|
||
alpha_matting_erode_size=alpha_matting_erode_size,
|
||
post_process_mask=post_process_mask
|
||
)
|
||
|
||
except Exception as e:
|
||
print(f"处理 {image_file.name} 时出错: {e}")
|
||
|
||
print("-" * 50)
|
||
print(f"处理完成!结果保存在 {output_folder} 文件夹中")
|
||
|
||
if __name__ == "__main__":
|
||
parser = argparse.ArgumentParser(
|
||
description='图片去背景工具 - 使用rembg自动去除图片背景',
|
||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||
epilog='''
|
||
示例用法:
|
||
# 使用默认参数处理images文件夹
|
||
python remove_background.py
|
||
|
||
# 处理单个文件
|
||
python remove_background.py input.jpg output.png
|
||
|
||
# 处理指定文件夹
|
||
python remove_background.py my_images/ my_output/
|
||
|
||
# 使用不同模型
|
||
python remove_background.py input.jpg output.png -m birefnet-portrait
|
||
|
||
# 自定义alpha matting参数
|
||
python remove_background.py input.jpg output.png -ft 260 -bt 12 -es 5
|
||
'''
|
||
)
|
||
|
||
# 必需参数
|
||
parser.add_argument('input', nargs='?', default='images',
|
||
help='输入文件或文件夹路径(默认: images)')
|
||
parser.add_argument('output', nargs='?', default=None,
|
||
help='输出文件或文件夹路径(可选,默认为output/)')
|
||
|
||
# 模型选择
|
||
parser.add_argument('-m', '--model', default='isnet-general-use',
|
||
choices=['u2net', 'u2netp', 'u2net_human_seg', 'silueta',
|
||
'isnet-general-use', 'isnet-anime',
|
||
'birefnet-general', 'birefnet-general-lite',
|
||
'birefnet-portrait', 'birefnet-dis',
|
||
'birefnet-hrsod', 'birefnet-cod', 'birefnet-massive'],
|
||
help='选择使用的模型 (默认: isnet-general-use)')
|
||
|
||
# Alpha Matting参数
|
||
parser.add_argument('-a', '--alpha-matting', type=str2bool, nargs='?', const=True, default=True,
|
||
metavar='true/false',
|
||
help='启用alpha matting后处理(默认: true)。用法: -a 或 -a true 或 -a false')
|
||
parser.add_argument('-ft', '--foreground-threshold', type=int, default=245,
|
||
help='前景阈值 (0-255),值越大保留越多细节 (默认: 245)')
|
||
parser.add_argument('-bt', '--background-threshold', type=int, default=8,
|
||
help='背景阈值 (0-255),值越大去除越多背景 (默认: 8)')
|
||
parser.add_argument('-es', '--erode-size', type=int, default=2,
|
||
help='侵蚀大小,用于平滑边缘,值越大越平滑但可能丢失细节 (默认: 2)')
|
||
|
||
# 其他选项
|
||
parser.add_argument('-p', '--post-process', type=str2bool, nargs='?', const=True, default=True,
|
||
metavar='true/false',
|
||
help='启用mask后处理(默认: true)。用法: -p 或 -p true 或 -p false')
|
||
|
||
args = parser.parse_args()
|
||
|
||
print("=" * 50)
|
||
print("图片去背景工具")
|
||
print("=" * 50)
|
||
|
||
# 判断输入是文件还是文件夹
|
||
input_path = Path(args.input)
|
||
|
||
if not input_path.exists():
|
||
print(f"错误: 输入路径不存在: {args.input}")
|
||
exit(1)
|
||
|
||
# 处理单个文件
|
||
if input_path.is_file():
|
||
# 确定输出路径
|
||
if args.output is None:
|
||
output_path = input_path.parent / 'output' / (input_path.stem + '_nobg.png')
|
||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||
else:
|
||
output_path = Path(args.output)
|
||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
||
print(f"输入文件: {input_path}")
|
||
print(f"输出文件: {output_path}")
|
||
print(f"模型: {args.model}")
|
||
print(f"Alpha Matting: {'启用' if args.alpha_matting else '禁用'}")
|
||
if args.alpha_matting:
|
||
print(f" - 前景阈值: {args.foreground_threshold}")
|
||
print(f" - 背景阈值: {args.background_threshold}")
|
||
print(f" - 侵蚀大小: {args.erode_size}")
|
||
print(f"Mask后处理: {'启用' if args.post_process else '禁用'}")
|
||
print("-" * 50)
|
||
|
||
# 创建会话
|
||
session = new_session(args.model)
|
||
|
||
# 处理图片
|
||
remove_background(
|
||
str(input_path),
|
||
str(output_path),
|
||
session=session,
|
||
alpha_matting=args.alpha_matting,
|
||
alpha_matting_foreground_threshold=args.foreground_threshold,
|
||
alpha_matting_background_threshold=args.background_threshold,
|
||
alpha_matting_erode_size=args.erode_size,
|
||
post_process_mask=args.post_process
|
||
)
|
||
|
||
print("-" * 50)
|
||
print(f"处理完成!结果保存在: {output_path}")
|
||
|
||
# 处理文件夹
|
||
elif input_path.is_dir():
|
||
output_folder = args.output if args.output else 'output'
|
||
|
||
process_images_folder(
|
||
str(input_path),
|
||
output_folder,
|
||
model_name=args.model,
|
||
alpha_matting=args.alpha_matting,
|
||
alpha_matting_foreground_threshold=args.foreground_threshold,
|
||
alpha_matting_background_threshold=args.background_threshold,
|
||
alpha_matting_erode_size=args.erode_size,
|
||
post_process_mask=args.post_process
|
||
)
|
||
|
||
else:
|
||
print(f"错误: 不支持的输入类型: {args.input}")
|
||
exit(1)
|