24 апреля 2011 г.

Автоматическая обработка фотографий на Linux

После покупки сканера для фотоплёнок и его применения у меня возникло 
несколько сложностей:

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 с кучей примеров и результатов 
обработки при вызове скриптов с определёнными параметрами.

Затем я использовал готовый скрипт для циклической обработки графических
файлов в директории. Скрипт взял здесь.

Но несколько его видоизменил для использования нескольких ядер процессора.

    #!/bin/bash 
    # loop_for_fotos.sh
    #
    #проверяем, установлен ли 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.

Конечно, скрипт можно несколько улучшить, встроив автоматическое распознание
количества ядер в системе. Но это уже - по желанию.

Комментариев нет:

Отправить комментарий