|
|
|
@ -81,6 +81,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
alert('모델 목록을 불러오는 데 실패했습니다.');
|
|
|
|
alert('모델 목록을 불러오는 데 실패했습니다.');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========== AI 모델 목록 로드 함수 끝 ==========
|
|
|
|
// ========== AI 모델 목록 로드 함수 끝 ==========
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -93,22 +94,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
headers: {
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ filename: filename }) // { "filename": "CUUVA_..." }
|
|
|
|
body: JSON.stringify({filename: filename}) // { "filename": "CUUVA_..." }
|
|
|
|
})
|
|
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
|
|
if (data.status === 'success') {
|
|
|
|
|
|
|
|
alert(`파일이 성공적으로 삭제되었습니다: ${filename}`);
|
|
|
|
|
|
|
|
loadModelList(); // 삭제 성공 시 목록 새로고침
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
alert(`삭제 실패: ${data.message}`);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.catch(error => {
|
|
|
|
.then(response => response.json())
|
|
|
|
console.error('Delete error:', error);
|
|
|
|
.then(data => {
|
|
|
|
alert('삭제 중 오류가 발생했습니다.');
|
|
|
|
if (data.status === 'success') {
|
|
|
|
});
|
|
|
|
alert(`파일이 성공적으로 삭제되었습니다: ${filename}`);
|
|
|
|
|
|
|
|
loadModelList(); // 삭제 성공 시 목록 새로고침
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
alert(`삭제 실패: ${data.message}`);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
|
|
console.error('Delete error:', error);
|
|
|
|
|
|
|
|
alert('삭제 중 오류가 발생했습니다.');
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 모델 삭제 요청 함수 끝 ==========
|
|
|
|
// ========== 모델 삭제 요청 함수 끝 ==========
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -178,29 +180,29 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
method: 'POST',
|
|
|
|
method: 'POST',
|
|
|
|
body: formData
|
|
|
|
body: formData
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.then(response => response.json())
|
|
|
|
.then(response => response.json())
|
|
|
|
.then(data => {
|
|
|
|
.then(data => {
|
|
|
|
if (data.status === 'success') {
|
|
|
|
if (data.status === 'success') {
|
|
|
|
alert(`업로드 성공!\n파일: ${file.name}`);
|
|
|
|
alert(`업로드 성공!\n파일: ${file.name}`);
|
|
|
|
globalFileInput.value = ''; // 파일 선택 초기화
|
|
|
|
globalFileInput.value = ''; // 파일 선택 초기화
|
|
|
|
fileNameDisplay.textContent = '선택된 파일 없음';
|
|
|
|
fileNameDisplay.textContent = '선택된 파일 없음';
|
|
|
|
|
|
|
|
|
|
|
|
// 업로드 성공 시 모델 목록 새로고침
|
|
|
|
// 업로드 성공 시 모델 목록 새로고침
|
|
|
|
loadModelList();
|
|
|
|
loadModelList();
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
alert(`업로드 실패: ${data.message}`);
|
|
|
|
alert(`업로드 실패: ${data.message}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.catch(error => {
|
|
|
|
.catch(error => {
|
|
|
|
console.error('Upload error:', error);
|
|
|
|
console.error('Upload error:', error);
|
|
|
|
alert('업로드 중 오류가 발생했습니다.');
|
|
|
|
alert('업로드 중 오류가 발생했습니다.');
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
.finally(() => {
|
|
|
|
// 버튼 다시 활성화
|
|
|
|
// 버튼 다시 활성화
|
|
|
|
globalUploadButton.disabled = false;
|
|
|
|
globalUploadButton.disabled = false;
|
|
|
|
globalUploadButton.textContent = '업로드';
|
|
|
|
globalUploadButton.textContent = '업로드';
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -254,14 +256,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
if (logoutButton) { // 로그아웃 버튼이 있는지 확인
|
|
|
|
if (logoutButton) { // 로그아웃 버튼이 있는지 확인
|
|
|
|
logoutButton.addEventListener('click', () => {
|
|
|
|
logoutButton.addEventListener('click', () => {
|
|
|
|
console.log('Logout clicked');
|
|
|
|
console.log('Logout clicked');
|
|
|
|
// 로그인 페이지(루트 '/')로 이동
|
|
|
|
|
|
|
|
window.location.href = '/';
|
|
|
|
// [수정됨] 사용자에게 확인을 받습니다.
|
|
|
|
|
|
|
|
if (confirm('정말로 로그아웃하시겠습니까?')) {
|
|
|
|
|
|
|
|
// 확인을 누르면 로그인 페이지(루트 '/')로 이동
|
|
|
|
|
|
|
|
window.location.href = '/';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 취소를 누르면 아무 일도 일어나지 않습니다.
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ========== 로그아웃 버튼 처리 끝 ==========
|
|
|
|
// ========== 로그아웃 버튼 처리 끝 ==========
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ========== video-test.html 스크립트 추가 시작 ==========
|
|
|
|
// ========== dashboard.html 스크립트 추가 시작 ==========
|
|
|
|
const uri = "ws://10.10.11.246:8765"; // 필요하면 여기만 수정
|
|
|
|
const uri = "ws://10.10.11.246:8765"; // 필요하면 여기만 수정
|
|
|
|
const imgEl = document.getElementById("frame");
|
|
|
|
const imgEl = document.getElementById("frame");
|
|
|
|
const statusEl = document.getElementById("status");
|
|
|
|
const statusEl = document.getElementById("status");
|
|
|
|
@ -270,6 +277,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
const bboxContainerEl = document.getElementById("bbox-container");
|
|
|
|
const bboxContainerEl = document.getElementById("bbox-container");
|
|
|
|
const modelContainerEl = document.getElementById("current-model-container");
|
|
|
|
const modelContainerEl = document.getElementById("current-model-container");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// [추가] 클래스별 색상 팔레트 (원하는 색상으로 수정 가능)
|
|
|
|
|
|
|
|
const CLASS_COLORS = [
|
|
|
|
|
|
|
|
'#FF3838', // 0: Red
|
|
|
|
|
|
|
|
'#38BFFF', // 1: Blue
|
|
|
|
|
|
|
|
'#38FF4E', // 2: Green
|
|
|
|
|
|
|
|
'#FFF238', // 3: Yellow
|
|
|
|
|
|
|
|
'#FF9D38', // 4: Orange
|
|
|
|
|
|
|
|
'#C538FF', // 5: Purple
|
|
|
|
|
|
|
|
'#FF38C5', // 6: Pink
|
|
|
|
|
|
|
|
'#FFFFFF' // 7: White
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
let lastFrameMeta = null;
|
|
|
|
let lastFrameMeta = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (imgEl && statusEl && frameInfoEl && detListEl && bboxContainerEl && modelContainerEl) {
|
|
|
|
if (imgEl && statusEl && frameInfoEl && detListEl && bboxContainerEl && modelContainerEl) {
|
|
|
|
@ -285,21 +304,21 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
headers: {
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ model: selectedModel }),
|
|
|
|
body: JSON.stringify({model: selectedModel}),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.then(response => response.json())
|
|
|
|
.then(response => response.json())
|
|
|
|
.then(data => {
|
|
|
|
.then(data => {
|
|
|
|
console.log('Server response:', data);
|
|
|
|
console.log('Server response:', data);
|
|
|
|
if (data.status === 'success') {
|
|
|
|
if (data.status === 'success') {
|
|
|
|
logStatus(`모델 변경 완료: ${selectedModel}`);
|
|
|
|
logStatus(`모델 변경 완료: ${selectedModel}`);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
logStatus(`모델 변경 실패: ${data.message}`, true);
|
|
|
|
logStatus(`모델 변경 실패: ${data.message}`, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.catch(error => {
|
|
|
|
.catch(error => {
|
|
|
|
console.error('Error setting model:', error);
|
|
|
|
console.error('Error setting model:', error);
|
|
|
|
logStatus('모델 변경 중 오류 발생', true);
|
|
|
|
logStatus('모델 변경 중 오류 발생', true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
@ -326,7 +345,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
` | FRAME ch=${meta.ch} ts=${meta.ts_us} w=${meta.w} h=${meta.h}`;
|
|
|
|
` | FRAME ch=${meta.ch} ts=${meta.ts_us} w=${meta.w} h=${meta.h}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Detections 표시 함수
|
|
|
|
|
|
|
|
// Detections 표시 함수 (수정됨)
|
|
|
|
// Detections 표시 함수 (수정됨)
|
|
|
|
function showDetections(meta) {
|
|
|
|
function showDetections(meta) {
|
|
|
|
const items = meta.items || [];
|
|
|
|
const items = meta.items || [];
|
|
|
|
@ -337,13 +355,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
if (!imgEl || !lastFrameMeta) {
|
|
|
|
if (!imgEl || !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
|
|
|
|
const x = it.x1;
|
|
|
|
const x = it.x1;
|
|
|
|
const y = it.y1;
|
|
|
|
const y = it.y1;
|
|
|
|
const w = it.x2 - it.x1;
|
|
|
|
const w = it.x2 - it.x1;
|
|
|
|
const h = it.y2 - it.y1;
|
|
|
|
const h = it.y2 - it.y1;
|
|
|
|
|
|
|
|
|
|
|
|
lines.push(
|
|
|
|
lines.push(
|
|
|
|
`#${i} cls=${it.cls} tid=${it.tid} tag=${it.tag}` // prob, resv 대신 tid, tag 사용
|
|
|
|
`#${i} cls=${it.cls} tid=${it.tid} tag=${it.tag}` // prob, resv 대신 tid, tag 사용
|
|
|
|
+ ` x=${x.toFixed(3)} y=${y.toFixed(3)}`
|
|
|
|
+ ` x=${x.toFixed(3)} y=${y.toFixed(3)}`
|
|
|
|
+ ` w=${w.toFixed(3)} h=${h.toFixed(3)}`
|
|
|
|
+ ` w=${w.toFixed(3)} h=${h.toFixed(3)}`
|
|
|
|
@ -362,13 +380,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
if (frameWidth === 0 || frameHeight === 0 || imgWidth === 0 || imgHeight === 0) {
|
|
|
|
if (frameWidth === 0 || frameHeight === 0 || imgWidth === 0 || imgHeight === 0) {
|
|
|
|
// [수정됨] 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
|
|
|
|
const x = it.x1;
|
|
|
|
const x = it.x1;
|
|
|
|
const y = it.y1;
|
|
|
|
const y = it.y1;
|
|
|
|
const w = it.x2 - it.x1;
|
|
|
|
const w = it.x2 - it.x1;
|
|
|
|
const h = it.y2 - it.y1;
|
|
|
|
const h = it.y2 - it.y1;
|
|
|
|
|
|
|
|
|
|
|
|
lines.push(
|
|
|
|
lines.push(
|
|
|
|
`#${i} cls=${it.cls} tid=${it.tid} tag=${it.tag}` // prob, resv 대신 tid, tag 사용
|
|
|
|
`#${i} cls=${it.cls} tid=${it.tid} tag=${it.tag}` // prob, resv 대신 tid, tag 사용
|
|
|
|
+ ` x=${x.toFixed(3)} y=${y.toFixed(3)}`
|
|
|
|
+ ` x=${x.toFixed(3)} y=${y.toFixed(3)}`
|
|
|
|
+ ` w=${w.toFixed(3)} h=${h.toFixed(3)}`
|
|
|
|
+ ` w=${w.toFixed(3)} h=${h.toFixed(3)}`
|
|
|
|
@ -394,8 +412,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
const w = it.x2 - it.x1;
|
|
|
|
const w = it.x2 - it.x1;
|
|
|
|
const h = it.y2 - it.y1;
|
|
|
|
const h = it.y2 - it.y1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// [추가] 현재 항목의 클래스(cls) 가져오기
|
|
|
|
|
|
|
|
const cls = it.cls;
|
|
|
|
|
|
|
|
|
|
|
|
lines.push(
|
|
|
|
lines.push(
|
|
|
|
`#${i} cls=${it.cls} tid=${it.tid} tag=${it.tag}` // prob, resv 대신 tid, tag 사용
|
|
|
|
`#${i} cls=${cls} tid=${it.tid} tag=${it.tag}` // prob, resv 대신 tid, tag 사용
|
|
|
|
+ ` x=${x.toFixed(3)} y=${y.toFixed(3)}`
|
|
|
|
+ ` x=${x.toFixed(3)} y=${y.toFixed(3)}`
|
|
|
|
+ ` w=${w.toFixed(3)} h=${h.toFixed(3)}`
|
|
|
|
+ ` w=${w.toFixed(3)} h=${h.toFixed(3)}`
|
|
|
|
);
|
|
|
|
);
|
|
|
|
@ -406,12 +427,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
const boxWidth = w * ratio;
|
|
|
|
const boxWidth = w * ratio;
|
|
|
|
const boxHeight = h * ratio;
|
|
|
|
const boxHeight = h * ratio;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// [추가] 클래스(cls) 값에 따라 색상 결정
|
|
|
|
|
|
|
|
// cls를 정수로 변환 (혹시 문자열일 경우 대비)
|
|
|
|
|
|
|
|
const classIndex = parseInt(cls, 10) || 0;
|
|
|
|
|
|
|
|
// 모듈러(%) 연산을 사용해 색상 배열을 순환
|
|
|
|
|
|
|
|
const color = CLASS_COLORS[classIndex % CLASS_COLORS.length];
|
|
|
|
|
|
|
|
|
|
|
|
const bbox = document.createElement('div');
|
|
|
|
const bbox = document.createElement('div');
|
|
|
|
bbox.className = 'bbox';
|
|
|
|
bbox.className = 'bbox';
|
|
|
|
bbox.style.left = `${boxLeft}px`;
|
|
|
|
bbox.style.left = `${boxLeft}px`;
|
|
|
|
bbox.style.top = `${boxTop}px`;
|
|
|
|
bbox.style.top = `${boxTop}px`;
|
|
|
|
bbox.style.width = `${boxWidth}px`;
|
|
|
|
bbox.style.width = `${boxWidth}px`;
|
|
|
|
bbox.style.height = `${boxHeight}px`;
|
|
|
|
bbox.style.height = `${boxHeight}px`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// [추가] CSS의 'border' 대신 'borderColor'를 동적으로 설정
|
|
|
|
|
|
|
|
// 이렇게 하면 style.css의 'border-width', 'border-style'은 유지됩니다.
|
|
|
|
|
|
|
|
bbox.style.borderColor = color;
|
|
|
|
|
|
|
|
|
|
|
|
bboxContainerEl.appendChild(bbox);
|
|
|
|
bboxContainerEl.appendChild(bbox);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
detListEl.textContent = lines.join("\n");
|
|
|
|
detListEl.textContent = lines.join("\n");
|
|
|
|
@ -421,7 +453,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
function connect() {
|
|
|
|
function connect() {
|
|
|
|
const ws = new WebSocket(uri);
|
|
|
|
const ws = new WebSocket(uri);
|
|
|
|
ws.binaryType = "arraybuffer";
|
|
|
|
ws.binaryType = "arraybuffer";
|
|
|
|
ws.onopen = () => { logStatus(`연결됨: ${uri}`); };
|
|
|
|
ws.onopen = () => {
|
|
|
|
|
|
|
|
logStatus(`연결됨: ${uri}`);
|
|
|
|
|
|
|
|
};
|
|
|
|
ws.onclose = (ev) => {
|
|
|
|
ws.onclose = (ev) => {
|
|
|
|
logStatus(`연결 종료 (code=${ev.code}) 재접속 대기중...`, true);
|
|
|
|
logStatus(`연결 종료 (code=${ev.code}) 재접속 대기중...`, true);
|
|
|
|
setTimeout(connect, 2000);
|
|
|
|
setTimeout(connect, 2000);
|
|
|
|
@ -448,7 +482,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (data instanceof ArrayBuffer && lastFrameMeta) {
|
|
|
|
if (data instanceof ArrayBuffer && lastFrameMeta) {
|
|
|
|
const blob = new Blob([data], { type: "image/jpeg" });
|
|
|
|
const blob = new Blob([data], {type: "image/jpeg"});
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
imgEl.onload = () => {
|
|
|
|
imgEl.onload = () => {
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
|