Перейти к содержимому
Compvision.ru
CornersKir

Поиск цветного фрагмента на полутоновом изображении

Recommended Posts

Есть отсканированная книга с набором иллюстраций. Стоит задача - отделить иллюстрации от текстовых данных. Иллюстрации - цветные, текст - визуально чёрный, фон - визуально серый. Пробовал рассматривать текст в качестве шума и использовал cvMorphologyEx с CV_MOP_CLOSE для его устранения. В результате изображения извлекаются с большой погрешностью. Какие функции в составе OpenCV могут помочь решить поставленную задачу?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Точно не скажу, какие конкретно функции могут помочь, но по Вашему описанию логика решения достаточно проста.

В ч/б изображении значения RGB компонент равны, в отличие от цветного. Почему бы не использовать этот признак? Например, обходите изображение и помечаете все пиксели с равными (ну или приблизительно равными) RGB компонентами нолями, а прочие единицами. В результате получите маску цветных иллюстраций (вероятно, с некоторым шумом).

P.S. В принципе, можно теперь открыть документацию OpenCV и поискать функцию, которая поможет нам провести подобную обработку, и избавиться при необходимости от возможного шума.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Посмотрите еще этот документ: http://www.compvision.ru/forum/index.php?a...=post&id=95

Не самый простой способ, но его часто используют при OCR.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Посмотрите еще этот документ: http://www.compvision.ru/forum/index.php?a...=post&id=95

Не самый простой способ, но его часто используют при OCR.

ИМХО, для поставленной задачи это слишком громоздкое решение. Я бы попытался сделать проще. По крайней мере, для начала.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Спасибо за советы. Попробую применить их на практике и посмотреть, что получится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Точно не скажу, какие конкретно функции могут помочь, но по Вашему описанию логика решения достаточно проста.

В ч/б изображении значения RGB компонент равны, в отличие от цветного. Почему бы не использовать этот признак? Например, обходите изображение и помечаете все пиксели с равными (ну или приблизительно равными) RGB компонентами нолями, а прочие единицами. В результате получите маску цветных иллюстраций (вероятно, с некоторым шумом).

P.S. В принципе, можно теперь открыть документацию OpenCV и поискать функцию, которая поможет нам провести подобную обработку, и избавиться при необходимости от возможного шума.

Реализовал пробный вариант. Приблизительное равенство определяется некоторым порогом. Для каждой отдельной иллюстрации можно подобрать порог, чтобы она определялась безошибочно. При уменьшении порога нарастает шум и сбивается работа cvFindContours. При увеличении порога возникают погрешности в определении границ. В среднем в первой реализации Ваш метод обеспечивает примерно такую же точность, как и cvMorphologyEx с CV_MOP_CLOSE.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Реализовал пробный вариант. Приблизительное равенство определяется некоторым порогом. Для каждой отдельной иллюстрации можно подобрать порог, чтобы она определялась безошибочно. При уменьшении порога нарастает шум и сбивается работа cvFindContours. При увеличении порога возникают погрешности в определении границ. В среднем в первой реализации Ваш метод обеспечивает примерно такую же точность, как и cvMorphologyEx с CV_MOP_CLOSE.

А можно код увидеть?

Я так понимаю, проблемы должны быть с самой иллюстрацией, ибо все остальное достаточно черно-белое и должно хорошо отсекаться. При увеличении порога на иллюстрации должны все более проявляться белые пятна (пиксели, достаточно близкие к оттенкам серого). Именно с ними возникают проблемы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
А можно код увидеть?

Я так понимаю, проблемы должны быть с самой иллюстрацией, ибо все остальное достаточно черно-белое и должно хорошо отсекаться. При увеличении порога на иллюстрации должны все более проявляться белые пятна (пиксели, достаточно близкие к оттенкам серого). Именно с ними возникают проблемы?

ImageWidth, ImageHeight - размеры изображения.

Data - ImageData pIplImage

WidthStep - widthStep pIplImage

GetMaximum - нахождение максимума в массиве.

  for y := 0 to ImageHeight - 1 do

begin

Row := pRGBArray(Data);

for x := 0 to ImageWidth - 1 do

begin

Maximum := GetMaximum([abs(Row^[x].rgbtRed - Row^[x].rgbtGreen),

abs(Row^[x].rgbtGreen - Row^[x].rgbtBlue),

abs(Row^[x].rgbtRed - Row^[x].rgbtGreen)]);

if (Maximum > Threshold) then

begin

Row^[x].rgbtRed := 0;

Row^[x].rgbtGreen := 0;

Row^[x].rgbtBlue := 0;

end

else

begin

Row^[x].rgbtRed := 255;

Row^[x].rgbtGreen := 255;

Row^[x].rgbtBlue := 255;

end;

end;

Data := pointer(integer(Data) + WidthStep);

end;

Слишком большой порог - области вне иллюстраций идеально белые, но и сами иллюстрации обрезаны. По краям многих иллюстраций идёт что-то вроде фона иллюстрации - он в основном и страдает. В результате, выделяется центральный фрагмент иллюстрации вместо полной иллюстрации.

Слишком малый порог - области вне иллюстраций очищены крайне плохо, cvFindContours считает иллюстрациями области, которые таковыми не являются. Применение дополнительной очистки шума (например, cvDilate) приводит к тем же проблемам, что и при применении большого порога - иллюстрация обрезается.

Проблема в том, что для каждой страницы с иллюстрациями нужен свой порог, при котором изображение выделится идеально. То есть никакой константный порог не подходит для решения задачи. Нужен адаптивный порог, но непонятно, по какому алгоритму его вычислять.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Как минимум, озадачивает уже этот код:

Maximum := GetMaximum([abs(Row^[x].rgbtRed - Row^[x].rgbtGreen),

abs(Row^[x].rgbtGreen - Row^[x].rgbtBlue),

abs(Row^[x].rgbtRed - Row^[x].rgbtGreen)]);

В третьей строчке явно нужно отнимать от синего красный (или наоборот).

Ну и далее.

"Слишком большой порог - области вне иллюстраций идеально белые, но и сами иллюстрации обрезаны".

В смысле обрезаны? По краю идеально обрезаны? Т.е. у них по краям что-то типа заливки, близкой к оттенкам серого? И Вы хотите ее сохранить?

В таком случае можно сделать, например, следующее.

1. Пропускаем изображение через данный алгоритм.

2. Определяем зоны иллюстраций.

3. Увеличиваем их на определенную величину (трудно сказать, какую, нужно оценить, думаю, процентов 30 будет достаточно).

4. Строим горизонтальную и вертикальную проекцию каждого куска на исходном изображении (суммируем интенсивность каждого столбца и строки), белый фон будет давать всплески, иллюстрация - провалы.

На самом деле, можно попробовать обработать сразу п.4 все исходное изображение, я как-то сразу не подумал об этом, но алгоритм существенно усложнится, если на одной странице несколько иллюстраций и они расположены на ней произвольным образом. А так сначала определяем позицию каждой иллюстрации, а потом уточняем ее границы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Как минимум, озадачивает уже этот код:

Maximum := GetMaximum([abs(Row^[x].rgbtRed - Row^[x].rgbtGreen),

abs(Row^[x].rgbtGreen - Row^[x].rgbtBlue),

abs(Row^[x].rgbtRed - Row^[x].rgbtGreen)]);

В третьей строчке явно нужно отнимать от синего красный (или наоборот).

Спасибо, исправил.

В смысле обрезаны? По краю идеально обрезаны? Т.е. у них по краям что-то типа заливки, близкой к оттенкам серого? И Вы хотите ее сохранить?

Да, на многих иллюстрациях есть "что-то типа заливки". Я хочу сохранить эту заливку.

На самом деле, можно попробовать обработать сразу п.4 все исходное изображение, я как-то сразу не подумал об этом, но алгоритм существенно усложнится, если на одной странице несколько иллюстраций и они расположены на ней произвольным образом. А так сначала определяем позицию каждой иллюстрации, а потом уточняем ее границы.

На одной странице может быть и несколько иллюстраций.

В таком случае можно сделать, например, следующее.

1. Пропускаем изображение через данный алгоритм.

2. Определяем зоны иллюстраций.

3. Увеличиваем их на определенную величину (трудно сказать, какую, нужно оценить, думаю, процентов 30 будет достаточно).

4. Строим горизонтальную и вертикальную проекцию каждого куска на исходном изображении (суммируем интенсивность каждого столбца и строки), белый фон будет давать всплески, иллюстрация - провалы.

Попробую реализовать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
На одной странице может быть и несколько иллюстраций.

Тут скорее проблема будет даже не с тем, что их несколько, а с тем, как они расположены на странице (если они пересекаются горизонтально и вертикально, то алгоритм анализа диаграмм существенно усложнится) и какого они размера (достаточно небольшие иллюстрации при достаточно жирном шрифте могут "тонуть" на общей диаграмме, что усложнит их поиск). В общем, трудно сказать, не видя исходных изображений, нужно пробовать, что получится. Благо, все обсуждаемые алгоритмы просты и не требуют даже OpenCV. :D

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4. Строим горизонтальную и вертикальную проекцию каждого куска на исходном изображении (суммируем интенсивность каждого столбца и строки), белый фон будет давать всплески, иллюстрация - провалы.

Реализовал указанный метод. Исходное изображение загружено с опцией CV_LOAD_IMAGE_GRAYSCALE. На нём рассматривается увеличенная на 30% область, найденная по прошлому методу. Суммы интенсивностей каждого столбца и каждой строки поделил на соответственно число элементов в каждом столбце (каждой строке). Получил два массива значений: XArr для столбцов и YArr для строк (все значения от 0 до 255).

Описываю, как находил новые границы изображения. Ввёл два пороговых значения: цветовое и процентное.

Прохожу по XArr, считаю число элементов XArr меньше цветового порога. Если их процент от общего числа меньше процентного порога, то увеличиваю на 1 минимальный X, уменьшаю на 1 максимальный X, осуществляю повторный проход в новых границах. Если их больше процентного порога, то минимальный и максимальный X - новые границы изображения. Аналогичную процедуру выполняю для Y.

Данный метод сильно зависит от выбранных порогов и не позволяет улучшить выделение иллюстраций (по крайней мере в моей реализации).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Реализовал указанный метод. Исходное изображение загружено с опцией CV_LOAD_IMAGE_GRAYSCALE. На нём рассматривается увеличенная на 30% область, найденная по прошлому методу. Суммы интенсивностей каждого столбца и каждой строки поделил на соответственно число элементов в каждом столбце (каждой строке). Получил два массива значений: XArr для столбцов и YArr для строк (все значения от 0 до 255).

Описываю, как находил новые границы изображения. Ввёл два пороговых значения: цветовое и процентное.

Прохожу по XArr, считаю число элементов XArr меньше цветового порога. Если их процент от общего числа меньше процентного порога, то увеличиваю на 1 минимальный X, уменьшаю на 1 максимальный X, осуществляю повторный проход в новых границах. Если их больше процентного порога, то минимальный и максимальный X - новые границы изображения. Аналогичную процедуру выполняю для Y.

Данный метод сильно зависит от выбранных порогов и не позволяет улучшить выделение иллюстраций (по крайней мере в моей реализации).

Есть одна авантюрная мысль, нормировать все компоненты точек (привести максимальные элементы к 255. Работать нужно с тройками - берем максимальный компонент из R,G и B и умножаем его на коэффициент такой чтобы он стал равным 255 и остальные оставшиеся два компонента умножаем на тот-же коэффициент), тогда все серое станет белым :D Потом через бинаризатор и очиститель мелкого шума.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Описываю, как находил новые границы изображения. Ввёл два пороговых значения: цветовое и процентное.

Прохожу по XArr, считаю число элементов XArr меньше цветового порога. Если их процент от общего числа меньше процентного порога, то увеличиваю на 1 минимальный X, уменьшаю на 1 максимальный X, осуществляю повторный проход в новых границах. Если их больше процентного порога, то минимальный и максимальный X - новые границы изображения. Аналогичную процедуру выполняю для Y.

Данный метод сильно зависит от выбранных порогов и не позволяет улучшить выделение иллюстраций (по крайней мере в моей реализации).

Не очень понял логику алгоритма. Может быть, поэтому он мне не нравится? :D

Куски мы определили.

Далее вычисляем проекции.

Сглаживаем обязательно!

После этого ищем "пики наоборот". Пример определения можно подсмотреть в одном из известных проектов (прикрепляю два файла на джаве, логику работы там можно посмотреть, правда, джавовское расширение не хотело загружаться, пришлось файлы переименовать). Смотреть функцию BandGraph::findPeaks();

Graph.txt

BandGraph.txt

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Есть одна авантюрная мысль, нормировать все компоненты точек (привести максимальные элементы к 255. Работать нужно с тройками - берем максимальный компонент из R,G и B и умножаем его на коэффициент такой чтобы он стал равным 255 и остальные оставшиеся два компонента умножаем на тот-же коэффициент), тогда все серое станет белым :D Потом через бинаризатор и очиститель мелкого шума.

Да вроде как уже отделить серое от цветного не проблема. Проблема в том, что на иллюстрациях оказалось слишком много серого цвета, особенно на границах.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Если страницу прогнать через детектор границ, а потом поискать прямоугольнки? Может кинете пример одной из страниц, которые плохо обрабатываются и результат отделения цветного от черно-белого?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ох и кода понаваял с циклами ...

Как говорится, да-здравствуют любители трудностей! :D

В библиотеке есть функция преобразования цветоного изображения к GrayScale.

Так вот возьми этот полученный GrayScale и отними от своего Color изображения.

Это пару строк всем понятного кода, а не двойные циклы с попиксельным доступом и хитромудрыми манипуляциями с данными.

Ну а потом кури докуменатцию по морфологии + squares.c из примеров к OpenCV.

Только учти, что пример squares.c писал по видимому невменяемый человек, поэтому код придется перешерстить.

Но это всё-таки проще, чем заново изобретать велосипед.

Проблема в том, что для каждой страницы с иллюстрациями нужен свой порог, при котором изображение выделится идеально. То есть никакой константный порог не подходит для решения задачи. Нужен адаптивный порог, но непонятно, по какому алгоритму его вычислять.
Как говорил великий философ современности Винни Пух: "No money - no honey!"

Что в переводе на русский означает: "Нет образцов изображений - нечем и помочь"...

Обсуждать сферического коня в вакууме не видя исходномо материала можно до Китайской Пасхи и так ни к чему путнему и не прийти ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×