省型旧形国電の残影を求めて

戦前型旧形国電および鉄道と変褪色フィルム写真を中心とした写真補正編集の話題を扱います。他のサイトでは得られない、筆者独自開発の写真補正ツールや補正技法についても情報提供しています。写真補正技法への質問はコメント欄へどうぞ

G'MIC をアップデートしても GIMP から起動するとアップデートされていない

 先日 GIMPプラグインソフト (厳密に言うと、現在では GIMP だけでなく、商用ソフトを含む複数の画像処理ソフトのプラグインとして動く) G'MIC のアップデートインストールをして、GIMP から起動してみたところ、アップデートされないという現象に出くわしました。

 また、以前 G'MIC に AI ノイズ低減機能が搭載されてすぐに検証してみましたが、その時は Windows 上でエラーメッセージが出て実行できませんでした。

 今回調べてみたところ、結局その原因は、G'MIC のインストールフォルダ構成が変わったり、古い設定ファイルにあったようです。

 その対策ですが、一旦ユーザ設定ファイルのフォルダを改名して、GIMP をインストールしなおし、さらに最新版 G'MIC をインストールしてみたところ、正しくバージョンアップもされ、かつAI ノイズ低減ツールも稼働するようになりました。

 どうやら G'MIC の場合 C:\Users\%USERNAME%\AppData\Roaming\GIMP\2.10 (Windows の場合) を消すか、適宜改名してから、G'MIC の新バージョンをインストールする、というのが基本のようです。その下に引き継ぐべきユーザが設定したファイル (プラグインなど) があれば、改名しておいたフォルダから必要なファイルを新しい設定ファイルフォルダにコピーし直します。

 どうも設定ファイルにあるフォルダの pluginrc ファイルが悪さをしていたのではないかと思われますがはっきり分かりません。

 

----------

[参考サイト]

www.gimp-forum.net

discuss.pixls.us

OM system 150-600mm f/5-6.3 IS に関する PetaPixel レビュー

 写真機材のレビューサイト PetaPixel に OM System の 150-600mm f/5-6.3IS (フルサイズ換算 300-1200mm 相当) のレビューが出ています。レビューアーは、DP Review にいたクリス・ニコルズです。

petapixel.com

 このレンズは SigmaOEM のようで、Sigma の他社フルフレーム用 150-600mm f/5-6.3 レンズをベースに作っているようです。形態もほぼ同じと指摘しています。性能的には申し分なく、フルフレームでは問題となっていた周辺光量低下も、m 4/3 のセンサーの小ささが幸いしてほとんど見られないようです。但し 600mm 端では、絞りを F 7~ 8 に絞ったほうがより良い結果が得られると指摘しています。

 とは言え、フルフレーム用レンズの転用ですので、m 4/3 専用に設計されていればもっと小さくできたはずだと指摘しています。それでも、1日持ち運んでもさほど苦にならない大きさとは言われていますが (おそらくアメリカ人の体格基準で)。

 もう一つの問題は価格の高さです。Sigma のフルフレーム用のアメリカでの希望価格は、$1500 ドルであるのに対し、OM System のレンズの希望価格は $2700 と2倍近くになっています。この「プロ」価格と、もっと小さく作れたはずだと考えると、OM System 150-400mm f/4.5 (フルサイズ換算 300 - 800mm 相当) の方がはるかにリーズナブルであり、あまり売れないのではないかと指摘しています。

 因みに本レンズの重さは、2065g それに対し、OM System ED100-400mm F5.0-6.3 IS の方は、1120g、本レンズの国内価格は、大手量販店価格で 44万円程度ですが、100-400mm は、16~17万円前後となっています。もちろん、m 4/3 でどうしてもテレコンバーターを使わずに、フルサイズ換算 1200mm までの望遠が欲しいとなるとこれ一択になるのですが... 因みにテレコンバーターですが、ヨドバシカメラの価格だと、1.4倍の MC-14 は 27000円強で重さ 105g、2.0倍の MC-20 は42000円強という価格で、重さ 150g。一段暗くはなりますが、重量、価格面でも有利です。あとは写りの問題ですが...

 ちなみに本レンズのベースとなった Sigma の 150-600mm はキャノンEF用、ニコン F用でも、12~14万円程度です。これを APS-C で使えば、225 - 900mm 相当で使えます。また、TAMROM もほぼ同重量、同価格帯で SP 150-600mm F/5-6.3 Di VC USD G2 を出しています。さらに Canon の F200-800mm F6.3-9 IS USM (重量 2Kg強) ならやはり APS-C で使えば、300-1200mm 相当で使え、お値段は 30万円程度、また単焦点ですと Canon の RF 800mm が、13-4 万程度であり (重量は 1260g)、これを APS-C で使えば、1200mm 相当で使えます。特に最近キャノンは、手振れ補正を強化してきており、OM system に迫ってきていますので... しかしこう考えると望遠域を手軽に使うというコンセプトなら、 センサーサイズの小さい、APS-C カメラこそ手振れ補正を強化することは必要ですね。

 以上のことを考えると、価格的にはもうちょっと何とかならないものかと思います。150-400mm f/4.5 よりちょっと高いぐらいだったら、かなりキラーレンズになったでしょうに。あるいはこの値段で出すなら、m 4/3 に最適化した設計にして、1.5 Kg ぐらいの重量で出してほしいところです。m 4/3 でどうしても 1200mm まで欲しい人がしかたなく買う (買わされる) レンズというあたりかと。

 要は m 4/3 だから軽く使える、にも m 4/3 だから安く買える、にもなっていないということです。

 いま、円安で、しかも工場がことごとく海外に出てしまったこともあり、カメラの価格も上げざるを得なくなっています。その中で、Nikon などは重くて高級感のある路線を追求してそれなりに成功しているようです。ただ私などは、軽く作れるのがミラーレスの真骨頂なのに重厚長大路線を追求してどうすると思ってしまうのですが。

 しかし、m 4/3 の特性を生かすには、被写界深度の深さを活かしたマクロ域の充実か、もしくは、フルフレームよりも軽く、安く、手持ちで望遠域が使えるという方向性を強化していくしかないと思います。この点では、今までオリンパス - OM が追及してきた手振れ補正を強化する路線は正しいのですが (しかし Canon がかなり追い上げてきています)、足りないのは、鳥や動物、飛行機などに追従できる、C-AF 機能の強化です。この点では Canon に負けているようです。

 さらに、他メーカーに追随して、重厚長大高価格路線を追求するような傾向が見られるように思われますが (それなら m 4/3 を買う意味がない!) 、それだと失敗するだけだと思うのですが...

 

ART におけるカメラの標準的プロファイル データについて

f:id:yasuo_ssi:20210904211415j:plain

 ART のカメラプロファイルは、デフォルトでは、一部のカメラについてはカメラ固有の DCP プロファイルがあり、Raw ファイルを読み込んだときにそれが自動的に適用されます。これはボランティアによって作成された DCP プロファイルです。

 しかし、ボランティアによって作られた DCP プロファイルがない場合は [カメラの標準的プロファイル] が適用されます。このデータはどこに定義されているかというと、ART のインストールディレクトリにある、cammatrices.json というファイルに定義されています。このファイルを見ると、例えば以下のように定義されています (一部を抜粋)。

-------------

    {
        "make_model" : "NIKON D5200",
        "dcraw_matrix" : [8322, -3111, -1047, -6367, 14342, 2179, -988, 1638, 6394]
    },
    {
        "make_model" : "NIKON D5300",
        "dcraw_matrix" : [6988, -1384, -714, -5631, 13410, 2447, -1485, 2204, 7318]
    },
    {
        "make_model" : "NIKON D5500",
        "dcraw_matrix" : [8821, -2938, -785, -4178, 12142, 2287, -824, 1651, 6860]
    },
    {
        "make_model" : "NIKON D5600",
        "dcraw_matrix" : [8821, -2938, -785, -4178, 12142, 2287, -824, 1651, 6860]
    },
    {
        "make_model" : "NIKON D6",
        "dcraw_matrix" : [9028, -3423, -1035, -6321, 14265, 2217, -1013, 1683, 6928]
    },

-------------

 ここに、Raw ファイルに記録されているセンサーから取得したデータを適切な RGB 値に変換するために掛けるカメラマトリックスデータが定義されています。センサーの 光スペクトラム に対する感度は人間の目の感度と異なりますので、それを人間の目が見て適切になるように変換する必要があるためです。各マトリックスデータは 9 個の要素のある配列データとなっていますが、これはセンサーの RGB 3チャンネルデータに対し、 3 x 3 の配列 (マトリックス) データを掛け、変換した RGB データを得ているためと考えられます。

 これを見ると、全てのカメラで同一のマトリックスが適用されているのでなく、カメラごとに異なったマトリックスデータが適用されているのが分かります。おそらく、カメラに使われているセンサーごとに異なった値が適用されるのでしょう。従って、この値が同一のカメラ同士では同じセンサーが使われているものと考えられます。例えば、上の例だと、D5500 と D5600 は同一の値が使われていますが、これは同じセンサーを使っていると判断できます。

 ところでこの値はどこから得ているのでしょう。これについては、cammatrices.json の冒頭でこのように書かれています。

/*

Matrices extracted from the D65 ColorMatrix tag of DNG files
generated by Adobe DNG Converter

Updated on Wed Oct 16 18:58:10 2019 (with Adobe DNG converter 11.3.0.197):

 

 つまり、Adobe DNG Converter から取得されているのです。ということは、この値は、Adobe DNG Converter に付属する、Adobe Standard DCP プロファイルのD65データ (一般的なカメラ標準色温度である昼光光源に相当する6500Kでの値) と同一の値が適用されているものと思われます (なお、DCP プロファイルには、D65 と D50 [昼白色光源 5000K 相当でのデータ]の両方のデータが定義されています。D65 の方が青みが強いです)。

 なお、ART には、より詳細なデータが記された camconst.json というファイルもありますが、カメラ機種によっては、camconst.json にデータがないものもあります。一方 RawTherapee の方は camconst.json ファイルのみです。この違いは、現在の ART の方は Raw の読み込みに Libraw を使っているのに対し、RawTherapee の方は基本的に DCRaw を使っているためと思われます (以前は ART も DCRaw を使っていました)。

 ART は現在のバージョンでは camconst.json は使用せず、カスタマイズされたカメラ固有の DCP プロファイルが用意されている場合はそちらを (カメラ固有のプロファイル)、それがない場合は cammatrices.jsonマトリックスを適用しているようです。したがって ART の標準的プロファイルは、Adobe Standard (のD65データ) と同一とみなしてよいと思います。

 一方、RawTherapee の方の標準プロファイルは、camconst.json  のデータを使っており、このデータは、ボランティアによる詳細データが得られる場合は、それを、得られない場合は、DNG Converter によって得られるデータを使って作成されているようです。したがって一部カメラ機種に関しては ART とは異なります。端的に言えば、RawTherapee は、ボランティアデータがないカメラは Adobe Standard を、ボランティアデータがあるカメラはカメラ出し Jpeg の色を模しているといえます。

 ただどうせボランティアデータに一部依存するなら、ART のように、*.json ファイルに記述するカメラマトリックスデータは、DNG Converter から得ることにして、ボランティアからデータが得られる場合は、ボランティア作成の DCP ファイルからデータを得るようにし、ボランティア作成 DCP ファイルの読み込みを優先するという形の方が、管理都合上合理的かと思います。

 ちなみに Adobe Standard の DCP プロファイルは Adobe が独自に作成しているプロファイルであって、カメラメーカーが作るカメラ出し Jpeg の色合いとはまた異なります。ただ、Adobe Standard はどのカメラであっても同一の色づくりを目指したプロファイルですので、カメラの特性を殺してしまうプロファイルでもありますが、逆に言うと、同一の結果を目指す故、Adobe Standard のカメラマトリックスデータがカメラごとのセンサーの特性の違いを一番よく反映できているはずです。その意味で、これをスタートポイントに持ってくるというのは正しいと思われます。

 一方、カメラ出し Jpeg に近い色合いを目指す場合は、それでは不都合です。ボランティア作成の DCP プロファイルがないカメラに関して、カメラ出し Jpeg に近い色合いを出したい場合は、同じ Adobe DNG コンバータに付属する DNG プロファイルの中でも、Adobe Standard ではなく、Adobe がカメラ出し Jpeg をエミュレートして作ったカメラ固有プロファイルを使ってください。

 あるいは、先の例に挙げた D5500 と D5600 のように、同じセンサーを使っているカメラで、片方はボランティアが作成した DCP プロファイルがあり、もう一方はないなら、一方の DCP プロファイルをコピーし、それらを DCP プロファイルのない方のカメラ名に変えることでカメラ固有プロファイルを追加することができます。

------------

[参考記事]

yasuo-ssi.hatenablog.com

yasuo-ssi.hatenablog.com

 

 

余剰サロ85を70系用制御車に改造した クハ77003 (蔵出し画像)

 戦前形旧形国電を主として紹介してきましたが、今回は戦後製の旧形国電です。新前橋区にいたクハ77003です。本車は元々 サロ85 でしたが、80系の地方転出に伴い余剰になった サロ85 を、地方転出に伴い不足していた 70系用制御車として転用した変わり種です。新前橋区のみに配置され、両毛線を中心に一部吾妻線でも使われました。

 70系に合わせて使用するために、ご覧のように 3 扉に改造され、ジャンパケーブルも2線になっています。なお、信越線長野地区、上・信越線新潟地区、中央西線・岡多線で使われた 70系は引き通し線は横須賀線を踏襲して 3 線で使われましたが (但し新潟地区では、クハ68に関しては、正面のジャンパ栓受けは 2 栓しかありませんでした)、新前橋区では、70系と40系の混結があったためか、2 線使用でした。但しクハ77 に関しては、3本目のジャンパ栓があるのが分かります。この写真でも確認できます。改造の際、他地区への転属を考慮していたものと思われます。またこの写真では暗くて不鮮明ですが、偶奇同仕様だったようで、奇数向きにも偶数向きにも連結できるようになっていたようです。おそらく他線区への転出も考慮しての仕様だったと思われますが、結局両毛線系統を離れることはありませんでした。

クハ77003 (高シマ) 1977.5 新前橋電車区

 本車は元番号が サロ85020 でしたが、1968年10月の両毛線電化に際して、1968.9 に改造されたようです。

褪色写真のカラー修復に有効な ImageJ 用クラシック・ヒストグラム平坦化プラグイン 16bit 画像出力版

 先日、褪色フィルム画像の補正に使える ImageJ 用の古典的ヒストグラム平坦化プラグインを公開しましたが、途中で ALT キーを押さなければならないのが煩わしいというのと、32bit 画像非対応の点、ならびに 8bit 画像にそのままヒストグラム平坦化を掛けるよりは、16bit 画像に直したほうがベターではないかという点から、改訂版を作成しました。

 なおヒストグラム平坦化アルゴリズムの褪色フィルム画像のカラー修復効果については、欧米のユーザにもほとんど知られていないので (私も偶然発見しました)、GIMP の平滑化コマンドも将来的に Photoshop のように「欠点」が「改善」されて、カラー修復効果がなくされてしまうことを恐れて、このプラグインを開発しました。以前にも指摘しましたが、このカラー修復効果は、本来のこのアルゴリズムの目的 (暗部を鮮明に見せる) からは色相が変わってしまう「欠点」に過ぎませんので。なお、ImageMagick にもヒストグラム平坦化コマンドがありますが、バージョンの進化でこの特徴が「改善」されてしまったようです。

 今回の改訂版の特徴は、読み込む画像の bit 深度にかかわらず、一旦 16bit 画像に変換してプロセスを実行し、常に 16bit 画像を出力する点です。また上でも触れたように ALT キーを押す必要はありません。なお読み込みファイルを上書きしないという特徴 (最後に、元のファイル名に、"_equalized.tif" をつけた名前で実行結果を保存) はそのまま維持されています。

 コード的には、ImageJ の ContrastEnhancer API に依存するのを止め、この API のクラシックなヒストグラム平坦化アルゴリズムをそのまま Python に移植することで、ALT キーを押さなくてもクラシックなヒストグラム平坦化を実行するように変えました。一部直接 Java の 命令を叩いているところもあります。

 実は先日ヒストグラム平坦化アルゴリズムの解説を書いたのは当プラグインを書くための準備でした。

 ImageJ 版のヒストグラム平坦化プラグインを使うとGIMP に比べ次の点で有利です。

GIMP の平滑化コマンドを実行するより、特に 16bit ネイティブ画像においてより諧調のきめ細かい画像が得られる

 この特徴は、前のバージョンの ImageJ 用プラグインも同じです。また性能面でも変わりはありません。

 一方注意を要する点は、

・一般の画像処理ソフトで読み込める形式に変換するには、拙作の GIMP 用 ImageJ RGB TIFF ファイルインポートプラグインで一旦読み込んで保存しておく必要あり (もしくは手動で RGB 合成が必要)。

・ImageJ はカラーマネジメントに非対応なので、オリジナルファイルが sRGB 以外の場合、他の画像ソフトに読み込んだ際、カラープロファイルを割り当て直す必要がある*1

 この注意点も、前のバージョンと同じです。

メニュー画面

 メニュー上は histogram equalization16 と表示されます。

 因みに当プラグインヒストグラム平坦化を実行した結果と、GIMP 上で実行した結果を比較して見ます。読み込むファイルは以下のファイルです。このファイルは以前こちらの記事でサンプルとして使用しました。なおこのサンプルは赤色褪色ポジを使っていますが (手持ち画像の関係です)、他の褪色パターンでも、不均等に変褪色しているのでなければ有効です。

f:id:yasuo_ssi:20210417112011j:plain

オリジナル

 オリジナルのヒストグラムも掲げます。

上のヒストグラム

 ハイライト域を中心に、R チャンネルの値が G, B チャンネルより高めに推移しているのが分かります。

 これを変換した結果のヒストグラムIrfanView で取ってみます。なお IrfanViewヒストグラムは 16bit 画像もいったん 8bit に直してからとっていることにご注意ください。比較のため GIMP 平滑化コマンドを適用した結果もヒストグラムをとります。

プラグイン 16bit → 16bit

プラグイン 8bit → 16bit

GIMP 平滑化 16bit

GIMP 平滑化 8bit

 8bit の場合諧調のきめの細かさは、当プラグインGIMP ではあまり変わらないようですが、16bit では顕著な差があり、当プラグインの方が諧調のきめが細かく、ヒストグラムもより文字通り平坦になっています。これだけ滑らかだと本アルゴリズムの弱点であるトーンジャンプはほぼ無視できるレベルだと思います。よく分かりませんが、GIMP の平滑化コマンドの方は、16bit ファイルの場合、ヒストグラムの諧調数が ImageJ より少ないものと思われます。ImageJ を使うとひと手間増えますが、16bit ファイルの場合そのひと手間を掛ける価値は十分あると思います。逆に元ネタが Jpeg などの 8bit ファイルならそのまま GIMP 上で平滑化コマンドをかけた方が楽で効果も同じです。

 ただ実行結果の見た目はどれもあまり変わりません。ヒストグラムが結構違うのにこれはちょっと不思議です。

実行結果 当プラグイン 16bit → 16bit

 因みにこの実行結果 (16bit → 16bit) を GIMP で通常の TIFF ファイルに変換した後、ART に読み込ませ、霞除去を掛け、露出でブラックポイント補正を行っただけで以下の結果が得られました。

上のファイルを ART で編集

 このブラックポイントの調整で、上のヒストグラムの右端の山はほぼクリップされました (下図ヒストグラム参照)。

 さらに、ART のチャンネルミキサーの原色補正モードで調整を掛けると...

さらに原色補正で編集を追加

出力結果 (周辺一部トリミング)

 更に筆者がこちらのフォーラムで公開している ART 用の CTL スクリプトを使ってさらに追加編集を加えると...

再々編集出力結果

 自画自賛で恐縮ですが、これはいいですね。

 当プラグインのダウンロードはこちらから。

 なお、インストールその他については以下の前のバージョンの記事をご参照ください。

yasuo-ssi.hatenablog.com

----------------

[最近の関連記事]

yasuo-ssi.hatenablog.com

yasuo-ssi.hatenablog.com

*1:GIMP におけるカラープロファイルの割り当てに関しては、以下の記事の、3. をご覧ください。

yasuo-ssi.hatenablog.com

ヒストグラム平坦化アルゴリズムの仕組みと褪色補正

 ヒストグラム平坦化は、暗部などで細部が見えにくい場合、そのような細部をはっきり見せる目的で使われるアルゴリズムです。基本的な考え方は、通常山があるピクセル分布のヒストグラムをなるべく平坦に直すことで、見えやすくするということです。

 ただ、この平坦化を r,g,b チャンネル別々に実行すると、多くの場合色相がずれます。そのため、その色相のずれをなるべくなくそうといくつかの改良版アルゴリズムが開発されています。しかし、先日お示ししたように、この色相のずれという欠点が、じつは褪色フィルム画像の修復に役立つと指摘しておきました。本稿ではこの色相のずれを生む古典的ヒストグラム平坦化アルゴリズムがどのようなものかを、ImageJ APIソースコードを使って解説します。

 以前にも、この原理について解説したサイトを紹介しておきましたが、ここでもそのリンクを紹介しておきます。

codezine.jp

 ただ、具体的にどのようにアルゴリズムを実装しているのでしょうか?要するに、山のあるヒストグラムをなるべく平坦になるように目指して並べ替えるということを行います。

 今、8bit の画像を例えに考えてみましょう。8 bit 画像にはそれぞれのチャンネルごとに、 0 ~ 255 の 256通りの明るさのデータを取ります。ブラックポイント (最暗点) が 0, ホワイトポイント (最明点) が 255 の値を取ります。そして、0 ~ 255 までの値に対してヒストグラムを取るということは、例えば 0 の値を取るピクセルは何個、1 の値を取るピクセルは何個、2 の値を取るピクセルは何個、というようなデータが、255 の明るさまで取得されます。

 これをどうやってなるべく平坦化するのでしょうか。例えば、今画像全体に、25600 ピクセルあるとします。すると、1つの明るさ当たりの平均ピクセル数は、100ピクセルとなります。とはいえ、実際に各明るさごとに入っているピクセル数はバラバラです。これを 100 ピクセルに均すということはできません。

 そこで、ピクセル数を均さない代わりに、各明るさごとのピクセル数に応じて、明るさの階調の間隔を調整します。つまり明るさの値を変えてしまうのです。そのために、各明るさごとに、明るさが 0 をスタートポイントとしたときに累積ピクセル数を求めます。例えば明るさが 128 の場合、明るさが 0 ~ 128 までのそれぞれのピクセル数を足し合わせたものが累積ピクセル数になります。

 例えば、仮に明るさ 128 の累積ピクセル数が、12800 だったとします。次に 129 の累積ピクセル数が、12801 だとします。つまり、129の値を取るピクセルが1つしかないわけです。その場合は、129 の値を、128に変更して、128 のピクセルに合併させてしまいます。逆に、128 の累積ピクセル数が、12800 のときに、129 の累積ピクセル数が、14800 だとします。つまり平均 100 ピクセルのところを、129 の値を取るピクセルが、その 20 倍の 2000ピクセルあるということです。この場合は、129 の値をもっと明るくして、元々 128 のピクセルとの間隔を開けます。その場合は、128 の値ももっと下げる必要があるでしょう。つまり累積ピクセル数の差が少ない隣接した明るさのピクセル同士はなるべく諧調の間隔を小さくし (場合によると同じ値にして合併させ)、累積ピクセル数の差が大きいピクセル同士は、ピクセル値を変更して諧調の間隔をあけることで、なるべく全体的にヒストグラムが均されるよう目指します。 これが上のリンク先の図3 の右下のグラフです。要は明度ヒストグラムにおける或る明度区間に属するピクセルに関して、明度 0 からその区間までの累積度数を基に明度の値を割り当てなおす、ということをやっているわけです。

 では、具体的なアルゴリズムを見てみたいと思います。ImageJ の Contrast Enhanser API を取り上げます。

API の説明はこちらです。

imagej.net

ソースコードはこちらです。Java で書かれています。

imagej.net

 元々は、ImageJ のプラグインとして書かれています。このコードは、ヒストグラム平坦化だけではないので、ヒストグラム平坦化の部分のみ抜粋してみてみましょう。

 基本は equalize というユーザ定義関数ですが、同名の関数が3つあります。一つは ImagePlus (= ImageJ 上でほぼファイルに相当) を引数として取るもの、他は ImageProcessor (= ImageJ 上でファイル中の RGB データの入った実体に相当) を引数として取るものです。このうち一つは、histogram 変数が引数として指定されていない場合、それを引数として取れるようにするためのダミー的関数です。

 そして、ImagePlus を引数として取る関数から、ImageProcessor を引数として取る関数を呼び出しています。この後者がアルゴリズムの核心部分が書かれた関数です。

------------

    private void equalize(ImageProcessor ip, int histogram) {
        ip.resetRoi();
        if (ip instanceof ShortProcessor) { // Short
            max = 65535;
            range = 65535;
        } else { //bytes
            max = 255;
            range = 255;
        }
        double sum;
        sum = getWeightedValue(histogram, 0);
        for (int i=1; i<max; i++)
            sum += 2 * getWeightedValue(histogram, i);
        sum += getWeightedValue(histogram, max);
        double scale = range/sum;
        int
lut = new int[range+1];
        lut[0] = 0;
        sum = getWeightedValue(histogram, 0);
        for (int i=1; i<max; i++) {
            double delta = getWeightedValue(histogram, i);
            sum += delta;
            lut[i] = (int)Math.round(sum*scale);
            sum += delta;
        }
        lut[max] = max;
        applyTable(ip, lut);
    }

-------------------

 この equalize 関数は、ヒストグラム平坦化実行対象の imageProcessor (以下 ip と略)と、ヒストグラムデータの入った配列を引数として取ります。この関数を呼び出す前に、ip に対し、getHistogram() メソッドを適用し、ヒストグラムデータの入った histogram という配列を引数として与えます。なお、ImageJ の場合、getHistogram() メソッドは 32bit 浮動小数点画像では無効なので、8bit もしくは 16bit 画像しかこのアルゴリズムを適用できません。

 まず、もし ROI が設定されている (=範囲指定されている) 場合は、リセットし消去します。

 次に、画像が 16bit なのか 8bit なのかを判定し、16bit の場合は、明るさの最大値 (max)、およびヒストグラムの区間数 (range) に 65535 を、そうでなければ 255 を与えます。

 次にピクセルの累積数を計算するための sum という変数を初期化し、まずヒストグラムの値が 0 (ブラックポイント) に属するピクセル数を入力します。この時、getWeightedValue(histogram, 0) というユーザ定義関数を使っていますが、これは古典的アルゴリズムを使う場合は、そのまま histogram[0] のピクセル数の値を返します。なお色相の変化が起こりにくいアルゴリズムを使う場合は、上の値の平方根を取りますが、この記事の関心は、褪色の修復を可能にする古典的アルゴリズムですので、とりあえず、

 getWeightedValue(histogram, i)

と出てきたら、明度 i に属するピクセル数、つまり histogram[i] を取得するものと解釈してください。

 その後、ホワイトポイントの1歩手前まで、ピクセル数を2倍して足し合わせていきます。ホワイトポイントに関しては、2倍せず、そのままピクセル数を足します。この理由については後述しますが、基本的には、画像の総ピクセル数 x 2 の値の近似値を求めることになります。但し、2 倍することはヒストグラム平坦化アルゴリズム上必然的に必要なことではなく、いわばこのプログラムの工夫の部分です。

 その後、ヒストグラムの区間数を画像の総ピクセル数 x 2 近似値で割りますが、いわば平均値の約2倍の逆数を取ることになります。この値を scale という変数に入れます。

 次に元の画像の明るさを変換するための対照表 (Look up table = Lut) を初期化します。この対照表は配列となっており、その要素数は、明度の階調 (256 もしくは 65356) と同じです。lut[i] には明度 i のピクセルをどの明度に変換するか、この後計算した変換後の明度値を入れていきます。そしてまず lut[0] に 0 の値を入れます。これはブラックポイントのデータは明度変換を行わない (0 のまま) ということを意味します。

 再び累積値を格納する変数 sum を初期化し、ホワイトポイントの一歩手前まで、for ループで以下の作業を反復します。

 まず変数 delta に、明度 i のピクセル数を格納します。

 そして、sum にデルタを足し合わせることでそこまでのピクセル数 (x 2) の累積値を計算します。

 ここで、lut[i] の値を計算します。この値は、ここまでの累積値に scale を掛けて、整数化した値です。この scale とはいわば各区間のピクセル数平均値 (実はそれをさらに2倍していますが) の逆数です。この意味はどういうことかと考えると (以下平均値を 2 倍していることは一時的に棚上げして説明します) ... 仮に、ヒストグラムの各区間のピクセル数がすべて同じで平均値に一致すると考えましょう。仮にこの平均ピクセル数が 100 だとすると (その場合 8bit 画像なら総ピクセル数は 25600 ピクセルになる)、明度 100 の区間の場合、そこまでの累積ピクセル数は、10000 になるはずです。そこで、ピクセル数の平均値の逆数、つまり 1 / 100 を掛けて、Lut 上の変更する明度の値を求めると、100 になります。ということは、元の明度値が 100 に対するLut の値はそのまま 100、つまり元の 100 の値は変化なし、ということになります。

 ところがこの画像がシャドウ域に寄っているとします。そうだとすると、 100 の値のところの累積ピクセル数は、20000 になっているかもしれません。そこに平均値の逆数を掛けると、200 になります。つまり、100 の明度のピクセルを、200 の明度に変更するということになります。これは、シャドウ域の偏りをなるべく直すために、シャドウ域にあるピクセルを明るくするということを意味します。

 逆に、画像がハイライト域に寄っている場合は、100 の明度までの累積値が、10000 を下回る数になっているはずです。例えば、5000になっているかもしれません。それに平均値の逆数を掛けると 50 になりますので、100 の明度を 50 に直す、つまり全般的に暗くして平坦化をなるべく実現しようとする、ということです。

 このようにして、0 から当該区間までの累積度数に基づいて、当該区間の明度値を Lut を使って振りなおしていきます。

 ただ、このコードでは scale に平均値の逆数ではなく平均値の2倍の逆数を取っています。これは lut の値を計算した後さらに、また delta 値を累積値に加算しているためです。これは値を移動する場合でもなるべく区間の中間値に変更させようという意図 (工夫) があるためだと思います。ですので scale は平均値の2倍の逆数を取るのです。また同様の意図から、scale 値を計算するときの sum を計算するときに、最初のブラックポイントと最後のホワイトポイントに関しては、ピクセル数を 2 倍せずに加算しています。

 そして最後にこうやって作成した lut を ip に適用して画像を変換します。

 これを、R, G, B 3チャンネルに対して実行しますので、各区間に入るピクセルの頻度は異なるものの、ある特定の明度まで (例えば 0 〜 100) の累積頻度は、多少のずれはあるものの概ね揃うことになります。結果として、R, G, B の各ヒストグラムは、全く同じになるわけではありませんが、概ね似た形になります。これは褪色補正の基本原理に合致しますので、褪色補正効果が現れる、ということになります。

 なお、ここでヒストグラムの形をある程度揃えたとしても、しっかり R, G, B の違いが残っている、ということが重要で、著しく褪色が進んだ画像の場合は R, G, B の違いがほとんどなくなりほぼモノクロ画像になる場合があります。この場合は色情報が失われたということを意味しますので、着色以外に修復手段がないということになります。

 一方、「改良」版のヒストグラム平坦化は、なるべく R, G, B の差を維持したまま (つまり色を変化させないまま)、ヒストグラムの平坦化を行おうとしますので、全く褪色補正効果が現れません。但し、単純に暗い部分をはっきり見せる、という目的のためには、色相が変わらない (R, G, B 差が維持されたままの) 方が好都合です。Photoshop はおそらくこちらの「改良」版のヒストグラム平坦化を実装しているものと思われますので、Photoshop では褪色補正効果がないのです。また、ImageMagick も最近のバージョンでは「改良」版を実装しています。

 なお、褪色画像に対して、画像によっては非常に効果的な修復効果が得られますが、その理由の一つには、Lut を使って画像の値を変換しているということがあると思います。それにより他の方法 (例えばトーンカーブを使うなど) で変換するよりも大胆な画像変換が可能になるからです。

 また、このアルゴリズムは褪色がある程度進んだ画像では有効ですが、褪色があまり進んでいない画像に適用すると結構色がおかしくなります。褪色が軽度の場合は別の補正手段を使った方が良いでしょう。

 なお、以上から明らかなように、このアルゴリズムは諧調併合やトーンジャンプが必然的に起こります。そこで、オリジナルが 16bit 画像であると、元々の諧調間隔が狭い分、ヒストグラム平坦化の結果もおおむね滑らかになりますので、トーンジャンプについても問題にならないレベルにとどまります。従ってこのアルゴリズムを使って、補正を行うつもりなら、なるべくフィルムは 16bit でスキャンして保存することが望ましいことになります。

-----------

 なお、褪色補正には色相のシフトを回避するアルゴリズムの「改良」はむしろ不都合で意味がありませんが、余談として、この「改良」について触れたいと思います。ImageJ のこのプログラムの「改良」版アルゴリズムでは、累積ピクセル数の平方根を取ることで色相のシフトを軽減するようになっています。しかし、他に L*a*b* や HSL, LCh に変換して L 値にのみヒストグラム平坦化を適用することで色相のシフトを回避するアルゴリズムを採用しているケースもあるようです。この辺りはプログラムによってどのように実装するかで結果が微妙に異なります。

-----------

[関連サイト]

yasuo-ssi.hatenablog.com

yasuo-ssi.hatenablog.com

yasuo-ssi.hatenablog.com

yasuo-ssi.hatenablog.com

【緊急!】GIMP Scripts サイトが 5/1 に閉鎖予定

 以前、GIMP 用のスクリプトを配布するサイト GIMP Scripts を紹介しましたが、5/1 限りで閉鎖との予告が出ています。もし必要なスクリプトをダウンロードする必要がある場合は、至急ダウンロードすることをお勧めします。

www.gimpscripts.net

 もちろん、スクリプトによっては GIMP Scripts でなくてもダウンロードできるものもありますが...

 例えば PSPI の 1.07 はこちらからしかダウンロードできないと思います。