Я хочу автоматически разделить изображение древнего рукописного текста по строкам (и словами в будущем).
Первой очевидной частью является предварительная обработка изображения...
Я просто использую простое оцифрование (основанное на яркости пикселя). После этого я храню данные в двумерном массиве.
Следующая очевидная часть - это анализ двоичного массива.
-
Мой первый алгоритм был довольно простым - если в строке массива больше черных пикселей, чем среднеквадратичное значение максимального и минимального значения, то эта строка является частью строки.
После формирования списка строк я обрезаю строки с высотой, которая меньше средней. Наконец, он оказался в виде линейной регрессии, пытаясь свести к минимуму разницу между пустыми строками и строками текста. (Я принял этот факт)
-
Моя вторая попытка - я попытался использовать GA с несколькими функциями фитнеса. Хромосома содержала 3 значения - xo, x1, x2. xo [-1; 0] x1 [0; 0,5] x2 [0; 0,5]
Функция, определяющая идентичность, строка с строкой (xo + α1 x1 + α2 x2) > 0, где α1 - масштабная сумма черных пикселей в строке, α2 - среднее значение диапазонов между крайние черные пиксели в ряду. (a1, a2 [0,1]) Другие функции, которые я пробовал, это (x1 < α1 OR x2 > α2) и (1/xo + [a1 x1]/[a2 x2]) > 0 Последняя функция является наиболее эффективной. Функция пригодности (1/(HeigthRange + SpacesRange)
Где диапазон - это разница между максимумом и минимумом. Он представляет собой однородность текста. Глобальный оптимум этой функции - самый гладкий способ разделить изображение на линии.
Я использую С# с моей самокодируемой GA (классический, с 2-точечным кроссовером, серо-кодовыми хромосомами, максимальная нагрузка равна 40, скорость мутации равна 0,05)
Теперь у меня кончились идеи о том, как разделить это изображение на строки с точностью до 100%.
Каков эффективный алгоритм для этого?
UPDATE: Исходное изображение Оригинальный BMP (1.3 MB)
UPDATE2: Улучшенные результаты по этому тексту до 100%
Как я это сделал:
- исправлена незначительная ошибка в диапазоне значений
- изменена функция работоспособности до 1/(расстоянияРасстояние + 1) * (высота 1))
- минимизированная классификация функции до (1/xo + x2/range) > 0 (точки в строке теперь не влияют на классификацию) (т.е. оптимизированные входные данные и более оптимизированные функции оптимизации функций).
Проблема:
GA на удивление не удалось распознать эту строку. Я просмотрел данные отладки функции "найти ярости" и обнаружил, что в "непризнанном" месте слишком много шума. Код функции ниже:
public double[] Ranges()
{
var ranges = new double[_original.Height];
for (int y = 0; y < _original.Height; y++ )
{
ranges[y] = 0;
var dx = new List<int>();
int last = 0;
int x = 0;
while (last == 0 && x<_original.Width)
{
if (_bit[x, y])
last = x;
x++;
}
if (last == 0)
{
ranges[y] = 0;
continue;
}
for (x = last; x<_original.Width; x++)
{
if (!_bit[x, y]) continue;
if (last != x - 1)
{
dx.Add((x-last)+1);
}
last = x;
}
if (dx.Count > 2)
{
dx.Sort();
ranges[y] = dx[dx.Count / 2];
//ranges[y] = dx.Average();
}
else
ranges[y] = 0;
}
var maximum = ranges.Max();
for (int i = 0; i < ranges.Length; i++)
{
if (Math.Abs(ranges[i] - 0) < 0.9)
ranges[i] = maximum;
}
return ranges;
}
Я использую некоторые хаки в этом коде. Основная причина - я хочу свести к минимуму диапазон между ближайшими черными пикселями, но если пикселей нет, значение становится "0", и решить эту проблему с поиском оптимальных решений становится невозможным. Вторая причина - этот код меняется слишком часто. Я попытаюсь полностью изменить этот код, но я понятия не имею, как это сделать.
В:
- Если есть более эффективная функция фитнеса?
- Как найти более универсальную функцию определения?