\documentclass[a4paper,10pt]{article}
\usepackage[T2A]{fontenc}
\usepackage[koi8-r]{inputenc}
\usepackage[russian]{babel}
\usepackage{indentfirst}
\usepackage{calc}
% page geometry
\setlength{\topmargin}{-\headheight-\headsep}
\setlength{\oddsidemargin}{0pt}
\setlength{\textwidth}{\paperwidth-2in}
\setlength{\textheight}{\paperheight-2in}
% other setting
\sloppy
\author{Поздняков С.Г.}
\title{Пакетная обработка изображений в GIMP}
\begin{document}
\maketitle
\section*{Введение}

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

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

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

\section*{Что хотим, чем хотим}

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

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

Мы точно не хотим написать: еще один plug-in для GIMP, какое-либо универсальное средство для исправления любых дефектов изображений. 

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

\section*{Немного теории}

Начнем с того что GIMP использует для описания дополнений клон LISPа --- Scheme. В LISPе операторы записываются в виде списков: \textbf{(оператор аргумент1 аргумент2 ... )}, например:

\begin{verbatim}
(gimp-quit 1)
\end{verbatim} 

Возникает законный вопрос о том, как узнать какие операторы или процедуры есть в GIMP?
Ответ на этот вопрос можно разбить на две части: определение какому пункту меню что соответствует, какие параметры получает оператор и что возвращает.

Первая часть ответа. Запускаем GIMP и вызываем через меню \textit{Расширения->Детали
дополнения} специальный диалог, в котором переходим на вкладку
"Просмотр дерева''. Смотрим на меню GIMP в виде дерева, выбираем соответствующий пункт, жмём кнопку
"Детали'' и запоминаем название, заменив в нем подчёркивание на минус. 

Вторая часть ответа. В том же GIMP открываем диалог при помощи меню \textit{Расширения->Просмотр базы данных}, в котором находим то что запомнили в первой части, и опять напрягаем память по поводу аргументов и результата.

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

Для работы потребуются встроенные операторы Scheme, описание которых можно найти в документации на сайте
http://www.cs.indiana.edu/scheme-repository/. Здесь опишу только то что будем использовать. 

LISP оперирует списками, которые можно рассматривать как последовательность из головы
- первого элемента и хвоста - всего остального.
Операторы \textbf{(car список)} и \textbf{(cdr список)} возвращают
голову и хвост списка соответственно. Оператор \textbf{(set! переменная значение)} просто присваивает значение.
Присваивание локальным переменным и выполнение других операторов производится при помощи \textbf{(let (список пар инициаллизации) операторы)} и \textbf{(let* (последовательность пар инициаллизации) операторы)}.
Для определения функции без имени используем оператор \textbf{(lambda (аргументы) операторы)}.
Опреатор \textbf{(mapcar (функция арг1 арг2) список1 список2 ...)} применяет функцию ко всем наборам аргументов, которые соответствуют первым элементам списков, вторым и т.д.

Для отладки отдельных операторов и всего скрипта можно использовать консоль GIMP, которая доступна через меню \textit{Расширения->Скрипт-Фу->Консоль}. 

\section*{Что делать}

Основная идея состоит в том, что GIMPу можно передать скрипт в качестве параметра командной строки. Это делается так:

\begin{verbatim}
gimp -i -s -b "скрипт"
\end{verbatim} 

Параметры "-i'' и "-s'' нужны для того, чтобы GIMP не использовал графический интерфейс.
Можно добавить параметр "-d'' для убыстрения работы за счёт отказа от загрузки градиентов, палитр, кистей и другой необязательной информации.

Первое что нам нужно --- открыть файл с изображением и подготовить ``рисовалку'':

\begin{verbatim}
(set! img (car (gimp-file-load 1 "/full/path" "/full/path")))
(set! drw (car (gimp-image-active-drawable img)))
\end{verbatim} 

Добавляем обработку изображения фильтром \textbf{unsharpen mask} с параметрами: радиус 3.0, величина 1.0, порог 0.

\begin{verbatim}
(plug-in-unsharp-mask 1 img drw 3.0 1.0 0)
\end{verbatim}

Теперь необходимо сохранить файл, произвести некоторую очистку и выйти из
GIMP. Параметры оператора \textbf{file-jpeg-save} влияющие на качество изображения и скорость работы начинаются после имени файла и имеют следующие значения:
качество (0 ... 1), сглаживание (0 ... 1), оптимизация (0/1), прогрессивная загрузка (0/1),
комментарий (текст), прореживание (номер), совместимость (0/1), перезапуск маркеров (число), алгоритм (номер). 

\begin{verbatim}
(file-jpeg-save 1 img drw "/full/path" "/full/path" 1.0 0 0 1 "" 1 1 0 1)
(gimp-image-delete img) 
(gimp-quit 1)
\end{verbatim}

Завершающий штрих - заставить это всё работать вместе в виде скрипта Scheme, который можно выполнить на консоли
GIMP.

\begin{verbatim}
(let* ((filename "/full/path") 
(img (car (gimp-file-load 1 filename filename))) 
(drw (car (gimp-image-active-drawable img))))
(plug-in-unsharp-mask 1 img drw 3.0 1.0 0)
(file-jpeg-save 1 img drw filename filename 1.0 0 0 1 "" 1 1 0 1)
(gimp-image-delete img) 
(gimp-quit 1)
)
\end{verbatim}

Осталось полученный Scheme скрипт завернуть в shell скрипт, который в цикле будет подставлять имя файла и запускать GIMP.
Казалось бы что всё. А где оптимизация? Зачем запускать GIMP для каждого изображения, это же не нужные нам тормоза! 

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

\begin{verbatim}
#!/bin/sh
# Scheme скрипт
script="
(let ((filelist '( `echo *[jpg,JPG]` )) (workpath \"$PWD/\"))
(mapcar (lambda (filename) 
(let* ((fullpath (string-append workpath filename)) 
(img (car (gimp-file-load 1 fullpath fullpath))) 
(drw (car (gimp-image-active-drawable img))))
(plug-in-unsharp-mask 1 img drw 3.0 1.0 0)
(file-jpeg-save 1 img drw fullpath fullpath 1.0 0 0 1 \"\" 1 1 0 1)
(gimp-image-delete img) 
)) filelist
)
(gimp-quit 1)
)"
#
Запуск gimp с пониженным приоритетом
nice -n 20 gimp -i -s -b "$script"
\end{verbatim}

Помните! Я показал Вам дверь, войти Вы должны сами...

\end{document}

Check Also

В королевстве PWN. Препарируем классику переполнения буфера в современных условиях

Сколько раз и в каких только контекстах не писали об уязвимости переполнения буфера! Однак…

Оставить мнение