DeepSkyStackerの改造その2

お盆は実家に帰省しましたが、満月直後でもあり撮影機材を持ち帰らなかったので、結構時間に余裕がありました。その時間を利用して、前回「DeepSkyStackerの改造」というタイトルで投稿した記事の続きを記載しました。

r77-maabow.hatenablog.com

内容は、「Dead pixel mapによるホットピクセル除去機能の追加」に関する具体的な処理についてです。長文になりますが、興味のある方はご覧ください。

DeepSkyStacker(DSS)のホットピクセル/コールドピクセル除去

追加した処理は、ホットピクセル/コールドピクセルの判定以外は元々DSSにある処理を流用しているだけなので、最初にDSSで行われている処理について説明したいと思います。なお、コールドピクセルはクールピクセルと呼ばれることが多いですが、DSSではコールドピクセルと表記されているのでこの記事ではそのままコールドピクセルと記載します。

Cosmetic画面の処理

まずは、Cosmetic画面の設定により行われる処理の説明です。
この処理は、ホットピクセルとコールドピクセル個別に設定を行うことができます。パラメータはフィルターサイズと閾値の2つです。これらがどう使われているか、ホットピクセル除去の事例(誤検出の発生理由が分かり易い様に誤検出した事例)を使って説明します。また私はカラーカメラ使っていて、フィルターサイズ=1、閾値=95%と設定して使っているので、説明もカメラはカラー、パラメータはこの数値を使います。

Cosmeticの設定画面: 左はオリジナル、右は日本語化したもの
(赤枠は中間画像の保存を指定するチェックボックス

上の画像の一番下にあるチェックボックスをONにすると、検出されたホットピクセルを白、コールドピクセルを黒、それ以外をグレーとした画像(マップ)を保存できます。下の画像の左はそのマップの一部を拡大表示したものです。右は同じ位置のライトフレームを同じサイズだけ切り出したものです。

保存された中間画像(左)と元画像(右): ホットピクセルと検出された同一箇所をクロップ

ご覧の通り、星がホットピクセルとして検出してしまっています。

検出処理は、着目する画素の周囲±フィルターサイズの範囲の画素値を使って行われます。但し、ベイヤー配列などのカラーカメラの場合は、指定したフィルターサイズは内部で2倍されます。この事例はカラーカメラの事例なので、フィルターサイズは2として処理されます。
上の画像から、検出処理で使われる画素(検出されたホットピクセルと周囲±フィルター数(=2)の合計25画素)の画素値を取り出した数値は以下の通りです。

DSSの内部では画素値を64bitの浮動小数で保持しています。フォーマットが16bit整数の場合は、画素値を256で割り、更に255.0以上をクリップしています。中心の画素値は16bit整数では65535と飽和している状態でした。それを256で割っているので255.996、255.0以上をクリップしているので保持している値は255.0です。

ホットピクセルの判定処理ですが、着目画素の画素値を pValue、周囲±フィルターサイズ内の同じ色フィルターの画素値のメディアン値(中央値)を pMedian としたとき、以下の式で判定されます(“^2”は2乗)。

(pValue^2 – pMedian^2)/pValue^2 > 指定された閾値

上の事例でいうと、pValue=255.0、pMedian=57.0117(9個の赤いセルの中央値)なので、上式の左辺は0.95001となり、指定した95%をギリギリ超えています。

一方、コールドピクセルの判定は、以下の様になっています。

(pMedian ^2 – pValue ^2)/pMedian ^2 > 指定された閾値

この様に検出されたホットピクセルとコールドピクセルは、ホットピクセルを白=255, コールドピクセルを黒=50、それ以外をグレー=128としたマップ(画像データ)として内部に保持されます(Cosmetic画面下側のチェックボックスONで出力される中間画像はこのデータを出力したものです)。

補完処理は、そのマップを見て白(>200)または黒(<100)の時に補完処理が呼び出される様になっています。補完のアルゴリズムメディアンフィルターによる補完とガウシアンフィルターによる補完の2つありますが、説明が長くなるのでここではメディアンフィルターによる補完について説明します。
補完値は、検出と同様に画素の周囲±フィルターサイズの範囲の画素値を使って以下の様に求められます(フィルターサイズがカラーカメラの場合2倍されるのも、検出処理と同様です)。

補完値 = 該当画素(ホットピクセル/コールドピクセル)を除く
      同じ色フィルターの画素値のメディアン値(中央値)

上の事例ですと、該当画素を除く8つの画素値のメディアン値なので、56.7031(偶数個中の中央値なので57.0117と56.3945の平均値)となります。

処理前の画像と処理後の画像を並べると以下の様になります。

ホットピクセルと判定された画素の補完結果(左:補完前、右:補完後)

ホットピクセル/コールドピクセルは周りに比べて1画素だけ明るい/暗いという状態になるので、この処理で正しく判定されるものも多いと思います。しかし上記事例から分かる様に、星像が鋭い場合などはホットピクセルの誤判定が起きやすくなります。また、周りの画素のメディアン値との(2乗の)比で判定しているので、閾値を小さく設定したりフィルターサイズを大きく設定したりすると、誤判定になる確率は高くなります。

また、カラーカメラの場合は同じ色フィルターの画素値を判定に使うため、フィルターサイズを指定値の2倍にしています。従って、カラーカメラの場合はモノクロの場合より誤判定の確立は高くなります。もしかすると判定処理に関してはカラーカメラでもフィルターサイズを2倍せず、違う色フィルターの画素も含めてメディアン値を求めた方が良いのかもしれません(補完については、同じ色フィルターの画素値で求める必要があるので2倍は必要)。

あと、誤判定が起きたからと言って必ずしも最終画像に大きな影響を与えるとは限りません。私の場合はAZ-GTiの経緯台モードとスカイメモSを使いますが、何れもある程度の追尾エラーがある(特にAZ-GTiは視野回転がある)ため、1ショットごとに星が動いていきます。これによりフレームごとに画素値の分布が変わるため、毎回誤判定される訳ではありません。そのため、この事例の最終画像では特に変な星像にはなりませんでした(以下の画像参照)。

処理後の画像(中央部分をトリミング): 2022/2/24 23:52@自宅ベランダ
FMA135, AZ-GTi, ASI533MCP -10°C Gain300 16s×180, UV/IRカットフィルター使用
DSS, Starnet2, GIMPなどで処理。

とは言え、パラメータの設定によっては最終画像がおかしくなりますし、誤判定が少ない最適なパラメータが一意的に決められるというものでもあません。Cosmetic画面の右下にある「Test on first frame...」を押すと、最初のフレームを使ってホットピクセル/コールドピクセルが何個検出されたかを確認できますが、誤検出の個数が分かるわけではありません。

説明が長くなりましたが、以上の様にCosmetic画面の処理は、設定するパラメータだけでなく撮影した画像の状況によっても誤判定のリスクが変わります。マニュアルに「結果の画像が大幅に変わる可能性があるため、注意して使用してください。」と記載されている通り、パラメータの設定には注意が必要です。

ダーク画面の処理

DSSには、ダークフレームを使ったホットピクセル除去の処理があります。単純なダーク減算でもホットピクセルは消えます。但し、ダーク撮影時のホットピクセルの値が引き算されスタックにより目立たなくなるだけなので、軽減されると言った方が正しいと思います。しかし、この処理はダーク画像からホットピクセルを検出しCosmeticの処理と同じ様に補完して除去するという処理です。なお、この処理はホットピクセルに対してのみ作用します。また、この処理はライトフレームに対するダーク/フラット等の前処理の最後に行われ、Cosmeticの処理より前に行われます。

設定は、ダーク設定画面の下の方にあるチェックボックス「Hot Pixels detection and removal」で行います。

Dark設定画面: 左はオリジナル、右は日本語化したもの

検出処理は、まず(マスター)ダーク全体の中央値と標準偏差を求めます。そして以下の式でホットピクセルを判定しています。

着目画素の値  > (中央値)+16 ×(標準偏差

補完処理は、Cosmeticでフィルターサイズを1と指定したときと同じ処理です。

私はこれをダークからホットピクセルを除去する処理だとずっと勘違いしていました。Cosmeticを使ってホットピクセルを除去する場合、ダークにホットピクセルが残っていると更にホットピクセルの値が減算されてしまうので、ことを避けるためにこの機能を使ってマスターダークからホットピクセル除去しておく必要があると勘違いしていたわけです(この処理とCosmeticの処理の順番も理解していませんでした)。今回、改造や日本語化する中でマニュアルをちゃんと読んだりソースを確認したりしたので、やっと理解できました。誤解していても特に悪影響はありませんでしたが、ソフトに限らず子供の頃からマニュアルを読まずに使う悪い癖がなかなか治りません。

話が少し逸れましたが、この処理で基本的には(目立つ)ホットピクセルは除去できるはずです。しかしダークを使い回していると同じ条件のライトフレームであっても除去できないホットピクセルが出てしまう場合があります。カメラの経時劣化なのかは分かりませんが、そうなってしまうと再度ダークを取り直さないといけません。そのような場合にCosmeticの機能を使うことになりますが、前述の様に使用するにあたっては注意が必要になります。

Dead Pixel Mapによるホットピクセル/コールドピクセル除去(追加した処理)

以上の様に、ダークによるホットピクセル除去では除去しきれないホットピクセルがあり、Cosmeticの処理では誤検出により星像に(多少の)影響があるという状況を何とかしたいと思い、この機能を追加しました。
処理の概要としては、ホットピクセルまたはコールドピクセルを白い点として直接Dead Pixel Mapで指定し、その画素値を周りの画素値から補完します。

検出の処理はDead Pixel Map上の画素値が200より大きいとき、ホットピクセルまたはコールドピクセルとして判定するようにしました。
私はDead Pixel MapをGIMPで作成していて、ホットピクセルまたはコールドピクセルを白=255とした8bitのPNGファイルを作成していますが、DSSでは16bit整数や32bit浮動小数の画像であっても最大値を255.0にした浮動小数で保持します。そのため、Dead Pixel Mapの形式はDSSでサポートされている形式であれば(8bitでなくても)良く、カラーフォーマットであってもGreenの値で上記の判定を行います。

補完処理は、フィルターサイズを1としてCosmeticのメディアンフィルターの補完処理を呼び出す様にしました(Cosmetic画面の設定値を使うのではなく、ソース内で固定)。

Dead Pixel Mapによる処理はCosmeticの処理の置き換えという位置づけにしていて、Dead Pixel Mapがメイン画面のリストに設定されると、Cosmetic画面の指定より優先して処理されるようにしています(Cosmeticの処理は行われない)。また、Dead Pixel Mapが複数設定されていた場合は、最初に設定されているマップしか使いません。
DSSは、ライトフレームにゲインや露光時間が違うものが含まれていると、それに合うダークフレームを自動的に関連付けて同じゲイン/露光時間のもの同士を振り分けてからスタック処理が行われます(どの様なアルゴリズムで振り分けているかまでは理解できていません)。

本来は、ゲインや温度が違えばDead Pixel Mapも違うはずなので、上図の様に近い条件のライトフレームと関連付けて処理できるようにした方が良いはずです。自動でなくても、ライトフレームはグループに分けて設定できるので、そのグループごとに違うDead Pixel Mapが指定できる様にした方が良いのですが、コーディングが大変そうなので現時点では非対応にしてあります(今後の課題です)。

まとめ

今回は改造のメイン部分でしたが、改造してから数か月経っていたので中身をだいぶ忘れていました。帰省中に纏まった時間が取れたので、思い出しながら記載することができました。ソースコードフローチャートなどは載せませんでしたが、これくらい書いておけば自分用の記録としては十分です。
一方、これを読まれた方には参考になったのか若干気になるところです。少なくとも、Cosmeticの処理を使っておかしくなった経験がある方が「こういう事だったのか」と思って頂ければ幸いです。

あと、最近はPixInsightなど他のソフトが主流でDSSを使っている方はそんなに多くはないと思っていたので、とりあえず自分が使うことを前提として改造していました。しかし、前回の記事は(数少ない)私の記事の中では最もアクセス数が多く、Twitterでも「日本語化だけでもニーズがあるのでは?」というコメントを頂きました。予想以上に興味をお持ちの方がいらっしゃる様なので、確かにニーズはあるのかも?とちょっと認識を改めました。
本来であればDSSの本家の方にソースをフィードバックして日本語もサポート対象にしてもらうのが筋だとは思いますが、私は英語が全くダメなのでそういう対応はできそうにありません。DSSのライセンス上は改造だけでなく配布もOKの様なので、動作保証は出来ませんがそれでも良いということであれば配布も考えたいと思います。とりあえず、今のところはDSSで使われているオープンソースのライブラリについてもライセンスを確認しているところです。(折しも「PixInsightの使い方[基本編]」が出版されたこのタイミングで、使ってみたいという方はどれだけ居るのだろうか?)