PJSR (PixInsight Script) コーディングTips

目次

  1. 1. 前置き
  2. 2. GUI とか
  3. 3. Image, View, ImageWindow
  4. 4. Image の演算
  5. 5. 2022.02.20 追記 engine 部分の記述位置

前置き

あぷらなーと氏発案の「クールファイル補正法」を行う PixInsight スクリプトを書いてみました.スクリプトの導入方法や使い方の詳細は,本件言い出しっぺのだいこもん氏の記事をご覧ください.
GitHub はこちら.バグなどを見つけた方は Pull Request を出すか Issue にスレ立てをお願いいたします.
本記事では,PixInsight スクリプト(PJSR)を書く上で気づいたことを短くまとめておきます.これから PJSR を触る人の参考になると良いかなと思います.

GUI とか

PJSR には未だドキュメントがなく,正直とっつきにくい印象を受けます.基本的には PI のObject Explorer で型や名前を見たり,既存のスクリプトを読んだりして理解していくことになるかと思います.
GUI については,以下の Youtube の動画が参考になるようですが,正直 Sizer の概念など,完全に理解しきれていない部分もあります.

Image, View, ImageWindow

PJSR で画像処理スクリプトを書く上で触れる概念として Image, View, ImageWindow があるようです.Image < View < ImageWindow の順で大きなオブジェクトであり,View は image (Image型,read-only) を,ImageWindow は mainView (View型,read-only) と currentView (View型,read-only でない) の2つをプロパティオブジェクトとしてもっています.currentView は画面表示のために使う View なので,オリジナルのデータに処理を施す場合は使いません.
ファイルから開く場合は,ImageWindow でとりあえず開くっぽいです.

1
var imageWindow = ImageWindow.open(filePath)[0];

こんな感じ,何故か配列で返ってくるようで先頭を取り出すとうまくいきます.
PI でこの imageWindow を見るには,

1
imageWindow.show();

とするだけです.よゆーですね.
イメージデータにアクセスするのも簡単です.

1
var image = imageWindow.mainView.image;

ここまではいいのですが,問題は Image から ImageWindow を作り出すことです.
画像の演算自体は Image オブジェクトでやります.クールファイル補正法ではスタック画像(Image オブジェクト)が新しく生成されるわけですから,これをなんとか ImageWindow にしたい.しかし,ImageWindow.mainView.image は read-only です.単純な代入などによる改変はうまくいきません.
そこで,以下のようなコードで解決しました.

1
2
3
4
5
6
var someImage = Image(width, height);
/* some process to someImage */
var someImageWindow = new ImageWindow(someImage.width, someImage.height);
someImageWindow.mainView.beginProcess();
someImageWindow.mainView.image.assign(someImage);
someImageWindow.mainView.endProcess();

beginProcess と endProcess で挟むことと,代入演算子 = ではなく assign メソッドを使うことがミソみたいです.
これで someImageWindow の image プロパティに someImage をぶちこむことができるので,show などを呼べば内容を確認したり,外部ファイルに出力したりできます.

1
2
someImageWindow.show();
someImageWindow.saveAs(outputFilePath, false, false, false, false);

こんなふうにね.今回ココが分かるまでに一番時間を使った….

Image の演算

Image 型の画像を演算するには Image.apply を使います.

1
2
3
4
5
6
7
#include<pjsr/ImageOp.jsh>

var lhsImage = Image(width, height);
var rhsImage = Image(width, height);
var n = someNumber;
lhsImage.apply(rhsImage, ImageOp_Type); //画像同士の演算
lhsImage.apply(n, ImageOp_Type); //画像と定数の演算

ImageOp_Type には,単純な四則演算(ImageOp_Add, ImageOp_Sub, ImageOp_Mul, ImageOp_Div)に加えて,累乗(ImageOp_Pow)やビット演算なんかもあります.詳しくは Object Explorer→Image→Constants を見てね.画像同士の演算の場合,サイズが違うとどうなるのかは試していませんが,たぶんエラーが返ってくるんじゃないかなと思います.
これまでのことを組み合わせれば,ファイルリストから位置合わせなしの加算平均は例えば以下のように書けます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var currentImageWindow = null;
var stackedImage = null;
for (var i = 0; i < this.inputFiles.length; ++i) {
currentImageWindow = ImageWindow.open(this.inputFiles[i])[0];
if (stackedImage == null) {
stackedImage = new Image(currentImageWindow.mainView.image.width, currentImageWindow.mainView.image.height);
}
//stacking
currentImageWindow.mainView.beginProcess();
var image = currentImageWindow.mainView.image;
image.apply(this.inputFiles.length, ImageOp_Div); //divide current image
stackedImage.apply(image, ImageOp_Add); //and add
currentImageWindow.mainView.endProcess();
}
//Convert to ImageWindow Object
var stackedImageWindow = new ImageWindow(stackedImage.width, stackedImage.height);
stackedImageWindow.mainView.beginProcess();
stackedImageWindow.mainView.image.assign(stackedImage);
stackedImageWindow.mainView.endProcess();
stackedImageWindow.show();

currentImageWindow.mainView.image に対して破壊的操作をするので,beginProcess と endProcess で挟んでいたりするところにご注目いただければ.
位置合わせなしのこれくらいの内容であれば,ImageIntegration を使ってパラメタを指定して書くよりもスッキリするんじゃないかと思いますが,そこは個人によるということで….

今回は以上です.PI スクリプトを書く人の参考になればいいなと思います.
では皆様,よいコーディングライフを!

2022.02.20 追記 engine 部分の記述位置