img --> canvas.

main
dongjin kim 7 months ago
parent ac157c2b6b
commit cd39c6d05a

@ -270,7 +270,10 @@ document.addEventListener('DOMContentLoaded', () => {
// ========== dashboard.html 스크립트 추가 시작 ========== // ========== dashboard.html 스크립트 추가 시작 ==========
const uri = "ws://10.10.11.246:8765"; // 필요하면 여기만 수정 const uri = "ws://10.10.11.246:8765"; // 필요하면 여기만 수정
const imgEl = document.getElementById("frame");
// [수정] imgEl -> canvasEl로 변경
const canvasEl = document.getElementById("frame");
const statusEl = document.getElementById("status"); const statusEl = document.getElementById("status");
const frameInfoEl = document.getElementById("frame-info"); const frameInfoEl = document.getElementById("frame-info");
const detListEl = document.getElementById("det-list"); const detListEl = document.getElementById("det-list");
@ -281,6 +284,12 @@ document.addEventListener('DOMContentLoaded', () => {
const modelDisplayEl = document.getElementById("current-model-display"); const modelDisplayEl = document.getElementById("current-model-display");
const fpsDisplayEl = document.getElementById("fps-display"); const fpsDisplayEl = document.getElementById("fps-display");
// [추가] 캔버스 2D 컨텍스트
let ctx = null;
if (canvasEl) {
ctx = canvasEl.getContext('2d');
}
// [추가] 클래스별 색상 팔레트 (원하는 색상으로 수정 가능) // [추가] 클래스별 색상 팔레트 (원하는 색상으로 수정 가능)
const CLASS_COLORS = [ const CLASS_COLORS = [
'#FF3838', // 0: Red '#FF3838', // 0: Red
@ -299,7 +308,8 @@ document.addEventListener('DOMContentLoaded', () => {
let lastFrameMeta = null; let lastFrameMeta = null;
if (imgEl && statusEl && frameInfoEl && detListEl && bboxContainerEl && modelContainerEl) { // [수정] canvasEl 및 ctx 존재 여부 확인
if (canvasEl && ctx && statusEl && frameInfoEl && detListEl && bboxContainerEl && modelContainerEl) {
// 모델 변경 이벤트 리스너 // 모델 변경 이벤트 리스너
modelContainerEl.addEventListener('change', (event) => { modelContainerEl.addEventListener('change', (event) => {
@ -335,11 +345,12 @@ document.addEventListener('DOMContentLoaded', () => {
// 박스 컨테이너 위치/크기 조절 함수 // 박스 컨테이너 위치/크기 조절 함수
function updateBboxContainerPosition() { function updateBboxContainerPosition() {
if (!imgEl || !bboxContainerEl) return; // [수정] imgEl -> canvasEl
const top = imgEl.offsetTop; if (!canvasEl || !bboxContainerEl) return;
const left = imgEl.offsetLeft; const top = canvasEl.offsetTop;
const width = imgEl.offsetWidth; const left = canvasEl.offsetLeft;
const height = imgEl.offsetHeight; const width = canvasEl.offsetWidth;
const height = canvasEl.offsetHeight;
bboxContainerEl.style.top = `${top}px`; bboxContainerEl.style.top = `${top}px`;
bboxContainerEl.style.left = `${left}px`; bboxContainerEl.style.left = `${left}px`;
bboxContainerEl.style.width = `${width}px`; bboxContainerEl.style.width = `${width}px`;
@ -382,7 +393,8 @@ document.addEventListener('DOMContentLoaded', () => {
lines.push(`DET ch=${meta.ch} seq=${meta.seq} ts=${meta.ts_us} cnt=${items.length}`); lines.push(`DET ch=${meta.ch} seq=${meta.seq} ts=${meta.ts_us} cnt=${items.length}`);
bboxContainerEl.innerHTML = ""; bboxContainerEl.innerHTML = "";
if (!imgEl || !lastFrameMeta) { // [수정] imgEl -> canvasEl
if (!canvasEl || !lastFrameMeta) {
// [수정됨] x1,y1,x2,y2 형식에 맞게 텍스트 로그 수정 // [수정됨] x1,y1,x2,y2 형식에 맞게 텍스트 로그 수정
items.forEach((it, i) => { items.forEach((it, i) => {
// x1, y1, x2, y2 -> x, y, w, h // x1, y1, x2, y2 -> x, y, w, h
@ -402,8 +414,9 @@ document.addEventListener('DOMContentLoaded', () => {
} }
updateBboxContainerPosition(); updateBboxContainerPosition();
const imgWidth = imgEl.clientWidth; // [수정] imgEl -> canvasEl
const imgHeight = imgEl.clientHeight; const imgWidth = canvasEl.clientWidth;
const imgHeight = canvasEl.clientHeight;
const frameWidth = lastFrameMeta.w; const frameWidth = lastFrameMeta.w;
const frameHeight = lastFrameMeta.h; const frameHeight = lastFrameMeta.h;
@ -511,14 +524,12 @@ document.addEventListener('DOMContentLoaded', () => {
} }
return; return;
} }
// [수정] ArrayBuffer 처리: img.src 대신 createImageBitmap 및 canvas.drawImage 사용
if (data instanceof ArrayBuffer && lastFrameMeta) { if (data instanceof ArrayBuffer && lastFrameMeta) {
const blob = new Blob([data], {type: "image/jpeg"});
const url = URL.createObjectURL(blob);
imgEl.onload = () => {
URL.revokeObjectURL(url);
updateBboxContainerPosition();
// [추가] FPS 계산 // ========== [수정됨] FPS 계산 로직 (이곳으로 이동) ==========
// WebSocket에서 ArrayBuffer(프레임)를 수신한 시점을 기준으로 FPS 계산
frameCount++; frameCount++;
const now = performance.now(); const now = performance.now();
const delta = now - lastFpsCheckTime; const delta = now - lastFpsCheckTime;
@ -529,8 +540,52 @@ document.addEventListener('DOMContentLoaded', () => {
frameCount = 0; frameCount = 0;
lastFpsCheckTime = now; lastFpsCheckTime = now;
} }
}; // ========== FPS 계산 로직 끝 ==========
imgEl.src = url;
const blob = new Blob([data], {type: "image/jpeg"});
// createImageBitmap으로 비동기 디코딩 및 렌더링
createImageBitmap(blob)
.then(imageBitmap => {
// 캔버스 크기를 CSS에 정의된 표시 크기로 맞춥니다.
// (object-fit: contain을 시뮬레이션하기 위해 매번 필요)
canvasEl.width = canvasEl.clientWidth;
canvasEl.height = canvasEl.clientHeight;
const canvasWidth = canvasEl.width;
const canvasHeight = canvasEl.height;
const frameWidth = imageBitmap.width; // 실제 이미지 비트맵의 너비
const frameHeight = imageBitmap.height; // 실제 이미지 비트맵의 높이
// 'object-fit: contain' 로직
const widthRatio = canvasWidth / frameWidth;
const heightRatio = canvasHeight / frameHeight;
const ratio = Math.min(widthRatio, heightRatio);
const videoDisplayWidth = frameWidth * ratio;
const videoDisplayHeight = frameHeight * ratio;
const offsetX = (canvasWidth - videoDisplayWidth) / 2;
const offsetY = (canvasHeight - videoDisplayHeight) / 2;
// 캔버스를 지웁니다 (CSS의 background-color가 비친다)
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// 계산된 위치에 이미지를 그립니다.
ctx.drawImage(imageBitmap, offsetX, offsetY, videoDisplayWidth, videoDisplayHeight);
// 비트맵 메모리 해제
imageBitmap.close();
// 프레임이 그려진 *이후*에 바운딩 박스 컨테이너 위치 업데이트
updateBboxContainerPosition();
// [수정됨] FPS 계산 로직이 위로 이동했으므로 여기서는 제거됩니다.
})
.catch(e => {
console.error("createImageBitmap error:", e);
});
} }
}; };
} }
@ -550,5 +605,4 @@ document.addEventListener('DOMContentLoaded', () => {
// ========== 페이지 로드 시 모델 목록 즉시 로드 ========== // ========== 페이지 로드 시 모델 목록 즉시 로드 ==========
loadModelList(); loadModelList();
}); });

@ -34,7 +34,7 @@
<span id="current-model-display" class="video-overlay top-right"></span> <span id="current-model-display" class="video-overlay top-right"></span>
<span id="fps-display" class="video-overlay bottom-right"></span> <span id="fps-display" class="video-overlay bottom-right"></span>
<img id="frame" alt="video frame"> <canvas id="frame"></canvas>
<div id="bbox-container"></div> <div id="bbox-container"></div>
</div> </div>
<div id="det-wrap"> <div id="det-wrap">

@ -276,7 +276,6 @@ main {
min-height: 0; min-height: 0;
max-width: 100%; max-width: 100%;
background: #000; background: #000;
object-fit: contain;
border: 1px solid #333; border: 1px solid #333;
position: relative; position: relative;
z-index: 1; z-index: 1;

Loading…
Cancel
Save