Permalink
Browse files

Adding parserMRC and test pages

  • Loading branch information...
1 parent 6e14210 commit 25ea88e2a1fe8f03970cd5f92aeae66d717d8b44 @emilysperanza emilysperanza committed Mar 23, 2014
View
@@ -40,6 +40,7 @@ goog.require('X.parserLBL');
goog.require('X.parserLUT');
goog.require('X.parserMGZ');
goog.require('X.parserNII');
+goog.require('X.parserMRC');
goog.require('X.parserNRRD');
goog.require('X.parserOBJ');
goog.require('X.parserOFF');
@@ -364,6 +365,8 @@ X.loader.extensions = {
'STL': [X.parserSTL, null],
'VTK': [X.parserVTK, null],
'TRK': [X.parserTRK, null],
+ 'MRC': [X.parserMRC, null],
+ 'ST': [X.parserMRC, null],
// FSM, INFLATED, SMOOTHWM, SPHERE, PIAL and ORIG are all freesurfer meshes
'FSM': [X.parserFSM, null],
'INFLATED': [X.parserFSM, null],
View
@@ -0,0 +1,359 @@
+/*
+*Parser for MRC files
+*
+*/
+
+// provides
+goog.provide('X.parserMRC');
+
+// requires
+goog.require('X.event');
+goog.require('X.object');
+goog.require('X.parser');
+goog.require('X.triplets');
+goog.require('goog.vec.Mat3');
+goog.require('goog.vec.Mat4');
+goog.require('Zlib.Gunzip');
+
+/**
+ * Create a parser for .mrc files.
+ *
+ * @constructor
+ * @extends X.parser
+ */
+X.parserMRC = function() {
+
+ //
+ // call the standard constructor of X.parser
+ goog.base(this);
+
+ //
+ // class attributes
+
+ /*
+ * @inheritDoc
+ * @const
+ */
+ this._classname = 'parserMRC';
+};
+// inhert from X.parser
+goog.inherits(X.parserMRC, X.parser);
+
+/**
+ * @inheritDoc
+ */
+X.parserMRC.prototype.parse = function(container, object, data, flag) {
+
+ X.TIMER(this._classname + '.parse');
+
+ var _data = data;
+
+ // parse the byte stream
+ var MRI = this.parseStream(_data);
+
+ // min and max intensities
+ var min = MRI.min;
+ var max = MRI.max;
+
+ //get dimsensions
+ var _dimensions = [MRI.nx, MRI.ny, MRI.nz];
+ object._dimensions = _dimensions
+
+ //get pixel spacing = xlen/mx
+ var spacingX = MRI.xlen / MRI.mx;
+ var spacingY = MRI.ylen / MRI.my;
+ var spacingZ = MRI.zlen / MRI.mz;
+ object._spacing = [ spacingX, spacingY, spacingZ ];
+
+ // attach the scalar range to the volume
+ object._min = object._windowLow = min;
+ object._max = object._windowHigh = max;
+
+ // set the default threshold
+ if (object._lowerThreshold == -Infinity) {
+ object._lowerThreshold = min;
+ }
+ if (object._upperThreshold == Infinity) {
+ object._upperThreshold = max;
+ }
+
+ // Create IJKtoXYZ matris
+ var IJKToRAS = goog.vec.Mat4.createFloat32();
+ goog.vec.Mat4.setRowValues(IJKToRAS,
+ 3,
+ 0,
+ 0,
+ 0,
+ 1);
+
+ // fill in IJKToRas
+
+ goog.vec.Mat4.setRowValues(IJKToRAS, 0, -1, 0, 0, MRI.nx);
+ goog.vec.Mat4.setRowValues(IJKToRAS, 1, 0, 0, -1, MRI.ny);
+ goog.vec.Mat4.setRowValues(IJKToRAS, 2, 0, -1, 0, MRI.nz);
+
+ // IJK to RAS and invert
+ MRI.IJKToRAS = IJKToRAS;
+ MRI.RASToIJK = goog.vec.Mat4.createFloat32();
+ goog.vec.Mat4.invert(MRI.IJKToRAS, MRI.RASToIJK);
+
+ // get bounding box
+ // Transform ijk (0, 0, 0) to RAS
+ var tar = goog.vec.Vec4.createFloat32FromValues(0, 0, 0, 1);
+ var res = goog.vec.Vec4.createFloat32();
+ goog.vec.Mat4.multVec4(IJKToRAS, tar, res);
+ // Transform ijk (spacingX, spacinY, spacingZ) to RAS
+ var tar2 = goog.vec.Vec4.createFloat32FromValues(1, 1, 1, 1);
+ var res2 = goog.vec.Vec4.createFloat32();
+ goog.vec.Mat4.multVec4(IJKToRAS, tar2, res2);
+
+ // get location of 8 corners and update BBox
+ var _dims = [MRI.nx, MRI.ny, MRI.nz];
+ var _rasBB = X.parser.computeRASBBox(IJKToRAS, _dims);
+
+ // grab the RAS dimensions
+ MRI.RASSpacing = [res2[0] - res[0], res2[1] - res[1], res2[2] - res[2]];
+ MRI.RASDimensions = [_rasBB[1] + _rasBB[0] + 1, _rasBB[3] - _rasBB[2] + 1, _rasBB[5] - _rasBB[4] + 1];
+
+ // grab the RAS Origin
+ MRI.RASOrigin = [_rasBB[0], _rasBB[2], _rasBB[4]];
+
+ //grab the IJK dimensions
+ object._dimensions = _dims;
+
+ // create the object
+ object.create_(MRI);
+
+ // re-slice the data according each direction.
+ object._image = this.reslice(object);
+
+ X.TIMERSTOP(this._classname + '.parse');
+
+ // the object should be set up here, so let's fire a modified event
+ var modifiedEvent = new X.event.ModifiedEvent();
+ modifiedEvent._object = object;
+ modifiedEvent._container = container;
+ this.dispatchEvent(modifiedEvent);
+
+};
+
+/**
+ *Parse the data stream following the MRC file format
+ *File format specifications can be found at http://bio3d.colorado.edu/imod/doc/mrc_format.txt
+ *
+ * @param {!ArrayBuffer} data The data stream
+ * @return {Object} the MRI structure which holds all parsed information
+ */
+X.parserMRC.prototype.parseStream = function(data) {
+
+ this._data = data;
+
+ var MRI = {
+ nx: 0, //Number of Columns
+ ny: 0, //Number of Rows
+ nz: 0, //Number of Sections
+ mode: 0, //Type of pixel in image. Values used by IMOD
+ nxstart: 0, //Startin poin to sub image (not used in IMOD)
+ nystart: 0,
+ nzstart: 0,
+ mx: 0, //Grid size in X, Y, Z
+ my: 0,
+ mz: 0,
+ xlen: 0, //Cell size; pixel spacing = xlen/mx...
+ ylen: 0,
+ zlen: 0,
+ alpha: 0, //cell angles - ignored by IMOD
+ beta: 0,
+ gamma: 0,
+ mapc: 0, //map column
+ mapr: 0, //map row
+ maps: 0, //map section
+ amin: 0, //Minimum pixel value
+ amax: 0, //Maximum pixel value
+ amean: 0, //mean pixel value
+ ispg: 0, //space group numbe (ignored by IMOD0
+ next: 0, //number of bytes in extended header
+ creatid: 0, //is 0
+ extra: null,
+ nint: 0, // number of intergers or bytes per section
+ nreal: 0, // Number of reals per section
+ extra: null,
+ imodStamp: 0, //1146047817 = file created by IMOD
+ imodFlags: 0, //Bit flags
+ idtype: 0,
+ lens: 0,
+ nd1: 0,
+ nd2: 0,
+ vd1: 0,
+ vd2: 0,
+ tiltangles: null,
+ xorg: 0, //Orgin of the image
+ yorg: 0,
+ zorg: 0,
+ cmap: 0, //Contains "MAP "
+ stamp: 0, //Frist two bytes = 17 17 for bin-endian or 68 and 65 for littl-edian
+ rms: 0, //RMS deviation of densitites from mean density
+ nlabl: 0, //number of lables with useful data
+ data: null, //10 lables of 80 characters
+ min: Infinity,
+ max: -Infinity,
+ mean: 0,
+ space: null,
+ spaceorientation: null,
+ rasspaceorientation: null,
+ orientation: null,
+ normcosine: null
+ };
+
+ //Check Edianness
+ this.jumpTo(parseInt(212));
+ MRI.stamp = this.scan('schar');
+ if (MRI.stamp == 17) {
+ data = this.filpEdianness;
+ }
+
+
+ this.jumpTo(parseInt(0));
+ // Reading the data. Names are the names used in C code.
+ MRI.nx = this.scan('sint');
+ MRI.ny = this.scan('sint');
+ MRI.nz = this.scan('sint');
+ MRI.mode = this.scan('sint');
+
+ // size of the image
+ var volsize = MRI.nx * MRI.ny * MRI.nz ;
+
+ // Read for the type of pixels
+ this.jumpTo(parseInt(1024));
+ switch (MRI.mode) {
+ case 0:
+ MRI.data = this.scan('schar', volsize);
+ break;
+ case 1:
+ MRI.data = this.scan('sshort', volsize);
+ break;
+ case 2:
+ MRI.data = this.scan('float', volsize);
+ break;
+ case 3:
+ MRI.data = this.scan('uint', volsize);
+ break;
+ case 4:
+ MRI.data = this.scan('double', volsize);
+ break;
+ case 6:
+ MRI.data = this.scan('ushort', volsize);
+ break;
+ case 16:
+ MRI.data = this.scan('uchar', volsize);
+ break;
+
+ default:
+ throw new Error('Unsupported MRC data type: ' +MRI.mode);
+ }
+
+ this.jumpTo(parseInt(28));
+
+ MRI.mx = this.scan('sint');
+ MRI.my = this.scan('sint');
+ MRI.mz = this.scan('sint');
+
+ // pixel spacing = xlem/mx
+ MRI.xlen = this.scan('float');
+ MRI.ylen = this.scan('float');
+ MRI.zlen = this.scan('float');
+ MRI.alpha = this.scan('float');
+ MRI.beta = this.scan('float');
+ MRI.gamma = this.scan('float');
+ MRI.mapc = this.scan('sint');
+ MRI.mapr = this.scan('sint');
+ MRI.maps = this.scan('sint');
+ MRI.amin = this.scan('float');
+ MRI.amax = this.scan('float');
+ MRI.amean = this.scan('float');
+ MRI.ispeg = this.scan('sint');
+ MRI.next = this.scan('sint');
+ MRI.creatid = this.scan('short');
+ //Not sure what to do with the extra data, says 30 for size
+ MRI.nint = this.scan('short');
+ MRI.nreal = this.scan('short');
+ //Need to figure out extra data, 20 for size
+ MRI.imodStamp = this.scan('sint');
+ MRI.imodFLags = this.scan('sint');
+ MRI.idtype = this.scan('short');
+ MRI.lens = this.scan('short');
+ MRI.nd1 = this.scan('short');
+ MRI.nd2 = this.scan('short');
+ MRI.vd1 = this.scan('short');
+ MRI.vd2 = this.scan('short');
+
+ // loop this around (6 different ones)
+ MRI.tiltangles = this.scan('float',6);
+
+ this.jumpTo(parseInt(196));
+
+ MRI.xorg = this.scan('float');
+ MRI.yorg = this.scan('float');
+ MRI.zorg = this.scan('float');
+
+ this.jumpTo(parseInt(216));
+
+ MRI.rms = this.scan('float');
+
+ MRI.nlabl = this.scan('sint');
+
+ // 10 of 80 characters
+ MRI.lables = this.scan('schar', 10);
+
+ //Dealing with extended header
+ if (MRI.next != 0) {
+ this.jumpTo(parseInt(MRI.next+1024))
+ switch (MRI.mode) {
+ case 0:
+ MRI.data = this.scan('schar', volsize);
+ break;
+ case 1:
+ MRI.data = this.scan('sshort', volsize);
+ break;
+ case 2:
+ MRI.data = this.scan('float', volsize);
+ break;
+ case 3:
+ MRI.data = this.scan('uint', volsize);
+ break;
+ case 4:
+ MRI.data = this.scan('double', volsize);
+ break;
+ case 6:
+ MRI.data = this.scan('ushort', volsize);
+ break;
+ case 16:
+ MRI.data = this.scan('uchar', volsize);
+ break;
+
+ default:
+ throw new Error('Unsupported MRC data type: ' +MRI.mode);
+ };
+ }
+
+
+ // minimum, maximum, mean intensities
+ // centered on the mean for best viewing ability
+ if (MRI.amean - (MRI.amax - MRI.amean) < 0) {
+ MRI.min = MRI.amin;
+ MRI.max = MRI.amean + (MRI.amean - MRI.amin);
+ }
+ else {
+ MRI.min = MRI.amean - (MRI.amax - MRI.amean);
+ MRI.max = MRI.amax
+ }
+
+ return MRI;
+
+};
+
+// export symbols (required fro advanced compilatoin)
+goog.exportSymbol('X.parserMRC', X.parserMRC);
+goog.exportSymbol('X.parserMRC.prototype.parse', X.parserMRC.prototype.parse);
+
+
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,15 @@
+test = function() {
+
+ //create a new test_renderer
+ test_renderer = new X.renderer3D();
+ test_renderer.init();
+
+ //load a .mrc file
+ var volume = new X.volume();
+ volume.file = 'data/test.mrc';
+
+ test_renderer.add(volume);
+
+ test_renderer.render();
+
+};
Oops, something went wrong.

0 comments on commit 25ea88e

Please sign in to comment.