mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
Added comprehensive logging throughout the panel detection system to aid in debugging and understanding detection flow: - detector.js: Log caching status, detection start, and attempts for each method (OpenCV, ML, Grid) - opencv.js: Log number of potential panels detected - coco-ssd.js: Log number of predictions from ML model - grid.js: Log final merged panel count These logs help track which detection method is being used and how many panels are found at each step, making it easier to diagnose detection issues.
128 lines
3.3 KiB
JavaScript
128 lines
3.3 KiB
JavaScript
// panel-detection/grid.js
|
|
// Grid-based panel detection (lightweight fallback)
|
|
export function detectPanelsGrid(imageData, rows = 3, cols = 3) {
|
|
const panels = [];
|
|
const cellWidth = imageData.width / cols;
|
|
const cellHeight = imageData.height / rows;
|
|
|
|
for (let y = 0; y < rows; y++) {
|
|
for (let x = 0; x < cols; x++) {
|
|
const startX = Math.floor(x * cellWidth);
|
|
const startY = Math.floor(y * cellHeight);
|
|
const cellData = extractCell(
|
|
imageData,
|
|
startX,
|
|
startY,
|
|
cellWidth,
|
|
cellHeight,
|
|
);
|
|
|
|
if (!isEmpty(cellData)) {
|
|
panels.push({
|
|
id: `grid-${panels.length}`,
|
|
x: (x / cols) * 100,
|
|
y: (y / rows) * 100,
|
|
width: (1 / cols) * 100,
|
|
height: (1 / rows) * 100,
|
|
reading_order: panels.length,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return mergeAdjacentPanels(panels);
|
|
}
|
|
function extractCell(imageData, startX, startY, width, height) {
|
|
const w = Math.floor(width);
|
|
const h = Math.floor(height);
|
|
const cellData = new Uint8ClampedArray(w * h * 4);
|
|
|
|
for (let y = 0; y < h; y++) {
|
|
for (let x = 0; x < w; x++) {
|
|
const srcIdx = ((startY + y) * imageData.width + (startX + x)) * 4;
|
|
const destIdx = (y * w + x) * 4;
|
|
cellData[destIdx] = imageData.data[srcIdx];
|
|
cellData[destIdx + 1] = imageData.data[srcIdx + 1];
|
|
cellData[destIdx + 2] = imageData.data[srcIdx + 2];
|
|
cellData[destIdx + 3] = imageData.data[srcIdx + 3];
|
|
}
|
|
}
|
|
|
|
return { data: cellData, width: w, height: h };
|
|
}
|
|
function isEmpty(cellData) {
|
|
let emptyPixels = 0;
|
|
const totalPixels = cellData.width * cellData.height;
|
|
|
|
for (let i = 3; i < cellData.data.length; i += 4) {
|
|
if (cellData.data[i] < 10) emptyPixels++;
|
|
}
|
|
|
|
return emptyPixels / totalPixels > 0.95;
|
|
}
|
|
function mergeAdjacentPanels(panels) {
|
|
const merged = [];
|
|
const used = new Set();
|
|
|
|
for (let i = 0; i < panels.length; i++) {
|
|
if (used.has(i)) continue;
|
|
|
|
let current = { ...panels[i] };
|
|
used.add(i);
|
|
|
|
let changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
for (let j = i + 1; j < panels.length; j++) {
|
|
if (used.has(j)) continue;
|
|
if (isAdjacent(current, panels[j])) {
|
|
current = mergePanels(current, panels[j]);
|
|
used.add(j);
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
console.log("[Grid] Merged to", merged.length, "panels");
|
|
merged.push(current);
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
function isAdjacent(p1, p2) {
|
|
const tolerance = 5;
|
|
if (
|
|
Math.abs(p1.y - p2.y) < tolerance &&
|
|
Math.abs(p1.height - p2.height) < tolerance
|
|
) {
|
|
return (
|
|
Math.abs(p1.x + p1.width - p2.x) < tolerance ||
|
|
Math.abs(p2.x + p2.width - p1.x) < tolerance
|
|
);
|
|
}
|
|
if (
|
|
Math.abs(p1.x - p2.x) < tolerance &&
|
|
Math.abs(p1.width - p2.width) < tolerance
|
|
) {
|
|
return (
|
|
Math.abs(p1.y + p1.height - p2.y) < tolerance ||
|
|
Math.abs(p2.y + p2.height - p1.y) < tolerance
|
|
);
|
|
}
|
|
return false;
|
|
}
|
|
function mergePanels(p1, p2) {
|
|
const minX = Math.min(p1.x, p2.x);
|
|
const minY = Math.min(p1.y, p2.y);
|
|
const maxX = Math.max(p1.x + p1.width, p2.x + p2.width);
|
|
const maxY = Math.max(p1.y + p1.height, p2.y + p2.height);
|
|
|
|
return {
|
|
id: p1.id,
|
|
x: minX,
|
|
y: minY,
|
|
width: maxX - minX,
|
|
height: maxY - minY,
|
|
reading_order: Math.min(p1.reading_order, p2.reading_order),
|
|
};
|
|
}
|