floodFillToRect function

IntRect floodFillToRect(
  1. Artifact binaryPixels,
  2. Artifact visited,
  3. int startX,
  4. int startY,
)

Performs a flood fill algorithm and directly calculates the bounding rectangle without storing all individual points.

Parameters: binaryPixels: A Matrix representing the binary image. visited: A Matrix to keep track of visited pixels. startX: The starting X coordinate for the flood fill. startY: The starting Y coordinate for the flood fill.

Returns: An IntRect representing the bounding rectangle of the connected region.

Implementation

IntRect floodFillToRect(
  final Artifact binaryPixels,
  final Artifact visited,
  final int startX,
  final int startY,
) {
  final int width = binaryPixels.cols;
  final int height = binaryPixels.rows;

  // Initialize bounds to starting point
  int minX = startX;
  int minY = startY;
  int maxX = startX;
  int maxY = startY;

  // Early bounds check
  if (startX >= 0 && startX < width && startY >= 0 && startY < height) {
    // Early check for valid starting pixel
    if (binaryPixels.cellGet(startX, startY)) {
      // Direct access to the underlying arrays
      final Uint8List pixelData = binaryPixels.matrix;
      final Uint8List visitedData = visited.matrix;

      final Queue<int> queue = Queue<int>();

      // Calculate initial index
      final int startIndex = startY * width + startX;

      // Mark start point as visited and add to queue
      visitedData[startIndex] = 1;
      queue.add(startIndex);

      // Direction offsets for adjacent pixels
      const List<int> rowOffsets = [0, 0, -1, 1]; // Row adjustments
      const List<int> colOffsets = [-1, 1, 0, 0]; // Column adjustments

      while (queue.isNotEmpty) {
        final int currentIndex = queue.removeFirst();
        final int x = currentIndex % width;
        final int y = currentIndex ~/ width;

        // Update bounds
        minX = min(minX, x);
        minY = min(minY, y);
        maxX = max(maxX, x);
        maxY = max(maxY, y);

        // Check all four directions
        for (int i = 0; i < 4; i++) {
          final int nx = x + colOffsets[i];
          final int ny = y + rowOffsets[i];

          // Skip out-of-bounds
          if (nx < 0 || nx >= width || ny < 0 || ny >= height) {
            continue;
          }

          final int neighborIndex = ny * width + nx;

          // Check if neighbor is valid and not visited
          if (pixelData[neighborIndex] == 1 &&
              visitedData[neighborIndex] == 0) {
            visitedData[neighborIndex] = 1;
            queue.add(neighborIndex);
          }
        }
      }
    }
  }

  // Calculate width and height
  final int regionWidth = maxX - minX + 1;
  final int regionHeight = maxY - minY + 1;

  return IntRect.fromLTWH(minX, minY, regionWidth, regionHeight);
}