Убираем пыль с 1000 фотографий с помощью Gimp и Script-Fu

Думаю многим фотографам приходилось чистить отснятые фотографии от пылинок на матрице. Не имея полного Photoshop-a или LightRoom-a быстро обработать большое количество фотографий крайне трудно.
Но у нас есть Gimp и желание написать к нему скрипт.
На Хабре уже было не мало статей про возможность написания скриптов в Gimp.
Вот самый подробные обзор самого языка Script-fu и возможности написания на нём расширений к Gimp
Вот тут статья про пакетную обработку.
По идее, прочитав 2 эти статьи, можно сделать что угодно. Но вот только при решении обозначенной в заголовке проблемы, я столкнулся с многими нюансам, на преодоление которых ушло не мало времени, и которые мало где описаны. Даже в англоязычных Tutorial-ах и Help-ах. О них и пойдёт речь.


Отступление


Зеркальные цифровые фотоаппараты, кроме всех своих достоинств наделены небольшим недостатком. Пыль на матрице. Для её устранения существует масса физический приспособлений, а в некоторых моделях даже встроены специальные внутренние системы для стряхивания пыли с матриц (вот большая статья про все технологии в этом направлении).

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

В таком случае большинство специалистов используют Adobe Photoshop Light Room или же последние редакции полного Adobe Photoshop.
В LR используют богатые возможностями пакетной обработки фотографий .
В полном Photoshop — возможности создания Action-ов.

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

Пишем скрипт


Для этого открываем Gimp а в нём Script-Fu консоль


Внешний вид консоли справа.

Скрипт лучше писать в каком-либо текстовом редакторе, отображающем связи скобок. Я для этого использовал Notepad++. После написания будем вставлять скрипт в консоль и проверять как он работает.

Для реализации идеи будем использовать некий функционал clone который по сути должен делать тоже что и инструмент копирования в GUI самого Gimp-a. Будем вводить координаты нашей пылинки на фотографии и как-то задавать область откуда клонировать участок, чтобы эту пылинку закрыть.

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

И начал подбирать параметры.
Тут началось самое интересное и не документированное. Дьявол скрывается в деталях.
Как видим из описания функции на вход её подаются 7 параметров, два первых из них, это DRAWABLE объекты. Немного погуглив легко можно найти примеры скриптов, получающих эти drawabale из пути к картинке

Вот код
( let* 
    (
      (image (car (gimp-file-load RUN-NONINTERACTIVE "E:/test.png" "E:/test.png")))
      (drawable (car (gimp-image-get-active-layer image)))
    )
)

Первые 2 параметра есть (т.к. и source и target у нас наша же картинка)
Третий параметр выставляем в IMAGE-CLONE, т.к. мы хотим клонировать из этой же картинки а не из какого-то там ранее созданного паттерна. 4й и 5й тоже всё ясно — пишем сюда координаты нашей пылинки.
А вот 6 и 7й параметры не так очевидны.

Методом проб и ошибок выяснил что работает этот инструмент кистью. И как раз 6й и 7й параметры задают путь по которому эта кисть будет двигаться. О том как задать верно кисть опишу ниже.
Больше всего времени ушло на понимание 6го параметра, и не мало сумятицы внёс коментарий к нему
Number of stroke control points (count each coordinate as 2 points) (num-strokes >= 2)
Я упорно вводил сюда количество координат, а не чисел. И получал непредвиденные результаты. Оказывается это просто количество чисел в следующем параметре (массиве). Т.е. допустим если мы хотим начать клонирование в x=50 y=50 и сделать кистью маршрут через 3 точки из точки 0, 0 в точку 10, 10 а затем в точку 20, 30 (точки соединятся прямыми, но не закольцовываются, т.е. последняя не соединяться с первой) то нам надо написать что-то вроде вот этого
  (gimp-clone drawable drawable IMAGE-CLONE 50 50 6 #(0 0 10 10 20 30) ) 

6 чисел в массиве, но они описывают всего 3 координаты. Если надо 4 координаты, то написали бы 8 и потом массив из 8 чисел. и так далее.

Теперь про кисть. Увы в данной версии Gimp (2.8.4) есть некий глюк при работе с кистями. Нельзя выбрать кисть из уже существующих и задать ей размер (вот этот баг). Размер будет браться либо стандартный либо тот что у вас в GUI сейчас для неё выставлен.
По-этому нам придётся делать свою собственную кисть и задавать ей параметры (что на самом деле более удобно)

Вот код открывающий тестовую картинку, создающий кисть и клонирующий левую часть картинки — в правой части по заданному маршруту (нарисуем треугольник).
( let* 
    ; create variables for get DRAWABLE
    (
      (image (car (gimp-file-load RUN-NONINTERACTIVE "E:/test.png" "E:/test.png")))
      (drawable (car (gimp-image-get-active-layer image)))
    )
    ; create and set brush	
    (gimp-brush-new "MyBrush")
    (gimp-brush-set-radius "MyBrush" 4)
    (gimp-brush-set-shape "MyBrush" BRUSH-GENERATED-CIRCLE)
    (gimp-brush-set-hardness "MyBrush" 0.50)
    (gimp-brush-set-spacing "MyBrush" 0)
    (gimp-brush-set-spikes "MyBrush" 0)
    (gimp-brushes-set-brush "MyBrush")
    ; clones
    (gimp-clone drawable drawable IMAGE-CLONE 100 10 8 #(450 10 360 150 540 150 450 10) )
    ; save result
    (gimp-file-save RUN-NONINTERACTIVE image drawable "E:/test_e.png" "E:/test_e.png")
    (gimp-image-delete image)
)

Копируем скрипт в консоль и жмём Enter. Если всё удалось — видим в консоли следующее

В случае ошибок — увидим описание ошибки.

А вот картинки, до скрипта и после.

С параметрами кисти можно поиграть на своё усмотрение.

Применяем результат к тысячам файлов


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

Получаем такой скрипт
(define (script-fu-batch-dust-remove inputFolder outputFolder dustX dustY dustRadius)
  (let* ((filelist (cadr (file-glob (string-append inputFolder DIR-SEPARATOR "*") 1))))
    ; create and set brush	
    (gimp-brush-new "DustBrush")
    (gimp-brush-set-radius "DustBrush" dustRadius)
    (gimp-brush-set-shape "DustBrush" BRUSH-GENERATED-CIRCLE)
    (gimp-brush-set-hardness "DustBrush" 0.70)
    (gimp-brush-set-spacing "DustBrush" 0)
    (gimp-brush-set-spikes "DustBrush" 0)
    (gimp-brushes-set-brush "DustBrush")
    ; go throw all files in inputFolder
    (while (not (null? filelist))
      (let* ((filename (car filelist))
          (image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
          (drawable (car (gimp-image-get-active-layer image)))
		  (dustCoordinates (vector dustX dustY))
        )
        ; clone
        (gimp-clone drawable drawable IMAGE-CLONE (+ dustX (* dustRadius 2)) dustY 2 dustCoordinates)
        ; save result to outputFolder
        (set! filename (string-append outputFolder DIR-SEPARATOR (car (gimp-image-get-name image))))
        (gimp-file-save RUN-NONINTERACTIVE image drawable filename  filename)
        (gimp-image-delete image)
      )
      (set! filelist (cdr filelist))
    )
    ; remove just created Brush for not spam brush list
    (gimp-brush-delete "DustBrush")
  )
)

Вставляем его в консоль. Теперь у нас в консоли есть функция script-fu-batch-dust-remove
Теперь открываем наши фотографии с пылью, находим с помощью подбора кисти размер пылинки (наведя мышью на пылинку и подобрав так размер кисти, чтобы она полностью покрывала пылинку). Слева с низу пишутся координаты нашего курсора на фотографии.
Выписываем полученные координаты и радиус
Копируем все файлы которые мы хотим исправить в папку. Копировать все подряд не стоит, я копировал только те где пылинка явно бросается в глаза, т.е. к примеру на фоне чистого неба или моря или другой однородной текстуры. Если скопировать все — даже те где пылинки не видно из-за неоднородности изображения в этом месте — то попортим эти фотографии не нужным клонированием.

Запускаем скрипт в консоли
(script-fu-batch-dust-remove "E:/toEdit/in" "E:/toEdit/out" 3186 682 15)

И в папке E:/toEdit/out получаем все файлы с теми же именами — но уже без пыли!
Результат достигнут.

P.S.
После ряда экспериментов пришёл в к выводу что лучше использовать функцию не gimp-clone а gimp-heal. С ней результаты лучше, вне зависимоти от окружающей пыль картинки. Параметры точно такие-же, только нету IMAGE-CLONE
Так что вызов в моём скрипте будет примерно такой
(gimp-heal drawable drawable (+ dustX2 (* dustRadius2 2)) dustY2 2 dustCoordinates2)


UPD1
Примеры работы скрипта с gimp-heal
Удачная обработка (диафрагма 22)
До

После


Не совсем удачная обработка (диафрагма 11)
До

После (половина окна теперь вместо пылинки)


Результат при диафрагме 7,0
До

После (видно что небольшая аура всё же осталась, надо было бы наверно увеличить радиус для этой фотографии)


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

UPD2
В свете того что в скрипте я использовал для сохранения результатов метод gimp-file-save выходные файлы получаются по размеру меньше исходных. Т.е. получается gimp-file-save жмёт JPEG в другом качестве, нежели исходные файлы. Если кому это критично — могут почитать в браузере процедур про file-jpeg-save и использовать её вместо предложенного мной, более простого решения с gimp-file-save.
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 24

    –13
    Убирать пыль с матрицы? Что за фетишизм?

    Я веду блог о своей учебе в Чехии (+ ряд других тематических) и выкладываю немало фотографий, очень много фотографирую. Опыт в фото с зеркалками у меня около 5. Меняю объективы, причем часто и в самых разных условиях, в т.ч. полевых.

    Чистить матрицу или заморачиваться пылью на матрице мне пока не доводилось. Вот пример с камеры и объектива, которыми полтора года активно пользуюсь — есть ли тут пыль? А то может надо чистить и фотошопить.
      +2
      На этой диафрагме пыль очень сложно увидеть если она есть. Сделайте тестовый кадр с полностью закрытой диафрагмой, что-нибудь равномерно освещённое, например лист белой бумаги на солнечном свете.
      Как раз при ярком солнечном свете пыль и даёт о себе знать и портит фотографии.
      • UFO just landed and posted this here
          0
          А в практике бывает, что надо снимать абсолютно белую стену с закрытой диафрагмой? Я вообще на закрытой диафрагме почти ничего не снимаю, диафрагмы ради люди и покупают светосильную технику.
          • UFO just landed and posted this here
              0
              Продувать? Вот дуть, как я думаю, точно не стоит — по законам физики тогда пыль переместится вглубь фотоаппарата, т.е. на матрицу. Как я предполагаю, если какая-то пыль и будет, то она на зеркале.

              Я не специалист, а просто пользователь, поэтому просто рассуждаю.
          0
          Было бы интересно почитать доводы минусующих. Повторюсь — я не вижу смысла в борьбе с проблемами, которые возникают только в искусственных условиях.
            0
            Белая стена это просто способ увидеть пыль на матрице, а проблемы появляются, когда снимаешь что-то светлое на закрытой диафрагме, например небо и пятна будут вот в точь такие же как у автора статьи.
              0
              Например мы с друзьями зимой устраивали покатушки на замёрзшем озере. Светило солнце, приходилось снимать на закрытой диафрагме. Пыль, которая накопилась была отлична видна на снимках. Точно так-же при съёмке под ярким летним солнцем приходится прикрывать диафрагму, т.к. даже выдержки 1/8000 не хватает. И если сильно зажать, то пыль тоже заметна. Так что проблема реальна и встречается.
            –2
            Хм, а gimp-то зачем? Здесь ImageMagic за глаза хватит!
            • UFO just landed and posted this here
                0
                Добавил (UPD1)
                • UFO just landed and posted this here
                    0
                    Там 2 пылинки. Просто диафрагма задрана на первой фотке аж до 22 -потому так чётко их видно.. Они же обе и на втором примере видны в тех же самых местах, но уже бледнее.
                    • UFO just landed and posted this here
                        0
                        Добавил ещё один пример.
                0
                Вот еще полезная статья как разрезать отсканированные фото с помощью гимпа и скриптов
                  –1
                  Народ, я с вас диву даюсь!
                  То они для исправления красных глаз фотожоп покупают, то гимпом фотографии режут!

                  Или это традиция нонче такая — гвозди микроскопом заколачивать?
                    0
                    Есть фри альтернативы способные разрезать 1000 сканов с разными по размерам фотографиями на скане? Поделитесь пожалуйста, я не нашел.
                      0
                      ImageMagic, ясен пень!
                  0
                  Что делать если зум разный, те на одних фотографиях пылинка четкая и отчетливо видная, на других размытая, но все еще видная?
                    0
                    Чёткость пылинки, как тут уже писали в коментариях, зависит не от зума, а от диафрагмы. Чем больше диафрагма — тем чётче пылинка. Добавил в UPD1 2 примера фоток. На первой пылинки сверх-чёткие, потому как там диафрагма выставлена аж в 22, на втором же снимке диафрагма 11 и как видим пыль гораздо более размыта. Но по идеи для gimp-heal или gimp-clone всё-равно что закрывать, главное что бы радиусом он был больше чем самый размытый варианта пылинки. Я делал именно так, не заморачивался с изменением радиуса под разную чёткость пылинок. Я просто выставлял радиус побольше, что бы уж наверняка
                    0
                    Регулярно сталкиваюсь с этой проблемой. Спасибо за статью.
                      0
                      Тут до уборки пыли, ещё полно работы:
                      (не могу запостить картинку в каммент)

                      Перспектива, провода в кадре… Ведь такие примеры бы были приятнее.

                      Only users with full accounts can post comments. Log in, please.