rembg-matting.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. """
  2. rembg 图像背景移除工具
  3. 支持单文件处理和批量文件夹处理
  4. """
  5. import sys
  6. import os
  7. from rembg import remove
  8. from PIL import Image
  9. from glob import glob
  10. SUPPORTED_FORMATS = ['.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tiff', '.tif']
  11. def extract_character_rembg(input_path, output_path):
  12. """
  13. 使用 rembg 库移除图像背景(单文件处理)
  14. """
  15. try:
  16. print(f' -> 读取图片: {os.path.basename(input_path)}')
  17. if not os.path.exists(input_path):
  18. print(f' [X] 错误: 文件不存在')
  19. return False
  20. # 创建输出目录
  21. output_dir = os.path.dirname(output_path)
  22. if output_dir and not os.path.exists(output_dir):
  23. print(f' -> 创建输出目录: {output_dir}')
  24. os.makedirs(output_dir, exist_ok=True)
  25. # 读取输入图像
  26. print(f' -> 加载图像...')
  27. input_image = Image.open(input_path)
  28. original_size = input_image.size
  29. print(f' 图像尺寸: {original_size[0]}x{original_size[1]}')
  30. # 确保输入图像是RGB模式
  31. if input_image.mode != 'RGB':
  32. print(f' -> 转换颜色模式: {input_image.mode} -> RGB')
  33. input_image = input_image.convert('RGB')
  34. # 使用 rembg 移除背景
  35. print(f' -> 执行AI抠图...')
  36. output_image = remove(input_image, post_process_mask=False)
  37. print(f' [OK] 抠图完成')
  38. # 确保输出图像尺寸与输入图像一致
  39. if output_image.size != original_size:
  40. print(f' -> 调整图像尺寸')
  41. final_image = Image.new('RGBA', original_size, (0, 0, 0, 0))
  42. final_image.paste(output_image, (0, 0), output_image if output_image.mode == 'RGBA' else None)
  43. output_image = final_image
  44. else:
  45. if output_image.mode != 'RGBA':
  46. output_image = output_image.convert('RGBA')
  47. # 保存结果
  48. print(f' -> 保存结果: {os.path.basename(output_path)}')
  49. output_image.save(output_path, 'PNG')
  50. print(f' [OK] 保存成功')
  51. return True
  52. except Exception as error:
  53. print(f' [X] 处理失败: {error}')
  54. return False
  55. def process_single_file(input_path, output_path):
  56. """
  57. 处理单个文件(静默模式,用于 API 调用)
  58. """
  59. try:
  60. if not os.path.exists(input_path):
  61. print(f"错误: 输入文件不存在: {input_path}", file=sys.stderr)
  62. sys.exit(1)
  63. # 读取输入图像
  64. input_image = Image.open(input_path)
  65. original_size = input_image.size
  66. # 确保输入图像是RGB模式
  67. if input_image.mode != 'RGB':
  68. input_image = input_image.convert('RGB')
  69. # 使用 rembg 移除背景
  70. output_image = remove(input_image, post_process_mask=False)
  71. # 确保输出图像尺寸与输入图像一致
  72. if output_image.size != original_size:
  73. final_image = Image.new('RGBA', original_size, (0, 0, 0, 0))
  74. final_image.paste(output_image, (0, 0), output_image if output_image.mode == 'RGBA' else None)
  75. output_image = final_image
  76. else:
  77. if output_image.mode != 'RGBA':
  78. output_image = output_image.convert('RGBA')
  79. # 创建输出目录(如果不存在)
  80. output_dir = os.path.dirname(output_path)
  81. if output_dir and not os.path.exists(output_dir):
  82. os.makedirs(output_dir, exist_ok=True)
  83. # 保存结果
  84. output_image.save(output_path, 'PNG')
  85. print("抠图完成")
  86. except Exception as error:
  87. print(f"错误: {error}", file=sys.stderr)
  88. sys.exit(1)
  89. def process_folder(input_folder, output_folder):
  90. """
  91. 批量处理文件夹中的所有图片
  92. """
  93. print('=' * 60)
  94. print('[Step 1/2] AI Image Matting')
  95. print('=' * 60)
  96. if not os.path.exists(input_folder):
  97. print(f'[X] Error: Input folder not found: {input_folder}')
  98. return 0
  99. print(f'-> Input folder: {input_folder}')
  100. # 创建输出文件夹
  101. if not os.path.exists(output_folder):
  102. print(f'-> Creating output folder: {output_folder}')
  103. os.makedirs(output_folder, exist_ok=True)
  104. else:
  105. print(f'-> Output folder: {output_folder}')
  106. # 获取所有支持的图片文件
  107. print(f'-> Scanning image files...')
  108. image_files = []
  109. for ext in SUPPORTED_FORMATS:
  110. image_files.extend(glob(os.path.join(input_folder, f'*{ext}')))
  111. image_files.extend(glob(os.path.join(input_folder, f'*{ext.upper()}')))
  112. # 去重(Windows文件系统不区分大小写,可能重复)
  113. image_files = list(set(image_files))
  114. image_files.sort()
  115. if not image_files:
  116. print(f'[X] No supported image files found')
  117. return 0
  118. print(f'[OK] Found {len(image_files)} images')
  119. print('-' * 60)
  120. success_count = 0
  121. for idx, input_path in enumerate(image_files, 1):
  122. filename = os.path.basename(input_path)
  123. name_without_ext = os.path.splitext(filename)[0]
  124. output_path = os.path.join(output_folder, f'{name_without_ext}.png')
  125. print(f'\n[{idx}/{len(image_files)}] {filename}')
  126. print(f'PROGRESS: {idx}/{len(image_files)}')
  127. if extract_character_rembg(input_path, output_path):
  128. success_count += 1
  129. print(f' [OK] Done')
  130. print('\n' + '=' * 60)
  131. print(f'[Step 1 Complete] Success: {success_count}/{len(image_files)}')
  132. print('=' * 60)
  133. return success_count
  134. def main():
  135. if len(sys.argv) < 3:
  136. print('用法:')
  137. print(' 单文件: python rembg-matting.py <输入文件> <输出文件>')
  138. print(' 批量处理: python rembg-matting.py <输入文件夹> <输出文件夹>')
  139. sys.exit(1)
  140. input_path = sys.argv[1]
  141. output_path = sys.argv[2]
  142. # 判断是文件还是文件夹
  143. if os.path.isfile(input_path):
  144. # 单文件处理
  145. process_single_file(input_path, output_path)
  146. elif os.path.isdir(input_path):
  147. # 批量处理
  148. processed = process_folder(input_path, output_path)
  149. sys.exit(0 if processed > 0 else 1)
  150. else:
  151. print(f'错误: 输入路径不存在: {input_path}', file=sys.stderr)
  152. sys.exit(1)
  153. if __name__ == '__main__':
  154. main()