301 lines
11 KiB
HTML
301 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Memory Module Detection</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
line-height: 1.6;
|
|
}
|
|
h1 {
|
|
color: #333;
|
|
text-align: center;
|
|
}
|
|
.section {
|
|
background: #f9f9f9;
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
border-radius: 5px;
|
|
border: 1px solid #ddd;
|
|
}
|
|
.section h2 {
|
|
margin-top: 0;
|
|
color: #444;
|
|
}
|
|
button {
|
|
background: #4CAF50;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 15px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
}
|
|
button:hover {
|
|
background: #45a049;
|
|
}
|
|
input[type="file"] {
|
|
margin: 10px 0;
|
|
}
|
|
.result-container {
|
|
margin-top: 20px;
|
|
}
|
|
.detection-image {
|
|
max-width: 100%;
|
|
border: 1px solid #ddd;
|
|
margin-top: 10px;
|
|
}
|
|
.detection-info {
|
|
background: #fff;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
margin-top: 10px;
|
|
}
|
|
.error {
|
|
color: #d32f2f;
|
|
margin-top: 10px;
|
|
}
|
|
.success {
|
|
color: #388e3c;
|
|
margin-top: 10px;
|
|
}
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 10px;
|
|
}
|
|
table, th, td {
|
|
border: 1px solid #ddd;
|
|
}
|
|
th, td {
|
|
padding: 8px;
|
|
text-align: left;
|
|
}
|
|
th {
|
|
background-color: #f2f2f2;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Memory Module Detection</h1>
|
|
|
|
<div class="section">
|
|
<h2>Health Check</h2>
|
|
<button id="healthCheckBtn">Check API Status</button>
|
|
<div id="healthStatus"></div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Image Detection</h2>
|
|
<input type="file" id="imageUpload" accept=".jpg,.jpeg,.png">
|
|
<button id="uploadBtn">Detect Memory Modules</button>
|
|
<div class="result-container" id="imageResult"></div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Video Detection</h2>
|
|
<input type="file" id="videoUpload" accept=".mp4,.avi,.mov,.mkv">
|
|
<div class="video-params">
|
|
<label for="fpsInput">Frames per second:</label>
|
|
<input type="number" id="fpsInput" min="1" max="30" value="1">
|
|
|
|
<label for="maxFramesInput">Max frames:</label>
|
|
<input type="number" id="maxFramesInput" min="1" max="100" value="50">
|
|
</div>
|
|
<button id="videoBtn">Process Video</button>
|
|
<div class="result-container" id="videoResult"></div>
|
|
</div>
|
|
|
|
<script>
|
|
// Health Check
|
|
document.getElementById('healthCheckBtn').addEventListener('click', async () => {
|
|
const statusDiv = document.getElementById('healthStatus');
|
|
statusDiv.innerHTML = 'Checking...';
|
|
|
|
try {
|
|
const response = await fetch("{{ url_for('health_check') }}");
|
|
const data = await response.json();
|
|
|
|
if (response.ok) {
|
|
statusDiv.innerHTML = `
|
|
<div class="success">
|
|
<p><strong>Status:</strong> ${data.status}</p>
|
|
<p><strong>Service:</strong> ${data.service}</p>
|
|
<p><strong>Model Loaded:</strong> ${data.model_loaded ? 'Yes' : 'No'}</p>
|
|
</div>
|
|
`;
|
|
} else {
|
|
statusDiv.innerHTML = `<div class="error">API Error: ${data.error || 'Unknown error'}</div>`;
|
|
}
|
|
} catch (error) {
|
|
statusDiv.innerHTML = `<div class="error">Failed to connect to API: ${error.message}</div>`;
|
|
}
|
|
});
|
|
|
|
// Image upload detection
|
|
document.getElementById('uploadBtn').addEventListener('click', async () => {
|
|
const fileInput = document.getElementById('imageUpload');
|
|
const resultDiv = document.getElementById('imageResult');
|
|
|
|
if (!fileInput.files || fileInput.files.length === 0) {
|
|
resultDiv.innerHTML = '<div class="error">Please select an image file</div>';
|
|
return;
|
|
}
|
|
|
|
const file = fileInput.files[0];
|
|
resultDiv.innerHTML = 'Processing...';
|
|
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append('image', file);
|
|
|
|
const response = await fetch("{{ url_for('detect_memory') }}", {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok && data.success) {
|
|
displayDetectionResult(resultDiv, data.data);
|
|
} else {
|
|
resultDiv.innerHTML = `<div class="error">${data.error || 'Detection failed'}</div>`;
|
|
}
|
|
} catch (error) {
|
|
resultDiv.innerHTML = `<div class="error">Error: ${error.message}</div>`;
|
|
}
|
|
});
|
|
|
|
// Video processing
|
|
document.getElementById('videoBtn').addEventListener('click', async () => {
|
|
const fileInput = document.getElementById('videoUpload');
|
|
const resultDiv = document.getElementById('videoResult');
|
|
const fps = document.getElementById('fpsInput').value;
|
|
const maxFrames = document.getElementById('maxFramesInput').value;
|
|
|
|
if (!fileInput.files || fileInput.files.length === 0) {
|
|
resultDiv.innerHTML = '<div class="error">Please select a video file</div>';
|
|
return;
|
|
}
|
|
|
|
const file = fileInput.files[0];
|
|
resultDiv.innerHTML = 'Processing... (This may take a while)';
|
|
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append('video', file);
|
|
formData.append('fps', fps);
|
|
formData.append('max_frames', maxFrames);
|
|
|
|
const response = await fetch("{{ url_for('detect_video') }}", {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok && data.success) {
|
|
displayVideoResult(resultDiv, data.data);
|
|
} else {
|
|
resultDiv.innerHTML = `<div class="error">${data.error || 'Video processing failed'}</div>`;
|
|
}
|
|
} catch (error) {
|
|
resultDiv.innerHTML = `<div class="error">Error: ${error.message}</div>`;
|
|
}
|
|
});
|
|
|
|
// Helper function to display detection results
|
|
function displayDetectionResult(container, data) {
|
|
const detections = data.detections || [];
|
|
|
|
let html = `
|
|
<div class="success">
|
|
<p>Detected ${data.detection_count} memory modules</p>
|
|
<img class="detection-image" src="{{ url_for('get_result_image', filename='') }}${data.result_image_url.split('/').pop()}" alt="Detection result">
|
|
</div>
|
|
<div class="detection-info">
|
|
<h4>Detection Details:</h4>
|
|
`;
|
|
|
|
if (detections.length > 0) {
|
|
html += '<table><tr><th>Class</th><th>Confidence</th><th>Position (x1,y1,x2,y2)</th></tr>';
|
|
|
|
detections.forEach(det => {
|
|
const className = 'Memory Module';
|
|
const confidence = (det.confidence * 100).toFixed(2);
|
|
const [x1, y1, x2, y2] = det.box.map(coord => coord.toFixed(1));
|
|
|
|
html += `
|
|
<tr>
|
|
<td>${className}</td>
|
|
<td>${confidence}%</td>
|
|
<td>${x1}, ${y1}, ${x2}, ${y2}</td>
|
|
</tr>
|
|
`;
|
|
});
|
|
|
|
html += '</table>';
|
|
} else {
|
|
html += '<p>No memory modules detected</p>';
|
|
}
|
|
|
|
html += '</div>';
|
|
container.innerHTML = html;
|
|
}
|
|
|
|
// Helper function to display video results
|
|
function displayVideoResult(container, data) {
|
|
const detections = data.detections || [];
|
|
const summary = data.summary || {};
|
|
|
|
let html = `
|
|
<div class="success">
|
|
<h3>Video Processing Results</h3>
|
|
<p><strong>Video:</strong> ${data.video_filename}</p>
|
|
<p><strong>Frames Processed:</strong> ${data.processing_info.frames_processed}</p>
|
|
<p><strong>Processing Time:</strong> ${data.processing_info.processing_time.toFixed(2)} seconds</p>
|
|
<p><strong>Average FPS:</strong> ${data.processing_info.average_fps.toFixed(2)}</p>
|
|
|
|
<h4>Summary:</h4>
|
|
<p>Total Detections: ${summary.total_detections || 0}</p>
|
|
<p>Average Confidence: ${summary.average_confidence ? (summary.average_confidence * 100).toFixed(2) + '%' : 'N/A'}</p>
|
|
</div>
|
|
|
|
<div class="detection-info">
|
|
<h4>Frame-by-Frame Detections:</h4>
|
|
`;
|
|
|
|
if (detections.length > 0) {
|
|
html += '<table><tr><th>Frame</th><th>Time (s)</th><th>Detections</th><th>Details</th></tr>';
|
|
|
|
detections.forEach(frame => {
|
|
html += `
|
|
<tr>
|
|
<td>${frame.frame_number}</td>
|
|
<td>${frame.timestamp.toFixed(2)}</td>
|
|
<td>${frame.detection_count}</td>
|
|
<td>
|
|
${frame.detections.map(d => `
|
|
Memory (${(d.confidence * 100).toFixed(2)}%) at ${d.box.map(coord => coord.toFixed(1)).join(',')}
|
|
`).join('; ')}
|
|
</td>
|
|
</tr>
|
|
`;
|
|
});
|
|
|
|
html += '</table>';
|
|
} else {
|
|
html += '<p>No memory modules detected in any frames</p>';
|
|
}
|
|
|
|
html += '</div>';
|
|
container.innerHTML = html;
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |