analyzeSkew static method

SkewAnalysis analyzeSkew(
  1. Uint8List imageBytes, {
  2. required int width,
  3. required int height,
})

Analyzes document skew/tilt angle from edge pixel patterns.

Implementation

static SkewAnalysis analyzeSkew(
  Uint8List imageBytes, {
  required int width,
  required int height,
}) {
  if (imageBytes.isEmpty || width <= 2 || height <= 2) {
    return const SkewAnalysis(
      angleDegrees: 0.0,
      isAligned: true,
      correctionAngle: 0.0,
    );
  }

  // Detect dominant edge direction using Sobel-like horizontal gradient
  double sumAngle = 0;
  int edgeCount = 0;

  for (int y = 1; y < height - 1 && y * width < imageBytes.length; y++) {
    for (int x = 1; x < width - 1; x++) {
      final idx = y * width + x;
      if (idx + width < imageBytes.length && idx - width >= 0) {
        // Horizontal Sobel: [-1, 0, 1]
        final gx = imageBytes[idx + 1] - imageBytes[idx - 1];
        // Vertical Sobel: [-1, 0, 1]
        final gy = imageBytes[idx + width] - imageBytes[idx - width];

        final magnitude = math.sqrt(gx * gx + gy * gy);
        if (magnitude > 30) {
          // Strong edge detected
          final angle = math.atan2(gy.toDouble(), gx.toDouble()) *
              (180.0 / math.pi);
          sumAngle += angle;
          edgeCount++;
        }
      }
    }
  }

  if (edgeCount == 0) {
    return const SkewAnalysis(
      angleDegrees: 0.0,
      isAligned: true,
      correctionAngle: 0.0,
    );
  }

  final avgAngle = sumAngle / edgeCount;
  // Normalize to deviation from horizontal/vertical
  final skewAngle = (avgAngle % 90.0).abs();
  final normalizedSkew =
      skewAngle > 45.0 ? 90.0 - skewAngle : skewAngle;

  return SkewAnalysis(
    angleDegrees: normalizedSkew,
    isAligned: normalizedSkew < 5.0,
    correctionAngle: -normalizedSkew,
  );
}