最終更新: a few seconds agoRemove Netlify-related code from main (grafted, HEAD)

202101 CIRCUS RS 改善

WebGL を用いた MPR レンダラ

概要

MPR は、「Viewer の <canvas> 内の画素 (2D) の 1 つ 1 つに対し、対応するボリューム内の 3D 位置を計算してそこの画素値を抽出する」ことで動作している。

特に 4K モニタを利用している場合などは、<canvas> のサイズはかなり大きくなることがあるので、CPU ベースでの MPR では非常にフレームレートが低下してしまうことがある(4K モニタでフルスクリーン表示などをすると 1 秒 1 フレーム未満に満たなくなってしまうこともある)。

これを改善するために MPR の計算を WebGL で行えるようにする。

要件

使う技術は基本的には VolumeRenderingImageSource で使っているものと同じ。VR と比べるとアルゴリズム自体は非常にシンプルなので、GPU にボリューム本体、Section, Window, interpolationMode を渡すとそれに対応する MPR 画像が返る形にする。

RawVolume はサーバサイドでも動作しないといけないので、WebGL 関連のコードは素の RawVolume とは分離する必要がある。最も望ましいのは MRP 計算部分だけを差し替えられるよう、以下のような形にするもの。いわゆる Strategy パターン+コンストラクタインジェクション。

const glRenderer = new MprRendererGL();
const options = { mprRenderer: glRenderr };
const vol = new RawVolume([512, 512, 200], 'binary', options);

(これまでの CPU ベースの MPR 計算を MprRendererCPU として抽出し、options を省略した場合はそちらが使われるようにする。)

今のところ class RawVolumeGL extends RawVolume とするのは避けたいが、実装難易度によってはこうすることも検討。

課題

巨大なテクスチャを GPU に転送しつつそれをメイン RAM と GPU 間で同期しないといけない。テクスチャの部分的な書き換え自体は texSubImage2D を使うと可能らしい(three.js でのデモ)。

setPixelAt / getPixelAt を弄って、ボリュームのどこが書き換わっており GPU への再転送が必要なのかをスライス単位で覚えておき、scanObliqueSection() が呼ばれたタイミングで更新があって必要になった部分だけを GPU に転送する、というような仕組みが必要と思われる。(getPixelAt などが遅くなるが結局その部分は GPU である再実装しないといけないのであまり問題ないはず)

PlaneFigure の一種としての PolyLine アノテーションの新規作成

概要

「折れ線」という 2 次元アノテーションを追加する。頂点をドラッグ可能にする。

これは今後の CIRCUS を使った読影実験などで必要になる。特に DICOM 規約にあるアノテーション仕様では、DICOM 画像上にこのような折れ線を描画する仕組みがあり、それを CIRCUS 上で再現する必要がある。

Polyline

仕様

PolyLine は PlaneFigure の一種なのでできるだけ多くのプロパティは Rectangle/Ellipse と共通化させる。大きな違いは以下の通り。

PolyLineTool はマウスで Viewer の複数箇所をクリックしていくことで PolyLine を新規作成するツール。

  • 最初のクリックで 1 つめの頂点を置き、その時点で「折れ線モード」に入る。つまり、2 個目以降の頂点を定義するためにキャンバス内のあらゆる他のアノテーションに優先してマウスイベントを受け取るようにし、更に window.addEventListener('keydown') を登録して ESC および Enter キーイベントを捕捉するようにする(イベントハンドラは折れ線モード終了時に remove すること)。
  • 「折れ線モード」は以下の条件の場合に終了する。
    • ESC キーまたは Enter キーが押下された場合
    • 始点と(ほぼ)同じ場所をクリックした場合
    • PolyLine 以外の他のツールが有効になった場合
    • ダブルクリックした場合
  • 始点と同じ場所をクリックした場合とダブルクリックした場合は closed: true の折れ線を作成する。その他の場合は closed: false の折れ線になる。

その他の仕様は以下の通り。

  • points.length が 1 の場合、とりあえず 1 個の頂点のみを描画する。points.length が 2 の場合、単なる線分として描画する(塗りは発生しない)。
  • closed === false の場合でも塗りは発生する(canvas の API を普通に使えばそうなるはず)。
  • 各頂点を直接ドラッグ際のマウスポインタは crosshair を使う。
  • 辺をドラッグ可能にする必要はない。つまり、頂点と頂点の間の線分をドラッグすることで隣り合う 2 個の頂点を同時に移動させる必要はない。
  • PowerPoint や Illustrator にあるような、バウンディングボックスとなる矩形を表示して全体を拡大/縮小/移動する機能も作成する。ただしバウンディングボックスは不使用にもできるようにする。またバウンディングボックスは points.length >= 2 の時にのみ描画する。

優先度

  • PolyLineTool の優先度は高くない。ひとまずデータを表示できることが優先。
  • バウンディングボックスの優先度は高くない。