Commit 243724bb authored by r03ert0's avatar r03ert0
Browse files

fix case sensitivity

parent 0375b551
This diff is collapsed.
{
"1.2.3.4": true,
"2.3.4.5": true
}
{
"1.2.3.4": true,
"2.3.4.5": true
}
/**
* @page AtlasMaker: Image Drawing
*/
var AtlasMakerDraw = {
/**
* @function resizeWindow
*/
resizeWindow: function resizeWindow() {
var me=AtlasMakerWidget;
var l=me.traceLog(resizeWindow,1);if(l)console.log.apply(undefined,l);
var wH=me.container.height();
var wW=me.container.width();
var wAspect=wW/wH;
var bAspect=me.brain_W*me.brain_Wdim/(me.brain_H*me.brain_Hdim);
/*
if(me.editMode==1) {
*/
// In edit mode width or height can be fixed to 100%
// depending on the slice and container aspect ratio
if(wAspect>bAspect)
$('#resizable').css({width:(100*bAspect/wAspect)+'%',height:'100%'});
else
$('#resizable').css({width:'100%',height:(100*wAspect/bAspect)+'%'});
/*
} else {
// In display mode slice width is always fixed to 100%
$('#resizable').css({width:'100%',height:(100*wAspect/bAspect)+'%'});
// Slice height cannot be larger than window's inner height:
var sliceH=me.container.height();
var windowH=window.innerHeight;
if(sliceH>windowH) {
var f=windowH/sliceH;
$('#resizable').css({width:(f*100)+'%',height:f*(100*wAspect/bAspect)+'%'});
}
}
*/
},
/**
* @function configureBrainImage
*/
configureBrainImage: function configureBrainImage() {
var me=AtlasMakerWidget;
var l=me.traceLog(configureBrainImage);if(l)console.log.apply(undefined,l);
if(me.User.view==null)
me.User.view="sag";
var s2v=me.User.s2v;
switch(me.User.view) {
case 'sag': me.brain_W=s2v.sdim[1]; me.brain_H=s2v.sdim[2]; me.brain_D=s2v.sdim[0]; me.brain_Wdim=s2v.wpixdim[1]; me.brain_Hdim=s2v.wpixdim[2]; break; // sagital
case 'cor': me.brain_W=s2v.sdim[0]; me.brain_H=s2v.sdim[2]; me.brain_D=s2v.sdim[1]; me.brain_Wdim=s2v.wpixdim[0]; me.brain_Hdim=s2v.wpixdim[2]; break; // coronal
case 'axi': me.brain_W=s2v.sdim[0]; me.brain_H=s2v.sdim[1]; me.brain_D=s2v.sdim[2]; me.brain_Wdim=s2v.wpixdim[0]; me.brain_Hdim=s2v.wpixdim[1]; break; // axial
}
me.canvas.width=me.brain_W;
me.canvas.height=me.brain_H*me.brain_Hdim/me.brain_Wdim;
me.brain_offcn.width=me.brain_W;
me.brain_offcn.height=me.brain_H;
me.brain_px=me.brain_offtx.getImageData(0,0,me.brain_offcn.width,me.brain_offcn.height);
if(me.User.slice==null || me.User.slice>=me.brain_D-1)
me.User.slice=parseInt(me.brain_D/2);
me.sendUserDataMessage(JSON.stringify({'view':me.User.view,'slice':me.User.slice}));
// configure toolbar slider
$(".slider#slice").data({max:me.brain_D-1,val:me.User.slice});
if($("#slice .thumb")[0]) $("#slice .thumb")[0].style.left=(me.User.slice/(me.brain_D-1)*100)+"%";
me.drawImages();
me.initCursor();
},
/**
* @function configureAtlasImage
*/
configureAtlasImage: function configureAtlasImage() {
var me=AtlasMakerWidget;
var l=me.traceLog(configureAtlasImage);if(l)console.log.apply(undefined,l);
// has to be run *after* configureBrainImage
me.atlas_offcn.width=me.brain_W;
me.atlas_offcn.height=me.brain_H;
me.atlas_px=me.atlas_offtx.getImageData(0,0,me.atlas_offcn.width,me.atlas_offcn.height);
},
/**
* @function nearestNeighbour
*/
nearestNeighbour: function nearestNeighbour(ctx) {
var me=AtlasMakerWidget;
var l=me.traceLog(nearestNeighbour,1);if(l)console.log.apply(undefined,l);
ctx.imageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
},
/**
* @function computeSegmentedVolume
*/
computeSegmentedVolume: function computeSegmentedVolume() {
var me=AtlasMakerWidget;
var l=me.traceLog(computeSegmentedVolume,1);if(l)console.log.apply(undefined,l);
var i,sum=0;
var data=me.atlas.data;
var dim=me.atlas.dim;
for(i=0;i<dim[0]*dim[1]*dim[2];i++) {
if(data[i]>0)
sum++;
}
return sum*me.User.pixdim[0]*me.User.pixdim[1]*me.User.pixdim[2];
},
/**
* @function displayInformation
* @desc Overlays text and vectorial information on top of the annotation volume slice. Text information is added from the AtlasMakerWidget.info object. Vectorial information is displayed using svg format
*/
displayInformation: function displayInformation() {
var me=AtlasMakerWidget;
var l=me.traceLog(displayInformation,1);if(l)console.log.apply(undefined,l);
me.info.slice=me.User.slice;
var i=0,str;
var text=me.container.find("#text-layer");
var vector=me.container.find("#vector-layer");
str="";
for(var k in me.info) {
str+="<span>"+k+": "+me.info[k]+"</span><br/>";
}
text.html(str);
str="";
if(me.User.measureLength) {
var W=parseFloat($('#atlasmaker canvas').css('width'));
var w=parseFloat($('#atlasmaker canvas').attr('width'));
var zx=W/w,zy=zx*me.brain_Hdim/me.brain_Wdim,p=me.User.measureLength,str1;
var W=parseFloat($('#atlasmaker canvas').css('width'));
var w=parseFloat($('#atlasmaker canvas').attr('width'));
str1="M"+zx*p[0].x+","+zy*p[0].y;
for(i=1;i<p.length;i++)
str1+="L"+zx*p[i].x+","+zy*p[i].y;
str+=[ "<circle fill='#00ff00' cx="+zx*p[0].x+" cy="+zy*p[0].y+" r=3 />",
"<path stroke='#00ff00' fill='none' d='"+str1+"'/>",
(i>0)?"<circle fill='#00ff00' cx="+zx*p[i-1].x+" cy="+zy*p[i-1].y+" r=3 />":""].join("\n");
}
vector.html(str);
},
/**
* @function drawImages
*/
drawImages: function drawImages() {
var me=AtlasMakerWidget;
var l=me.traceLog(drawImages,1);if(l)console.log.apply(undefined,l);
if(me.brain_img.img
&& me.flagLoadingImg.view
&& me.flagLoadingImg.slice) {
me.context.clearRect(0,0,me.context.canvas.width,me.canvas.height);
me.displayInformation();
me.nearestNeighbour(me.context);
me.context.drawImage(me.brain_img.img,0,0,me.brain_W,me.brain_H*me.brain_Hdim/me.brain_Wdim);
me.drawAtlasImage(me.flagLoadingImg.view,me.flagLoadingImg.slice);
}
if(!me.brain_img.img || me.brain_img.view!=me.User.view || me.brain_img.slice!=me.User.slice) {
me.sendRequestSliceMessage();
}
},
/**
* @function drawAtlasImage
*/
drawAtlasImage: function drawAtlasImage(view,slice) {
var me=AtlasMakerWidget;
var l=me.traceLog(drawAtlasImage,1);if(l)console.log.apply(undefined,l);
if(!me.atlas)
return;
var data=me.atlas.data;
var dim=me.atlas.dim;
var s,val;
ys=yc=ya=slice;
for(y=0;y<me.brain_H;y++)
for(x=0;x<me.brain_W;x++) {
switch(view) {
case 'sag':s=[ys,x,me.brain_H-1-y]; break;
case 'cor':s=[x,yc,me.brain_H-1-y]; break;
case 'axi':s=[x,me.brain_H-1-y,ya]; break;
}
i=me.S2I(s,me.User);
var c=me.ontologyValueToColor(data[i]);
var alpha=(data[i]>0)?255:0;
i=(y*me.atlas_offcn.width+x)*4;
me.atlas_px.data[ i ] =c[0];
me.atlas_px.data[ i+1 ]=c[1];
me.atlas_px.data[ i+2 ]=c[2];
me.atlas_px.data[ i+3 ]=alpha*me.alphaLevel;
}
me.atlas_offtx.putImageData(me.atlas_px, 0, 0);
me.nearestNeighbour(me.context);
me.context.drawImage(me.atlas_offcn,0,0,me.brain_W,me.brain_H*me.brain_Hdim/me.brain_Wdim);
}
};
/**
* @page AtlasMaker: Input/Output
*/
var AtlasMakerIO = {
NiiHdrLE: Struct()
.word32Sle('sizeof_hdr') // Size of the header. Must be 348 (bytes)
.chars('data_type',10) // Not used; compatibility with analyze.
.chars('db_name',18) // Not used; compatibility with analyze.
.word32Sle('extents') // Not used; compatibility with analyze.
.word16Sle('session_error') // Not used; compatibility with analyze.
.word8('regular') // Not used; compatibility with analyze.
.word8('dim_info') // Encoding directions (phase, frequency, slice).
.array('dim',8,'word16Sle') // Data array dimensions.
.floatle('intent_p1') // 1st intent parameter.
.floatle('intent_p2') // 2nd intent parameter.
.floatle('intent_p3') // 3rd intent parameter.
.word16Sle('intent_code') // nifti intent.
.word16Sle('datatype') // Data type.
.word16Sle('bitpix') // Number of bits per voxel.
.word16Sle('slice_start') // First slice index.
.array('pixdim',8,'floatle') // Grid spacings (unit per dimension).
.floatle('vox_offset') // Offset into a .nii file.
.floatle('scl_slope') // Data scaling, slope.
.floatle('scl_inter') // Data scaling, offset.
.word16Sle('slice_end') // Last slice index.
.word8('slice_code') // Slice timing order.
.word8('xyzt_units') // Units of pixdim[1..4].
.floatle('cal_max') // Maximum display intensity.
.floatle('cal_min') // Minimum display intensity.
.floatle('slice_duration') // Time for one slice.
.floatle('toffset') // Time axis shift.
.word32Sle('glmax') // Not used; compatibility with analyze.
.word32Sle('glmin') // Not used; compatibility with analyze.
.chars('descrip',80) // Any text.
.chars('aux_file',24) // Auxiliary filename.
.word16Sle('qform_code') // Use the quaternion fields.
.word16Sle('sform_code') // Use of the affine fields.
.floatle('quatern_b') // Quaternion b parameter.
.floatle('quatern_c') // Quaternion c parameter.
.floatle('quatern_d') // Quaternion d parameter.
.floatle('qoffset_x') // Quaternion x shift.
.floatle('qoffset_y') // Quaternion y shift.
.floatle('qoffset_z') // Quaternion z shift.
.array('srow_x',4,'floatle') // 1st row affine transform
.array('srow_y',4,'floatle') // 2nd row affine transform.
.array('srow_z',4,'floatle') // 3rd row affine transform.
.chars('intent_name',16) // Name or meaning of the data.
.chars('magic',4), // Magic string.
NiiHdrBE: Struct()
.word32Sbe('sizeof_hdr') // Size of the header. Must be 348 (bytes)
.chars('data_type',10) // Not used; compatibility with analyze.
.chars('db_name',18) // Not used; compatibility with analyze.
.word32Sbe('extents') // Not used; compatibility with analyze.
.word16Sbe('session_error') // Not used; compatibility with analyze.
.word8('regular') // Not used; compatibility with analyze.
.word8('dim_info') // Encoding directions (phase, frequency, slice).
.array('dim',8,'word16Sbe') // Data array dimensions.
.floatbe('intent_p1') // 1st intent parameter.
.floatbe('intent_p2') // 2nd intent parameter.
.floatbe('intent_p3') // 3rd intent parameter.
.word16Sbe('intent_code') // nifti intent.
.word16Sbe('datatype') // Data type.
.word16Sbe('bitpix') // Number of bits per voxel.
.word16Sbe('slice_start') // First slice index.
.array('pixdim',8,'floatbe') // Grid spacings (unit per dimension).
.floatbe('vox_offset') // Offset into a .nii file.
.floatbe('scl_slope') // Data scaling, slope.
.floatbe('scl_inter') // Data scaling, offset.
.word16Sbe('slice_end') // Last slice index.
.word8('slice_code') // Slice timing order.
.word8('xyzt_units') // Units of pixdim[1..4].
.floatbe('cal_max') // Maximum display intensity.
.floatbe('cal_min') // Minimum display intensity.
.floatbe('slice_duration') // Time for one slice.
.floatbe('toffset') // Time axis shift.
.word32Sbe('glmax') // Not used; compatibility with analyze.
.word32Sbe('glmin') // Not used; compatibility with analyze.
.chars('descrip',80) // Any text.
.chars('aux_file',24) // Auxiliary filename.
.word16Sbe('qform_code') // Use the quaternion fields.
.word16Sbe('sform_code') // Use of the affine fields.
.floatbe('quatern_b') // Quaternion b parameter.
.floatbe('quatern_c') // Quaternion c parameter.
.floatbe('quatern_d') // Quaternion d parameter.
.floatbe('qoffset_x') // Quaternion x shift.
.floatbe('qoffset_y') // Quaternion y shift.
.floatbe('qoffset_z') // Quaternion z shift.
.array('srow_x',4,'floatbe') // 1st row affine transform
.array('srow_y',4,'floatbe') // 2nd row affine transform.
.array('srow_z',4,'floatbe') // 3rd row affine transform.
.chars('intent_name',16) // Name or meaning of the data.
.chars('magic',4), // Magic string.
MghHdr: Struct()
.word32Sbe('v')
.word32Sbe('ndim1')
.word32Sbe('ndim2')
.word32Sbe('ndim3')
.word32Sbe('nframes')
.word32Sbe('type')
.word32Sbe('dof')
.word16Sbe('ras_good_flag')
.array('delta',3,'floatbe')
.array('Mdc',9,'floatbe')
.array('Pxyz_c',3,'floatbe'),
MghFtr: Struct()
.array('mrparms',4,'floatbe'),
/**
* @function encodeNifti
*/
encodeNifti: function encodeNifti() {
var me=AtlasMakerWidget;
var l=me.traceLog(encodeNifti);if(l)console.log.apply(undefined,l);
var sizeof_hdr=348;
var dimensions=4; // number of dimension values provided
var spacetimeunits=2+8; // 2=nifti code for millimetres | 8=nifti code for seconds
var datatype=2; // datatype for 8 bits (DT_UCHAR8 in nifti or UCHAR in analyze)
var vox_offset=352;
var bitsPerVoxel=8;
var newHdr = {
sizeof_hdr: sizeof_hdr,
data_type: '', db_name: '', extents: 0, session_error: 0, regular: 0, dim_info: 0,
dim: [3, me.User.dim[0], me.User.dim[1], me.User.dim[2], 1, 1, 1, 1],
intent_p1: 0, intent_p2: 0, intent_p3: 0, intent_code: 0,
datatype: datatype, // uchar
bitpix: bitsPerVoxel,
slice_start: 0,
pixdim: [-1, me.User.pixdim[0], me.User.pixdim[1], me.User.pixdim[2], 0, 1, 1, 1],
vox_offset: vox_offset,
scl_slope: 1, scl_inter: 0, slice_end: 0, slice_code: 0,
xyzt_units: 10,
cal_max: 0, cal_min: 0, slice_duration: 0, toffset: 0,
glmax: 0, glmin: 0,
descrip: 'BrainBox, 20 August 2016',
aux_file: '',
qform_code: 0,
sform_code: 1,
quatern_b: 0, quatern_c: 0, quatern_d: 0,
qoffset_x: 0, qoffset_y: 0, qoffset_z: 0,
srow_x: [me.User.v2w[0][0], me.User.v2w[1][0], me.User.v2w[2][0], me.User.wori[0]],
srow_y: [me.User.v2w[0][1], me.User.v2w[1][1], me.User.v2w[2][1], me.User.wori[1]],
srow_z: [me.User.v2w[0][2], me.User.v2w[1][2], me.User.v2w[2][2], me.User.wori[2]],
intent_name: '',
magic: 'n+1'
};
me.NiiHdrLE.allocate();
niihdr = me.NiiHdrLE.buffer();
for(i in newHdr)
me.NiiHdrLE.fields[i] = newHdr[i];
hdr = toArrayBuffer(niihdr);
var data=me.atlas.data;
var nii = new Uint8Array(vox_offset+data.length);
for(i=0;i<sizeof_hdr;i++)
nii[i]=hdr[i];
for(i=0;i<data.length;i++)
nii[i+vox_offset]=data[i];
var niigz=new pako.Deflate({gzip:true});
niigz.push(nii,true);
return niigz.result;
},
/**
* @function saveNifti
*/
saveNifti: function saveNifti() {
var me=AtlasMakerWidget;
var l=me.traceLog(saveNifti);if(l)console.log.apply(undefined,l);
var niigz=me.encodeNifti();
var niigzBlob = new Blob([niigz]);
$("a#download_atlas").attr("href",window.URL.createObjectURL(niigzBlob));
$("a#download_atlas").attr("download",me.User.atlasFilename);
},
swapInt16: function swapInt16(arr) {
var i,dv = new DataView(arr.buffer);
for(i=0;i<arr.length;i++) {
arr[i]= dv.getInt16(2*i,false);
}
return arr;
},
swapUint16: function swapUint16(arr) {
var i,dv = new DataView(arr.buffer);
for(i=0;i<arr.length;i++) {
arr[i]= dv.getUint16(2*i,false);
}
return arr;
},
swapInt32: function swapInt32(arr) {
var i,dv = new DataView(arr.buffer);
for(i=0;i<arr.length;i++) {
arr[i]= dv.getInt32(4*i,false);
}
return arr;
},
swapFloat32: function swapFloat32(arr) {
var i,dv = new DataView(arr.buffer);
for(i=0;i<arr.length;i++) {
arr[i]= dv.getFloat32(4*i,false);
}
return arr;
},
/**
* @function loadNifti
*/
loadNifti: function loadNifti(nii) {
var me=AtlasMakerWidget;
var l=me.traceLog(loadNifti,1);if(l)console.log.apply(undefined,l);
var endianness='le';
me.NiiHdrLE._setBuff(toBuffer(nii));
var h=JSON.parse(JSON.stringify(me.NiiHdrLE.fields));
if(h.sizeof_hdr!=348) {
me.NiiHdrBE._setBuff(toBuffer(nii));
h=JSON.parse(JSON.stringify(me.NiiHdrBE.fields));
endianness='be';
}
var vox_offset=h.vox_offset;
var sizeof_hdr=h.sizeof_hdr;
var mri={};
mri.hdr=nii.slice(0,vox_offset);
mri.datatype=h.datatype;
mri.dim=[h.dim[1],h.dim[2],h.dim[3]];
mri.pixdim=[h.pixdim[1],h.pixdim[2],h.pixdim[3]];
switch(mri.datatype)
{
case 2: // UCHAR
mri.data=new Uint8Array(nii,vox_offset);
break;
case 256: // INT8
mri.data=new Uint8Array(nii,vox_offset);
break;
case 4: // SHORT
if(endianness=='le')
mri.data=new Int16Array(nii,vox_offset);
else
mri.data=me.swapInt16(new Int16Array(nii,vox_offset));
break;
case 8: // INT
if(endianness=='le')
mri.data=new Int32Array(nii,vox_offset);
else
mri.data=me.swapInt32(new Int32Array(nii,vox_offset));
break;
case 16: // FLOAT
if(endianness=='le')
mri.data=new Float32Array(nii,vox_offset);
else
mri.data=me.swapFloat32(new Float32Array(nii,vox_offset));
break;
case 256: // INT8
mri.data=new Int8Array(nii,vox_offset);
break;
case 512: // UINT16
if(endianness=='le')
mri.data=new Uint16Array(nii,vox_offset);
else
mri.data=me.swapUint16(new Uint16Array(nii,vox_offset));
break;
default:
console.log("ERROR: Unknown dataType: "+mri.datatype);
}
return mri;
},
/*
{Linear algebra
*/
/**
* @function computeS2VTransformation
*/
computeS2VTransformation: function computeS2VTransformation() {
var me=AtlasMakerWidget;
var l=me.traceLog(computeS2VTransformation);if(l)console.log.apply(undefined,l);
/**
* @todo Much of the code downstairs can be removed
*/
var mri = me.User;
var v2w=mri.v2w;
var wori=mri.wori;
var wpixdim=me.subVecVec(me.mulMatVec(v2w,[1,1,1]),me.mulMatVec(v2w,[0,0,0]));
var wvmax=me.addVecVec(me.mulMatVec(v2w,[mri.dim[0]-1,mri.dim[1]-1,mri.dim[2]-1]),wori);
var wvmin=me.addVecVec(me.mulMatVec(v2w,[0,0,0]),wori);
var wmin=[Math.min(wvmin[0],wvmax[0]),Math.min(wvmin[1],wvmax[1]),Math.min(wvmin[2],wvmax[2])];
var wmax=[Math.max(wvmin[0],wvmax[0]),Math.max(wvmin[1],wvmax[1]),Math.max(wvmin[2],wvmax[2])];
var w2s=[[1/Math.abs(wpixdim[0]),0,0],[0,1/Math.abs(wpixdim[1]),0],[0,0,1/Math.abs(wpixdim[2])]];
var i=v2w[0];
var j=v2w[1];
var k=v2w[2];
var mi={i:0,v:0};i.map(function(o,n){if(Math.abs(o)>Math.abs(mi.v)) mi={i:n,v:o}});
var mj={i:0,v:0};j.map(function(o,n){if(Math.abs(o)>Math.abs(mj.v)) mj={i:n,v:o}});
var mk={i:0,v:0};k.map(function(o,n){if(Math.abs(o)>Math.abs(mk.v)) mk={i:n,v:o}});
mri.s2v = {
// old s2v fields
s2w: me.invMat(w2s),
sdim: [],
sori: [-wmin[0]/Math.abs(wpixdim[0]),-wmin[1]/Math.abs(wpixdim[1]),-wmin[2]/Math.abs(wpixdim[2])],
wpixdim: [],
w2v: me.invMat(v2w),
wori: wori,
// new s2v transformation
x: mi.i, // correspondence between space coordinate x and voxel coordinate i
y: mj.i, // same for y
z: mk.i, // same for z
dx: (mi.v>0)?1:(-1), // direction of displacement in space coordinate x with displacement in voxel coordinate i
dy: (mj.v>0)?1:(-1), // same for y
dz: (mk.v>0)?1:(-1), // same for z
X: (mi.v>0)?0:(mri.dim[0]-1), // starting value for space coordinate x when voxel coordinate i starts
Y: (mj.v>0)?0:(mri.dim[1]-1), // same for y
Z: (mk.v>0)?0:(mri.dim[2]-1) // same for z
};
mri.v2w=v2w;
mri.wori=wori;
mri.s2v.sdim[mi.i] = mri.dim[0];
mri.s2v.sdim[mj.i] = mri.dim[1];
mri.s2v.sdim[mk.i] = mri.dim[2];
mri.s2v.wpixdim[mi.i] = mri.pixdim[0];
mri.s2v.wpixdim[mj.i] = mri.pixdim[1];
mri.s2v.wpixdim[mk.i] = mri.pixdim[2];
},
/**
* @function testS2VTransformation
*/
testS2VTransformation: function testS2VTransformation() {
var me=AtlasMakerWidget;
var l=me.traceLog(testS2VTransformation);if(l)console.log.apply(undefined,l);
/*
check the S2V transformation to see if it looks correct.
If it does not, reset it
*/
var mri=me.User; // this line is different from server
var doReset=