Существуют изображения, на которых встаёт задача понижения шума при сохранении значимых контуров.

Предположу первое возражение:

"Есть же медианный фильтр. Применить его и всё."

"Медианный фильтр..." то есть, но на рассматриваемых изображениях он даёт не просто плохой результат, а вообще "никакой". То есть важные контуры в результате утрачиваются. Причём все.

Предположу второе возражение:

"Есть куча средств в Фильтры->Улучшения: Подавление шума, Удаление пятен, Удаление штрихов. Зачем изобретать велосипед?"

Ни один из указанных инструментов не дал удовлетворительного результата.

Пришло время показать, о каких изображениях идёт речь:

Зашумлённый скан книги.
Зашумлённый скан книги.

Видим сильно зашумлённый скан книги, на котором присутствуют два вида контуров: важные - контуры букв, и вредные - контуры шума. Имеем задачу - не трогать вообще контура букв и подавить штрихи шума. Задача включает два диаметрально противоположных компонента, которые зависят только от размера контуров (для больших контуров одна компонента, для мелких - другая).

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

Для чего вдруг понадобилось решение данной задачи?

Ежели применить "Порог" к данному изображению с автоматическим определением порогового значения (кнопка "Авто"), то получим следующий результат:

Автоматический порог исходного скана.
Автоматический порог исходного скана.

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

Понижение шумов.

Для понижения шумов будут использованы простейшие стандартные средства, не зависящие от версии GIMP, либо установленных плагинов.

Создается копия исходного слоя. К нему применяется фильтр "Гауссово размывание" с размерами, разделяющими контуры изображения на важные и вредные (в данном случае 3 и 3):

"Гауссово размывание" 3x3.
"Гауссово размывание" 3x3.

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

Разница размытого и исходного слоя.
Разница размытого и исходного слоя.

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

"Гауссово размывание" контуров 3x3.
"Гауссово размывание" контуров 3x3.

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

Маска важных контуров.
Маска важных контуров.

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

Наложение маски в режиме "Добавить".
Наложение маски в режиме "Добавить".

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

Размытое изображение с прозрачными областями контуров.
Размытое изображение с прозрачными областями контуров.

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

Слой с пониженными шумами.
Слой с пониженными шумами.

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

Порог обработанного слоя.
Порог обработанного слоя.

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

Участок зашумлённого скана обложки.
Участок зашумлённого скана обложки.
"Гауссово размывание" 3x3.
"Гауссово размывание" 3x3.
Контура.
Контура.
"Гауссово размывание" контуров 3x3.
"Гауссово размывание" контуров 3x3.
Маска важных контуров
Маска важных контуров
Размытое вне маски.
Размытое вне маски.
Обложка с пониженными шумами.
Обложка с пониженными шумами.

Вот теперь всё.

Насколько доктринальна данная метода?

Ни на сколько. Можно применять не только "Гауссово размывание", а любое размывание из "Фильтры"->"Размытие". Так же нет ограничение на то, что использовать для замены зон вне зон контуров. Возможно также применение в сочетании с какими то плагинами. Но! Всё это уже за пределами данной статьи.

Комментарии (27)


  1. CBET_TbMbI
    21.05.2025 15:44

    Вот в таких задачах ИИ должен идеально работать. И перевести весь скан в распознанный документ. При то с нужным форматированием абзацев, отступов и прочего.


    1. zvezdochiot Автор
      21.05.2025 15:44

      Ну при чем тут ИИ? Статья про GIMP.


      1. CBET_TbMbI
        21.05.2025 15:44

        Я думал про обработку сканов. Видимо ошибся. Прошу прощения.


        1. zvezdochiot Автор
          21.05.2025 15:44

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


          1. CBET_TbMbI
            21.05.2025 15:44

            Так что тут нового? Условный ФайнРидер это делает уже более 10 лет. Уж не знаю, с ИИ или без ИИ, но делает. И делает если не отлично, то хорошо. Наверное, и другие аналоги уже подтянулись. А уж для современных технологий эта задача должна быть совсем тривиальной, про что в комментарии и написал.

            ИИ может быть средне-хорош в болтологии и разных написаниях кода, но для таких задач он может быть идеален.


            1. zvezdochiot Автор
              21.05.2025 15:44

              Так и не вижу ни одной ссылки ни на GIMP, ни на решение данной задачи иными средствами. Не по теме. Я бы сказал даже не близко к статье.


            1. Jijiki
              21.05.2025 15:44

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


  1. zvezdochiot Автор
    21.05.2025 15:44

    Результат применения данного метода: Щавелев Алексей Федорович "Геодезия", 1962.


  1. 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):

    На обложке и медианный фильтр, мне кажется, должен неплохо работать.


    1. zvezdochiot Автор
      21.05.2025 15:44

      "Медианный фильтр" на обложке радиусом 3:

      Медианный фильтр радиусом 3
      Медианный фильтр радиусом 3

      Как то не очень, мелкий текст "всмятку". И ни разу не решает проблему иллюстраций среди текста. Возможно стоит использовать медиану для замены областей, но не в чистом виде.

      Использование "Медианного фильтра" радиусом 4 для замены областей вне зон контуров:

      Замена областей медианой.
      Замена областей медианой.

      Но такая опция упоминается в конце статьи.


      1. SquareRootOfZero
        21.05.2025 15:44

        Фиг знает, по-моему, как минимум, не хуже последней картинки из поста. Но в обложке цвета присутствуют, её, вероятно, логичнее в HSV разложить (или ещё во что-нибудь) и по H пофильтровать (или по ещё чему-нибудь). Для чёрно-белых иллюстраций из тонких линий, которые, вероятно, и встречаются в тексте, понятно, медианный фильтр не сработает, как и для самого текста.


    1. U235U235
      21.05.2025 15:44

      Можно полностью избавиться от цикла for, использовав np.isin для меток.

      фильтровать тоже можно без if с np.nonzero/np.flatnonzero


      1. 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


        1. 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


          1. SquareRootOfZero
            21.05.2025 15:44

            Так output получается чёрный и пустой, потому что np.nonzero пакует результат в tuple. Надо либо во второй строчке взять area_indices[0][1:], либо в первой использовать не nonzero, а flatnonzero, ну либо там же от обычного nonzero взять только 0-й элемент, уж не знаю, что эффективнее.


  1. Zara6502
    21.05.2025 15:44

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


    1. zvezdochiot Автор
      21.05.2025 15:44

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

      Ещё раз процитирую себя же: "Можно применять не только "Гауссово размывание", а любое размывание из "Фильтры"->"Размытие". Так же нет ограничение на то, что использовать для замены зон вне зон контуров."

      И ещё раз процитирую себя же: "Использование "Медианного фильтра" радиусом 4 для замены областей вне зон контуров"

      Что с иллюстрациями в тексте делать? Точнее, как чистить текст при наличии иллюстраций?


      1. Zara6502
        21.05.2025 15:44

        не совсем понял зачем мне ваши цитаты, всё что я хотел сказать я сказал, я не подписывался решать ваши проблемы с иллюстрациями.

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


        1. zvezdochiot Автор
          21.05.2025 15:44

          При чём тут DjVu? GIMP же!

          Ежели есть какое решение задачи другими инструментами, выкладывайте ссылку.


          1. Zara6502
            21.05.2025 15:44

            а тут принимаются советы только по GIMP?

            гугл никто не запрещал, но вот вам ссылка


            1. zvezdochiot Автор
              21.05.2025 15:44

              И? Где решение данной или похожей задачи?


              1. Zara6502
                21.05.2025 15:44

                мужик, а тебе не кажется что ты слишком по-хамски себя ведёшь расставляя минусы?

                если ты не понимаешь что такое djvu, как он работает и как пользоваться этими инструментами то по ссылке ты найдешь всю информацию, сиди, читай, учи, пробуй, я в учителя не нанимался. сам по себе djvu это кусочек OCR.

                ну и как советовали - поставь себе Fine Reader и пользуйся без всякого GIMP на котором свет клином не сошёлся. Сам напиши фильтр на C/C++/C#/Python, всё в твоих руках.

                или поставь CamScanner на телефоне и фильтруй им, у тебя же с этим проблема, а не у нас.


                1. zvezdochiot Автор
                  21.05.2025 15:44

                  Вас под дулом пистолета заставляют писать сюда комментарии? Вы теперь решаете, какие кому оценки ставить и за что?

                  Статья про GIMP и решение определённой задачи в нём. Выше люди написали решение задачи другими средствами. К ним претензий нет. К вам есть.


                  1. Zara6502
                    21.05.2025 15:44

                    Вас под дулом пистолета заставляют писать сюда комментарии?

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

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

                    Вы теперь решаете, какие кому оценки ставить и за что?

                    я ожидаю как минимум адекватности в оценках, вы себя ведёте неадекватно.

                    Статья про GIMP и решение определённой задачи в нём

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

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

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

                    Выше люди написали решение задачи другими средствами

                    замечательно, мне какое дело до того что вам там написали выше?

                    К ним претензий нет. К вам есть.

                    Какие претензии ко мне?


                    1. zvezdochiot Автор
                      21.05.2025 15:44

                      Вы пишете, что в голову взбредёт. Поток сознания. Ни разу не по теме.


                      1. Zara6502
                        21.05.2025 15:44

                        И что же конкретно не по теме?

                        То что обложка лучше выглядит до обработки - это по теме, но вы вправе не соглашаться.

                        Остальное - ваши вопросы ко мне, на которые я даю ответ. По теме они или нет не суть, мы же не роботы, можем затрагивать любые темы касающиеся проблематики, а данном случае вы обсуждаете проблематику в OCR, так что проблема проистекающая из одного места. То что лично вам хочется услышать что-то про GIMP - это ваша хотелка, окружающие вполне могут не разделять ваших хотелок и затрагивать вопрос с разных сторон. Человек который этого не понимает и собеседникам за это раздаёт минусы - неадекватен.

                        За сим кланяюсь, вы более мне не интересны как собеседник, ни в этой теме ни в любой другой. Стекловата и всё в этом духе.


  1. zvezdochiot Автор
    21.05.2025 15:44

    Использование "Медианы" радиусом 3 вместо первого "Гауссового размывания" на том же материале:

    Обложка
    Обложка
    Текст.
    Текст.