用 Python 给照片打分:自动挑一张最适合做竖屏 AI 跳舞视频的照片
最近 TikTok 上流行的 angry dance(愤怒舞蹈)这类“单图生成跳舞视频”,效果好坏很大程度取决于输入照片:清不清楚、亮不亮、能不能裁成 9:16。手机相册里一堆候选照片时,一张张肉眼挑很费时间。本文写一个不到 40 行的 Python 脚本,用 Pillow + NumPy 给照片打分并排序。脚本不依赖 OpenCV,也不做人脸识别。
一、打分规则

四个维度都是经验规则:
- 分辨率:长边 1500 像素以上记满分;
- 亮度:灰度均值越接近 140(中等偏亮)越好;
- 清晰度:用 4 邻域拉普拉斯算子的方差衡量,边缘越锐利方差越大;
- 竖构图适配:竖图直接满分,横图裁成 9:16 损失更多,按 (h/w)² 递减。
二、代码
#!/usr/bin/env python3
"""给一组候选照片打分,挑出最适合做竖屏 AI 跳舞视频(如 angry dance)的一张。
评分只是经验规则:分辨率、亮度、清晰度、竖构图适配度。不做人脸识别。"""
import sys, glob
import numpy as np
from PIL import Image, ImageOps
def sharpness(g):
g = g.astype(np.float32)
lap = -4*g[1:-1,1:-1] + g[:-2,1:-1] + g[2:,1:-1] + g[1:-1,:-2] + g[1:-1,2:]
return float(lap.var())
def score(path):
im = ImageOps.exif_transpose(Image.open(path)).convert("L")
w, h = im.size
g = np.asarray(im.resize((min(w, 1200), int(h * min(w, 1200) / w))))
s_res = min(max(w, h) / 1500, 1.0) # 长边 1500px 以上记满分
s_light = 1 - min(abs(g.mean() - 140) / 140, 1.0) # 越接近中等亮度越好
s_sharp = min(sharpness(g) / 150, 1.0) # 拉普拉斯方差
s_fit = 1.0 if h >= w else (h / w) ** 2 # 横图裁成 9:16 会损失更多
total = 0.25*s_res + 0.25*s_light + 0.3*s_sharp + 0.2*s_fit
return total, (w, h, s_res, s_light, s_sharp, s_fit)
if __name__ == "__main__":
files = sys.argv[1:] or sorted(glob.glob("*.jpg"))
rows = sorted(((score(f), f) for f in files), reverse=True)
print(f"{'file':<24}{'size':>11}{'res':>6}{'light':>7}{'sharp':>7}{'fit':>6}{'total':>7}")
for (t, (w, h, a, b, c, d)), f in rows:
print(f"{f:<24}{f'{w}x{h}':>11}{a:>6.2f}{b:>7.2f}{c:>7.2f}{d:>6.2f}{t:>7.2f}")
print(f"推荐: {rows[0][1]} (注意: 分数不判断是否只有一个人、是否获得本人同意)")
两个细节:ImageOps.exif_transpose 先按 EXIF 方向把照片转正,否则手机竖拍的照片可能被当成横图;计算清晰度前先把图缩到宽 1200,这样不同分辨率的照片之间可比。
三、运行结果
测试用的 5 张图是用 Pillow 画的火柴人,不是真人照片:


半身竖图得分最高(0.96),暗图和小缩略图垫底,符合预期。
四、脚本的局限

排第二的是一张三人合照:从像素统计上看它又大又清楚,但单人模板最怕的就是多人照片。想解决这个问题,需要加人脸检测(比如 OpenCV 的 Haar 级联或 MediaPipe),统计人脸数量和占比,本文没有实现。另外,分数再高也替代不了一件事:确认照片里的人同意被做成视频。
挑出照片后,可以放进 CapCut 模板,也可以交给专门做这类视频的网站,例如 AngryDance。
浙公网安备 33010602011771号