После покупки сканера для фотопленок и его применения у меня возникло несколько сложностей:1. переименование последовательности фотографий в случае сканирования в обратной последовательности
2. автоматическое переворачивание фотографий относительно какой-то оси. Если фотография вверх ногами, то это можно разобрать сразу,
но если у изображений перепутаны стороны, то такое бросается в глаза далеко не сразу. Например, только по одной-двум фотографиям из пленки.
3. автоматическая обработка мелких дефектов в конвейере, с наиболее полным задействованием ядер процессора
Для реверсивной последовательности в именах файлов и изменения её в нормальную я написал этот скрипт
#!/bin/bash
#
# reversenames.sh
#
# маска для моих файлов после сканирования
DEFMASK="*.JPG"
REVLIST=$(ls -r *.JPG)
REVARRAY=($REVLIST)
# только до половины списка обрабатывать
len=`expr ${#REVARRAY[@]} / 2`
echo "$len"
j=0
for i in $DEFMASK; do
if [ ! -e $i ]; then
echo "Error: current directory must contain files with the mask $MASK"
echo
exit 1
fi
echo "rename $i -> ${REVARRAY[j]}"
mv $i $i.old
mv ${REVARRAY[j]} $i
mv $i.old ${REVARRAY[j]}
j=`expr $j + 1`
if [ $j -eq $len ]; then
break
fi
done
echo "ready"
Для случая, когда нужно поменять стороны фотографий местами я дополнил скрипт, найденный в интернете для кручения фотографий на определённый угол. Вот расширенная версия этого скрипта:
#!/bin/bash
#
# jpegsrotate.sh
#
if [ -z `which jpegtran` ]; then
usage
echo "Error: jpegtran is needed"
echo
exit 1
fi
shopt -s extglob
DEFMASK="*.JPG"
DEFEVENMASK="*[02468].JPG"
DEFODDMASK="*[13579].JPG"
FLIPMASK=""
DEFDEG=270
function usage() {
echo
echo "usage:"
echo "$0"
echo " rotates files with the mask $DEFMASK by $DEFDEG degrees clockwise"
echo "$0 --even"
echo " rotates even files with the mask $DEFEVENMASK by 180 degrees"
echo "$0 --odd"
echo " rotates odd files with the mask $DEFODDMASK by 180 degrees"
echo "$0 --params \"REGEXP\" (90|180|270)"
echo " rotates files with the mask REGEXP by the given aspect ratio clockwise"
echo "$0 --flip [h|v]"
echo " flip pictures horizontal or vertical"
echo
}
if [ "$1" == "--even" ]; then
MASK=$DEFEVENMASK
DEG=180
elif [ "$1" == "--odd" ]; then
MASK=$DEFODDMASK
DEG=180
elif [ "$1" == "--flip" ]; then
MASK=$DEFMASK
if [ "$2" == "v" ]; then
FLIPMASK="vertical"
else
FLIPMASK="horizontal"
fi
elif [ "$1" == "--params" ]; then
if [ -n "$2" -a -n "$3" ]; then
MASK=$2
DEG=$3
else
usage
exit 1
fi
elif [ -n "$1" ]; then
usage
exit 1
else
MASK=$DEFMASK
DEG=$DEFDEG
fi
echo $MASK
for i in $MASK; do
if [ ! -e $i ]; then
usage
echo "Error: current directory must contain files with the mask $MASK"
echo
exit 1
fi
echo "$i"
if [ "$1" == "--flip" ]; then
jpegtran -flip $FLIPMASK $i > $i.flipped
mv $i.flipped $i
else
jpegtran -rotate $DEG $i > $i.rotated
mv $i.rotated $i
fi
done
Скрипт нужно вызвать следующим образом (флипнуть по горизонтали):
./jpegsrotate.sh --flip h
Как видно, необходимо наличие программы jpegtran.
Третий пункт с автоматической обработкой самый интересный. Для этих целей я выбрал программу ImageMagick не по каким-то причинам. Позже я испробую подобную обработку с GIMP, но в этот раз я использовал достаточно интересный ресурс со скриптами для обработки изображений http://www.fmwconcepts.com/imagemagick с кучей примеров и результатов обработки при вызове скриптов с определёнными параметрами.
Затем я использовал готовый скрипт для циклической обработки графических файлов в директории. Скрипт взял [[http://habrahabr.ru/blogs/linux/82394/ здесь]].
Но несколько его видоизменил для использования нескольких ядер процессора.
#!/bin/bash
#проверяем, установлен ли convert
convert > /dev/null
if [ $? -ne 0 ] ; then
echo "Error: convert is needed, it's a part of ImageMagick" ;
fi;
DIR=$1;
# велосипед, убирающий "/" в конце
if [ -z $1 ]; then $DIR=`pwd`;
else
TEMP=`pwd`;
cd $DIR; TEMP2=`pwd`;
cd $TEMP;
DIR=$TEMP2;
echo $TEMP2;
fi;
#наши старые файлы копируем в DIR.orig
echo $DIR
mkdir $DIR/orig;
for i in `ls $DIR/*.JPG`;
do
cp $i orig/;
done;
ERR=0;
CPUS=1;
echo "Start in " $DIR
files=$(ls $DIR/*.JPG)
list=($files)
len=${#list[@]}
echo $len
for(( i=0; i<$len ; i=i+$CPUS))
do
for(( j=0; j<$CPUS ; j++))
do
if [ ${list[i+j]} ]; then
./denoise -f 2 -s "20x20+203+152" ${list[i+j]} ${list[i+j]}.den.jpg && ./isonoise -r 5 ${list[i+j]}.den.jpg ${list[i+j]}.iso.jpg &
fi
done;
for job in `jobs -p`
do
echo $job
wait $job || let "FAIL+=1"
done;
if [ $? -eq 0 ]; then
echo "denoise, isonoise successfully ;) next step";
else ERR=$[$ERR+1]; #считаем ошибки
fi;
for(( j=0; j<$CPUS ; j++))
do
if [ ${list[i+j]} ]; then
rm ${list[i+j]}.den.jpg
fi
done;
done;
CPUS=2;
echo "Start in brightness calibration"
for(( i=0; i<$len ; i=i+$CPUS))
do
for(( j=0; j<$CPUS ; j++))
do
if [ ${list[i+j]} ]; then
./omnistretch -m HSB -ab 1 -s 1.5 ${list[i+j]}.iso.jpg ${list[i+j]} &
fi
done;
for job in `jobs -p`
do
echo $job
wait $job || let "FAIL+=1"
done;
if [ $? -eq 0 ]; then
echo "omnistretch successfully ;) next step";
else ERR=$[$ERR+1]; #считаем ошибки
fi;
for(( j=0; j<$CPUS ; j++))
do
if [ ${list[i+j]} ]; then
rm ${list[i+j]}.iso.jpg
fi
done;
done;
if [ $ERR -eq 0 ]; then
echo "Job done!";
else echo "Job done with some errors.";
fi;
echo "You can find your old files in $DIR.orig"
#end
Вызываем скрипт с параметром "." для актуального директория, где находятся наши фотографии.
В первом цикле я использовал вызов двух скриптов
./denoise -f 2 -s "20x20+203+152" ${list[i+j]} ${list[i+j]}.den.jpg \
&& ./isonoise -r 5 ${list[i+j]}.den.jpg ${list[i+j]}.iso.jpg
для последовательного профильтровывания небольших дефектов. В этих скриптах задействованы оба ядра, поэтому для цикла обработки использовалась переменная CPUS=1, если в вашем процессоре четыре ядра, то можете увеличить значение в два раза и т.д.
Для цикла обработки яркости
./omnistretch -m HSB -ab 1 -s 1.5 ${list[i+j]}.iso.jpg ${list[i+j]} &
уже использовалось вызов двух скриптов одновременно, т.к. при вызове одного используется только одно ядро. Поэтому значению переменной CPUS перед циклом было присвоено 2.
Конечно, скрипт можно несколько улучшить, встроив автоматическое распознание количества ядер в системе. Но это уже - по желанию.
URL:
Обсуждается: http://www.opennet.dev/tips/info/2498.shtml