New object-oriented iPACS VivoScript Integration
With the release of VivoQuant 1.23, new functionality has been added to facilitate iPACS communication within VivoScript. Users are now able to easily filter though entire iPACS projects easily and pick out the desired data sets in clean, simple scripts. The functionality has been written in VivoScript and included in every new install of VivoQuant 1.23 as ipacs.vqs, so implementing it within your VivoScrips is very easy.
To use ipacs.vqs, it must first be included in a VivoScript by adding the following line to the first line of your script:
#include "ipacs.vqs"
This will allow the script to access the iPACS object and all of its methods.
iPACS VivoScript Basics
Communication between VivoScript and the iPACS is implemented in an object-oriented fashion. Queries to the iPACS are returned as objects or lists of objects, particularly in dealing with studies and series. The study and series objects returned by the query methods are in turn used by subsequent methods to access the data on the iPACS.
To interact with the iPACS, an iPACS object must be created. To do so, the following constructor should be used:
var repo = new iPACS(ipacs_url,project_location);
The iPACS, study and series objects have several properties associated with them. To access object properties, use the following convention:
var project = repo.project;
The following are accessible properties of the iPACS object:
- dcmRep: DICOM repository object
- repository_url: Address of repository (eg ipacss://invicro.ipacs.invicro.com)
- project: Project path
The study object has the following properties associated with it:
- PatientComments
- PatientID
- PatientsName
- StudyDate
- StudyDescription
- StudyInstanceUID
- StudyTime
The series object has the following properties associated with it:
- ManufacturersModelName
- Modality
- SeriesDate
- SeriesDescription
- SeriesInstanceUID
- SeriesNumber
- SeriesTime
- StudyInstanceUID
Series and studies properties can be used in the following methods to filter results or to grab data from the iPACS data
Overview of Available Methods
The following methods can be used by the iPACS object to query, retrieve, and store data to the iPACS
- getStudies()
- getSeries()
- getImages()
- submitData()
- getROIs()
- mergeROIs()
- submitROIs()
- getInjectedDose()
- getQuantification()
getStudies()
Returns an array of all study objects within a project. Filters can be used to limit the output so as to only return a certain subset of a project, such as time point or group.
Optional Arguments:
- -namefilter: A filter for PatientsName
- -idfilter: A filter for PatientID
- -sort: Option to sort the output data. Can sort on PatientsName, PatientID, or Study Date
- -datestart: A filter that only gets projects more recent that the date requested. Must be in the format YYYYMMDD.
- -dateend: A filter that only gets studies older than date submitted. Must be in the format YYYYMMDD.
All arguments are optional and can be added in any order.
Example Usage:
//Assume iPACS object repo has already been created. var studies = repo.getStudies(); // Gets all studies in repo var studies = repo.getStudies('-namefilter','*S1*') // Gets all studies with the pattern "S1" in repo var studies = repo.getStudies('-datestart','20140101') // Only gets studies with a 2014 study date var studies = repo.getStudies('-datestart','20140101','-dateend','20140131') // Only gets studies with a January 2014 study date var studies = repo.getStudies('-idfilter','A1007','sort','StudyDate','-datestart','20130901'); // Only gets studies with PatientID A1007, from September 1,2013 on and sorted by date.
getSeries(study)
Returns an array of all series object within study ‘study.’ Filters can be used to limit the output based on modality or series description.
Required Arguments
- study: Study Object to get the series objects from
Optional Arguments
- -modality: DICOM modality code. Usually used are CT, PT, and NM. A full list can be found here
- -seriesdescription: A filter that only returns series that match the series description
The optional arguments can be added in any order, but the required argument must always come first
Example Usage:
//Assume iPACS object repo and array of study objects studies have been created var ct = repo.getSeries(series[0],'-modaltiy','CT'); var nm = repo.getSeries(series[0],'-modality','NM','-seriesdescription','*focused*');
getImages(study,series,input)
Downloads and opens the image located at study ‘study’ and series ‘series.’ It will load the image into input ‘input’ in the Data Manager. If series has more than one image associated with it, all images will be loaded.
Required Arguments
- study: Study Object image is located in
- series: Series Object image is located in
- input: Input in data manager to load image into
Example Usage:
// Assumes iPACS object repo, study object studies and series objects ct and nm repo.getImages(studies[0],ct[0],0); repo.getImages(studies[0],nm[0],1);
submitData(input)
Stores data located at input ‘input’ to the iPACS
Required Arguments:
- input: Input of data to store to the iPACS repository
Example Usage:
// Assumes iPACS repository repo repo.submitData(0); repo.submitData(1);
getROIs()
Retrieves and loads most recent ROI meeting criteria specified in optional arguments
Optional Arguments:
- -creator: name of person who submitted ROI (must match quantification data point). Exact match only
- -names: List of ROIs to get. Will return most recent ROI that contains at least all of the ROIs found in names array.
- -savepath: Optional save location of temporary rmha file. Necessary if computer permissions prohibit saving to VQ root directory.
Example Usage
// Assumes iPACS object repo and images are loaded that have ROI data points repo.getROIs('-creator','anovicki') // Last ROI submitted by anovicki repo.getROIs('-names',['Muscle','Brain']) // Last ROI submitted containing Muscle and Brain ROIs (and any other ROIs included in the .rmha files) repo.getROIs('-names',['Liver'],'-creator','jtierney','-savepath','C:/tmp.rmha')
mergeROIs()
Similar to getROIs() but supports merging of ROIs from separate rmha files. Also supports removal of unwanted ROIs once loaded.
Required Arguments:
- -names: List of ROIs to get. Will get the most recent ROI file for each of the ROIs in roilist and merge them into VivoQuant
Optional Arguments:
- -creator: name of person who submitted ROI (must match quantification data point). Exact match only
- -savepath: Optional save location of temporary rmha file. Necessary if computer permissions prohibit saving to VQ root directory.
- -exactlist: Boolean on whether or not to delete ROIs not located on the -names list. If true, end result will ONLY be the ROIs in -names (Default: TRUE)
Example Usage
// Assumes iPACS object repo, and image with quantification data points is loaded repo.mergeROIs('-names',['Heart','Muscle'],'-exactlist',true) // Merges most recent version of Heart and Muscle. Removes other ROIs repo.mergeROIs('-names',['Heart','Muscle'],'-exactlist',false) // Merges most recent version of Heart and Muscle. Leaves any other ROIs located in rmha folder
submitROIs()
Submits all ROIs as a single rmha file to the iPACS. Submits data points for all inputs loaded. (Note: Inputs must be turned on in the Visual controller in order for them to be submitted. Inputs higher than Input 2 will be submitted if Input 2 is turned on).
Example Usage
// Assumes ROIs are loaded in 3D ROI Tool and iPACS object repo exists repo.submitROIs()
getInjectedDose()
Returns injected dose found in the iPACS subject information data point. Will return 0 if no information is entered on the data point
Required Arguments
- input: Input number to check injected dose
Example Usage:
// Assumes iPACS object repo and images with subject information data points loaded var inj = repo.getInjectedDose(1); // Gets injected dose of input 1
getQuantification()
Returns list of all quantification data points associated with a given input. Useful for grabbing specific data about ROIs without loading them. Each item in the list is a quantification data point object that has the same properties as the actual data points visible on the iPACS. For example, to get the mean value of the data in the ROI, type quant[0].mean , where quant[0] is the first item in the list returned by the method.
Required Arguments
- input: Index of input to get quantification data points
Example Usage:
// Assumes iPACS Object repo and images loaded into VQ var quant = repo.getQuantification(1); // Lists names of all quantification data points (ROI names) for Input 1 for (i=0; i<quant.length;i++){ VQ.debug(quant[i].name); }
Example VivoScript
This example VivoScript iterates through each study within a project and performs the following
- Downloads the image
- Converts to %ID/g
- Sets min and max range
- Downloads the ROIs associated with the image
- Builds file name using Patient Name and Patient ID from Study Object
- Makes each ROI invisible
- Iterates through each ROI and takes an image of subject centered at the ROI center of mass with the ROI visible
The script assumes that injected doses (in uCi) are entered for each subject on the Subject Information data point on the iPACS (for conversion to %ID/g)
#include "ipacs.vqs" // Location to save images var obase = 'C:/path/to/local/folder/' // Minimum and Maximum %ID/g values to scale to var pidgmin = 0; var pidgmax = 60; // VivoQuant Variables var dm = VQ.dataManager(); var mw = VQ.mainWin(); var mm = VQ.minMaxTool(); var ctl = VQ.controler(); // Instantiate a new iPACS object var repo = new iPACS('ipacss://ipacsname.ipacs.invicro.com','/path/to/remote/folder/'); var studies = repo.getStudies(); for (var i = 0; i < studies.length; i++){ // Get CT and NM series var ct = repo.getSeries(studies[i],'-modality','CT') var nm = repo.getSeries(studies[i],'-modality','NM','-seriesdescription','*In-111 *'); // Only gets nm series that have In-111 in the description // Test to make sure ct and nm are both one object long (for this project they should be) if (ct.length != 1 || nm.length != 1) VQ.suspend('ERROR'); // Load images repo.getImages(studies[i],ct[0],0); repo.getImages(studies[i],nm[0],1); // Get injected dose and voxel size var inj = repo.getInjectedDose(1); var vox_sizex = dm.voxelSizeX(0); var vox_sizey = dm.voxelSizeY(0); var vox_sizez = dm.voxelSizeZ(0); var vox_size = vox_sizex * vox_sizey * vox_sizez; // Conversion mw.setViewMode("Slice View",'Arithmetics'); // Convert to %ID VQ.currentOp().multScalar(1,100/inj); // Convert to %ID/g (assume 1 g = 1 cm^3) VQ.currentOp().multScalar(1,1000/vox_size); // Set %ID/g Range dm.setMinMaxCache(1,pidgmin,pidgmax); mm.resetValues(); mm.applyValues(); mm.updateDisplay(); // Download ROIs. The method will ONLY get the ROIs listed in the '-names' list repo.mergeROIs('-names',['Heart','Lungs','Liver','Spleen','LeftKidney','RightKidney','Bladder','Brain','Tumor','Bone'],'-exactlist',true); // Make file name pname = studies[i].PatientsName; pid = studies[i].PatientID; pname = pname.replace('+','_'); pid = pid.replace(' ','_'); fname = pname + '-' + pid; mw.setViewMode('Slice View','3D ROI Tool'); var roi = VQ.currentOp(); // Make all ROIs invisible for (var j = 1; j < roi.numROIs(); j++){ var det = roi.getROIDetails(j); roi.editROI(j,det[0],det[1],det[2],true,det[4],det[5]); } // Loop through each ROI and take a picture centered on it with ROI on/off for (var j = 1; j < roi.numROIs(); j++){ var det = roi.getROIDetails(j); roi.editROI(j,det[0],det[1],det[2],false,det[4],det[5]); fname_out = fname + '-' + det[0]; // Set COM var centers = roi.getROICenterOfMass(j); centers = centers.substr(1,centers.length-2).split(" "); ctl.setPos(0,centers[0]); ctl.setPos(1,centers[1]); ctl.setPos(2,centers[2]); ctl.setRange(0,0,0.6); // Take picture mw.saveImage(obase + fname_out + '-roi',5); // Make ROI invisible roi.editROI(j,det[0],det[1],det[2],true,det[4],det[5]); // Take picture mw.saveImage(obase + fname_out + '-noroi',5); } // Remove all ROIs while(roi.numROIs() > 1) roi.deleteROI(1,0); }