findContours static method
Detects all contours in a binary edge map.
edgeMap — Binary image (0 or 255 per pixel) from Canny or binarization.
width, height — Image dimensions.
minContourLength — Minimum number of points in a valid contour.
Returns a list of contours, each represented as a list of Offset points.
Implementation
static List<List<Offset>> findContours(
Uint8List edgeMap,
int width,
int height, {
int minContourLength = 20,
}) {
if (edgeMap.length < width * height || width < 3 || height < 3) {
return [];
}
final contours = <List<Offset>>[];
final visited = Uint8List(width * height);
// Moore-Neighbor boundary tracing
// 8-connectivity neighbor offsets (clockwise from East)
const dx = [1, 1, 0, -1, -1, -1, 0, 1];
const dy = [0, 1, 1, 1, 0, -1, -1, -1];
for (int y = 1; y < height - 1; y++) {
for (int x = 1; x < width - 1; x++) {
final idx = y * width + x;
// Look for unvisited edge pixel with non-edge pixel to its left
// (contour entry point: transition from background to edge)
if (edgeMap[idx] == 0 || visited[idx] != 0) continue;
if (edgeMap[idx - 1] != 0) continue; // Must be a boundary pixel
final contour = <Offset>[];
int cx = x, cy = y;
int startDir = 0; // Start searching from East
// Trace the contour boundary
int maxSteps = width * height; // Safety limit
bool firstPixel = true;
do {
contour.add(Offset(cx.toDouble(), cy.toDouble()));
visited[cy * width + cx] = 1;
// Search 8-connected neighbors for next boundary pixel
bool found = false;
final searchStart = (startDir + 5) % 8; // Backtrack direction + 1
for (int i = 0; i < 8; i++) {
final dir = (searchStart + i) % 8;
final nx = cx + dx[dir];
final ny = cy + dy[dir];
if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;
if (edgeMap[ny * width + nx] != 0) {
cx = nx;
cy = ny;
startDir = dir;
found = true;
break;
}
}
if (!found) break;
if (firstPixel) firstPixel = false;
maxSteps--;
} while ((cx != x || cy != y) && maxSteps > 0);
if (contour.length >= minContourLength) {
contours.add(contour);
}
}
}
// Sort by contour length (largest first)
contours.sort((a, b) => b.length.compareTo(a.length));
return contours;
}