さて今回は以前紹介した AI upscaler のアルゴリズムを解読していきます。このプラグインのダイアログは下記のようになっています。

この内の output factor はアップスケールをする倍率を指定します。その後に、アップスケールアルゴリズムのモデルの選択があり、その後の Scope では適用範囲を指定します。これはイメージ全体に適用するのか、選択範囲のみに適用するのか、選択したレイヤーのみに適用するのかを選択します。
このプラグインの基本構成は、class AIUpscale でレジストレーション情報を定義し、実質的なメインプロシジャーは、def ai_upscale になっています。それ以外にユーザ定義関数がありますが、それらはサブルーチンです。
また、基本エンジンは Windows および Linux 用のバイナリーが用意されていて、Python スクリプトからサブプロセスとして呼び出して実行します。従って基本的な構成は、以前紹介した、AI Remove BG と似ています。また Mac OS 用のバイナリーは用意されていないので、Mac OS では走りません。
この def ai_upscale を中心に基本的なアルゴリズムを見ていきます。


ソースコードを見て気づくのは、各ユーザ定義関数の宣言に、
というように -> という記号が見えます。これはアノテーションで、戻り値の型を注記しています。同様に、引数にも : がついていますが、やはり型が注記されています。ただしあくまでも注記なので、型チェックは行わないようです。
また、class AIUpscale の中で、output_factor という引数を、Gimp.ImageProcedure.add_double_argument メソッドを使って定義しています。
proc.add_double_argument(
"output_factor",
_txt("Output _Factor"),
_txt("Final output size relative to original size (entire image mode)"),
0.05, 8.0, DEFAULT_OUTPUT_FACTOR,
GObject.ParamFlags.READWRITE
)
この add_xxxxxxxxxxxxxx_argument というメソッドは、GIMP 2.10 のレジスター関数で、UI から引数を受け取るディスクリプションがありましたが、どうやらそれに相当するもののようです。
https://lazka.github.io/pgi-docs/#Gimp-3.0/classes/Procedure.html#Gimp.Procedure.add_double_argument
ここで記述しておくと、GimpUi.ProcedureDialog でダイアログを作成したときに、自動的にここで記述していたとおりの UI が設定されるようです。また、自動的に config という辞書型リスト変数に、add_xxxxxxxxxxxxxx_argument で指定したインデックス名で値が格納されるようです。
個人的には、今まで Gtk の標準的なウィジェットのみ使用してきました。しかし、おそらく、この機能は、Gtk の標準的なウィジェットを使っていては利用できないものと思います。というわけでこのあたりは全く知りませんでした。

さらに、ダイアログの定義は、317行以下で行われていますが、この内ラジオボタンについては次のような構成になっています。

この内、上のモデルのラジオボタンについては、発見したモデルの数だけラジオボタンを設置するようになっています。したがってモデルが増えればラジオボタンも増えます。
# --- Model radios ---
frame = Gtk.Frame.new(_txt("Model"))
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
frame.add(vbox)
radio_group = None
for stem in model_options:
btn = Gtk.RadioButton.new_with_label_from_widget(radio_group, stem)
if radio_group is None:
radio_group = btn
if stem == current_model:
btn.set_active(True)
def _on_toggle(button, s=stem):
nonlocal current_model
if button.get_active():
current_model = s
btn.connect('toggled', _on_toggle)
vbox.pack_start(btn, False, False, 0)
dialog.get_content_area().pack_start(frame, False, False, 6)