#!/usr/bin/env python3
"""把 report.json + 结果图生成为自包含 HTML 报告(支持 896 / 1024 / 原图0 三档)。"""
import json, os, html
OUT = "/home/ubuntu/hair/image/compare_test/out"
REPORT_HTML = os.path.join(OUT, "report.html")
results = json.load(open(os.path.join(OUT, "report.json")))
IMAGES = ["girl2", "girl5", "qwer", "asdf"]
STYLES = ["ellipse", "flower", "heart", "straight", "wave"]
SIDES = [
("default896", "默认 896", "#2563eb", "d"),
("side1024", "1024", "#10b981", "m"),
("origin0", "原图直送 0", "#f59e0b", "o"),
]
IMG_LONGSIDE = {"girl2": 1082, "girl5": 767, "qwer": 1678, "asdf": 1666}
STYLE_CN = {"ellipse": "椭圆", "flower": "花瓣", "heart": "心形", "straight": "直线", "wave": "波浪"}
def get(img, style, side):
for r in results:
if r["img"] == img and r["style"] == style and r["side"] == side:
return r
return None
# 总览统计(>60s 视为冷启动/异常,不进均值)
total = len(results)
ok = sum(1 for r in results if r["ok"])
COLD_S = 60.0
def avg(seq):
seq = [x for x in seq if x is not None]
return sum(seq) / len(seq) if seq else 0
def times(side, img=None):
out = []
for r in results:
if not r["ok"] or r["side"] != side:
continue
if img is not None and r["img"] != img:
continue
if r["elapsed"] >= COLD_S:
continue
out.append(r["elapsed"])
return out
cold_n = sum(1 for r in results if r["ok"] and r["elapsed"] >= COLD_S)
side_avgs = {sid: avg(times(sid)) for sid, *_ in SIDES}
all_times = [t for sid, *_ in SIDES for t in times(sid)]
max_bar = max(all_times + [1])
# 构造速度对比图数据:每图 × 三档
chart_rows = []
for img in IMAGES:
chart_rows.append((img, IMG_LONGSIDE[img], [avg(times(sid, img)) for sid, *_ in SIDES]))
def bar_svg():
bar_h = 22
gap = 12
label_w = 78
chart_w = 760
n_bars = len(SIDES)
rows = len(chart_rows)
h = rows * (bar_h * n_bars + gap) + 40
parts = [f'")
return "".join(parts)
def img_cell(r, cls):
if not r:
return f'
缺失
'
fname = r["key"] + ".jpg"
status = "✅" if r["ok"] else "❌"
t = f'{r["elapsed"]}s'
dim = f'{r["out_w"]}×{r["out_h"]}'
err = f'
{html.escape(r["err"])}
' if r["err"] else ""
img_tag = (f''
if r["ok"] else '
无图
')
return (f'
{img_tag}
'
f'
{status} {t} · {dim}
{err}
')
def compare_cards():
out = []
for img in IMAGES:
out.append(f'
📷 {html.escape(img)} 原图长边 {IMG_LONGSIDE[img]}px
')
heads = "".join(f'
{html.escape(label)}
' for _, label, _, cls in SIDES)
out.append(f'
发型
{heads}
')
for style in STYLES:
sc = STYLE_CN[style]
cells = "".join(img_cell(get(img, style, sid), cls) for sid, _, _, cls in SIDES)
out.append(f'
{html.escape(style)}{sc}
{cells}
')
out.append("
")
return "".join(out)
# 结论
small = [img for img in IMAGES if IMG_LONGSIDE[img] <= 1100]
large = [img for img in IMAGES if IMG_LONGSIDE[img] > 1100]
def ratio_range(num_side, den_side="default896"):
ratios = []
for img in large:
den = avg(times(den_side, img))
num = avg(times(num_side, img))
if den:
ratios.append(num / den)
if not ratios:
return 0, 0
return min(ratios), max(ratios)
r1024_lo, r1024_hi = ratio_range("side1024")
r0_lo, r0_hi = ratio_range("origin0")
cold_note = f"冷启动 {cold_n} 次(≥{COLD_S:.0f}s)已从均值剔除。" if cold_n else ""
conclusion = (
f"原图长边 ≤ 1100({'/'.join(small)})时三档耗时接近;"
f"长边 > 1600({'/'.join(large)})时相对默认896:"
f"1024 约 {r1024_lo:.1f}~{r1024_hi:.1f}×,"
f"原图直送约 {r0_lo:.1f}~{r0_hi:.1f}×。"
f"{cold_note}画质对比见下方三列并排,点击可放大。"
)
avg896 = side_avgs.get("default896", 0)
avg1024 = side_avgs.get("side1024", 0)
avg0 = side_avgs.get("origin0", 0)
ratio1024 = avg1024 / avg896 if avg896 else 0
ratio0 = avg0 / avg896 if avg896 else 0
legend = "".join(
f'{html.escape(label)}'
for _, label, color, _ in SIDES
)
html_doc = f"""
接口2 分辨率对比测试报告
"""
with open(REPORT_HTML, "w") as f:
f.write(html_doc)
# 同步首页
with open(os.path.join(OUT, "index.html"), "w") as f:
f.write(html_doc)
print(f"已生成: {REPORT_HTML}")
print(f"图片目录: {OUT}")