
「比較明合成」という画像編集技法が、主に天体写真や夜景写真の
分野で流行していると聞く。
これは、2枚あるいは、それ以上の枚数の画像を読み込み、
それらの画像の各点(座標)を比較して、輝度の明るい点(ドット)を
採用するという、ごくシンプルな画像処理の手法である。
「コンポジット」とも言われているみたいであるが、コンポジット
というのは、1つは、昔からTVなどの画像分野で信号の形式に
使われている技術用語であり、また、広く一般的には「合成」を
表す英語であるから、この「比較明合成」を指して、イコール
「コンポジット」と呼ぶのは相当無理があると思う。
本来の「技術用語」を知らずして好き勝手に名前をつける事には
全く賛同できないのだ。(注:「トンネル効果」も同様)
その用語の存在は無視して、以降「比較明合成」で通す事にする。
さて、比較明合成自体は単純な処理であり、それができるフリー
ソフトがいくつか出ているようだ、しかし、それをダウンロード
して使うだけはあまりに普通すぎて、記事のネタにはならないし、
単に「流行り物を追いかけているだけ」にもなってしまう。
私がやりたいのは、単に輝度を比較するだけではなく、他の手法、
例えば、彩度を比較するとか、そういう事も試してみたいのだ。
そうなれば、これは「勉強」あるいは「研究」に成り得る。
じゃあ、他の方法、あるいはソフトはあるか?
この処理には、レイヤー演算を必要とするので、あまりそれが
できる汎用画像編集ソフトは多くはない、PhotoShopなどでは
勿論出来るだろうが、それも普通すぎて面白くない。
あるいは、GIMPというフリーソフトが様々なレイヤー演算が可能だ、
比較合成も2タイプ出来る模様だが、このソフトも一般的すぎるし、
そもそも比較や足し算とか引き算とかではなく、もう少し複雑な
または変わった演算や処理内容がやってみたい訳だ。
・・え~い、面倒だ、自分で作ってしまえ!
ということで、まずは演算用のプログラムを、Windows上で
Visual C++ で書く。

こちらがVisual Studio だ、まあ、これは開発環境と言うものの、
普通にテキストエディターであり、コンソールアプリケーション
(DOS窓で動く)を制作する上では、昔のC言語のコマンドライン
コンパイラと大きく変わるものでは無い。
で、とりあえず2枚の画像で処理できるように作ろう、
それ以上画像の枚数が多くなっても、計算時間あるいは試行錯誤
の時間が長くなって無駄になりそうな気がする。
で、「比較明合成」だけだったら、演算部そのものは超簡単だ。
まず、輝度を計算するには、入力画像のR(赤),G(緑),,B(青)
の各プレーン(色の層)を、以下の計算式で輝度に変換する。
Y(輝度)=0.299xR + 0.587xG + 0.114xB
ちなみに、画像をグレースケール化する場合等も、明度を使ったり、
彩度をゼロにするのではなく、上の式で輝度値を得るのがベターだ。
で、実際には、double(倍精度浮動小数点)形式で計算するのは
演算時間がかかるので、R,G,Bの各1byteを、unsigned longに
変換してから、整数のままで計算処理を行う、
Y=306*(unsigned long)R+601*(unsigned long)G+
117*(unsigned long)B+512
この式の方が画素数が大きくなった場合等で計算時間が短縮できる。
後は、2つの画像の各々ピクセルの輝度の数値を比較して、
大きい方を採用し、出力画像用バッファに、入力画像のいずれかの
RGB値を埋め込む。
これを画素数分だけ計算すれば良い。C/C++言語においては、
演算部分そのものは短く書けば10数行程度以内に収まるであろう。
たったこれだけだ・・
しかし、これだけでは面白くない、ついでといってはなんだが、
他の計算モードを追加してみよう。
まずは、同じ計算方法で暗い方の画素を採用する「比較暗合成」
処理を追加する。
3つ目は、RGB値を、いったんHSV(色相、彩度、輝度)に変換後、
その彩度(色の濃さ)を比較する「比較高彩度合成」の処理。
さらに、そのHSVの彩度と輝度に着目し、彩度と輝度のいずれかの
高いものを選択して合成する「比較明高彩度合成」の処理、の、
合計4モードを作ってみよう。
なお、HSV変換部を除き、いずれも10数行くらいのプログラミング
である。
(こういう風に、合成には色々な方法論がある訳なので、単純な
比較明合成だけを、合成を意味する「コンポジット」と、断定
して呼んではならないと思う)
で、C/C++では、標準的な関数ではJPEGやBITMAPの画像データ
の読み書きはできない。ここは外部ライブラリを使うか、あるいは
自分で1からプログラムを書かなければならない。
外部ライブラリやフリーのソースは使いたくない。エラー処理等が
不完全な上、下手をすると空間フィルター処理等では端の画素が
未計算であったりするからだ、つまり、それらはちゃんど動作する
保証が無く、あまり信用できない。
幸い、以前から使っている、自前でC言語で1から作った
各種画像の読み書きルーチンがあるので、それを利用しよう。
あと問題点は、2枚の画像の縦横比(アスペクト)が異なったり、
2枚の画像の各々の画素数(解像度)が異なったりする場合だ。
ここも、自動アスペクト調整(自動トリミング)、自動解像度調整
(カラーでのLanczos3 アルゴリズムでの画像縮小)のプログラム
を追加しよう(このあたりも、自分で作ったものがある)
結局、新たなプログラミングは100行程度なのに、プログラム全体
のサイズは、37KByte (37,000文字)にも膨れ上がってしまった。
けど、自分で作ってあった既存のソースコードを組み合わせただけ
なので、プログラミング時間はさほどかかっていない、3時間位だ。
ビルド(コンパイル)も1発で通った、では、早速、デバッグを
兼ねて「比較明合成」を試してみよう。
まずは適当な画像(写真)を用意して・・

幸いに自分で撮った写真はいくらでもある、何十万枚もあって
選びきれないので、ミラーレス・マニアックスの記事用のを
再利用しよう(汗)
あとは、夜景などがあればいいな・・星空とかの写真だと、殆どが
暗部で、星の部分が輝度が高ので、そこが合成されるであろう。
しかし、そんな写真が無い・・
天文写真とかは、趣味ではないのだ(汗)
しょうがない、画像編集ソフトを使って自分で星空写真を作って
しまえ。

まあ、こんなものであろう、長時間露光で丸く動いているような
星空の写真は、作るのが面倒だったのでやめた(汗)
けど、その代わりに、おまけとして「流星」を3つほど入れて
おいた(笑)
後は、雷とかも良いかも知れない、いくつか編集で作っておこう。

あ、そうだ、花火の写真があるではないか・・・
昨年末のATCでの花火ショーを撮ったのが確かあったはず・・

う~ん、空中でポンと開くような花火の写真の方が合成には使い
勝手が良さそうなんだけどなあ・・・
昔撮ったのが、いくらでもあったと思うが、探すのが面倒だ。
それに、たいてい縦位置撮影なので、使えそうも無い。
まあ、こんなもので良いか。
あとは風景とか、昆虫とか、色々用意して・・
じゃあ、C++のソースコードからビルドしたEXEを、
Visual Studio上でデバッグモードで動かしてみよう。

ほう、出来た模様だ、これが「比較明合成」の処理結果か。
では、デバッグモードをやめて、リリースモードで再ビルドし、
単体のEXEを作っておく。
しかし、EXEに対して、2つのファイル名を指定する方法が面倒だ、
その方法は、プログラミングにおいて以下の7通りが考えられる。
1:ソースコードの中に、直接、読み込むファイル名を書き込む
2:EXEを実行する際のコマンドライン引数とする
3:ファイル名入りのバッチファイルを書いて、それでEXEを動かす
4:テキストデータファイルに、ファイル名を書き込んでおき、
それをEXEから読み込んで実行する
5:固定フォルダーを用意し、そこに予め処理する画像を入れておく
6:任意のフォルダーを指定し、そこに2枚の処理するべき画像を
予め入れておく
7:所定のフォルダー内に、大量の画像を入れておき、その中から
2枚の画像を選ぶ組み合わせを全て抽出し、計算する。
これらの内、7は論外であろう、計算時間がかかりすぎる。
5と6は、画像を移動したりコピーしたりする手間が大変だ。
結局、1~4が、オーソゾックスながら、妥当な処理方法であろう。
しかし、1~4のどのケースにおいてもファイル名を全部入力
しなければならない事は変わらない、様々な画像の組み合わせを
試す際に大変だ。
で、画像を置いてあるディレクトリが、EXE実行用の
ワークディレクトリと場所が大きく異なったりする場合は、
相対パスでは面倒で追えないので、絶対パスで画像ファイル名を
全て書かなければならない。
これは数十文字もあるので入力が極めて面倒臭い。
まあ、そんなこんなで、EXEはコマンドライン引数で動かすように
作っておいたが、やはりファイル名の入力が大変だ。
え~い、面倒だ、GUI(Graphical User Interface)を
作ってしまえ。
GUIは、Visual C#という言語で作ってみよう。
これは、C++と同じVisual Studioの環境で作れるのだが、
言語が異なると開発環境の画面もずいぶんと変わる。
C#のエディター画面では、まずはグライフィカルな入力作業となる、
テキストボックス、ボタンや画像表示といったパーツを、ペタペタと
貼っていき、それをクリックすると、どんな処理をするか、という
ソースコードを順次書き込んでいく。プログラミングが極めて
容易な言語で、近年のWindows GUIアプリケーション開発では、
このC#言語が主流な模様だ。

「フォーム」という白紙の上に、画面をデザインしていく。
画面を綺麗に並べようとすると、プロパティというところの
数値を直接色々と入力するので、ちょっと面倒だが、まあ、
それくらいはやむを得ない。
GUIが出来たら、計算部は、先ほどC++で作ったEXEが既にある。
C#から、外部のC++のEXEを実行させる事は可能だ。
多少の「お作法」のソースの書き方を理解しておけば問題は無い。
2枚の画像をGUIで選んで、それらのファイル名をEXEに渡す、
加えて4種類の計算モードも選べて、それもEXEに渡せば良い。
その受け渡しには、3種類の方法がある、
1:テキスト等でデータファイルを吐き出し、EXE側でそれを読む
2:EXEのコマントライン引数にする
3:EXEをやめてDLLにする(関数の引数渡しとする)
まあ、ここは2の方法が簡便であろう。
ということで、C#を使ってGUIができた、ここは2時間くらいで完成。
しかし、プログラミングという作業もずいぶん楽になったものだ、
最初は、20年ほど前のVisual Basicの時代あたりからか?
その頃から、こういう風なイベント・ドリブンのプログラミングが
開発環境を用いて簡便にできるようになったし、それ以降の
ネット時代においては、わからないプログラミングは、検索すれば、
サンプルの公開ソースコードがいくらでも見つかる、
つまり、プログラミングの技術や知識や経験なんか、何もなくても、
プログラムが書けてしまうわけだ。
なお、「ネット時代」と言ったのは、インターネットのみならず、
「.NET Framework」というものも関係してるダブルミーニング。
.NET とは、一種の巨大なライブラリであり、Windows OSの一部
でもある。これの機能を使えば、たいていの事は自分で1から
プログラミングしなくても、実現できてしまう。
逆に言えば、こういう開発では安直すぎて、近年の若手エンジニア
における、モノを考える力や創造する力が低下してきている、
という危惧もあるのだが・・
加えて注意点をあげれば、公開ソースコードは、わざとわかりにくい
書き方をしている事が殆どであり、可読性が悪い。
まあ、それをわざわざ公開するということは情報提供者の
自己アピールの意味もあるので、やむをえないであろう。
ただ、プログラムが正しければそれでも良いが、バグがあったり
した場合は可読性の悪いソースコードでは、かなりやっかいな
状態になる。
それに、大抵の場合、その手の公開ソースはエラー耐性が強くない、
想定外の入力値等が発生した場合には、計算途中で思いもよらぬ
結果になったりして、メモリーを壊したり暴走したり停止したり
してしまう。
具体例では、ゼロのゼロ割りが発生したりすると、これは非数
(数値では無い)となって、その後の計算の続行がかなり困難になる。
そういう異常なデータを入れるのが悪い、と開発者は言うだろうが、
どんな状況でも安定して動作する事は、優れたプログラムの
必須条件だ。
こうしたエラー耐性、別の言い方をすれば「ロバスト」である事に
対して殆ど考慮されていないソースコードを、そのまま業務目的
等に使うのは危険極まりない。
まあ、今回の比較明合成ソフトのように完全な趣味の範囲で使うの
では暴走しようが落ちようが構わないのではあるが、
そうであっても、やっかいなバグなどでは、OSを破壊してしまう
ような危険性もあるので、他人の作ったコードを使う際には
要注意だ。(というか、本来は使わない方が良い。私もそういう
意味で、外部ライブラリを使わない事等も含め、殆ど全て自前で
書いてしまう。中身が全部わかっていないと安心できないからだ)
----
さて、作ったGUIを動かす。 おっと!早速バグが発生・・
計算部の外部EXEの実行中に、途中で止まってしまう(汗)
原因を調べると、GUIのC#側で画像を表示している際は、
その画像はC#側がハンドルとして掴んでいるので、C++のEXE側
では、同じ画像を読み込んで計算する事が出来ないのだ。
これは以前も同じミスをやった事があったので、すぐ原因がわかった。
では、計算直前に一旦表示画像をディスポーズ(破棄)して、
計算終了後に再度GUI側に表示させる事にしよう。
これでGUIも計算部も、全て上手く動作した。
そうしたら、これを使って、画像を簡便に読み込んで「比較明合成」
を色々と試してみよう。

ちなみに、画像のアスペクト(縦横比)は4:3で統一する事とした。
ミラーレスのμ4/3機や、コンパクト機でよく使われる縦横比率
であり、PCの世界ではクラッシックなIBM-PCの時代から
「VGAサイズ」画面の比率として一般的だ。
だが、銀塩(フィルム)&デジタル一眼、ミラーレス機の一部の
写真は、概ね3:2比率であるので、それらが入力された場合は
自動トリミングの関数が効いて、画像の左右が適宜カットされる
ように作った。
計算は意外に時間がかかる、自作Lanczos3関数による、
高精度な自動縮小ルーチンが時間を喰っている模様だ。
出力解像度は1600x1200の約200万画素を基準としているが、
入力解像度が大きいと(400万~最大1600万画素)、自動縮小する
ようにしているのであるが、画素数が大きければ大きいほど
縮小に時間がかかってしまう。
これだったら、最初から小さ目の画像を入力にした方が
(あるいは他のソフトで縮小しておいた方が)、試行錯誤の際に
都度、計算時間をかけずに済むので良いかも知れない。

こちらは、ヘリの写真に稲妻(CG)を組み合わせて「比較明合成」
処理を行った、無難な合成結果だが、当たり前すぎて面白くない。
もっと変わった組み合わせ(や計算方法)は無いものか?

トンボの写真と、ぐるぐる風CGの組み合わせ、
こちらも「比較明合成」のモードだ、どうも、これ以外の
「比較暗合成」「比較高彩度合成」などは、写真をかなり上手く
選ばないと良い結果が得られない事や、合成結果が予測しずらい
点が問題なようだ。

それにしても、良い組み合わせを試行錯誤で探すのが面倒だ、
いちいちC++のEXEが起動して計算をする事も、少々うっとうしく
なってきた。
これだったら、計算部を含め、最初からC#で全て書いておけば
よかった。
C#では、.NET Framework を利用してJPEGやBITMAPの
読み書きも自在だ、ただ、計算部はもうC++で作って完成して
しまっているので、いまさらC#に移植する気にはならない。

最初は面白かったのだが、膨大な組み合わせの試行錯誤の
繰り返しだ、だんだん飽きてきて、嫌になってきた(汗)
それに、細かいところの合成がうまくいかない。

これだったら、たとえば、画面の一部しか合成しないとか・・
まあ、それだと選択範囲を細かく決めるGUIを作るのも、
操作するのも面倒なので、
元の画像全体の輝度をオフセット量を決めてシフトするとか、
元画像にグラデーション風の階調(輝度)補正をかける機能を
追加するとか、が必要かも知れない。
それらは技術的に出来ない事はなく、計算部とGUI部の両方を
修正すれば、多分1~2時間ほどで出来るとは思うが、
そこまでしても、結局の所、試行錯誤の繰り返しという点は
変わらないであろう。相当暇が無いと出来ない作業だ。
で、そもそも画像編集における合成の作業は、本来は
「切り出し作業」を、いかに丁寧に行うか、と、
その事につきると思う。
例えば、人物を切り抜いて背景に貼りつける、このような合成作業
は、商業写真、ポスター、商用チラシ、WEB制作、プレゼン等、
あらゆるビジネスシーンで使われるのであるが、この作業が
非常に面倒なのだ。
具体的には、マウスの操作で人物の髪の毛の部分などを丁寧に
切り抜くのは至難の業だ。高性能編集ソフトでは、自動切抜き機能
を備えている場合もあるが、この精度があまり良く無い。完全に
綺麗に切り抜くには、絶対的に手作業での追加処理が必要になる。
「人物等を綺麗に自動で切り抜けたら」と昔から思っていて、
そういう事ができるソフトや技術をずっとウォッチしていたが、
良いものが出てこない。
いっそ自分で作るか?とも思ってもみたが、輝度、彩度、あるいは
テクスチャー(模様とかの意味)解析とか、ウォーターシェッド法
の画像処理とか、何を使ったとしても上手く切り出せそうもない。
某大学の画像処理に詳しい教授に相談したのだが、
「完全に自動では無理だろう」という答えだった。
まあ、私もそう思う。その教授まではいかないが、私も画像処理に
ついては知らない訳ではない。
---
余談だが、以前、どこかの少し怪しげなベンチャー企業の人と
話をしていて、私が「画像処理ができる」と言ったら、
その企業の社長さんから
「ウチのスタッフも、PhotoShopとかは使える」と言い返された。
どうやら、その社長さんは、作業としての「画像編集」と、
アルゴリズムの創造・開発を含めた「画像処理」の区別がついて
いない模様だった。
「画像編集」は、あくまで作業であり、あえて言えば「技能」だ。
「画像処理」は、開発あるいは研究であり、こちらは「技術」だ。
両者は全く別ものである、まあ、両方できればそれに越した事は
無いが・・
さて、人物等の自動切り出しの画像処理アルゴリズムの話だが、
例えば、ディープラーニング(深層学習)系の人工知能的処理では
どうか?とも思ったが、大量の良質なサンプルを用意する時点で
手間が掛かり過ぎるであろうし、出来上がったアルゴリズムを
人間が修正する事も出来ずに、改良の度に再学習となるのであれば、
正直な話、そんなブラックボックス的ソフトは、出来たとしても
あまり嬉しく無い。
というか、出来たソフトを時間をかけて熟成させ、精度や完成度を
向上させる事が困難であるならば、そこがネックになりそうだ。
まあ、結局、本来必要な本格的な「合成処理」を編集や自動処理で
行うのは困難であるという事になる。
そういう状況だからこそ、「比較明合成」のような簡易的な処理が
流行するのかもしれない。まともに合成編集をやるのは大変すぎるし
そういうのは、仕事でもなければ、やる気は起こらないであろう。
だとすると、趣味の世界で、楽しみながら試行錯誤する、と言うには
まあ、「比較明合成」くらいが適しているのかもしれない。
このソフトは合計5時間くらいで作り上げたものだ、さらに手を
入れれば、もっと使いやすいものになるかも知れないのだが、
でも、それをやっても、結局は「お遊び」の範囲にしかならない事が、
色々と試してみて、わかってきた。
ならばもう、これ以上ソフトに手間をかける事はぜず、テキトーに
遊んでみる事にしよう。

こちらの建物の画像は、CGではなく実写だ。
ただし、撮影時にオリジナルで設定したエフェクトを掛けている。
星野写真(CG)との比較明合成の結果は、建物の前に星が出てきて、
ちょっと失敗だ。
こういう場合に画面下部に向かってグラデーションで輝度を変化
させる機能が欲しくなるが、それはあえてGUI上で操作しなくても
最初からそういう編集を加えた画像を用意しておけば良いであろう。
でも、合成結果としてシュールすぎる、世の終わりみたいだ(汗)
これは無かった事として、別の画像、そう、花火が良いな、それと
合成してみよう。

まあ、こんなものか・・・
ちなみに、こちらは、比較明合成ではなく、演算モード4の
HSV変換による「比較明高彩度合成」を行っている。

1日ほど、色々いじくって試してみたが、結局飽きてしまった(汗)
何が問題か?、と言えば、この画像処理はシンプルすぎるので、
細かい部分までには手が行き届かず、もしそれを、きちんとやろう
とするならば、本来の「合成編集」と同様の手作業の手間を
加えないとならない、という事だ。
私としては、プログラムを作っている時の方が面白かった。
ならば、より複雑な画像処理アルゴリズムを考えて、それを
プログラミングして試してみる方が、出来上がったソフトで
受動的に試行錯誤を繰り返すよりも面白いかも知れない。
あるいは、入力する画像を、非常に個性的なものをチョイスする
というのも面白いかもしれない。
カメラマニアである事を活かすのであれば、あらゆる撮影機材
は揃っているし、変な写真はいくらでも撮れる(笑)
例えば、本記事の冒頭の写真は「宙玉」(そらたま)という
機材を使用して撮影した実写写真にCGを組み合わせたものだ。
まあ、実写によるエフェクト写真とCGとの組み合わせが結構
効果的なようにも思えている。
すなわち「合成」ならば何でも出来る、という訳ではなく、
まずはベースとなる写真のバリエーションが撮れる技術が無くては
ならない。これはまあ、基本であろう。
そして、勿論、何と何を組み合わせたら、どういう結果になるか?
というのを想像しながら、それをできるだけ無駄の無い試行錯誤を
するセンスが必要になるだろう。
これは料理と同じで、Aという素材とBという素材を組み合わせたら
どんな味になるかが想像できなければ、料理は上達しない。
レシピを見て、ただ、その通りに作っているだけでは、
料理が出来る、とは言えないのだ。
そういえば、ベテランのバーテンダーなんかもそうだ、作った
カクテルの味見は(お客さんの前では)ちょっと格好悪いので、
スピリッツやリキュールの組み合わせ比率から、出来上がりの味を
完全に想像できる。
まあ、そういう技術や経験やセンスが、何をするにしても必要だ
という事か・・
本ソフトは、気が向いたら、いずれまた続きをやってみようか・・