Синхронизация с server/: нормализация видео, овал-подсказка, хосты с путём, DNR-стенд
- app.py: probe_video(), HDR→bt709, fps=30, -t 20, логирование progress/face_ok, split_host_path() для хостов с путём (domain.com/v1/giga), FPG_WS_PORT - templates/index.html: овал-подсказка, canvas 1080×1080, запас 10% - templates/result.html: стилевые правки (цвета) - gigadoc_ws.py: поддержка пути в --sdk-host - test_fpg.py: переведён на DNR-стенд (bearer subprotocol, Origin) - README: хосты с путём, FPG_WS_PORT, нормализация - .gitignore: server/, wordpress/, wordpress-plugin/ (отдельные репозитории)
This commit is contained in:
1 parent
421183b7e3
commit
7375618b1d
9 files changed
+423
-108
No files matched your search
+31
-18
@@ -47,7 +47,7 @@
|
||||
margin: 0 auto;
|
||||
}
|
||||
.card {
|
||||
background: #fff;
|
||||
background: #faf6ec;
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
||||
@@ -190,6 +190,16 @@
|
||||
object-fit: cover;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
/* Овал — безопасная зона: лицо должно помещаться в него целиком */
|
||||
.scan-oval {
|
||||
position: absolute;
|
||||
inset: 12%;
|
||||
border: 3px solid rgba(255, 255, 255, 0.9);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.4);
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
.scan-progress { color: #fff; margin-top: 20px; font-size: 16px; text-align: center; }
|
||||
.scan-progress-bar {
|
||||
width: 280px;
|
||||
@@ -249,8 +259,8 @@
|
||||
/* Результат */
|
||||
.result { display: none; }
|
||||
.summary-box {
|
||||
background: #f0f4ff;
|
||||
border-left: 4px solid #0014FC;
|
||||
background: linear-gradient(135deg, #061A40, #0B4F9C, #2D9CDB);
|
||||
color: #fff;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
@@ -281,20 +291,20 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-ok { background: #d4edda; color: #155724; }
|
||||
.status-warning { background: #fff3cd; color: #856404; }
|
||||
.status-warning { background: #ffe0d6; color: #a04a2f; }
|
||||
.status-danger { background: #f8d7da; color: #721c24; }
|
||||
.status-info { background: #d1ecf1; color: #0c5460; }
|
||||
.status-info { background: #dbe9ff; color: #1e4a8a; }
|
||||
|
||||
.warnings-box {
|
||||
background: #fff3cd;
|
||||
border-left: 4px solid #ffc107;
|
||||
background: #ffe0d6;
|
||||
border-left: 4px solid #ff7f50;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.warnings-box h3 { color: #856404; margin-bottom: 10px; font-size: 16px; }
|
||||
.warnings-box h3 { color: #a04a2f; margin-bottom: 10px; font-size: 16px; }
|
||||
.warnings-box ul { padding-left: 20px; }
|
||||
.warnings-box li { margin: 5px 0; color: #856404; }
|
||||
.warnings-box li { margin: 5px 0; color: #a04a2f; }
|
||||
|
||||
.advice-box {
|
||||
background: #d4edda;
|
||||
@@ -414,6 +424,7 @@
|
||||
<div class="scan-modal" id="scanModal">
|
||||
<div class="scan-video-wrap">
|
||||
<video class="scan-video" id="scanVideo" autoplay playsinline muted></video>
|
||||
<div class="scan-oval"></div>
|
||||
</div>
|
||||
<div class="scan-progress">
|
||||
<div id="scanProgressText">Кадров: 0 / 300 (0%)</div>
|
||||
@@ -422,7 +433,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<button class="scan-cancel" id="scanCancelBtn">✖ Отмена</button>
|
||||
<div class="scan-hint">Держите лицо в круге, смотрите прямо в камеру, не двигайтесь</div>
|
||||
<div class="scan-hint">Поместите лицо в овал целиком: лоб, глаза и подбородок — с запасом. Если голова не помещается — отодвиньте телефон</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -656,7 +667,7 @@
|
||||
video: {
|
||||
facingMode: 'user',
|
||||
width: { ideal: 1280 },
|
||||
height: { ideal: 720 }
|
||||
height: { ideal: 1280 }
|
||||
},
|
||||
audio: false
|
||||
});
|
||||
@@ -676,11 +687,11 @@
|
||||
scanLastFrameTime = 0;
|
||||
updateScanProgress(0);
|
||||
|
||||
// Canvas 720×720 — квадрат, лицо целиком влезает无论是 portrait или landscape.
|
||||
// Canvas 1080×1080 — квадрат, лицо целиком влезает в portrait и landscape.
|
||||
// Серверное extract_frames масштабирует до 1280×720 для SDK.
|
||||
scanCanvas = document.createElement('canvas');
|
||||
scanCanvas.width = 720;
|
||||
scanCanvas.height = 720;
|
||||
scanCanvas.width = 1080;
|
||||
scanCanvas.height = 1080;
|
||||
scanCtx = scanCanvas.getContext('2d');
|
||||
|
||||
let captureStream;
|
||||
@@ -719,16 +730,18 @@
|
||||
return;
|
||||
}
|
||||
if (ts - scanLastFrameTime >= FRAME_INTERVAL) {
|
||||
// Квадратный center-crop: берём центральную квадратную область из видео.
|
||||
// Квадратный center-crop с запасом 10%: берём чуть меньший
|
||||
// квадрат, чтобы голова гарантированно помещалась целиком
|
||||
// (иначе SDK не находит лицо из-за обрезанной головы).
|
||||
const vw = scanVideo.videoWidth;
|
||||
const vh = scanVideo.videoHeight;
|
||||
if (vw && vh) {
|
||||
const side = Math.min(vw, vh);
|
||||
const side = Math.min(vw, vh) * 0.9;
|
||||
const sx = (vw - side) / 2;
|
||||
const sy = (vh - side) / 2;
|
||||
scanCtx.drawImage(scanVideo, sx, sy, side, side, 0, 0, 720, 720);
|
||||
scanCtx.drawImage(scanVideo, sx, sy, side, side, 0, 0, 1080, 1080);
|
||||
} else {
|
||||
scanCtx.drawImage(scanVideo, 0, 0, 720, 720);
|
||||
scanCtx.drawImage(scanVideo, 0, 0, 1080, 1080);
|
||||
}
|
||||
scanFrameCount++;
|
||||
scanLastFrameTime = ts;
|
||||
|
||||
Reference in new issue
Block a user