merge static method

Merges multiple OCR pass results into a single best-confidence output.

passes — List of OCR pass results with their preprocessing context.

Returns a MergedOcrResult with the best-confidence text and per-block scores.

Implementation

static MergedOcrResult merge(List<OcrPassResult> passes) {
  if (passes.isEmpty) {
    return const MergedOcrResult(
      text: '',
      confidence: 0.0,
      blockConfidences: [],
      passesUsed: 0,
      mergeStrategy: 'empty',
    );
  }

  if (passes.length == 1) {
    return MergedOcrResult(
      text: passes[0].text,
      confidence: passes[0].confidence,
      blockConfidences: [passes[0].confidence],
      passesUsed: 1,
      mergeStrategy: 'single_pass',
    );
  }

  // Strategy 1: If passes agree closely, use highest-confidence pass
  final bestPass = passes.reduce((a, b) => a.confidence > b.confidence ? a : b);
  final agreement = _computeAgreement(passes);

  if (agreement > 0.95) {
    return MergedOcrResult(
      text: bestPass.text,
      confidence: math.min(1.0, bestPass.confidence * 1.05), // Boost for agreement
      blockConfidences: [bestPass.confidence],
      passesUsed: passes.length,
      mergeStrategy: 'consensus_highest',
    );
  }

  // Strategy 2: Line-level voting and merging
  final mergedLines = _mergeByLines(passes);

  return MergedOcrResult(
    text: mergedLines.text,
    confidence: mergedLines.confidence,
    blockConfidences: mergedLines.lineConfidences,
    passesUsed: passes.length,
    mergeStrategy: 'line_level_voting',
  );
}