export function connectedComponentLabeling(binaryImage: number[], width: number, height: number) { const labels = Array(binaryImage.length).fill(0); const linked: number[][] = []; let nextLabel = 1; function getNeighbors(row: number, col: number) { const neighbors = []; if (row > 0 && labels[(row - 1) * width + col] > 0) { neighbors.push(labels[(row - 1) * width + col]); } if (col > 0 && labels[row * width + col - 1] > 0) { neighbors.push(labels[row * width + col - 1]); } return neighbors; } // First pass for (let row = 0; row < height; row++) { for (let col = 0; col < width; col++) { const idx = row * width + col; if (binaryImage[idx] !== 0) { const neighbors = getNeighbors(row, col); if (neighbors.length === 0) { linked[nextLabel] = [nextLabel]; labels[idx] = nextLabel; nextLabel++; } else { neighbors.sort(); const smallestLabel = neighbors[0]; labels[idx] = smallestLabel; for (let i = 1; i < neighbors.length; i++) { linked[neighbors[i]] = linked[neighbors[i]].concat(linked[smallestLabel]); linked[smallestLabel] = linked[smallestLabel].concat(linked[neighbors[i]]); linked[neighbors[i]] = Array.from(new Set(linked[neighbors[i]])); linked[smallestLabel] = Array.from(new Set(linked[smallestLabel])); } } } } } // Second pass for (let idx = 0; idx < binaryImage.length; idx++) { if (binaryImage[idx] !== 0) { labels[idx] = Math.min(...linked[labels[idx]]); } } return labels; } export function computeBounds(labels: number[], width: number, height: number) { const bounds: Record = {}; for (let row = 0; row < height; row++) { for (let col = 0; col < width; col++) { const idx = row * width + col; const label = labels[idx]; if (label > 0) { if (!bounds[label]) { bounds[label] = { minRow: row, minCol: col, maxRow: row, maxCol: col, area: 1 }; } else { if (row < bounds[label].minRow) bounds[label].minRow = row; if (col < bounds[label].minCol) bounds[label].minCol = col; if (row > bounds[label].maxRow) bounds[label].maxRow = row; if (col > bounds[label].maxCol) bounds[label].maxCol = col; ++bounds[label].area; } } } } return bounds; }