You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
10 KiB
245 lines
10 KiB
|
7 months ago
|
// app.js
|
||
|
|
|
||
|
|
// DOM(HTML)이 모두 로드되었을 때 실행
|
||
|
|
document.addEventListener('DOMContentLoaded', () => {
|
||
|
|
|
||
|
|
// 탭 버튼과 콘텐츠 요소를 가져옵니다.
|
||
|
|
const tabVideo = document.getElementById('tab-video');
|
||
|
|
const tabModels = document.getElementById('tab-models');
|
||
|
|
|
||
|
|
const contentVideo = document.getElementById('content-video');
|
||
|
|
const contentModels = document.getElementById('content-models');
|
||
|
|
|
||
|
|
// 비디오 탭 클릭 시
|
||
|
|
if (tabVideo && tabModels) { // 탭 요소가 있는지 확인
|
||
|
|
tabVideo.addEventListener('click', () => {
|
||
|
|
// 버튼 활성화
|
||
|
|
tabVideo.classList.add('active');
|
||
|
|
tabModels.classList.remove('active');
|
||
|
|
|
||
|
|
// 콘텐츠 표시
|
||
|
|
contentVideo.classList.add('active');
|
||
|
|
contentModels.classList.remove('active');
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// AI 모델 탭 클릭 시
|
||
|
|
if (tabVideo && tabModels) { // 탭 요소가 있는지 확인
|
||
|
|
tabModels.addEventListener('click', () => {
|
||
|
|
// 버튼 활성화
|
||
|
|
tabModels.classList.add('active');
|
||
|
|
tabVideo.classList.remove('active');
|
||
|
|
|
||
|
|
// 콘텐츠 표시
|
||
|
|
contentModels.classList.add('active');
|
||
|
|
contentVideo.classList.remove('active');
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== 추가된 부분 시작 ==========
|
||
|
|
// 로그아웃 버튼 처리
|
||
|
|
const logoutButton = document.getElementById('logout-button');
|
||
|
|
|
||
|
|
if (logoutButton) { // 로그아웃 버튼이 있는지 확인
|
||
|
|
logoutButton.addEventListener('click', () => {
|
||
|
|
console.log('Logout clicked');
|
||
|
|
// 로그인 페이지(루트 '/')로 이동
|
||
|
|
window.location.href = '/';
|
||
|
|
});
|
||
|
|
}
|
||
|
|
// ========== 추가된 부분 끝 ==========
|
||
|
|
|
||
|
|
|
||
|
|
// ========== video-test.html 스크립트 추가 시작 ==========
|
||
|
|
const uri = "ws://10.10.11.246:8765"; // 필요하면 여기만 수정
|
||
|
|
const imgEl = document.getElementById("frame");
|
||
|
|
const statusEl = document.getElementById("status");
|
||
|
|
const frameInfoEl = document.getElementById("frame-info");
|
||
|
|
const detListEl = document.getElementById("det-list");
|
||
|
|
const bboxContainerEl = document.getElementById("bbox-container");
|
||
|
|
|
||
|
|
// [수정] 1. 'current-model' select 대신 'current-model-container' div 요소를 가져옵니다.
|
||
|
|
const modelContainerEl = document.getElementById("current-model-container");
|
||
|
|
|
||
|
|
let lastFrameMeta = null;
|
||
|
|
|
||
|
|
// [수정] 2. 비디오 관련 요소 확인 if문에 modelContainerEl을 추가합니다.
|
||
|
|
if (imgEl && statusEl && frameInfoEl && detListEl && bboxContainerEl && modelContainerEl) {
|
||
|
|
|
||
|
|
// [수정] 3. 모델 변경 이벤트 리스너 추가 (이벤트 위임 사용)
|
||
|
|
modelContainerEl.addEventListener('change', (event) => {
|
||
|
|
// 이벤트가 'name'이 'current-model'인 라디오 버튼에서 발생했는지 확인
|
||
|
|
if (event.target && event.target.name === 'current-model') {
|
||
|
|
const selectedModel = event.target.value; // 선택된 라디오 버튼의 값
|
||
|
|
console.log(`Model changed to: ${selectedModel}`);
|
||
|
|
|
||
|
|
// 서버에 /set-model 엔드포인트로 POST 요청 전송
|
||
|
|
fetch('/set-model', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
},
|
||
|
|
body: JSON.stringify({ model: selectedModel }), // { "model": "OBJDET" }
|
||
|
|
})
|
||
|
|
.then(response => response.json())
|
||
|
|
.then(data => {
|
||
|
|
console.log('Server response:', data);
|
||
|
|
// 서버 응답에 따라 상태 메시지 업데이트
|
||
|
|
if (data.status === 'success') {
|
||
|
|
// logStatus 함수가 아래에 정의되어 있으므로 사용 가능
|
||
|
|
logStatus(`모델 변경 완료: ${selectedModel}`);
|
||
|
|
} else {
|
||
|
|
logStatus(`모델 변경 실패: ${data.message}`, true);
|
||
|
|
}
|
||
|
|
})
|
||
|
|
.catch(error => {
|
||
|
|
console.error('Error setting model:', error);
|
||
|
|
logStatus('모델 변경 중 오류 발생', true);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
// [수정] 모델 변경 리스너 끝
|
||
|
|
|
||
|
|
// [기존] 박스 컨테이너 위치/크기 조절 함수
|
||
|
|
function updateBboxContainerPosition() {
|
||
|
|
if (!imgEl || !bboxContainerEl) return;
|
||
|
|
// ... (기존 코드와 동일)
|
||
|
|
const top = imgEl.offsetTop;
|
||
|
|
const left = imgEl.offsetLeft;
|
||
|
|
const width = imgEl.offsetWidth;
|
||
|
|
const height = imgEl.offsetHeight;
|
||
|
|
bboxContainerEl.style.top = `${top}px`;
|
||
|
|
bboxContainerEl.style.left = `${left}px`;
|
||
|
|
bboxContainerEl.style.width = `${width}px`;
|
||
|
|
bboxContainerEl.style.height = `${height}px`;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
function logStatus(msg, isError = false) {
|
||
|
|
statusEl.textContent = msg;
|
||
|
|
statusEl.className = "status" + (isError ? " err" : "");
|
||
|
|
}
|
||
|
|
|
||
|
|
function showFrameMeta(meta) {
|
||
|
|
frameInfoEl.textContent =
|
||
|
|
` | FRAME ch=${meta.ch} ts=${meta.ts_us} w=${meta.w} h=${meta.h}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
// [기존] showDetections 함수
|
||
|
|
function showDetections(meta) {
|
||
|
|
// ... (기존 코드와 동일) ...
|
||
|
|
const items = meta.items || [];
|
||
|
|
let lines = [];
|
||
|
|
lines.push(`DET ch=${meta.ch} seq=${meta.seq} ts=${meta.ts_us} cnt=${items.length}`);
|
||
|
|
bboxContainerEl.innerHTML = "";
|
||
|
|
if (!imgEl || !lastFrameMeta) {
|
||
|
|
items.forEach((it, i) => {
|
||
|
|
lines.push(
|
||
|
|
`#${i} cls=${it.cls} prob=${it.prob.toFixed(3)}`
|
||
|
|
+ ` x=${it.x.toFixed(3)} y=${it.y.toFixed(3)}`
|
||
|
|
+ ` w=${it.w.toFixed(3)} h=${it.h.toFixed(3)}`
|
||
|
|
+ ` resv=${it.resv}`
|
||
|
|
);
|
||
|
|
});
|
||
|
|
detListEl.textContent = lines.join("\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
updateBboxContainerPosition();
|
||
|
|
const imgWidth = imgEl.clientWidth;
|
||
|
|
const imgHeight = imgEl.clientHeight;
|
||
|
|
const frameWidth = lastFrameMeta.w;
|
||
|
|
const frameHeight = lastFrameMeta.h;
|
||
|
|
if (frameWidth === 0 || frameHeight === 0 || imgWidth === 0 || imgHeight === 0) {
|
||
|
|
items.forEach((it, i) => {
|
||
|
|
lines.push(
|
||
|
|
`#${i} cls=${it.cls} prob=${it.prob.toFixed(3)}`
|
||
|
|
+ ` x=${it.x.toFixed(3)} y=${it.y.toFixed(3)}`
|
||
|
|
+ ` w=${it.w.toFixed(3)} h=${it.h.toFixed(3)}`
|
||
|
|
+ ` resv=${it.resv}`
|
||
|
|
);
|
||
|
|
});
|
||
|
|
detListEl.textContent = lines.join("\n");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const widthRatio = imgWidth / frameWidth;
|
||
|
|
const heightRatio = imgHeight / frameHeight;
|
||
|
|
const ratio = Math.min(widthRatio, heightRatio);
|
||
|
|
const videoDisplayWidth = frameWidth * ratio;
|
||
|
|
const videoDisplayHeight = frameHeight * ratio;
|
||
|
|
const offsetX = (imgWidth - videoDisplayWidth) / 2;
|
||
|
|
const offsetY = (imgHeight - videoDisplayHeight) / 2;
|
||
|
|
items.forEach((it, i) => {
|
||
|
|
lines.push(
|
||
|
|
`#${i} cls=${it.cls} prob=${it.prob.toFixed(3)}`
|
||
|
|
+ ` x=${it.x.toFixed(3)} y=${it.y.toFixed(3)}`
|
||
|
|
+ ` w=${it.w.toFixed(3)} h=${it.h.toFixed(3)}`
|
||
|
|
+ ` resv=${it.resv}`
|
||
|
|
);
|
||
|
|
const boxLeft = (it.x * ratio) + offsetX;
|
||
|
|
const boxTop = (it.y * ratio) + offsetY;
|
||
|
|
const boxWidth = it.w * ratio;
|
||
|
|
const boxHeight = it.h * ratio;
|
||
|
|
const bbox = document.createElement('div');
|
||
|
|
bbox.className = 'bbox';
|
||
|
|
bbox.style.left = `${boxLeft}px`;
|
||
|
|
bbox.style.top = `${boxTop}px`;
|
||
|
|
bbox.style.width = `${boxWidth}px`;
|
||
|
|
bbox.style.height = `${boxHeight}px`;
|
||
|
|
bboxContainerEl.appendChild(bbox);
|
||
|
|
});
|
||
|
|
detListEl.textContent = lines.join("\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
// [기존] connect 함수
|
||
|
|
function connect() {
|
||
|
|
// ... (기존 코드와 동일) ...
|
||
|
|
const ws = new WebSocket(uri);
|
||
|
|
ws.binaryType = "arraybuffer";
|
||
|
|
ws.onopen = () => { logStatus(`연결됨: ${uri}`); };
|
||
|
|
ws.onclose = (ev) => {
|
||
|
|
logStatus(`연결 종료 (code=${ev.code}) 재접속 대기중...`, true);
|
||
|
|
setTimeout(connect, 2000);
|
||
|
|
};
|
||
|
|
ws.onerror = (err) => {
|
||
|
|
logStatus("WebSocket 오류 발생", true);
|
||
|
|
console.error(err);
|
||
|
|
};
|
||
|
|
ws.onmessage = (event) => {
|
||
|
|
const data = event.data;
|
||
|
|
if (typeof data === "string") {
|
||
|
|
try {
|
||
|
|
const meta = JSON.parse(data);
|
||
|
|
const t = meta.type;
|
||
|
|
if (t === "frame") {
|
||
|
|
lastFrameMeta = meta;
|
||
|
|
showFrameMeta(meta);
|
||
|
|
} else if (t === "det") {
|
||
|
|
showDetections(meta);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
console.error("JSON parse error:", e, data);
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (data instanceof ArrayBuffer && lastFrameMeta) {
|
||
|
|
const blob = new Blob([data], { type: "image/jpeg" });
|
||
|
|
const url = URL.createObjectURL(blob);
|
||
|
|
imgEl.onload = () => {
|
||
|
|
URL.revokeObjectURL(url);
|
||
|
|
updateBboxContainerPosition();
|
||
|
|
};
|
||
|
|
imgEl.src = url;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// WebSocket 연결 시작
|
||
|
|
connect();
|
||
|
|
|
||
|
|
// [기존] 창 크기 변경 시 이벤트
|
||
|
|
window.addEventListener('resize', updateBboxContainerPosition);
|
||
|
|
|
||
|
|
} // if (요소 확인) 끝
|
||
|
|
// ========== video-test.html 스크립트 추가 끝 ==========
|
||
|
|
|
||
|
|
});
|