最終更新: a few seconds ago Remove 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 上で再現する必要がある。

DICOM C.10.5 Graphic Annotation Module: http://dicom.nema.org/medical/dicom/2015c/output/chtml/part03/sect_C.10.5.html
仕様
PolyLine は PlaneFigure の一種なのでできるだけ多くのプロパティは Rectangle/Ellipse と共通化させる。大きな違いは以下の通り。
min/maxをベースに四角や丸を描画するのではなく、points: Vector2D[]から折れ線を描画する。- 始点と終点を接続する辺を描画するかどうかを
closed: booleanで切り替えられるようにする。デフォルトはfalseにする。(この指定はpoints.length >= 3でない場合は無効) - 内部の塗りモードを
fillMode: 'nonzero' | 'evenodd'で切り替えられるようにし、デフォルトはevenoddにする。
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 の優先度は高くない。ひとまずデータを表示できることが優先。
- バウンディングボックスの優先度は高くない。