save
This commit is contained in:
+4
-3
@@ -116,7 +116,7 @@ def _resolve_image_bytes(image_bytes: bytes = None, image_url: str = None) -> by
|
||||
|
||||
|
||||
def _local_face_shape(image_bytes: bytes = None, image_url: str = None) -> str:
|
||||
"""MediaPipe 脸型分类,返回 display(含混合脸型描述)或主脸型。"""
|
||||
"""MediaPipe 脸型分类,只返回主脸型(7 类之一),不含混合描述。"""
|
||||
import cv2
|
||||
import numpy as np
|
||||
from face.face_shape_classifier import classify_from_image
|
||||
@@ -126,11 +126,12 @@ def _local_face_shape(image_bytes: bytes = None, image_url: str = None) -> str:
|
||||
if bgr is None:
|
||||
raise ValueError("图片格式不支持,无法解码")
|
||||
result = classify_from_image(bgr, return_details=True, return_annotated=False)
|
||||
shape = result.get("display") or result["face_shape"]
|
||||
shape = result["face_shape"]
|
||||
logger.info(
|
||||
"local face_shape=%s conf=%.3f",
|
||||
"local face_shape=%s conf=%.3f display=%s",
|
||||
shape,
|
||||
float(result.get("confidence") or 0),
|
||||
result.get("display") or shape,
|
||||
)
|
||||
return shape
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
"""把 static/annotations 根目录下的图片按创建时间(天)归入 YYYY-MM-DD 子目录。
|
||||
|
||||
用法:
|
||||
python3 scripts/organize_annotations_by_day.py # 实际移动
|
||||
python3 scripts/organize_annotations_by_day.py --dry-run # 只预览
|
||||
python3 scripts/organize_annotations_by_day.py --dir /path # 指定目录
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from collections import Counter
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp"}
|
||||
|
||||
|
||||
def file_day(path: Path) -> str:
|
||||
"""取文件创建日(优先 birth time,否则 mtime),本地时区 YYYY-MM-DD。"""
|
||||
st = path.stat()
|
||||
ts = getattr(st, "st_birthtime", None) or st.st_mtime
|
||||
return datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
repo = Path(__file__).resolve().parent.parent
|
||||
parser = argparse.ArgumentParser(description="按天整理 annotations 图片")
|
||||
parser.add_argument(
|
||||
"--dir",
|
||||
type=Path,
|
||||
default=repo / "static" / "annotations",
|
||||
help="annotations 目录(默认 static/annotations)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="只打印将要执行的操作,不实际移动",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
root: Path = args.dir.resolve()
|
||||
|
||||
if not root.is_dir():
|
||||
print(f"目录不存在: {root}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
files = [
|
||||
p
|
||||
for p in root.iterdir()
|
||||
if p.is_file() and p.suffix.lower() in IMAGE_EXTS
|
||||
]
|
||||
if not files:
|
||||
print(f"根目录没有待整理图片: {root}")
|
||||
return 0
|
||||
|
||||
by_day: Counter[str] = Counter()
|
||||
moved = 0
|
||||
skipped = 0
|
||||
|
||||
for src in sorted(files):
|
||||
day = file_day(src)
|
||||
dest_dir = root / day
|
||||
dest = dest_dir / src.name
|
||||
by_day[day] += 1
|
||||
|
||||
if dest.exists():
|
||||
print(f"SKIP 目标已存在: {dest.relative_to(root)}")
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
if args.dry_run:
|
||||
print(f"MOVE {src.name} -> {day}/")
|
||||
else:
|
||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||
shutil.move(str(src), str(dest))
|
||||
moved += 1
|
||||
|
||||
print("---")
|
||||
print(f"目录: {root}")
|
||||
print(f"{'预览' if args.dry_run else '完成'}: {moved} 个文件"
|
||||
+ (f", 跳过 {skipped}" if skipped else ""))
|
||||
for day in sorted(by_day):
|
||||
print(f" {day}: {by_day[day]}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user