Существуют изображения, на которых встаёт задача понижения шума при сохранении значимых контуров.
Предположу первое возражение:
"Есть же медианный фильтр. Применить его и всё."
"Медианный фильтр..." то есть, но на рассматриваемых изображениях он даёт не просто плохой результат, а вообще "никакой". То есть важные контуры в результате утрачиваются. Причём все.
Предположу второе возражение:
"Есть куча средств в Фильтры->Улучшения: Подавление шума, Удаление пятен, Удаление штрихов. Зачем изобретать велосипед?"
Ни один из указанных инструментов не дал удовлетворительного результата.
Пришло время показать, о каких изображениях идёт речь:

Видим сильно зашумлённый скан книги, на котором присутствуют два вида контуров: важные - контуры букв, и вредные - контуры шума. Имеем задачу - не трогать вообще контура букв и подавить штрихи шума. Задача включает два диаметрально противоположных компонента, которые зависят только от размера контуров (для больших контуров одна компонента, для мелких - другая).
Приведённый образец содержит только текст, но скан может содержать и иллюстрации. Это накладывает ограничения на применяемые методы и средства решения. Но сама задача сформулирована хорошо и решается ровно так, как сформулирована.
Для чего вдруг понадобилось решение данной задачи?
Ежели применить "Порог" к данному изображению с автоматическим определением порогового значения (кнопка "Авто"), то получим следующий результат:

Видим кучу мелких точек шума, которые не просто портят результат, но и ухудшают читаемость системами OCR. Да, есть алгоритмы, удаляющие BW-шум, но в данной статье рассматривается GIMP. К тому же было упомянуто, что скан может содержать иллюстрации.
Понижение шумов.
Для понижения шумов будут использованы простейшие стандартные средства, не зависящие от версии GIMP, либо установленных плагинов.
Создается копия исходного слоя. К нему применяется фильтр "Гауссово размывание" с размерами, разделяющими контуры изображения на важные и вредные (в данном случае 3 и 3):

Накладывается данный слой на исходный в режиме "Разница":

На разнице светлыми становятся и светлые и тёмные контуры исходного изображения, тёмными остаются участки на которых нет контуров. Но нужны то не все контура, а только те, что больше заданного размера (т.е. важные). Поэтому к контурам применяется ещё раз "Гауссово размывание" с размерами, разделяющими контуры изображения на важные и вредные (в данном случае 3 и 3):

Применяется "Порог" к размытым контурам с автоматическим определением порогового значения (кнопка "Авто"). После порога применяется "Инвертировать яркость". Это даёт маску важных контуров:

В случае скана, содержащего только текст, можно выбелить всё, что не оказалось в маске важных контуров, просто наложив маску в режиме "Добавить" на исходный слой:

Для данного скана получилось вполне себе ничего. Но! Только для этого. засвеченного гама-коррекцией скана, не содержащего иллюстраций. Но! При нормальном сканировании без засветки цвет страниц вовсе не белый. И некоторые страницы содержат ещё более небелые иллюстрации. Поэтому выбеливать вне контуров не будем, а заменим области вне контуров на размытую версию этих областей. Для этого используем инструмент выделения "Выделить по цвету", кликаем на любом белом участке маски. Получаем выделение всех белых зон. На размытом слое, использованном в самом начале, в списке слоёв делаем правый клик и выбираем "Добавить маску слоя", в открывшемся диалоге выбираем "Выделение". После получения маски слоя снимаем выделение:

Так как слой имеет прозрачность в нужных местах, то просто накладываем его на исходный слой в режиме "Нормальный":

Для сравнения применим порог с авто определением порогового значения:

На этом как бы всё. Но! Разговор был так же за иллюстрации. Поэтому продемонстрирую данную методу на участке зашумлённого скана обложки:







Вот теперь всё.
Насколько доктринальна данная метода?
Ни на сколько. Можно применять не только "Гауссово размывание", а любое размывание из "Фильтры"->"Размытие". Так же нет ограничение на то, что использовать для замены зон вне зон контуров. Возможно также применение в сочетании с какими то плагинами. Но! Всё это уже за пределами данной статьи.
Комментарии (27)
zvezdochiot Автор
21.05.2025 15:44Результат применения данного метода: Щавелев Алексей Федорович "Геодезия", 1962.
SquareRootOfZero
21.05.2025 15:44Спорные улучшения, за OCR не скажу, а глазами текст с исходной картинки, как будто, легче читается - видимо, глазу проще игнорировать визуальные излишества в виде шума, чем достраивать визуальные изъяны в виде погрызенных алгоритмами элементов буков.
Медианный фильтр, понятно, не будет работать - слишком тонкие буквы, и по той же причине не будет работать dilate/erode. Какого-нибудь фильтра на connected components нет в GIMP-е? Типа (не GIMP, конечно, но чем могу):
import cv2 import numpy as np img_gs = cv2.imread("original.png", cv2.IMREAD_GRAYSCALE) # чем выше - тем больше шума останется, но нам пофиг - # шум мелкий, удалим через фильтр по площади threshold_value = 200 _, img_bw = cv2.threshold(img_gs, threshold_value, 255, cv2.THRESH_BINARY_INV) analysis = cv2.connectedComponentsWithStats(img_bw, 4, cv2.CV_32S) n_labels, label_ids, values, _ = analysis output = np.zeros(img_gs.shape, dtype = np.uint8) # 1 - объединяем все компоненты с площадью больше пороговой area_threshold = 10 for i in range(1, n_labels): area = values[i, cv2.CC_STAT_AREA] if area > area_threshold: mask = (label_ids == i).astype(np.uint8) * 255 output = cv2.bitwise_or(output, mask) result = cv2.bitwise_not(output) cv2.imwrite("output.png", result) # 2 - чуть растопырив полученный выше результат, используем его # как маску для исходного изображения, получая "антиалиасинг" img_inv = cv2.bitwise_not(img_gs) result2 = cv2.bitwise_and(img_inv, img_inv, mask = cv2.dilate(output, np.ones((3, 3)))) cv2.imwrite("output2.png", cv2.bitwise_not(result2))
Если поставить побольше значение для
area_threshold
, можно избавиться вообще от всего шума (но заодно и от всех знаков препинания - хотя эта проблема вряд ли вообще решаема исключительно в парадигме фильтрации изображений).Чтобы глазами приятней читать, можно чуть размазать этот результат и использовать в качестве маски на исходном изображении (см.
# 2
):На обложке и медианный фильтр, мне кажется, должен неплохо работать.
zvezdochiot Автор
21.05.2025 15:44"Медианный фильтр" на обложке радиусом 3:
Медианный фильтр радиусом 3 Как то не очень, мелкий текст "всмятку". И ни разу не решает проблему иллюстраций среди текста. Возможно стоит использовать медиану для замены областей, но не в чистом виде.
Использование "Медианного фильтра" радиусом 4 для замены областей вне зон контуров:
Замена областей медианой. Но такая опция упоминается в конце статьи.
SquareRootOfZero
21.05.2025 15:44Фиг знает, по-моему, как минимум, не хуже последней картинки из поста. Но в обложке цвета присутствуют, её, вероятно, логичнее в HSV разложить (или ещё во что-нибудь) и по H пофильтровать (или по ещё чему-нибудь). Для чёрно-белых иллюстраций из тонких линий, которые, вероятно, и встречаются в тексте, понятно, медианный фильтр не сработает, как и для самого текста.
U235U235
21.05.2025 15:44Можно полностью избавиться от цикла for, использовав np.isin для меток.
фильтровать тоже можно без if с np.nonzero/np.flatnonzero
SquareRootOfZero
21.05.2025 15:44Так нормально? В смысле, цикл со всем содержимым на это заменить, результат идентичен:
areas = values[:, cv2.CC_STAT_AREA] - area_threshold areas[0] = 0 # шоб не мешала area_indices = np.nonzero(areas > 0) output = np.isin(label_ids, area_indices).astype(np.uint8) * 255
U235U235
21.05.2025 15:44Да, так будет быстрее.
Хотя тоже чуть сократить можно.
area_indices=np.nonzero(values[:, cv2.CC_STAT_AREA]> area_threshold)
output = np.isin(label_ids, area_indices[1:]).astype(np.uint8) * 255
SquareRootOfZero
21.05.2025 15:44Так
output
получается чёрный и пустой, потому чтоnp.nonzero
пакует результат в tuple. Надо либо во второй строчке взятьarea_indices[0][1:]
, либо в первой использовать неnonzero
, аflatnonzero
, ну либо там же от обычногоnonzero
взять только 0-й элемент, уж не знаю, что эффективнее.
Zara6502
21.05.2025 15:44ымха: обложку фильтровать не нужно, она просто отлично выглядит, ну есть небольшой шум, совсем не страшно. а вот после фильтра она размытая и пластмассовая стала.
zvezdochiot Автор
21.05.2025 15:44Процитирую себя же: "На этом как бы всё. Но! Разговор был так же за иллюстрации. Поэтому продемонстрирую данную методу на участке зашумлённого скана обложки"
Ещё раз процитирую себя же: "Можно применять не только "Гауссово размывание", а любое размывание из "Фильтры"->"Размытие". Так же нет ограничение на то, что использовать для замены зон вне зон контуров."
И ещё раз процитирую себя же: "Использование "Медианного фильтра" радиусом 4 для замены областей вне зон контуров"
Что с иллюстрациями в тексте делать? Точнее, как чистить текст при наличии иллюстраций?
Zara6502
21.05.2025 15:44не совсем понял зачем мне ваши цитаты, всё что я хотел сказать я сказал, я не подписывался решать ваши проблемы с иллюстрациями.
в качестве совета из личного опыта - возьмите инструменты для формирования djvu, там картинку можно рассекать на иллюстрацию и текст, для текста можно делать фильтр, там всё само делается, но много ручной работы по компоновке самой книжки.
zvezdochiot Автор
21.05.2025 15:44При чём тут DjVu? GIMP же!
Ежели есть какое решение задачи другими инструментами, выкладывайте ссылку.
Zara6502
21.05.2025 15:44а тут принимаются советы только по GIMP?
гугл никто не запрещал, но вот вам ссылка
zvezdochiot Автор
21.05.2025 15:44И? Где решение данной или похожей задачи?
Zara6502
21.05.2025 15:44мужик, а тебе не кажется что ты слишком по-хамски себя ведёшь расставляя минусы?
если ты не понимаешь что такое djvu, как он работает и как пользоваться этими инструментами то по ссылке ты найдешь всю информацию, сиди, читай, учи, пробуй, я в учителя не нанимался. сам по себе djvu это кусочек OCR.
ну и как советовали - поставь себе Fine Reader и пользуйся без всякого GIMP на котором свет клином не сошёлся. Сам напиши фильтр на C/C++/C#/Python, всё в твоих руках.
или поставь CamScanner на телефоне и фильтруй им, у тебя же с этим проблема, а не у нас.
zvezdochiot Автор
21.05.2025 15:44Вас под дулом пистолета заставляют писать сюда комментарии? Вы теперь решаете, какие кому оценки ставить и за что?
Статья про GIMP и решение определённой задачи в нём. Выше люди написали решение задачи другими средствами. К ним претензий нет. К вам есть.
Zara6502
21.05.2025 15:44Вас под дулом пистолета заставляют писать сюда комментарии?
то что я пишу комментарий не создаёт никаких обязательств, я поделился с вами определенной информацией безвозмездно не требуя ничего взамен, я потратил на это время. вы вправе распорядиться этой информацией по своему усмотрению. я проявил уважение к вашей статье и вполне уважительно написал ответ, почему вы себя ведёте так словно вам кто-то чем-то обязан? вы же почти на все комментарии отписались как озлобленная овчарка. к чему это?
вы написали статью на открытый ресурс, значит и обратная связь ожидаема.
Вы теперь решаете, какие кому оценки ставить и за что?
я ожидаю как минимум адекватности в оценках, вы себя ведёте неадекватно.
Статья про GIMP и решение определённой задачи в нём
и мой комментарий вполне себе по теме, он однозначно определен мной как "моё скромное мнение", где я указал, что обложка до применения фильтров смотрится заметно лучше. Вы зачем-то стали что-то там цитировать и потом буквально потребовали с меня ответа на вопросы про иллюстрации. Но мой комментарий никак с этим не связан.
в духе доброй воли я вам написал как я решал вопрос с иллюстрациями и я не понимаю почему вы решили что все вокруг обязательно должны эти вопросы решать с помощью GIMP.
я дал полную и исчерпывающую информацию. то что лично вы не желаете пользоваться поиском - не моя проблема. Но и даже после вашего хамства я вам дал ссылку на материал которым я пользовался, но и тут вам не понравилось что я недостаточно разжевал для вас, вы продолжаете хамить.
Выше люди написали решение задачи другими средствами
замечательно, мне какое дело до того что вам там написали выше?
К ним претензий нет. К вам есть.
Какие претензии ко мне?
zvezdochiot Автор
21.05.2025 15:44Вы пишете, что в голову взбредёт. Поток сознания. Ни разу не по теме.
Zara6502
21.05.2025 15:44И что же конкретно не по теме?
То что обложка лучше выглядит до обработки - это по теме, но вы вправе не соглашаться.
Остальное - ваши вопросы ко мне, на которые я даю ответ. По теме они или нет не суть, мы же не роботы, можем затрагивать любые темы касающиеся проблематики, а данном случае вы обсуждаете проблематику в OCR, так что проблема проистекающая из одного места. То что лично вам хочется услышать что-то про GIMP - это ваша хотелка, окружающие вполне могут не разделять ваших хотелок и затрагивать вопрос с разных сторон. Человек который этого не понимает и собеседникам за это раздаёт минусы - неадекватен.
За сим кланяюсь, вы более мне не интересны как собеседник, ни в этой теме ни в любой другой. Стекловата и всё в этом духе.
zvezdochiot Автор
21.05.2025 15:44Использование "Медианы" радиусом 3 вместо первого "Гауссового размывания" на том же материале:
Обложка Текст.
CBET_TbMbI
Вот в таких задачах ИИ должен идеально работать. И перевести весь скан в распознанный документ. При то с нужным форматированием абзацев, отступов и прочего.
zvezdochiot Автор
Ну при чем тут ИИ? Статья про GIMP.
CBET_TbMbI
Я думал про обработку сканов. Видимо ошибся. Прошу прощения.
zvezdochiot Автор
Нет, не ошибся. И ежели бы выложил ссылку на статью, в которой ИИ решает эту же, или похожую задачу, то был бы по теме. Но этого то и нету.
CBET_TbMbI
Так что тут нового? Условный ФайнРидер это делает уже более 10 лет. Уж не знаю, с ИИ или без ИИ, но делает. И делает если не отлично, то хорошо. Наверное, и другие аналоги уже подтянулись. А уж для современных технологий эта задача должна быть совсем тривиальной, про что в комментарии и написал.
ИИ может быть средне-хорош в болтологии и разных написаниях кода, но для таких задач он может быть идеален.
zvezdochiot Автор
Так и не вижу ни одной ссылки ни на GIMP, ни на решение данной задачи иными средствами. Не по теме. Я бы сказал даже не близко к статье.
Jijiki
а там(то о чем вы в той степи) впринципе ее так и делают на известных языках(я на java тыкал - работало), уже ИИ есть по распознованию, тоесть определив текст она либо напечатает по новой либо вырежет как в скане, вы наверно хотите не нативную ИИ(клоню к тому что тут она дообучивается от промптов, а там уже в матрицу заложен сам нюанс определения), а по промпту(там где к концу подставляется искомое и ИИ обучается помните было такое, да и щас наверно есть)