artifactValleysOffsets function
Returns a list of column indices where the artifact should be split
This method analyzes the horizontal histogram of the artifact to identify valleys (columns with fewer pixels) that are good candidates for splitting.
If all columns have identical values (no valleys or peaks), returns an empty list indicating no splitting is needed.
Returns: A list of column indices where splits should occur.
Implementation
List<int> artifactValleysOffsets(final Artifact artifact) {
final List<int> peaksAndValleys = artifact.getHistogramHorizontal();
// Check if all columns have identical values
final bool allIdentical = peaksAndValleys.every(
(value) => value == peaksAndValleys[0],
);
if (allIdentical) {
// no valleys
return [];
}
final List<int> offsets = [];
// Calculate a more appropriate threshold for large artifacts
final int threshold = calculateThreshold(peaksAndValleys);
if (threshold >= 0) {
// Find columns where the pixel count is below the threshold
final List<List<int>> gaps = [];
List<int> currentGap = [];
// Identify gaps (consecutive columns below threshold)
for (int i = 0; i < peaksAndValleys.length; i++) {
if (peaksAndValleys[i] <= threshold) {
currentGap.add(i);
} else if (currentGap.isNotEmpty) {
gaps.add(List.from(currentGap));
currentGap = [];
}
}
// Add the last gap if it exists
if (currentGap.isNotEmpty) {
gaps.add(currentGap);
}
// Filter out gaps that are at the edges of the artifact
// These are likely serifs or other character features, not actual gaps between characters
gaps.removeWhere((gap) {
// Remove gaps that start at column 0 (left edge)
if (gap.first == 0) {
return true;
}
// Remove gaps that end at the last column (right edge)
if (gap.last == peaksAndValleys.length - 1) {
return true;
}
// Keep all other gaps
return false;
});
// Sort the gaps by position (ascending) to maintain left-to-right order
gaps.sort((a, b) => a[0].compareTo(b[0]));
// For each gap, use the middle of the gap as the split column
for (final List<int> gap in gaps) {
if (gap.isNotEmpty) {
// Calculate the middle point of the gap
final int splitPoint = gap.first + (gap.length ~/ 2);
offsets.add(splitPoint);
}
}
}
return offsets;
}