CremyX Vision avatar

CremyX Vision

Under maintenance

Pricing

Pay per usage

Go to Apify Store
CremyX Vision

CremyX Vision

Under maintenance

Face detection + tracking (SCRFD ONNX), torch-free active-speaker detection (mouth motion x audio envelope) and auto-reframe: returns normalized 9:16 crop keyframes ready for an editplan.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Andrew Babo

Andrew Babo

Maintained by Community

Actor stats

0

Bookmarked

1.3K

Total users

747

Monthly active users

a day ago

Last modified

Categories

Share

cremyx-vision

Nhận diện + bám khuôn mặt (SCRFD ONNX), active-speaker detection (ai đang nói — không cần torch) và auto-reframe: trả về crop keyframes chuẩn hoá, dán thẳng vào editplan của cremyx-render-engine. Thay cho việc bắt user cài torch/UniFace trên máy.

  • Base image: node:22-bookworm-slim (onnxruntime-node là binary glibc)
  • Model nướng sẵn: SCRFD-10g (antelopev2/detection, ~17 MB) — không tải weight lúc chạy

Input

{
"op": "reframe", // faces | reframe | asd
"source": "kv:<storeId>/proxy.mp4", // hoặc https://…
"options": {
"sample_fps": 2, // số frame phân tích mỗi giây (tối đa 10; mặc định 8 cho asd)
"score_threshold": 0.5,
"start_sec": 0,
"duration_sec": null,
"threads": null,
"track_iou": 0.3, // ghép detection thành track
"track_max_gap_ms": 700, // mất mặt lâu hơn ngần này thì cắt track
"min_track_ms": 400,
"include_frames": false, // kèm box từng frame vào artifact
// chỉ dùng cho op=reframe (và asd khi muốn crop theo người nói)
"target_aspect": "9:16",
"track_id": null, // mặc định: track "nổi bật nhất" (bị bỏ qua khi asd có segments)
"smooth_window": 5, // median filter, lớn hơn = camera ì hơn
"dead_zone": 0.02, // bỏ rung nhỏ hơn 2% chiều khung
"headroom": 0.12, // đẩy mặt lên trên tâm một chút
"interp": "linear", // linear | hold
// chỉ dùng cho op=asd
"silence_ratio": 0.25, // RMS < 25% peak coi như im lặng
"min_segment_ms": 600, // đoạn nói ngắn hơn ngần này bị gộp/bỏ (chống giật)
"min_correlation": 0.05 // track có score thấp hơn coi như "không bao giờ nói"
},
"output": { "signed_upload_url": null },
"cleanup": "on_success",
"callback": null
}

Nên phân tích trên bản proxy 480p (op=proxy của cremyx-media-tools) — nhanh hơn nhiều lần và kết quả chuẩn hoá theo tỉ lệ nên áp lại lên bản master vẫn đúng.

Output

{
"status": "success",
"op": "reframe",
"artifacts": [{ "name": "reframe", "kv_key": "reframe.json" }],
"meta": {
"engine": "scrfd-onnx",
"width": 1280, "height": 720, "duration_sec": 61.4,
"sample_fps": 2, "frame_count": 123, "face_frame_ratio": 0.951,
"track_count": 2,
"tracks": [
{ "id": "face_01", "start_ms": 0, "end_ms": 58000, "duration_ms": 58000,
"sample_count": 112, "avg_area_px": 20480, "avg_score": 0.912 }
],
"reframe": {
"target_aspect": 0.5625,
"crop_px": { "w": 405, "h": 720 },
"track_id": "face_01",
"face_coverage": 0.951,
"keyframes": [{ "t_ms": 0, "rect": { "x": 0.31, "y": 0, "w": 0.316, "h": 1 }, "interp": "linear" }]
}
}
}
  • tracks[].samples (box từng thời điểm) nằm trong artifact JSON, không nằm trong dòng dataset cho nhẹ.
  • recttoạ độ chuẩn hoá 0..1 so với khung nguồn → không phụ thuộc độ phân giải.

Dùng kết quả để render dọc

reframe.keyframes khớp đúng schema crop.keyframes của render engine:

{
"mode": "editplan",
"plan": {
"canvas": { "width": 1080, "height": 1920, "fps": 30 },
"tracks": [{
"type": "media",
"clips": [{
"source": "https://…/master.mp4",
"start_ms": 0, "end_ms": 61400,
"layout": "single-center",
"crop": { "keyframes": [ /* dán nguyên reframe.keyframes vào đây */ ] }
}]
}]
}
}

op=asd — ai đang nói?

Active-speaker detection theo hướng không cần torch/LR-ASD: với mỗi face track, actor đo chuyển động vùng miệng theo thời gian rồi đối chiếu với envelope âm lượng của audio. Miệng cử động đúng lúc có tiếng → người đó đang nói.

// meta.asd
{
"segments": [
{ "track_id": "face_01", "start_ms": 0, "end_ms": 4000 },
{ "track_id": "face_02", "start_ms": 4000, "end_ms": 8000 }
],
"track_scores": [
{ "track_id": "face_01", "speech_score": 0.41, "speaking_ms": 4000 },
{ "track_id": "face_02", "speech_score": 0.41, "speaking_ms": 4000 }
],
"speech_ratio": 1.0,
"note": null
}
  • segments — khoảng thời gian từng người nói (đã qua hysteresis min_segment_ms).
  • track_scores[].speaking_ms — tổng thời gian nói ước lượng của mỗi track.
  • Truyền thêm target_aspect (vd "9:16") → meta.reframe.keyframes sẽ bám theo người đang nói thay vì một track cố định (track_id lúc này là "active_speaker"). Dán keyframes vào editplan của render engine như thường.
  • Kết hợp cremyx-diarize khi cần đối chiếu theo giọng nói (audio-only) — hai tín hiệu bổ sung nhau: diarize không cần nhìn mặt, asd không cần tách giọng.

Giới hạn cần biết

  • ASD dạng này cần nhìn thấy miệng: người quay lưng, che miệng, hoặc video không có mặt người thì không kết luận được (trả note giải thích). Với podcast phỏng vấn/talking-head quay chính diện thì hoạt động tốt.
  • sample_fps cao làm chi phí tăng tuyến tính; 2 fps là đủ cho reframe mượt (đã có smoothing + nội suy), 8 fps mặc định cho asd vì miệng cử động nhanh.
  • Không phát hiện được mặt che khuất/quay lưng — những đoạn đó dùng khung của keyframe gần nhất.

Ví dụ nối chuỗi

const proxy = await tools.mediaTools({ op: 'proxy', source: masterUrl, options: { height: 480 } });
const vis = await tools.vision({ op: 'reframe', source: proxy.kv('proxy'), options: { target_aspect: '9:16' } });
plan.tracks[0].clips[0].crop = { keyframes: vis.meta.reframe.keyframes };

Shard window (v2)

options.start_sec / duration_sec: mọi timestamp trong kết quả (frames[].time_ms, tracks[].start_ms/end_ms, samples[].time_ms, asd.segments[], reframe.keyframes[].t_ms) đều được offset về timeline gốc; meta.shard.offset_applied: true.

Memory mặc định run: 16 GB (4 vCPU); có thể override khi start run nhưng 16 GB là cấu hình khuyến nghị cho ASD.

Chạy nhanh op=asd (v0.3)

ASD chậm không phải vì thuật toán mà vì detect mọi frame ở 640×640. Bản này tách hai nhịp: sample_fps (nhịp đọc miệng) và detect_fps (nhịp thật sự chạy detector — box giữa hai lần detect được nội suy).

Mặc định mới cho asd: sample_fps=8, detect_fps=2, det_size=480, batch_size=8, dùng toàn bộ vCPU → giảm ~4x số lần inference.

Thứ tự tối ưu (nhanh nhất → chậm nhất):

  1. Proxy 480p trước. cremyx-media-tools op: "proxy" → lấy artifacts[].url làm source cho vision. Đừng phân tích bản master.
  2. Tái dùng faces. Chạy op: "faces" một lần, rồi truyền URL công khai của kết quả vào options.faces_url khi chạy asdbỏ hẳn bước detect, track id giữ nguyên giữa hai run.
  3. Chỉ chấm điểm chỗ có tiếng. Truyền options.words_url (kết quả cremyx-asr) hoặc options.vad_url → phần im lặng không tính mouth motion.
{
"op": "asd",
"source": "https://…/proxy.mp4", // 480p proxy, KHÔNG phải master
"options": {
"start_sec": 0, "duration_sec": 120, // client tự chia shard
"faces_url": "https://…/faces.json", // tuỳ chọn
"words_url": "https://…/asr.json", // tuỳ chọn
"det_size": 480, "detect_fps": 2, "sample_fps": 8, "batch_size": 8,
"target_aspect": "9:16"
}
}

Nguyên nhân thật của "chậm 10–12x" (đo được)

os.cpus() trong container Apify trả về số core của máy chủ (16), không phải quota thật của run. Actor cũ set intraOpNumThreads theo con số đó → 16 luồng ONNX giành nhau 2 core → mỗi frame ~0.7–1.0s. Bản 0.4 tính vCPU theo ACTOR_MEMORY_MBYTES / 4096 (đúng quy tắc Apify: 1 vCPU / 4 GB).

Đo trên cùng một video, 30 frame detect, det_size=320:

BảnMemorythreadsdetectms/frame
0.3 (os.cpus)8 GB1623.8s~790 ms
0.3 (os.cpus)8 GB820.7s~690 ms
0.416 GB41.02s~34 ms

→ nhanh hơn ~20x. Với shard 120s, detect_fps=2 (240 frame) phần detect chỉ còn khoảng 8–10 giây; thời gian còn lại là decode + mouth motion.

Chạy với 16384 MB (4 vCPU) cho op=asd. 8192 MB vẫn chạy nhưng chậm hơn ~2x; 4096 MB (1 vCPU) thì đừng dùng — log sẽ cảnh báo.

meta trả thêm để đối chiếu: detect_fps, det_size, detect_frames, batch_size, batched, threads, vcpus, faces_url_used, speech_gated, và timings.decode_ms / detect_ms / mouth_ms để biết nút thắt nằm ở đâu.

Actor không tự chia shard: client vẫn tự fan-out bằng start_sec / duration_sec và tự khử vùng overlap.

Reframe quality (v0.7) — sửa A-B IoU 0.54

Ba nguyên nhân làm crop cloud lệch so với local, đã sửa hết trong 0.7:

  1. Tracker vỡ track. Matching cũ chỉ dùng IoU giữa 2 frame liên tiếp; ở 2-4 fps, mặt di chuyển hơn 1 bề rộng box là IoU về 0 → một người bị tách thành nhiều track, crop nhảy sang người khác. Nay matching dùng box dự đoán theo vận tốc + fallback khoảng cách tâm / tỉ lệ kích thước, và track sống lâu được ưu tiên nhận box trước.
  2. Không có định danh bám dính. reframeKeyframes trước đây fallback về "mặt to nhất mỗi frame" → mặt phụ to hơn sẽ cướp khung. Nay thứ tự ưu tiên là active speaker > track_id ép > track đang bám > mặt to nhất, giữ khung qua khoảng mất nhận diện ngắn (sticky_hold_ms, mặc định 600 ms). Mọi keyframe đều mang track_id thật; kết quả có thêm track_idsparams.
  3. Cadence + smoothing quá thưa. Mặc định mới: sample_fps=4 (cho faces/reframe), keyframe_fps=4, dead_zone=0.006; cửa sổ median được căn giữa (bản cũ lệch trái nên crop trễ ở cuối mỗi shard).

Đo A-B trên fixture tổng hợp (1 người di chuyển nhanh + 1 mặt tĩnh to hơn, 30 s, so với crop lý tưởng từ ground truth):

Cấu hìnhtrackskeyframesmean IoU
cũ (sample 2 / kf 1 / dz 0.02, tracker IoU)2 (vỡ)440.344
0.7, sample 4 / kf 2 / dz 0.00611110.994
0.7 mặc định, sample 4 / kf 4 / dz 0.00611200.994

Tuỳ chọn liên quan: sample_fps, keyframe_fps, dead_zone (alias deadzone_ratio), smooth_window (alias smooth_window_ms), sticky_hold_ms, track_id, min_keyframes, asd_url, faces_url. reason của keyframe:

initial | face_move | speaker_switch | cadence | min_keyframes | fallback_center
.

op=asd — điều kiện đạt ≤0.05x realtime (v0.5)

Con số ≤0.05x realtime chỉ đúng khi chạy đúng fast path:

  1. Nguồn là proxy 480p do cremyx-media-tools op=proxy tạo (không đưa file gốc 1080p/4K).
  2. Truyền options.faces_url (kết quả op=faces đã có) để ASD bỏ hẳn bước detect.
  3. Không ép sample_fps > 8; mặc định 8 với detect_fps 2 là điểm cân bằng.
  4. Nếu có options.words_url, ASD chỉ decode các khoảng có thoại (speech gating).

Thiếu bước 1 hoặc 2 thì ASD phải decode/detect lại và thời gian tăng nhiều lần — đó là hành vi đúng, không phải hồi quy.

op=capabilities trả memory_mb, vcpus, host_cpusasd_fast_path.requires để phía gọi tự kiểm tra cấu hình trước khi đo.