にほんブログ村 写真ブログ デジタル写真へ
にほんブログ村のランキングに参加中です

ExifTool : Lightroomが露出補正値のフィルタリングをしてくれないから・・・

2014年07月26日 00:00

untitled

untitled

Pentax K-5, SMC P55mmF1.8

※ブログに視覚要素を加えるlightboxを導入しています。上記画像をクリックすると少し大きな画像をポップアップして見る事が出来、暗くなった部分をクリックするか、画像下部のCloseをクリックすると元に戻ります。



今日は長いぞ~(笑)。何せ、Exiftoolを完璧に把握して書いている訳じゃなく、書いていながら疑問がどんどん湧いてきちゃうし、書きながら学んでいるから・・・。

検索機能(フィルタ機能と行った方が正しいかな)が半端じゃないLightroomなのに何故か不可能なのが露出補正値で写真を見つけ出す事。例えば「-1EVの露出補正を掛けている写真」、こんなのが探せない。検索項目に露出補正値がないんだ。

そこでExiftoolで表示されるタグを調べていたら、ExposureCompensationってのがあったじゃないの!。ならば簡単だ!、と思ったら、どうも上手く行かない。かなり試行錯誤・・・。長い時間Exiftoolのサイトを見続けやっと判った。ポイントはオプションの-n。これをかまさないと露出補正値を数値として扱ってくれない。

exiftool -n -if "$ExposureCompensation <= -1" -RawFileName -ExposureCompensation -T *.xmp

-Tオプションは該当タグの値をテーブル風に表示せよ、なるオプションみたい。だから上は判るでしょ?。-1以上(以下と言うべきか?)露出補正しているファイル名とその値を表示しなさいよ!、ってコマンドになる。

下は+0.5、もしくは-0.5の露出補正をしている写真のファイル名と補正値を、そして表示する。

exiftool -n -if "$ExposureCompensation == 0.5 || $ExposureCompensation==-0.5" -RawFileName -ExposureCompensation -T *.xmp

次は-2/3EVのレンズの絞りにF4.5を採用した写真のファイル名と絞り、露出補正値を表示する。

exiftool -n -if "$ExposureCompensation == -0.67 && $FNumber == 4.5" -RawFileName -FNumber -ExposureCompensation -T *.xmp

※exiftoolって様々なプラットフォームで使えるような仕様みたいで、-ifオプションで使える演算子は基本的にperl準拠のようで、"||"、"&&"、"or"、"and"と何でも使えた

いやぁ、個人的にこの露出補正値を見つけ出すコマンドは非常に使い勝手がある!。そもそも何故Lightroomで露出補正値のフィルタリングが出来ないのか?。

と・・・、今日はここで終えちゃっても良かっただけど、ここで終わらせると、このexiftoolネタ、4回どころが倍の8回くらいになりそうで、流石に16日間もパソコン関連のネタってのも・・・、そう思って、次回ネタにする予定だったネタを下に紹介しちゃおう!。

前々回の記事でWidnwos用のexiftoolは、0x5c問題で日本語のフォルダ、ファイルには対応していないと書いた。調べてみるとこの0x5cで引っかかるのが次。

― ソ Ы Ⅸ 噂 浬 欺 圭 構 蚕 十 申 曾 箪 貼 能 表 暴 予 禄 兔 喀 媾 彌 拿 杤 歃 濬 畚 秉 綵 臀 藹 觸 軆 鐔 饅 鷭 偆 砡 纊 犾

※他にも異なるコードで誤認識する文字が100個くらいあったような気がする

だから十条、十二社、飯能で引っかかるし、伊予や庚申塚でも駄目だったりする。exiftool.exeをコマンドラインから起動する時は、そのフォルダに移動してからだから、ファイル名が半角英数字だったら運用上問題はないのだが、仮にファイル名に漢字を使う事も将来あるんじゃねぇか?、なんて考えると夜も眠れない(笑)。

そこでPerlで書かれたオリジナルのExiftoolを覗いてみた。提供されているのはIamge::Exiftoolと言うクラス(Perlではモジュールと言うのかな?)。だからそのモジュールを利用する為のラッパープログラムを作る必要がある。まぁプログラマーだったらさほど難しくはない。

うちのパソコン環境にはWidnwos用のActivePerlがインストールされているが、せっかくなので本家perlを使おうと、cygwinのperlをインストールした。

ここからが問題。Eixftoolは外部モジュールなのでどうやってperlに組み込むのか?。色々とネットを見ていたらCPANからインストールしろなんて書かれていたけど、それよりもIamge::Exiftoolに梱包されているREADMEに書かれているまま操作した方が失敗しない。

インストールするには別途makeが必要との事でcygwinにmakeを追加し、あとはREADMEに書かれているまま、cygwinのシェルからコマンドラインに打ち込めば勝手にインストールしてくれた。それとexiftoo.exeとそっくりに動作するperlで書かれたexiftoolスクリプトも自動で/usr/local/binにインストールされていた。

うん?、これを使えば上に書いた0x5c問題なんて関係ないんじゃん!。果たしてその通りだった。Windowsのシェル(cmd.exeやnyaos等)からexiftool.exeを使うと、十条、十二社、飯能と言った文字が入っているフォルダを誤認識したが、cygwinのbashやtcshでperlで書かれたexiftoolを使えば、全く問題なく動作してくれちゃった。なんだよ~、最初からcygwinを使えば良かったじゃないか!。

exiftool -s -RawFileName -LensID /f/temp/photo/十条、飯能、伊予、庚申塚/pef/*.xmp

こんなのもperlスクリプトのexiftoolとUTF-8に対応しているcygwinのコンソールはこけない!。こうなるとわざわざ自分でperlスクリプトを書く必要がなくなるが、せっかくperlやImage::Exiftoolをインストールしたのだから、やらないなんて勿体無い!。

まず、cygwin上でperlを動かす場合のお約束。これ頭の片隅にあって良かった~。と言うのもcygwinのコンソールは今も書いた通り、文字コードがUTF-8。だからperlのスクリプトを書く際、SJISでなく、BOM無しのUTF-8で保存しないと標準入出力で日本語が文字化けする。また、改行コードはLF、これをエディターで設定しないとエライコッチャ。


#!/usr/bin/perl

use Image::ExifTool;

my $exifTool = new Image::ExifTool;
my $dstLens = "Sigma 17-70mmF2.8-4 DC Macro OS HSM";

foreach (@ARGV) {
  $exifTool->ImageInfo($_);

  if ($exifTool->GetValue("LensID") =~ /Sigma 17-70/) {
    $exifTool->SetNewValue("Lens", $dstLens);
    $exifTool->SetNewValue("LensModel",  $dstLens);
    $exifTool->WriteInfo($_);
  }
}


プログラミング、そしてperlをご存じない方は上のソース、暗号にしか見えないと思う。簡単に説明すると@ARGVは引数、ここでは「*.xmp」を想定し、それを展開したものが入っている。100個あったら100個の拡張子がxmpのファイル名が格納されていて、foreachで1つずつ読んで行くとその1つずつのファイル名が$_に格納される。あとは英語みたいなものだから、、、

もしLensIDがSigma 17-70mmだったらLens、LensModelにそれぞれSigma 17-70mmF2.8-4 DC Macro OS HSMとセットして、ファイルを上書きしなさいよ!、と言う事。

これを/usr/local/binにset_s1770.plと保存し、xmpファイルのあるフォルダに移動。

s1770set.pl *.xmp

これだけであとはLightroomでxmpを再読み込みすれば「不明」となっていた写真全てSigma 17-70mmF2.8-4 DC Macro OS HSMと表示される。勿論、SJISでこけちゃうフォルダ名が引数に入っていても、、、

s17070se.pl /f/temp/photo/十条、飯能、伊予、庚申塚/pef/*.xmp

全く問題なく、あっさりと変換してくれた。嬉しいじゃないの!。

うん、perlでこんなに簡単にラッパーが書けるのなら、モノホンのexiftoolのクラスライブラリを利用したC++のラッパーを作るのも簡単だろうね。これは後日!。

ところでLensIDに記録されている内容は「Sigma 17-70mmF2.8-4.0 DC Macro OS HSM」であり、これと同じ情報をLensとLensModelに登録したいのなら・・・。


#!/usr/bin/perl

use Image::ExifTool;

my $exifTool = new Image::ExifTool;
my $i = 0;

foreach (@ARGV) {
  $exifTool->ImageInfo($_);

  my $lensId = $exifTool->GetValue("LensID");
  if ($lensId =~ /Sigma 17-70mm/) {
    $exifTool->SetNewValue("Lens", $lensId);
    $exifTool->SetNewValue("LensModel", $lensId);
    $exifTool->WriteInfo($_);
    print "$_ update!\n";
    $i++;
  }
}

print "\n$i files update!\n\\n";


こうした方が間違いはないのだろう。あと、実行したら終わるまで何の表示もされないのは不安なので、変更毎に標準出力にファイル名を、そして変更したファイルを数を記する事にした。

ではSigma APO70-300mmのLensIDはどうなっているのか。調べてみよう。

exiftool -s -LensID hogehoge.xmp

「Sigma 18-200mm F3.5-6.3 DC or Sigma DL Zoom 75-300mm F4-5.6 or Sigma 70-300mm F4-5.6 Macro or Sigma 55-200mm F4-5.6 DC」

へぇ、なるほどねぇ、こうやって記録されているんだ。こうなるとLens、LensModelにLensIDをそのまま登録しちゃ駄目なんだな。

※オプションの-sは正式なタグネームを表示させるオプションで、例えば-sを付けないと表示は「Lens ID」となるが、-sを付けると「LensID」となる。exiftool.exeを利用したり、Perlスクリプト作成において正しいタグネームを調べたい時に使うと良い。

ついでにexiftoolのオプションは上手く作られていて、タグ名に正規表現が使えちゃう。だから、、、

exiftool -s '-Len.*' hogehoge.xmp

なんてするとLensModel、Lens、LensManualIDistortionAmout、LensProfileEnable、LensProfileSetup、LensID・・・と幾つも参照出来ちゃう。

下はSigma APO70-300mmF4.-5.6用のスクリプト。


#!/usr/bin/perl

use Image::ExifTool;

my $exifTool = new Image::ExifTool;
my $dstLens = "Sigma APO 70-300mm F4-5.6 DG MACRO";
my $i = 0;

foreach (@ARGV) {
  $exifTool->ImageInfo($_);

  if ($exifTool->GetValue("LensID") =~ /Sigma.*70-300/) {
    $exifTool->SetNewValue("Lens", $dstLens;);
    $exifTool->SetNewValue("LensModel", $dstLens;
    $exifTool->WriteInfo($_);
    print "$_ update!\n";
    $i++;
  }
}

print "\n$i files update!\n\n";


もう1つの懸案事項。電子接点のないKマウントレンズを使った時・・・。前回の記事で解決しているが、せっかくだからPerlでも作っちゃおう。

この場合、問題はどんなレンズでも「K or M Lens」となり、しかもLens IDすら同一になってしまう。だから同じ日に何本もそんなレンズを使っていて、それが1つのフォルダに収められていたら、ユニークなキーがないからど~にもならない。

ちゃんと焦点距離入力をしていれば「LenSIDがK or M lensで焦点距離が24mmなら・・・」、そんな手法が取れるが、私のように24mmレンズで撮っていたのに正しい焦点距離入力を忘れ、間違えて50mmや135mmになっていたりすると駄目なんだな。それ以前に50mmレンズを何本も使っていたら、全ての焦点距離が50mmだから・・・。

でも幸いに電子接点のないレンズを使った写真にはLightroomのキーワードタグにレンズ名を加えていた。これがそれこそキーになってくれる。調べてみるとSubject(XMP:Subject)タグと、HierarchicalSubjectタグ(XMP:HierarchicalSubject)の2つにそれが記録されていた。だから、、、


#!/usr/bin/perl

use Image::ExifTool;

my $exifTool = new Image::ExifTool;
my $dstLens = "smc PENTAX 24mmF2.8";
my $i = 0;

foreach (@ARGV) {
  $exifTool->ImageInfo($_);

  if ($exifTool->GetValue("Subject") =~ /24mmF2.8/) {
    $exifTool->SetNewValue("Lens", $dstLens);
    $exifTool->SetNewValue("LensModel", $dstLens);
    $exifTool->WriteInfo($_);
    print "$_ update!\n";
    $i++;
  }
}

print "\n$i files update!\n\n";


これをレンズ毎に作ってやって実行すれば簡単に書き換えられる。

今回紹介したPerlのスクリプトでなくてもファイル名に漢字を使っていなければカレントフォルダに移動し、exiftoo.exeを起動するだけで全く同じ事が出来、それをバッチファイルに記述しておけば何度もキーパンチせずとも良い。

ただ、実際の写真が結構深い階層にあるのでいちいちにそこまで降りるのにパス、ファイル名補完機能があるとは言え、「pushd なんちゃら」と打ち込んでフォルダ移動するのが面倒だから、今回紹介しているperlスクリプトは遥かに楽。

と言うよりも、すでにSigma 17-70mm、APO70-300mmを使用した全てのpef(xmp)ファイルのEXIFの書き換えをこのネタを書いている時点で終了しちゃった(笑)。思った以上に早く済んだ。明日からはK or Mレンズの書き換え作業だが、これは数が少ないので1時間足らずで終わるだろう。

さて、上のスクリプトは電子接点のないレンズが「K or M Lens」と表示されちゃうので、正しいレンズ名をセットさせる。でも前回の記事の通り、撮影時、カメラに誤った焦点距離を入力している写真が仰山ある。24mで撮影しているのに135mmになっていたりと・・・。

だからPerlのスクリプトで両方を一気に修正したい。xmpファイル内にはFocalLength、FocalLengthIn35mmFormatなるタグがあるが、これを修正しても、どうやらLightroomでは本体PEFののFocalLength、FocalLengthIn35mmFormatの値を採用しちゃう。つまり、xmp、PEFの両方(もしくはPEFだけ)を修正しないとならない。

「xmpファイルのLightroomで入力したコメントの24mmF2.8を探し、レンズ名の"K or M Lens"を"24mmF2.8"に変更。そして同名のPEFファイルの焦点距離、35mm換算焦点距離をそれぞれ"24"、"36"とセットする」

日本語にするととっても簡単。でもPerlの基本は、与えられたファイルを1つずつ、そして1行ずつ読み込んで処理をするのだから、xmpファイルとpefファイルを同時に読み込んでなんちゃらするにはロジックが難しいような・・・。

でもちょっと書いてみた(Perlに精通している訳じゃないので、ソースがごちゃっとしているのはご勘弁!)。


#!/usr/bin/perl

use Image::ExifTool;
use File::Basename;

my $pefExif = new Image::ExifTool;
my $xmpExif = new Image::ExifTool;

my $dstLens = 'SMC P24mmF2.8';
my $keyWard = '24mmF2.8';
my $FocalLength = '24';
my $FocalLengthIn35mmFormat = '36';

my ($dirName, $baseName, $ext) = "";
my ($xmpBaseName, $pefBaseName, $pefFullName) = "";

my $cnt = 0;

foreach (@ARGV) {
  ($baseName, $dirName, $ext) = fileparse($_, '\..*$');

  if ($ext =~ /PEF/) {
    $pefBaseName = $baseName;
    $pefFullName = $_;
    $pefExif->ImageInfo($_);
  }
	
  if($ext =~ /xmp/ and $baseName == $pefBaseName) {
    $xmpExif->ImageInfo($_);

    if ($xmpExif->GetValue('Subject') =~ /$keyWard/) {
      $xmpExif->SetNewValue('Lens', $dstLens);
      $xmpExif->SetNewValue('LensModel', $dstLens);
      $xmpExif->SetNewValue('FocalLength', $FocalLength);
      $xmpExif->SetNewValue('FocalLengthIn35mmFormat', $FocalLengthIn35mmFormat);
      $xmpExif->WriteInfo($_);

      $pefExif->SetNewValue('FocalLength', $FocalLength);
      $pefExif->SetNewValue('FocalLengthIn35mmFormat', $FocalLengthIn35mmFormat);
      $pefExif->WriteInfo($pefFullName);

      print "$_ update!\n";
      print "$pefFullName update!\n";
	
      $cnt += 2;
    }
  }
}

print "\n$cnt files update!\n\n";


これは個人用に書いたスクリプトだから特定の条件でしか動作しない。起動する時の引数は「*.*」。xmpとPEFファイルの両方を読み込み処理をさせる。要するに対象フォルダの中にはxmpとPEFしかなく、両者はペアになっている、それが前提。勿論、JPGは論外。

そしてcygwinの場合、*.*を展開にしてくれるのはシェル。調べてみるとアルファベット順にソートして展開してくれている。hoge.xmpとhoge.pefと2つのファイルがあったら必ずhoge.pef、hoge.xmpの順で読み込まれる。

だからワイルドカードが常にアルファベット順に展開しているのも条件。そうでないOSやシェル、はたまたperlだとこれは使えない。

※シェルがソートしてくれなかったらPerlの内部関数のsortを使えば良いのか?

SMCM200mmF4が使われている写真には(LightroomのコメントにSMCM200mmF4と記述されていたら)、上のソースの変数の初期値を・・・、

my $dstLens = 'SMC M200mmF4';
my $keyWard = '200mmF4';
my $FocalLength = '200';
my $FocalLengthIn35mmFormat = '306';

と書き直すだけ。

何かもっと良い方法がありそうだけど、こういう必要に迫れて作る個人用スクリプトは凝ったら疲れるだけ(笑)。これを見た方が「オレならこうするぜ!」と、効率良くかつ美しいスクリプトを書いてくれれば・・・。とりあえずうちの環境では問題なく動作して、思った通りの結果を得られているから満足。

複雑なキーで該当するファイルのみを変更したいなんて場合、exiftool.exeの-ifオプションは面倒なる。例えば、何月何日の撮影で、simgaレンズを使っていて、かつ焦点距離が35mm以上で・・・、ここまで複数のフィルタリングをするならPerlで書いた方が簡単だろう。Perlもオブジェクト指向言語に変化してから、非常に扱いやすくなった。

汎用的に、*.*の引数だけでなく、レンズ名、キーワード(Lightroomのキーワードタグの中身)、焦点距離、35mm換算焦点距離の4つを設けるのも良いだろう。そうすればレンズ毎のPerlのソースは不要になる。


if ($#ARGV < 5) {
  print "Usage : set_k_or_m.pl [lensname] [keyword] [focallength] [35mm frocallength] [*.*]\n";
  print "\tex) set_k_or_m.pl \"SMC P24mmF2.8\" \"24mmF2.8\" \"24\" \"36\" *.*\n\n";
  exit(0);
}

my $dstLens = $ARGV[0];
my $keyWord = $ARGV[1];
my $FocalLength = $ARGV[2];
my $FocalLengthIn35mmFormat = $ARGV[3];

shift(@ARGV); shift(@ARGV); shift(@ARGV); shift[@ARGV];

my ($dirName, $baseName, $ext) = "";
my ($xmpBaseName, $pefBaseName, $pefFullName) = "";

my $cnt = 0;

foreach (@ARGV) {
    ($baseName, $dirName, $ext) = fileparse($_, '\..*$');
          :
          :
          :
          :


そしてこれをset_k_or_m_lens.plで保存したら、実行は次の通り。

set_k_or_m_lens.pl 'SMC P24mmF2.8' 24mmF2.8 24 36 *.*

まぁこれで使いやすくなったが、いかんせんロジックが駄目、自分ながら糞だと思う。

今回のロジックだとフォルダ内にある全ての(関係の無い)PEFファイルもなめていくから、ファイルが100個くらいなら我慢出来るものの、それを超えたらイライラしてくる。って事ですぐに作り直し。もう完成しているけど、流石にネタが長過ぎちゃうから次回!(なんたって今日のネタ、元々は3日分だったのだから(笑))。

うちはHOWTOブログじゃない、あくまでも日記!。今日みたいに失敗した内容だって記するぜぇ!。


にほんブログ村 写真ブログ デジタル写真へ
にほんブログ村のランキングに参加中です



コメント

    コメントの投稿

    (コメント編集・削除に必要)
    (管理者にだけ表示を許可する)