first commit
48
README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# 微信头像批量合成主界面图片——实现思路
|
||||
|
||||
## 需求拆解
|
||||
|
||||
1. **读取主界面截图**
|
||||
- 路径:`./微信无头像主界面截图/`
|
||||
- 每张图片尺寸:2560x1527 px
|
||||
2. **读取头像素材**
|
||||
- 路径:`./微信头像素材/`
|
||||
3. **确定头像合成区域**
|
||||
- 区域基准点:左上角 (x=8, y=31)
|
||||
- 区域尺寸:宽75,高70
|
||||
4. **头像素材处理**
|
||||
- 每张头像素材需缩放/裁剪为 54x54 px
|
||||
5. **头像合成**
|
||||
- 将处理后的头像粘贴到主界面截图的指定区域(左上角 x=8, y=31,区域内随机偏移,区域宽高为75x75)
|
||||
- 粘贴算法:
|
||||
- 头像尺寸为54x54,区域为75x75,允许的偏移范围:
|
||||
- x: [8, 8+75-54] = [8, 29]
|
||||
- y: [31, 31+75-54] = [31, 52]
|
||||
- 每次随机生成x、y偏移值,将头像贴到(x, y)处
|
||||
- 合成后图片命名规则:
|
||||
- `avatar_01_实际x-实际y_55x55.jpg`
|
||||
- avatar_01:头像文件名+序号
|
||||
- 实际x-实际y:本次随机偏移后的左上角坐标
|
||||
- 55x55:头像尺寸
|
||||
6. **输出**
|
||||
- 合成图片保存到 `./output/` 目录
|
||||
|
||||
## 实现流程
|
||||
|
||||
1. 遍历主界面截图文件夹,读取每张主界面图片
|
||||
2. 遍历头像素材文件夹,读取每张头像图片
|
||||
3. 对每张头像图片:
|
||||
- 缩放/裁剪为 54x54 px
|
||||
- 随机生成偏移坐标,将头像粘贴到每张主界面图片的 (8, 31, 75x75) 区域内
|
||||
- 记录实际坐标,生成合成图片,按命名规则保存到 output 目录
|
||||
4. 可选:批量处理,支持多线程/进度提示
|
||||
|
||||
## 技术选型
|
||||
- 使用 Python 的 Pillow (PIL) 库进行图片读取、缩放、粘贴和保存
|
||||
- 使用 os/pathlib 遍历文件夹
|
||||
- 兼容 jpg/png 格式
|
||||
|
||||
## 注意事项
|
||||
- 头像素材尺寸不一时,需等比缩放后居中裁剪为 54x54
|
||||
- 合成区域如有特殊对齐需求可调整
|
||||
- 文件命名需防止重名覆盖
|
||||
69
main.py
Normal file
@ -0,0 +1,69 @@
|
||||
import os
|
||||
import random
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
|
||||
# 配置参数
|
||||
MAIN_BG_DIR = './微信无头像主界面截图'
|
||||
AVATAR_DIR = './微信头像素材'
|
||||
OUTPUT_DIR = './output'
|
||||
|
||||
# 区域参数
|
||||
REGION_X = 8
|
||||
REGION_Y = 31
|
||||
REGION_W = 75
|
||||
REGION_H = 75
|
||||
AVATAR_SIZE = 54 # 54x54 px
|
||||
|
||||
# 输出目录准备
|
||||
def ensure_output_dir():
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
def get_image_files(folder):
|
||||
exts = ['.jpg', '.jpeg', '.png']
|
||||
return [f for f in Path(folder).iterdir() if f.suffix.lower() in exts]
|
||||
|
||||
def process_avatar(avatar_path):
|
||||
"""缩放/裁剪为54x54,保持居中"""
|
||||
img = Image.open(avatar_path).convert('RGBA')
|
||||
# 等比缩放
|
||||
min_side = min(img.width, img.height)
|
||||
# 居中裁剪为正方形
|
||||
left = (img.width - min_side) // 2
|
||||
top = (img.height - min_side) // 2
|
||||
img = img.crop((left, top, left + min_side, top + min_side))
|
||||
img = img.resize((AVATAR_SIZE, AVATAR_SIZE), Image.LANCZOS)
|
||||
return img
|
||||
|
||||
def random_offset():
|
||||
x = random.randint(REGION_X, REGION_X + REGION_W - AVATAR_SIZE)
|
||||
y = random.randint(REGION_Y, REGION_Y + REGION_H - AVATAR_SIZE)
|
||||
return x, y
|
||||
|
||||
def main():
|
||||
ensure_output_dir()
|
||||
main_imgs = get_image_files(MAIN_BG_DIR)
|
||||
avatar_imgs = get_image_files(AVATAR_DIR)
|
||||
if not main_imgs or not avatar_imgs:
|
||||
print('未找到主界面或头像素材图片')
|
||||
return
|
||||
avatar_count = 0
|
||||
for avatar_idx, avatar_path in enumerate(avatar_imgs, 1):
|
||||
avatar_img = process_avatar(avatar_path)
|
||||
avatar_name = avatar_path.stem
|
||||
for main_idx, main_path in enumerate(main_imgs, 1):
|
||||
with Image.open(main_path).convert('RGBA') as main_img:
|
||||
x, y = random_offset()
|
||||
composed = main_img.copy()
|
||||
composed.paste(avatar_img, (x, y), avatar_img)
|
||||
# 命名规则
|
||||
out_name = f"avatar_{avatar_idx:02d}_{x}-{y}_{AVATAR_SIZE}x{AVATAR_SIZE}.jpg"
|
||||
out_path = os.path.join(OUTPUT_DIR, out_name)
|
||||
# 转为RGB再保存为jpg
|
||||
composed.convert('RGB').save(out_path, 'JPEG', quality=95)
|
||||
print(f"保存: {out_path}")
|
||||
avatar_count += 1
|
||||
print(f"共生成{avatar_count}张合成图片。")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
output/avatar_01_12-41_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_01_15-35_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_01_9-32_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_02_22-35_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_02_29-45_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_02_9-44_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_03_10-45_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_03_13-44_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_03_24-51_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_04_19-42_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_04_26-40_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_04_8-33_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
output/avatar_05_11-43_54x54.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
output/avatar_05_26-36_54x54.jpg
Normal file
|
After Width: | Height: | Size: 309 KiB |
BIN
output/avatar_05_9-51_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
output/avatar_06_13-34_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_06_14-35_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_06_17-46_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_07_23-34_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_07_28-34_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_07_29-40_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_08_13-37_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_08_16-36_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_08_8-48_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_09_11-46_54x54.jpg
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
output/avatar_09_29-43_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_09_8-50_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_100_12-49_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_100_13-36_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_100_13-52_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_101_11-52_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_101_13-42_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_101_17-44_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_102_13-37_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
output/avatar_102_19-34_54x54.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
output/avatar_102_19-47_54x54.jpg
Normal file
|
After Width: | Height: | Size: 309 KiB |
BIN
output/avatar_103_11-40_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_103_11-46_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_103_24-50_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_104_11-47_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_104_13-39_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_104_13-45_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_105_12-33_54x54.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
output/avatar_105_12-45_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_105_16-43_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
output/avatar_10_14-45_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
output/avatar_10_18-52_54x54.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
output/avatar_10_19-36_54x54.jpg
Normal file
|
After Width: | Height: | Size: 309 KiB |
BIN
output/avatar_11_13-44_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_11_14-40_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_11_8-33_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_12_17-50_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_12_24-46_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_12_29-33_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_13_10-39_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_13_11-50_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_13_19-39_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_14_23-51_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_14_25-48_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_14_9-49_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_15_17-45_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_15_21-40_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_15_29-46_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_16_10-35_54x54.jpg
Normal file
|
After Width: | Height: | Size: 311 KiB |
BIN
output/avatar_16_20-42_54x54.jpg
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
output/avatar_16_26-49_54x54.jpg
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
output/avatar_17_19-48_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_17_19-51_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_17_25-50_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_18_11-47_54x54.jpg
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
output/avatar_18_20-51_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_18_24-44_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_19_13-32_54x54.jpg
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
output/avatar_19_20-34_54x54.jpg
Normal file
|
After Width: | Height: | Size: 311 KiB |
BIN
output/avatar_19_24-47_54x54.jpg
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
output/avatar_20_10-52_54x54.jpg
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
output/avatar_20_18-52_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_20_29-46_54x54.jpg
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
output/avatar_21_16-35_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_21_17-48_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_21_23-50_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_22_11-40_54x54.jpg
Normal file
|
After Width: | Height: | Size: 309 KiB |
BIN
output/avatar_22_19-41_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_22_28-39_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
output/avatar_23_18-47_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
output/avatar_23_25-43_54x54.jpg
Normal file
|
After Width: | Height: | Size: 309 KiB |
BIN
output/avatar_23_9-38_54x54.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
output/avatar_24_10-45_54x54.jpg
Normal file
|
After Width: | Height: | Size: 311 KiB |
BIN
output/avatar_24_11-39_54x54.jpg
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
output/avatar_24_20-43_54x54.jpg
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
output/avatar_25_10-47_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_25_21-51_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_25_22-36_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_26_14-39_54x54.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
output/avatar_26_24-37_54x54.jpg
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
output/avatar_26_26-51_54x54.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
output/avatar_27_19-34_54x54.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
output/avatar_27_23-43_54x54.jpg
Normal file
|
After Width: | Height: | Size: 312 KiB |