使用 XTK 或 AMI.js 在 T1.mgz 上显示 Freesurfer while/pial 个对象
Using XTK or AMI.js to display Freesurfer while/pial objects on T1.mgz
我想重新创建一个网络版的 FreeSurfer pial/white 表面覆盖在 T1.mgz 上,类似于 https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/PialEdits_freeview. Using XTK I can get something that hints at that using advice from Othographic Projection in XTK 上的第一个 freeview 图像。我用来创建图像的代码(以及多次尝试的 kruft)在图像下方。
XTK 是否可行,或者我应该切换到 AMI.js(其路线图上有 freesurfer 表面和 MGZ 文件格式,但尚未实施)?
在任何一种情况下,如果能指出如何实现这一点,我们将不胜感激。
谢谢。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>FS XTK test</title>
</head>
<body>
<script type="text/javascript" src="/Xdevel/lib/google-closure-library/closure/goog/base.js"></script>
<script type="text/javascript" src="/Xdevel/xtk-deps.js"></script>
<script type="text/javascript" src="/Xdevel/xtk_xdat.gui.js"></script>
<script type="text/javascript">
var view2D_X = null;
var view2D_Y = null;
var view2D_Z = null;
var view3D = null;
var volume3D = null;
var meshes = new Array(6);
var meshFiles = new Array(6);
var t1File = 'T1.mgz';
meshFiles[0]='lh.orig';
meshFiles[1]='rh.orig';
meshFiles[2]='lh.pial';
meshFiles[3]='rh.pial';
meshFiles[4]='lh.white.pial';
meshFiles[5]='rh.white.pial';
var colors = [ //Matlab jet(28)
[ 0, 1, 0],
[ 0, 1, 0],
[ 1, 0, 0],
[ 1, 0, 0],
[ 0, 0, 1],
[ 0, 0, 1]
];
function setView(pos)
{
switch(pos)
{
case 1:
camPos=[ 0, 0, -1, 0,
-1, 0, -0, 0,
0, 1, 0, 0,
1, 0, -1, 1];
break;
case 2:
camPos=[-1, 0, 0, 0,
0, 0, 1, 0,
0, 1, -0, 0,
0, -1, -1, 1];
break;
default: //Case 3
camPos=[-1, 0, -0, 0,
-0, 1, -0, 0,
0, 0, 1, 0,
0, -0, -1, 1];
break;
}
camPos[14] = 200*camPos[14]; //zoomout
view3D.camera.view=new Float32Array(camPos);
}
// include all used X-classes here
// this is only required when using the xtk-deps.js file
goog.require('X.renderer2D');
goog.require('X.renderer3D');
goog.require('X.mesh');
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
</script>
<div id="view3D_div" style="background-color: #000; width: 399px; height: 399px;"></div>
<script type="text/javascript">
function loadMeshes()
{
for (var a = 0; a < 6; a++)
{
try
{
meshes[a] = new X.mesh();
meshes[a].file=meshFiles[a];
meshes[a].color = colors[a];
meshes[a].visible=true;
view3D.add(meshes[a]);
}
catch(err)
{
console.log('failed to load: '+meshFiles[a]);
console.log(err.message);
}
}
}
var _meshConfig = {
'width' : 399,
'height' : 399,
'unknown' : 180.5,
'diff' : 0.3
};
function setMainSlice()
{
// console.log('height: ' + height + ' width: ' + width);
console.log('X: ' + volume3D.indexX + 'Y: ' + volume3D.indexY + 'Z: ' + volume3D.indexZ);
_meshConfig.unknown=volume3D.indexZ+92.5;
console.log('width: '+_meshConfig.width + ' height: ' + _meshConfig.height + ' unknown: ' + _meshConfig.unknown);
view3D.camera._perspective=X.matrix.makeOrtho(X.matrix.identity(), -(_meshConfig.width/2), (_meshConfig.width/2), -(_meshConfig.height/2), (_meshConfig.height/2), _meshConfig.unknown+_meshConfig.diff, _meshConfig.unknown-_meshConfig.diff);
// view3D.camera._perspective=goog.vec.Mat4.createFromValues(1,0,0,0,0,1,0,0,0,0,1,0,volume3D.indexX,volume3D.indexY,volume3D.indexZ,1);
// view3D.camera._perspective=goog.vec.Mat4.createFromValues(0.005,0,0,0, 0,0.005,0,0, 0,0,3,0, 0,0,256+(volume3D.indexZ*2),1);
}
addLoadEvent(function () {
view3D = new X.renderer3D();
view3D.container = 'view3D_div';
view3D.init();
volume3D = new X.volume();
volume3D.file = t1File;
// volume3D.labelmap.file='all.white.mgz';
view3D.add(volume3D);
loadMeshes();
setView(3);
// view3D.camera.position=[-0, 0, 90];
// view3D.camera.view[14] = -200;
view3D.render();
view3D.onShowtime = function () {
view2D_X.onScroll = setMainSlice;
view2D_X.add(volume3D);
view2D_X.render();
view2D_Y.onScroll = setMainSlice;
view2D_Y.add(volume3D);
view2D_Y.render();
view2D_Z.onScroll = setMainSlice;
view2D_Z.add(volume3D);
view2D_Z.render();
setView(3);
};
var gui = new dat.GUI();
var anat_folder = gui.addFolder('T1');
anat_folder.add(volume3D,'visible');
anat_folder.add(volume3D,'opacity',0,1);
anat_folder.add(volume3D,'indexX');
anat_folder.add(volume3D,'indexY');
anat_folder.add(volume3D,'indexZ',0,256);
anat_folder.open();
var lh_orig_folder = gui.addFolder('Freesurfer lh.orig');
lh_orig_folder.add(meshes[0],'visible');
lh_orig_folder.add(meshes[0],'opacity',0,1);
lh_orig_folder.addColor(meshes[0],'color');
// lh_orig_folder.open();
var rh_orig_folder = gui.addFolder('Freesurfer rh.orig');
rh_orig_folder.add(meshes[1],'visible');
rh_orig_folder.add(meshes[1],'opacity',0,1);
rh_orig_folder.addColor(meshes[1],'color');
// rh_orig_folder.open();
var lh_pial_folder = gui.addFolder('Freesurfer lh.pial');
lh_pial_folder.add(meshes[2],'visible');
lh_pial_folder.add(meshes[2],'opacity',0,1);
lh_pial_folder.addColor(meshes[2],'color');
// lh_pial_folder.open();
var rh_pial_folder = gui.addFolder('Freesurfer rh.pial');
rh_pial_folder.add(meshes[3],'visible');
rh_pial_folder.add(meshes[3],'opacity',0,1);
rh_pial_folder.addColor(meshes[3],'color');
// rh_pial_folder.open();
var lh_white_folder = gui.addFolder('Freesurfer lh.white');
lh_white_folder.add(meshes[4],'visible');
lh_white_folder.add(meshes[4],'opacity',0,1);
lh_white_folder.addColor(meshes[4],'color');
// lh_white_folder.open();
var rh_white_folder = gui.addFolder('Freesurfer rh.white');
rh_white_folder.add(meshes[5],'visible');
rh_white_folder.add(meshes[5],'opacity',0,1);
rh_white_folder.addColor(meshes[5],'color');
// rh_white_folder.open();
var mesh_folder = gui.addFolder('Mesh');
mesh_folder.add(_meshConfig,'height');
mesh_folder.add(_meshConfig,'width');
mesh_folder.add(_meshConfig,'unknown');
mesh_folder.open();
for (c in gui.__controllers)
{
gui.__controllers[c].onFinishChange(update);
}
});
</script>
<table style="border-collapse: collapse">
<tr>
<td style="background-color: red;">
<div id="view2D_X_div" style="background-color: #000; width: 131px; height: 131px;"></div>
<script type="text/javascript">
addLoadEvent(function () {
view2D_X = new X.renderer2D();
view2D_X.container = 'view2D_X_div';
view2D_X.orientation = 'X';
view2D_X.init();
});
</script>
</td>
<td style="background-color: green;">
<div id="view2D_Y_div" style="background-color: #000; width: 131px; height: 131px;"></div>
<script type="text/javascript">
addLoadEvent(function () {
view2D_Y = new X.renderer2D();
view2D_Y.container = 'view2D_Y_div';
view2D_Y.orientation = 'Y';
view2D_Y.init();
});
</script>
</td>
<td style="background-color: blue;">
<div id="view2D_Z_div" style="background-color: #000; width: 131px; height: 131px;"></div>
<script type="text/javascript">
addLoadEvent(function () {
view2D_Z = new X.renderer2D();
view2D_Z.container = 'view2D_Z_div';
view2D_Z.orientation = 'Z';
view2D_Z.init();
});
</script>
</td>
</tr>
<tr>
<td style="background-color: red;">
<!-- <button onClick="setView([-90,0,0]);">Set View</button>-->
<button onClick="setView(1);">Set View</button>
</td>
<td style="background-color: green;">
<!-- <button onClick="setView([0,90,0]);">Set View</button>-->
<button onClick="setView(2);">Set View</button>
</td>
<td style="background-color: blue;">
<!-- <button onClick="setView([0,0,90]);">Set View</button>-->
<button onClick="setView(3);">Set View</button>
</td>
</tr>
</table>
Green is orig<br>
Red is pial<br>
Blue is white<br>
</body>
</html>
您现在可以在 AMI 中执行此操作(感谢您的 PR:https://fnndsc.github.io/ami/#viewers_quadview)
显示网格与平面的交集
Post 处理交叉点以显示等高线。
有不同的技术来显示 mesh/plane 交叉点:
- 使用模板缓冲区(https://github.com/daign/clipping-with-caps)
- 播放网格不透明度(https://github.com/FNNDSC/ami/tree/dev/examples/viewers_quadview)
所有这些技术在计算上都是昂贵的,因为它需要 3 个渲染通道来显示 1 个网格的轮廓,可能有更好的方法,但不确定什么是最好的选择。
HTH
我想重新创建一个网络版的 FreeSurfer pial/white 表面覆盖在 T1.mgz 上,类似于 https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/PialEdits_freeview. Using XTK I can get something that hints at that using advice from Othographic Projection in XTK 上的第一个 freeview 图像。我用来创建图像的代码(以及多次尝试的 kruft)在图像下方。
XTK 是否可行,或者我应该切换到 AMI.js(其路线图上有 freesurfer 表面和 MGZ 文件格式,但尚未实施)?
在任何一种情况下,如果能指出如何实现这一点,我们将不胜感激。
谢谢。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>FS XTK test</title>
</head>
<body>
<script type="text/javascript" src="/Xdevel/lib/google-closure-library/closure/goog/base.js"></script>
<script type="text/javascript" src="/Xdevel/xtk-deps.js"></script>
<script type="text/javascript" src="/Xdevel/xtk_xdat.gui.js"></script>
<script type="text/javascript">
var view2D_X = null;
var view2D_Y = null;
var view2D_Z = null;
var view3D = null;
var volume3D = null;
var meshes = new Array(6);
var meshFiles = new Array(6);
var t1File = 'T1.mgz';
meshFiles[0]='lh.orig';
meshFiles[1]='rh.orig';
meshFiles[2]='lh.pial';
meshFiles[3]='rh.pial';
meshFiles[4]='lh.white.pial';
meshFiles[5]='rh.white.pial';
var colors = [ //Matlab jet(28)
[ 0, 1, 0],
[ 0, 1, 0],
[ 1, 0, 0],
[ 1, 0, 0],
[ 0, 0, 1],
[ 0, 0, 1]
];
function setView(pos)
{
switch(pos)
{
case 1:
camPos=[ 0, 0, -1, 0,
-1, 0, -0, 0,
0, 1, 0, 0,
1, 0, -1, 1];
break;
case 2:
camPos=[-1, 0, 0, 0,
0, 0, 1, 0,
0, 1, -0, 0,
0, -1, -1, 1];
break;
default: //Case 3
camPos=[-1, 0, -0, 0,
-0, 1, -0, 0,
0, 0, 1, 0,
0, -0, -1, 1];
break;
}
camPos[14] = 200*camPos[14]; //zoomout
view3D.camera.view=new Float32Array(camPos);
}
// include all used X-classes here
// this is only required when using the xtk-deps.js file
goog.require('X.renderer2D');
goog.require('X.renderer3D');
goog.require('X.mesh');
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
</script>
<div id="view3D_div" style="background-color: #000; width: 399px; height: 399px;"></div>
<script type="text/javascript">
function loadMeshes()
{
for (var a = 0; a < 6; a++)
{
try
{
meshes[a] = new X.mesh();
meshes[a].file=meshFiles[a];
meshes[a].color = colors[a];
meshes[a].visible=true;
view3D.add(meshes[a]);
}
catch(err)
{
console.log('failed to load: '+meshFiles[a]);
console.log(err.message);
}
}
}
var _meshConfig = {
'width' : 399,
'height' : 399,
'unknown' : 180.5,
'diff' : 0.3
};
function setMainSlice()
{
// console.log('height: ' + height + ' width: ' + width);
console.log('X: ' + volume3D.indexX + 'Y: ' + volume3D.indexY + 'Z: ' + volume3D.indexZ);
_meshConfig.unknown=volume3D.indexZ+92.5;
console.log('width: '+_meshConfig.width + ' height: ' + _meshConfig.height + ' unknown: ' + _meshConfig.unknown);
view3D.camera._perspective=X.matrix.makeOrtho(X.matrix.identity(), -(_meshConfig.width/2), (_meshConfig.width/2), -(_meshConfig.height/2), (_meshConfig.height/2), _meshConfig.unknown+_meshConfig.diff, _meshConfig.unknown-_meshConfig.diff);
// view3D.camera._perspective=goog.vec.Mat4.createFromValues(1,0,0,0,0,1,0,0,0,0,1,0,volume3D.indexX,volume3D.indexY,volume3D.indexZ,1);
// view3D.camera._perspective=goog.vec.Mat4.createFromValues(0.005,0,0,0, 0,0.005,0,0, 0,0,3,0, 0,0,256+(volume3D.indexZ*2),1);
}
addLoadEvent(function () {
view3D = new X.renderer3D();
view3D.container = 'view3D_div';
view3D.init();
volume3D = new X.volume();
volume3D.file = t1File;
// volume3D.labelmap.file='all.white.mgz';
view3D.add(volume3D);
loadMeshes();
setView(3);
// view3D.camera.position=[-0, 0, 90];
// view3D.camera.view[14] = -200;
view3D.render();
view3D.onShowtime = function () {
view2D_X.onScroll = setMainSlice;
view2D_X.add(volume3D);
view2D_X.render();
view2D_Y.onScroll = setMainSlice;
view2D_Y.add(volume3D);
view2D_Y.render();
view2D_Z.onScroll = setMainSlice;
view2D_Z.add(volume3D);
view2D_Z.render();
setView(3);
};
var gui = new dat.GUI();
var anat_folder = gui.addFolder('T1');
anat_folder.add(volume3D,'visible');
anat_folder.add(volume3D,'opacity',0,1);
anat_folder.add(volume3D,'indexX');
anat_folder.add(volume3D,'indexY');
anat_folder.add(volume3D,'indexZ',0,256);
anat_folder.open();
var lh_orig_folder = gui.addFolder('Freesurfer lh.orig');
lh_orig_folder.add(meshes[0],'visible');
lh_orig_folder.add(meshes[0],'opacity',0,1);
lh_orig_folder.addColor(meshes[0],'color');
// lh_orig_folder.open();
var rh_orig_folder = gui.addFolder('Freesurfer rh.orig');
rh_orig_folder.add(meshes[1],'visible');
rh_orig_folder.add(meshes[1],'opacity',0,1);
rh_orig_folder.addColor(meshes[1],'color');
// rh_orig_folder.open();
var lh_pial_folder = gui.addFolder('Freesurfer lh.pial');
lh_pial_folder.add(meshes[2],'visible');
lh_pial_folder.add(meshes[2],'opacity',0,1);
lh_pial_folder.addColor(meshes[2],'color');
// lh_pial_folder.open();
var rh_pial_folder = gui.addFolder('Freesurfer rh.pial');
rh_pial_folder.add(meshes[3],'visible');
rh_pial_folder.add(meshes[3],'opacity',0,1);
rh_pial_folder.addColor(meshes[3],'color');
// rh_pial_folder.open();
var lh_white_folder = gui.addFolder('Freesurfer lh.white');
lh_white_folder.add(meshes[4],'visible');
lh_white_folder.add(meshes[4],'opacity',0,1);
lh_white_folder.addColor(meshes[4],'color');
// lh_white_folder.open();
var rh_white_folder = gui.addFolder('Freesurfer rh.white');
rh_white_folder.add(meshes[5],'visible');
rh_white_folder.add(meshes[5],'opacity',0,1);
rh_white_folder.addColor(meshes[5],'color');
// rh_white_folder.open();
var mesh_folder = gui.addFolder('Mesh');
mesh_folder.add(_meshConfig,'height');
mesh_folder.add(_meshConfig,'width');
mesh_folder.add(_meshConfig,'unknown');
mesh_folder.open();
for (c in gui.__controllers)
{
gui.__controllers[c].onFinishChange(update);
}
});
</script>
<table style="border-collapse: collapse">
<tr>
<td style="background-color: red;">
<div id="view2D_X_div" style="background-color: #000; width: 131px; height: 131px;"></div>
<script type="text/javascript">
addLoadEvent(function () {
view2D_X = new X.renderer2D();
view2D_X.container = 'view2D_X_div';
view2D_X.orientation = 'X';
view2D_X.init();
});
</script>
</td>
<td style="background-color: green;">
<div id="view2D_Y_div" style="background-color: #000; width: 131px; height: 131px;"></div>
<script type="text/javascript">
addLoadEvent(function () {
view2D_Y = new X.renderer2D();
view2D_Y.container = 'view2D_Y_div';
view2D_Y.orientation = 'Y';
view2D_Y.init();
});
</script>
</td>
<td style="background-color: blue;">
<div id="view2D_Z_div" style="background-color: #000; width: 131px; height: 131px;"></div>
<script type="text/javascript">
addLoadEvent(function () {
view2D_Z = new X.renderer2D();
view2D_Z.container = 'view2D_Z_div';
view2D_Z.orientation = 'Z';
view2D_Z.init();
});
</script>
</td>
</tr>
<tr>
<td style="background-color: red;">
<!-- <button onClick="setView([-90,0,0]);">Set View</button>-->
<button onClick="setView(1);">Set View</button>
</td>
<td style="background-color: green;">
<!-- <button onClick="setView([0,90,0]);">Set View</button>-->
<button onClick="setView(2);">Set View</button>
</td>
<td style="background-color: blue;">
<!-- <button onClick="setView([0,0,90]);">Set View</button>-->
<button onClick="setView(3);">Set View</button>
</td>
</tr>
</table>
Green is orig<br>
Red is pial<br>
Blue is white<br>
</body>
</html>
您现在可以在 AMI 中执行此操作(感谢您的 PR:https://fnndsc.github.io/ami/#viewers_quadview)
显示网格与平面的交集
Post 处理交叉点以显示等高线。
有不同的技术来显示 mesh/plane 交叉点:
- 使用模板缓冲区(https://github.com/daign/clipping-with-caps)
- 播放网格不透明度(https://github.com/FNNDSC/ami/tree/dev/examples/viewers_quadview)
所有这些技术在计算上都是昂贵的,因为它需要 3 个渲染通道来显示 1 个网格的轮廓,可能有更好的方法,但不确定什么是最好的选择。
HTH