├── CMakeLists.txt ├── Docs ├── MatlabBridgeDesign.pptx ├── logo │ ├── MatlabBridgeLogo.png │ ├── MatlabBridgeLogo.xcf │ ├── MatlabBridgeLogo_128x128.png │ ├── MatlabModuleGenerator.xcf │ └── description.txt └── tutorial │ ├── MatlabBridgeTutorial.pdf │ └── MatlabBridgeTutorial.ppt ├── Examples ├── FillAroundSeeds │ ├── FillAroundSeeds.bat │ ├── FillAroundSeeds.m │ └── FillAroundSeeds.xml ├── LandmarkRegistration │ ├── LandmarkRegistration.bat │ ├── LandmarkRegistration.m │ ├── LandmarkRegistration.xml │ └── absor.m ├── MatlabBridgeParameterPassingTest │ ├── MatlabBridgeParameterPassingTest.bat │ ├── MatlabBridgeParameterPassingTest.m │ └── MatlabBridgeParameterPassingTest.xml └── MeshScale │ ├── MeshScale.bat │ ├── MeshScale.m │ └── MeshScale.xml ├── MatlabBridge.png ├── MatlabCommander ├── CMakeLists.txt ├── MatlabCommander.cxx ├── MatlabCommander.xml └── commandserver │ ├── cli_argsread.m │ ├── cli_argswrite.m │ ├── cli_commandserver.m │ ├── cli_geometryread.m │ ├── cli_geometrywrite.m │ ├── cli_imageread.m │ ├── cli_imagewrite.m │ ├── cli_lineartransformread.m │ ├── cli_lineartransformwrite.m │ ├── cli_measurementread.m │ ├── cli_measurementwrite.m │ ├── cli_pointfileread.m │ ├── cli_pointfilewrite.m │ ├── cli_pointvectordecode.m │ ├── cli_stringvectordecode.m │ ├── cli_transformread.m │ ├── cli_transformwrite.m │ ├── cli_version.m.in │ ├── fcsvwrite.m │ ├── nrrdaddmetafield.m │ ├── nrrdread.m │ ├── nrrdwrite.m │ ├── read_ply.m │ ├── stlread.m │ ├── stlwrite.m │ └── write_ply.m ├── MatlabModuleGenerator ├── CMakeLists.txt ├── Logic │ ├── CMakeLists.txt │ ├── vtkSlicerMatlabModuleGeneratorLogic.cxx │ └── vtkSlicerMatlabModuleGeneratorLogic.h ├── Resources │ ├── Icons │ │ └── MatlabModuleGenerator.png │ ├── Templates │ │ ├── MatlabModuleTemplate │ │ ├── MatlabModuleTemplate.bat │ │ ├── MatlabModuleTemplate.m │ │ └── MatlabModuleTemplate.xml │ ├── UI │ │ └── qSlicerMatlabModuleGeneratorModuleWidget.ui │ └── qSlicerMatlabModuleGeneratorModule.qrc ├── Testing │ ├── CMakeLists.txt │ └── Cxx │ │ └── CMakeLists.txt ├── qSlicerMatlabModuleGeneratorModule.cxx ├── qSlicerMatlabModuleGeneratorModule.h ├── qSlicerMatlabModuleGeneratorModuleWidget.cxx └── qSlicerMatlabModuleGeneratorModuleWidget.h └── README.md /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(MatlabBridge) 4 | 5 | #----------------------------------------------------------------------------- 6 | OPTION(MATLABBRIDGE_ENABLE_MATLAB_TESTING "Enable using of Matlab for testing. Turn this option requires Matlab to be installed on this computer." OFF) 7 | 8 | # ------------------------------------------------------------------------ 9 | set(MATLABBRIDGE_VERSION_MAJOR "0") 10 | set(MATLABBRIDGE_VERSION_MINOR "14") 11 | set(MATLABBRIDGE_VERSION_PATCH "0") 12 | set(MATLABBRIDGE_VERSION ${MATLABBRIDGE_VERSION_MAJOR}.${MATLABBRIDGE_VERSION_MINOR}.${MATLABBRIDGE_VERSION_PATCH}) 13 | 14 | #----------------------------------------------------------------------------- 15 | set(EXTENSION_HOMEPAGE "https://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge") 16 | set(EXTENSION_CATEGORY "Developer Tools") 17 | set(EXTENSION_CONTRIBUTORS "Andras Lasso (PerkLab, Queen's University), Jean-Christophe Fillion-Robin (Kitware), Kevin Wang (Radiation Medicine Program, Princess Margaret Hospital, University Health Network Toronto)") 18 | set(EXTENSION_DESCRIPTION "The Matlab Bridge extension allows running Matlab scripts as command-line interface (CLI) modules directly from 3D Slicer. The only prerequisites for running Matlab scripts are having this extension and Matlab installed on the 3D Slicer computer (building of 3D Slicer, MEX files, etc. is not needed). Extension version: ${MATLABBRIDGE_VERSION}.") 19 | set(EXTENSION_ICONURL "https://www.slicer.org/slicerWiki/images/e/e8/MatlabBridgeLogo.png") 20 | set(EXTENSION_SCREENSHOTURLS "https://www.slicer.org/slicerWiki/images/2/2f/MatlabBridgeScreenshot1.png https://www.slicer.org/slicerWiki/images/1/16/MatlabBridgeScreenshot2.png https://www.slicer.org/slicerWiki/images/b/b9/MatlabBridgeScreenshot3.png") 21 | set(EXTENSION_DEPENDS SlicerOpenIGTLink) 22 | 23 | #----------------------------------------------------------------------------- 24 | find_package(Slicer REQUIRED) 25 | include(${Slicer_USE_FILE}) 26 | 27 | #----------------------------------------------------------------------------- 28 | add_subdirectory(MatlabCommander) 29 | add_subdirectory(MatlabModuleGenerator ) 30 | 31 | #----------------------------------------------------------------------------- 32 | include(${Slicer_EXTENSION_GENERATE_CONFIG}) 33 | include(${Slicer_EXTENSION_CPACK}) 34 | -------------------------------------------------------------------------------- /Docs/MatlabBridgeDesign.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/MatlabBridgeDesign.pptx -------------------------------------------------------------------------------- /Docs/logo/MatlabBridgeLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabBridgeLogo.png -------------------------------------------------------------------------------- /Docs/logo/MatlabBridgeLogo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabBridgeLogo.xcf -------------------------------------------------------------------------------- /Docs/logo/MatlabBridgeLogo_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabBridgeLogo_128x128.png -------------------------------------------------------------------------------- /Docs/logo/MatlabModuleGenerator.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/logo/MatlabModuleGenerator.xcf -------------------------------------------------------------------------------- /Docs/logo/description.txt: -------------------------------------------------------------------------------- 1 | Image source: http://commons.wikimedia.org/wiki/File:Matlab_Logo.png -------------------------------------------------------------------------------- /Docs/tutorial/MatlabBridgeTutorial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/tutorial/MatlabBridgeTutorial.pdf -------------------------------------------------------------------------------- /Docs/tutorial/MatlabBridgeTutorial.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/Docs/tutorial/MatlabBridgeTutorial.ppt -------------------------------------------------------------------------------- /Examples/FillAroundSeeds/FillAroundSeeds.bat: -------------------------------------------------------------------------------- 1 | @set MODULE_NAME=FillAroundSeeds 2 | @rem MatlabBridge proxy version: 1.0 3 | 4 | @echo off 5 | if not "%~1"=="--xml" goto :launch_module 6 | 7 | :print_xml 8 | rem Print CLI descriptor XML 9 | type %MODULE_NAME%.xml 10 | rem Return with success 11 | exit /b 0 12 | 13 | :launch_module 14 | rem Print error messages if any of the required environment variables are not set 15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable. 18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is) 19 | pushd "%~dp0" 20 | rem Forward parameters to the Matlab CLI 21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %* 22 | if errorlevel 1 exit /b 1 23 | rem Return with success 24 | exit /b 0 25 | -------------------------------------------------------------------------------- /Examples/FillAroundSeeds/FillAroundSeeds.m: -------------------------------------------------------------------------------- 1 | function outputParams=FillAroundSeeds(inputParams) 2 | % Example function for filling the image with a selected intensity around the chosen seed points 3 | % 4 | % Parameters: 5 | % inputParams.seed: seed locations 6 | % inputParams.radius: radius around the seed for filling (in mm) 7 | % inputParams.fillvalue: pixel value to fill 8 | % inputParams.unnamed{1}: input image filename 9 | % inputParams.unnamed{2}: output image filename (value is 0 if below threshold, 100 if above threshold) 10 | % 11 | 12 | img=cli_imageread(inputParams.inputvolume); 13 | 14 | seeds_LPS=cli_pointvectordecode(inputParams.seed); 15 | [seedDim seedCount]=size(seeds_LPS); 16 | radius_LPS=[inputParams.radius inputParams.radius inputParams.radius 0]'; 17 | radius_IJK=abs(round(img.ijkToLpsTransform\radius_LPS)); 18 | for seedIndex=1:seedCount 19 | seed_IJK=round(img.ijkToLpsTransform\[seeds_LPS(:,seedIndex); 1]); 20 | img.pixelData(seed_IJK(1)-radius_IJK(1):seed_IJK(1)+radius_IJK(1),seed_IJK(2)-radius_IJK(2):seed_IJK(2)+radius_IJK(2),seed_IJK(3)-radius_IJK(3):seed_IJK(3)+radius_IJK(3))=ones(radius_IJK(1)*2+1,radius_IJK(2)*2+1,radius_IJK(3)*2+1)*inputParams.fillvalue; 21 | end 22 | 23 | cli_imagewrite(inputParams.outputvolume, img); 24 | -------------------------------------------------------------------------------- /Examples/FillAroundSeeds/FillAroundSeeds.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Matlab 4 | FillAroundSeeds 5 | 6 | 0.0.0.1 7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge 8 | 9 | Andras Lasso (PerkLab) 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | seed 18 | 0,0,0 19 | 20 | 21 | 22 | 23 | fillvalue 24 | 500 25 | 26 | -1000 27 | 1000 28 | 5 29 | 30 | 31 | 32 | 33 | 34 | radius 35 | 5 36 | 37 | 0.5 38 | 50 39 | 0.5 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | inputvolume 50 | input 51 | 52 | 53 | 54 | 55 | outputvolume 56 | output 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Examples/LandmarkRegistration/LandmarkRegistration.bat: -------------------------------------------------------------------------------- 1 | @set MODULE_NAME=LandmarkRegistration 2 | @rem MatlabBridge proxy version: 1.0 3 | 4 | @echo off 5 | if not "%~1"=="--xml" goto :launch_module 6 | 7 | :print_xml 8 | rem Print CLI descriptor XML 9 | type %MODULE_NAME%.xml 10 | rem Return with success 11 | exit /b 0 12 | 13 | :launch_module 14 | rem Print error messages if any of the required environment variables are not set 15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable. 18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is) 19 | pushd "%~dp0" 20 | rem Forward parameters to the Matlab CLI 21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %* 22 | if errorlevel 1 exit /b 1 23 | rem Return with success 24 | exit /b 0 25 | -------------------------------------------------------------------------------- /Examples/LandmarkRegistration/LandmarkRegistration.m: -------------------------------------------------------------------------------- 1 | function outputParams=LandmarkRegistration(inputParams) 2 | % Example function that computes a rigid similarity transform between two sets of points 3 | 4 | fixedPoints=cli_pointvectordecode(inputParams.fixedpoints); 5 | movingPoints=cli_pointvectordecode(inputParams.movingpoints); 6 | doScale=isfield(inputParams,'enablescaling'); 7 | 8 | [regParams,Bfit,ErrorStats]=absor(fixedPoints,movingPoints,'doScale',doScale); 9 | 10 | outputParams.lsqerror=ErrorStats.errlsq; 11 | outputParams.maxerror=ErrorStats.errmax; 12 | 13 | cli_lineartransformwrite(inputParams.movingtofixedtransform,regParams.M); 14 | -------------------------------------------------------------------------------- /Examples/LandmarkRegistration/LandmarkRegistration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Matlab 4 | Landmark Registration 5 | 6 | 0.0.0.1 7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge 8 | 9 | Andras Lasso (PerkLab) 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | fixedpoints 18 | 0,0,0 19 | 20 | 21 | 22 | 23 | movingpoints 24 | 0,0,0 25 | 26 | 27 | 28 | 29 | enablescaling 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | movingtofixedtransform 40 | output 41 | 42 | 43 | 44 | 45 | lsqerror 46 | output 47 | 48 | 49 | 50 | 51 | 52 | maxerror 53 | output 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Examples/LandmarkRegistration/absor.m: -------------------------------------------------------------------------------- 1 | function [regParams,Bfit,ErrorStats]=absor(A,B,varargin) 2 | %ABSOR - a tool for solving the absolute orientation problem using Horn's 3 | %quaternion-based method, that is, for finding the rotation, translation, and 4 | %optionally also the scaling, that best maps one collection of point coordinates 5 | %to another in a least squares sense. The function works for both 2D and 3D 6 | %coordinates, and also gives the option of weighting the coordinates non-uniformly. 7 | %The code avoids for-loops to maximize speed. 8 | % 9 | %DESCRIPTION: 10 | % 11 | %As input data, one has 12 | % 13 | % A: a 2xN or 3xN matrix whos columns are the coordinates of N source points. 14 | % B: a 2xN or 3xN matrix whos columns are the coordinates of N target points. 15 | % 16 | %The syntax 17 | % 18 | % [regParams,Bfit,ErrorStats]=absor(A,B) 19 | % 20 | %solves the unweighted/unscaled registration problem 21 | % 22 | % min. sum_i ||R*A(:,i) + t - B(:,i)||^2 23 | % 24 | %for unknown rotation matrix R and unknown translation vector t. 25 | % 26 | %This is a special case of the more general problem 27 | % 28 | % min. sum_i w(i)*||s*R*A(:,i) + t - B(:,i)||^2 29 | % 30 | %where s>=0 is an unknown global scale factor to be estimated along with R and t 31 | %and w is a user-supplied length N vector of weights. One can include either 32 | %s or w or both in the problem formulation using the syntax, 33 | % 34 | % [regParams,Bfit,ErrorStats]=absor(A,B,'param1',value1,'param2',value2,...) 35 | % 36 | %with parameter/value pair options 37 | % 38 | % 'doScale' - Boolean flag. If TRUE, the global scale factor, s, is included. 39 | % Default=FALSE. 40 | % 41 | % 'weights' - the length N-vector of weights, w. Default, no weighting. 42 | % 43 | % 44 | % 45 | %out: 46 | % 47 | % 48 | % regParams: structure output with estimated registration parameters, 49 | % 50 | % regParams.R: The estimated rotation matrix, R 51 | % regParams.t: The estimated translation vector, t 52 | % regParams.s: The estimated scale factor (set to 1 if doScale=false). 53 | % regParams.M: Homogenous coordinate transform matrix [s*R,t;[0 0 ... 1]]. 54 | % 55 | % For 3D problems, the structure includes 56 | % 57 | % regParams.q: A unit quaternion [q0 qx qy qz] corresponding to R and 58 | % signed to satisfy max(q)=max(abs(q))>0 59 | % 60 | % For 2D problems, it includes 61 | % 62 | % regParams.theta: the counter-clockwise rotation angle about the 63 | % 2D origin 64 | % 65 | % 66 | % Bfit: The rotation, translation, and scaling (as applicable) of A that 67 | % best matches B. 68 | % 69 | % 70 | % ErrorStats: structure output with error statistics. In particular, 71 | % defining err(i)=sqrt(w(i))*norm( Bfit(:,i)-B(:,i) ), 72 | % it contains 73 | % 74 | % ErrorStats.errlsq = norm(err) 75 | % ErrorStats.errmax = max(err) 76 | % 77 | % 78 | % 79 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 80 | % Author: Matt Jacobson 81 | % Copyright, Xoran Technologies, Inc. http://www.xorantech.com 82 | 83 | 84 | %%Input option processing and set up 85 | 86 | options.doScale = 0; 87 | options.weights = []; 88 | 89 | for ii=1:2:length(varargin) 90 | param=varargin{ii}; 91 | val=varargin{ii+1}; 92 | if strcmpi(param,'doScale'), 93 | options.doScale=val; 94 | elseif strcmpi(param,'weights') 95 | options.weights=val; 96 | else 97 | error(['Option ''' param ''' not recognized']); 98 | end 99 | end 100 | 101 | doScale = options.doScale; 102 | weights = options.weights; 103 | 104 | 105 | 106 | if ~isempty(which('bsxfun')) 107 | matmvec=@(M,v) bsxfun(@minus,M,v); %matrix-minus-vector 108 | mattvec=@(M,v) bsxfun(@times,M,v); %matrix-minus-vector 109 | else 110 | matmvec=@matmvecHandle; 111 | mattvec=@mattvecHandle; 112 | end 113 | 114 | 115 | dimension=size(A,1); 116 | 117 | if dimension~=size(B,1), 118 | error 'The number of points to be registered must be the same' 119 | end 120 | 121 | 122 | %%Centering/weighting of input data 123 | 124 | 125 | if isempty(weights) 126 | 127 | sumwts=1; 128 | 129 | lc=mean(A,2); rc=mean(B,2); %Centroids 130 | left = matmvec(A,lc); %Center coordinates at centroids 131 | right = matmvec(B,rc); 132 | 133 | else 134 | 135 | sumwts=sum(weights); 136 | 137 | weights=full(weights)/sumwts; 138 | weights=weights(:); 139 | sqrtwts=sqrt(weights.'); 140 | 141 | 142 | lc=A*weights; rc=B*weights; %weighted centroids 143 | 144 | left = matmvec(A,lc); 145 | left = mattvec(left,sqrtwts); 146 | right = matmvec(B,rc); 147 | right = mattvec(right,sqrtwts); 148 | 149 | end 150 | 151 | M=left*right.'; 152 | 153 | 154 | %%Compute rotation matrix 155 | 156 | switch dimension 157 | 158 | case 2 159 | 160 | 161 | Nxx=M(1)+M(4); Nyx=M(3)-M(2); 162 | 163 | N=[Nxx Nyx;... 164 | Nyx -Nxx]; 165 | 166 | [V,D]=eig(N); 167 | 168 | [trash,emax]=max(real( diag(D) )); emax=emax(1); 169 | 170 | q=V(:,emax); %Gets eigenvector corresponding to maximum eigenvalue 171 | q=real(q); %Get rid of imaginary part caused by numerical error 172 | 173 | 174 | q=q*sign(q(2)+(q(2)>=0)); %Sign ambiguity 175 | q=q./norm(q); 176 | 177 | R11=q(1)^2-q(2)^2; 178 | R21=prod(q)*2; 179 | 180 | R=[R11 -R21;R21 R11]; %map to orthogonal matrix 181 | 182 | 183 | 184 | 185 | case 3 186 | 187 | [Sxx,Syx,Szx, Sxy,Syy,Szy, Sxz,Syz,Szz]=dealr(M(:)); 188 | 189 | N=[(Sxx+Syy+Szz) (Syz-Szy) (Szx-Sxz) (Sxy-Syx);... 190 | (Syz-Szy) (Sxx-Syy-Szz) (Sxy+Syx) (Szx+Sxz);... 191 | (Szx-Sxz) (Sxy+Syx) (-Sxx+Syy-Szz) (Syz+Szy);... 192 | (Sxy-Syx) (Szx+Sxz) (Syz+Szy) (-Sxx-Syy+Szz)]; 193 | 194 | [V,D]=eig(N); 195 | 196 | [trash,emax]=max(real( diag(D) )); emax=emax(1); 197 | 198 | q=V(:,emax); %Gets eigenvector corresponding to maximum eigenvalue 199 | q=real(q); %Get rid of imaginary part caused by numerical error 200 | 201 | [trash,ii]=max(abs(q)); sgn=sign(q(ii(1))); 202 | q=q*sgn; %Sign ambiguity 203 | 204 | %map to orthogonal matrix 205 | 206 | quat=q(:); 207 | nrm=norm(quat); 208 | if ~nrm 209 | 'Quaternion distribution is 0' 210 | end 211 | 212 | quat=quat./norm(quat); 213 | 214 | q0=quat(1); 215 | qx=quat(2); 216 | qy=quat(3); 217 | qz=quat(4); 218 | v =quat(2:4); 219 | 220 | 221 | Z=[q0 -qz qy;... 222 | qz q0 -qx;... 223 | -qy qx q0 ]; 224 | 225 | R=v*v.' + Z^2; 226 | 227 | otherwise 228 | error 'Points must be either 2D or 3D' 229 | 230 | end 231 | 232 | %% 233 | 234 | if doScale 235 | 236 | summ = @(M) sum(M(:)); 237 | 238 | sss=summ( right.*(R*left))/summ(left.^2); 239 | t=rc-R*(lc*sss); 240 | 241 | 242 | else 243 | 244 | sss=1; 245 | t=rc-R*lc; 246 | 247 | 248 | end 249 | 250 | 251 | regParams.R=R; 252 | regParams.t=t; 253 | regParams.s=sss; 254 | 255 | 256 | if dimension==2 257 | 258 | regParams.M=[sss*R,t;[0 0 1]]; 259 | regParams.theta=atan2(q(2),q(1))*360/pi; 260 | 261 | else%dimension=3 262 | 263 | regParams.M=[sss*R,t;[0 0 0 1]]; 264 | regParams.q=q/norm(q); 265 | 266 | end 267 | 268 | if nargout>1 269 | 270 | Bfit=matmvec((sss*R)*A,-t); 271 | 272 | end 273 | 274 | if nargout>2 275 | 276 | l2norm = @(M,dim) sqrt(sum(M.^2,dim)); 277 | 278 | err=l2norm(Bfit-B,1); 279 | 280 | if ~isempty(weights), err=err.*sqrtwts; end 281 | 282 | ErrorStats.errlsq=norm(err)*sqrt(sumwts); %unnormalize the weights 283 | ErrorStats.errmax=max(err); 284 | 285 | 286 | end 287 | 288 | 289 | 290 | 291 | function M=matmvecHandle(M,v) 292 | %Matrix-minus-vector 293 | 294 | for ii=1:size(M,1) 295 | M(ii,:)=M(ii,:)-v(ii); 296 | end 297 | 298 | function M=mattvecHandle(M,v) 299 | %Matrix-times-vector 300 | 301 | for ii=1:size(M,1) 302 | M(ii,:)=M(ii,:).*v; 303 | end 304 | 305 | function varargout=dealr(v) 306 | 307 | varargout=num2cell(v); 308 | 309 | 310 | 311 | 312 | %Copyright (c) 2009, Matt Jacobson, Xoran Technologies, Inc. http://www.xorantech.com 313 | %All rights reserved. 314 | % 315 | %Redistribution and use in source and binary forms, with or without 316 | %modification, are permitted provided that the following conditions are 317 | %met: 318 | % 319 | % * Redistributions of source code must retain the above copyright 320 | % notice, this list of conditions and the following disclaimer. 321 | % * Redistributions in binary form must reproduce the above copyright 322 | % notice, this list of conditions and the following disclaimer in 323 | % the documentation and/or other materials provided with the distribution 324 | % 325 | %THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 326 | %AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 327 | %IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 328 | %ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 329 | %LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 330 | %CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 331 | %SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 332 | %INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 333 | %CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 334 | %ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 335 | %POSSIBILITY OF SUCH DAMAGE. 336 | -------------------------------------------------------------------------------- /Examples/MatlabBridgeParameterPassingTest/MatlabBridgeParameterPassingTest.bat: -------------------------------------------------------------------------------- 1 | @set MODULE_NAME=MatlabBridgeParameterPassingTest 2 | @rem MatlabBridge proxy version: 1.0 3 | 4 | @echo off 5 | if not "%~1"=="--xml" goto :launch_module 6 | 7 | :print_xml 8 | rem Print CLI descriptor XML 9 | type %MODULE_NAME%.xml 10 | rem Return with success 11 | exit /b 0 12 | 13 | :launch_module 14 | rem Print error messages if any of the required environment variables are not set 15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable. 18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is) 19 | pushd "%~dp0" 20 | rem Forward parameters to the Matlab CLI 21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %* 22 | if errorlevel 1 exit /b 1 23 | rem Return with success 24 | exit /b 0 25 | -------------------------------------------------------------------------------- /Examples/MatlabBridgeParameterPassingTest/MatlabBridgeParameterPassingTest.m: -------------------------------------------------------------------------------- 1 | function outputParams=MatlabBridgeParameterPassingTest(inputParams) 2 | % Example function that returns the minimum and maximum voxel value in a volume 3 | % and performs thresholding operation on the volume. 4 | % 5 | % Parameters: 6 | % inputParams.threshold: threshold value 7 | % inputParams.unnamed{1}: input image filename 8 | % inputParams.unnamed{2}: output image filename (value is 0 if below threshold, 100 if above threshold) 9 | % outputParams.min: image minimum value 10 | % outputParams.max: image maximum value 11 | % etc. 12 | % 13 | 14 | % Read inputs 15 | integerValue=inputParams.integer 16 | doubleValue=inputParams.double 17 | floatVectorValue=inputParams.f 18 | stringVectorValue=cli_stringvectordecode(inputParams.string_vector) 19 | stringEnumerationValue=inputParams.enumeration 20 | boolean1Value=isfield(inputParams,'boolean1') 21 | boolean2Value=isfield(inputParams,'boolean2') 22 | boolean3Value=isfield(inputParams,'boolean3') 23 | filenameValue=inputParams.file1 24 | filenameListValue=cli_stringvectordecode(inputParams.files) 25 | directoryValue=cli_stringvectordecode(inputParams.directory1) 26 | imageValue=cli_imageread(inputParams.image1) 27 | transformValue=cli_lineartransformread(inputParams.transform1) 28 | regionValue=cli_pointvectordecode(inputParams.region); 29 | seedValue=inputParams.seed 30 | inputMeasurementFilenameValue=cli_measurementread(inputParams.inputFA) 31 | unnamedInputImageValue=cli_imageread(inputParams.unnamed{1}); 32 | surfaceMeshValue = cli_geometryread(inputParams.model1); 33 | 34 | % Do some simple processing 35 | 36 | [regionDim regionCount]=size(regionValue); 37 | fillValue = 10; 38 | for regionIndex=1:regionCount 39 | center_IJK=round(imageValue.ijkToLpsTransform\[regionValue(1:3,regionIndex); 1]) 40 | radius_IJK=abs(round(imageValue.ijkToLpsTransform\[regionValue(4:6,regionIndex); 0])) 41 | imageValue.pixelData(center_IJK(1)-radius_IJK(1):center_IJK(1)+radius_IJK(1),center_IJK(2)-radius_IJK(2):center_IJK(2)+radius_IJK(2),center_IJK(3)-radius_IJK(3):center_IJK(3)+radius_IJK(3))=ones(radius_IJK(1)*2+1,radius_IJK(2)*2+1,radius_IJK(3)*2+1)*fillValue; 42 | end 43 | 44 | scaleFactor = 1.2; % enlarge by 20% 45 | surfaceMeshValue.vertices = surfaceMeshValue.vertices * diag([scaleFactor scaleFactor scaleFactor]); 46 | 47 | % Write outputs 48 | outputParams.anintegerreturn=integerValue*10; 49 | outputParams.abooleanreturn=boolean1Value && boolean2Value && boolean3Value; 50 | outputParams.afloatreturn=123.456; 51 | outputParams.adoublereturn=246.81012; 52 | outputParams.astringreturn=['the input was ' stringEnumerationValue]; 53 | outputParams.anintegervectorreturn=floatVectorValue*2; 54 | outputParams.astringchoicereturn=stringEnumerationValue; 55 | 56 | cli_imagewrite(inputParams.image2, imageValue); % Write the input image on the output unchanged 57 | cli_lineartransformwrite(inputParams.transform2,transformValue); % Write the input transform on the output unchanged 58 | cli_imagewrite(inputParams.unnamed{2},unnamedInputImageValue); % Write the input image on the output unchanged 59 | cli_measurementwrite(inputParams.outputFA, [inputMeasurementFilenameValue; 1 2 0.2; 2 4 0.3; 3 5 0.2]); % Write the input image on the output with a few extra numbers added 60 | cli_geometrywrite(inputParams.model2, surfaceMeshValue); % Write the input surface mesh on the output unchanged 61 | -------------------------------------------------------------------------------- /Examples/MatlabBridgeParameterPassingTest/MatlabBridgeParameterPassingTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Matlab 4 | MatlabBridge parameter passing test 5 | 6 | 0.1.0.$Revision: 21227 $(alpha) 7 | http://wiki.slicer.org/slicerWiki/index.php/Documentation/4.2/Modules/ExecutionModelTour 8 | 9 | Daniel Blezek (GE), Bill Lorensen (GE) 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | integer 18 | 30 19 | 20 | 21 | 22 | 23 | double 24 | 30 25 | 26 | 0 27 | 1.e3 28 | 10 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | f 39 | 1.3,2,-14 40 | 41 | 42 | 43 | 44 | string_vector 45 | foo,bar,foobar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | enumeration 55 | Bill 56 | Ron 57 | Eric 58 | Bill 59 | Ross 60 | Steve 61 | Will 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | boolean1 71 | true 72 | 73 | 74 | 75 | 76 | boolean2 77 | false 78 | 79 | 80 | 81 | 82 | boolean3 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | file1 92 | input 93 | 94 | 95 | 96 | 97 | files 98 | input 99 | 100 | 101 | 102 | 103 | directory1 104 | input 105 | 106 | 107 | 108 | 109 | image1 110 | input 111 | 112 | 113 | 114 | 115 | image2 116 | output 117 | 118 | 119 | 120 | 121 | model1 122 | input 123 | 124 | 125 | 126 | 127 | model2 128 | output 129 | 130 | 131 | 132 | 133 | transform1 134 | input 135 | 136 | 137 | 138 | 139 | transform2 140 | output 141 | 142 | 143 | 144 | 145 | seed 146 | 0,0,0 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | index0 156 | 0 157 | input 158 | 159 | 160 | 161 | 162 | index1 163 | 1 164 | output 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | region 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | inputFA 181 | input 182 | 183 | 184 | 185 | 186 | outputFA 187 | output 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | anintegerreturn 196 | output 197 | 5 198 | 199 | 200 | 201 | 202 | abooleanreturn 203 | output 204 | false 205 | 206 | 207 | 208 | 209 | afloatreturn 210 | output 211 | 7.0 212 | 213 | 214 | 215 | 216 | adoublereturn 217 | output 218 | 14.0 219 | 220 | 221 | 222 | 223 | astringreturn 224 | output 225 | Hello 226 | 227 | 228 | 229 | 230 | anintegervectorreturn 231 | output 232 | 1,2,3 233 | 234 | 235 | 236 | 237 | astringchoicereturn 238 | output 239 | Bill 240 | Ron 241 | Eric 242 | Bill 243 | Ross 244 | Steve 245 | Will 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /Examples/MeshScale/MeshScale.bat: -------------------------------------------------------------------------------- 1 | @set MODULE_NAME=MeshScale 2 | @rem MatlabBridge proxy version: 1.0 3 | 4 | @echo off 5 | if not "%~1"=="--xml" goto :launch_module 6 | 7 | :print_xml 8 | rem Print CLI descriptor XML 9 | type %MODULE_NAME%.xml 10 | rem Return with success 11 | exit /b 0 12 | 13 | :launch_module 14 | rem Print error messages if any of the required environment variables are not set 15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable. 18 | rem Make the .bat file location to be the working directory (that's where the MatlabCommander.exe is) 19 | pushd "%~dp0" 20 | rem Forward parameters to the Matlab CLI 21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch %SLICER_MATLAB_COMMANDER_PATH% --call-matlab-function %MODULE_NAME% %* 22 | if errorlevel 1 exit /b 1 23 | rem Return with success 24 | exit /b 0 25 | -------------------------------------------------------------------------------- /Examples/MeshScale/MeshScale.m: -------------------------------------------------------------------------------- 1 | function outputParams=MeshScale(inputParams) 2 | % Example function that changes scales of a surface mesh 3 | 4 | mesh = cli_geometryread(inputParams.inputmesh); 5 | 6 | mesh.vertices = mesh.vertices * diag([inputParams.scalex inputParams.scaley inputParams.scalez]); 7 | 8 | cli_geometrywrite(inputParams.outputmesh, mesh); 9 | -------------------------------------------------------------------------------- /Examples/MeshScale/MeshScale.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Matlab 4 | Change model scale 5 | 6 | 0.0.0.1 7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge 8 | 9 | Andras Lasso (PerkLab) 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | inputmesh 18 | input 19 | 20 | 21 | 22 | 23 | scalex 24 | 1.5 25 | 26 | 0.1 27 | 10 28 | 0.1 29 | 30 | 31 | 32 | 33 | 34 | scaley 35 | 1.0 36 | 37 | 0.1 38 | 10 39 | 0.1 40 | 41 | 42 | 43 | 44 | 45 | scalez 46 | 0.8 47 | 48 | 0.1 49 | 10 50 | 0.1 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | outputmesh 61 | output 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /MatlabBridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabBridge.png -------------------------------------------------------------------------------- /MatlabCommander/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | set(MODULE_NAME MatlabCommander) 3 | 4 | find_package(OpenIGTLink REQUIRED) 5 | 6 | include(${OpenIGTLink_USE_FILE}) 7 | 8 | #----------------------------------------------------------------------------- 9 | set(MODULE_INCLUDE_DIRECTORIES 10 | ${OpenIGTLink_INCLUDE_DIRS} 11 | ) 12 | 13 | set(MODULE_SRCS 14 | ) 15 | 16 | set(MODULE_TARGET_LIBRARIES 17 | ${ITK_LIBRARIES} 18 | OpenIGTLink 19 | ) 20 | 21 | #----------------------------------------------------------------------------- 22 | SEMMacroBuildCLI( 23 | NAME ${MODULE_NAME} 24 | TARGET_LIBRARIES ${MODULE_TARGET_LIBRARIES} 25 | INCLUDE_DIRECTORIES ${MODULE_INCLUDE_DIRECTORIES} 26 | ADDITIONAL_SRCS ${MODULE_SRCS} 27 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}" 28 | LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_LIB_DIR}" 29 | ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_LIB_DIR}" 30 | #EXECUTABLE_ONLY 31 | ) 32 | 33 | #----------------------------------------------------------------------------- 34 | if(BUILD_TESTING) 35 | #add_subdirectory(Testing) 36 | endif() 37 | 38 | #----------------------------------------------------------------------------- 39 | 40 | # Copy (and install) al cli_*.m script files 41 | 42 | file(GLOB SCRIPT_FILES 43 | RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/commandserver" 44 | "${CMAKE_CURRENT_SOURCE_DIR}/commandserver/*.m" 45 | ) 46 | 47 | foreach(SCRIPT_FILE ${SCRIPT_FILES}) 48 | configure_file( 49 | ${CMAKE_CURRENT_SOURCE_DIR}/commandserver/${SCRIPT_FILE} 50 | ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/${SCRIPT_FILE} 51 | COPYONLY) 52 | install( 53 | FILES ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/${SCRIPT_FILE} 54 | DESTINATION ${Slicer_INSTALL_CLIMODULES_BIN_DIR}/commandserver COMPONENT Runtime) 55 | endforeach() 56 | 57 | # Create (and install) version info function 58 | 59 | configure_file( 60 | ${CMAKE_CURRENT_SOURCE_DIR}/commandserver/cli_version.m.in 61 | ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/cli_version.m) 62 | install( 63 | FILES ${CMAKE_BINARY_DIR}/${Slicer_CLIMODULES_BIN_DIR}/commandserver/cli_version.m 64 | DESTINATION ${Slicer_INSTALL_CLIMODULES_BIN_DIR}/commandserver COMPONENT Runtime) 65 | -------------------------------------------------------------------------------- /MatlabCommander/MatlabCommander.cxx: -------------------------------------------------------------------------------- 1 | #include "MatlabCommanderCLP.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "igtlOSUtil.h" 9 | #include "igtlStringMessage.h" 10 | #include "igtlClientSocket.h" 11 | 12 | #include "vtksys/SystemTools.hxx" 13 | #include "vtksys/Process.h" 14 | 15 | const std::string CALL_MATLAB_FUNCTION_ARG="--call-matlab-function"; 16 | const std::string EXIT_MATLAB_ARG="--exit-matlab"; 17 | const std::string MATLAB_DEFAULT_HOST="127.0.0.1"; 18 | const int MATLAB_DEFAULT_PORT=4100; 19 | 20 | const int MAX_MATLAB_STARTUP_TIME_SEC=60; // maximum time allowed for Matlab to start 21 | 22 | // If the Matlab function response string starts with this string then it means 23 | // the function execution failed 24 | const std::string RESPONSE_ERROR_PREFIX="ERROR:"; 25 | 26 | enum ExecuteMatlabCommandStatus 27 | { 28 | COMMAND_STATUS_FAILED=0, 29 | COMMAND_STATUS_SUCCESS=1 30 | }; 31 | 32 | std::string ReceiveString(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) 33 | { 34 | // Create a message buffer to receive transform data 35 | igtl::StringMessage::Pointer stringMsg; 36 | stringMsg = igtl::StringMessage::New(); 37 | stringMsg->SetMessageHeader(header); 38 | stringMsg->AllocatePack(); 39 | 40 | // Receive transform data from the socket 41 | bool receiveTimedOut = false; 42 | int received=socket->Receive(stringMsg->GetPackBodyPointer(), stringMsg->GetPackBodySize(), receiveTimedOut); 43 | if (received!=stringMsg->GetPackBodySize()) 44 | { 45 | std::cerr << "WARNING: failed to receive complete message body" << std::endl; 46 | } 47 | if (receiveTimedOut) 48 | { 49 | std::cerr << "WARNING: receiving timed out" << std::endl; 50 | } 51 | 52 | // Deserialize the transform data 53 | // If you want to skip CRC check, call Unpack() without argument. 54 | int c = stringMsg->Unpack(); 55 | 56 | if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK 57 | { 58 | return stringMsg->GetString(); 59 | } 60 | 61 | // error 62 | return ""; 63 | } 64 | 65 | void SetReturnValues(const std::string &returnParameterFile,const char* reply, bool completed) 66 | { 67 | // Write out the return parameters in "name = value" form 68 | std::ofstream rts; 69 | rts.open(returnParameterFile.c_str() ); 70 | rts << "reply = " << reply << std::endl; 71 | rts << "completed = " << (completed?"true":"false") << std::endl; 72 | rts.close(); 73 | } 74 | 75 | // Returns true if execution is successful. Matlab start may take an additional minute after this function returns. 76 | bool StartMatlabServer() 77 | { 78 | const char* matlabExecutablePath=getenv("SLICER_MATLAB_EXECUTABLE_PATH"); 79 | const char* matlabCommandServerScriptPath=getenv("SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH"); 80 | 81 | if ( matlabExecutablePath == NULL ) 82 | { 83 | std::cerr << "ERROR: The SLICER_MATLAB_EXECUTABLE_PATH environment variable is not set. Cannot start the Matlab command server." << std::endl; 84 | return false; 85 | } 86 | if ( matlabCommandServerScriptPath == NULL ) 87 | { 88 | std::cerr << "ERROR: The SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not set. Cannot start the Matlab command server." << std::endl; 89 | return false; 90 | } 91 | 92 | if ( !vtksys::SystemTools::FileExists( matlabExecutablePath, true) ) 93 | { 94 | std::cerr << "ERROR: Unable to find Matlab executable defined in the SLICER_MATLAB_EXECUTABLE_PATH environment variable: " 95 | << matlabExecutablePath << std::endl; 96 | return false; 97 | } 98 | 99 | bool success = true; 100 | try 101 | { 102 | std::vector command; 103 | command.clear(); 104 | 105 | // Compose Matlab launching command 106 | std::cout << "Starting Matlab server: " << matlabExecutablePath; 107 | command.push_back(matlabExecutablePath); 108 | 109 | // start in minimized, with text console only 110 | std::cout << " -automation"; 111 | command.push_back("-automation"); 112 | 113 | // script directory (-sd) option does not work with the automation option, so need to use the run command to specify full script path 114 | 115 | // run script after startup 116 | #if defined( _WIN32 ) && !defined(__CYGWIN__) 117 | // Windows requires parameter and script name as two separate arguments 118 | std::string startupCommand1=std::string("-r"); 119 | std::cout << " " << startupCommand1; 120 | command.push_back(startupCommand1.c_str()); 121 | std::string startupCommand2=std::string("\"run('")+matlabCommandServerScriptPath+"');\""; 122 | std::cout << " " << startupCommand2; 123 | command.push_back(startupCommand2.c_str()); 124 | #else 125 | // Linux/Mac OS X requires parameter and script name as one argument 126 | std::string startupCommand=std::string("-r \"run('")+matlabCommandServerScriptPath+"');\""; 127 | std::cout << " " << startupCommand; 128 | command.push_back(startupCommand.c_str()); 129 | #endif 130 | 131 | // The array must end with a NULL pointer. 132 | std::cout << std::endl; 133 | command.push_back(0); 134 | 135 | // Create new process 136 | vtksysProcess* gp = vtksysProcess_New(); 137 | 138 | // Set command 139 | vtksysProcess_SetCommand(gp, &*command.begin()); 140 | 141 | // Hide window 142 | vtksysProcess_SetOption(gp,vtksysProcess_Option_HideWindow, 1); 143 | 144 | #if defined( _WIN32 ) && !defined(__CYGWIN__) 145 | // No need to redirect process output on Windows 146 | #else 147 | // Need to redirect the outputs to dev/null on Linux and Mac OS X, 148 | // otherwise Matlab terminates right after it is started 149 | vtksysProcess_SetPipeFile(gp, vtksysProcess_Pipe_STDOUT, "/dev/null"); 150 | vtksysProcess_SetPipeFile(gp, vtksysProcess_Pipe_STDERR, "/dev/null"); 151 | #endif 152 | 153 | // Start a detached process, because we don't want to block the MatlabCommander if the started Matlab process does not exit 154 | // (usually the Matlab process exits within a few seconds, but on some configurations it does not) 155 | vtksysProcess_SetOption(gp, vtksysProcess_Option_Detach, 1); 156 | 157 | // Run the application 158 | vtksysProcess_Execute(gp); 159 | 160 | // Release the application and let it run in the background 161 | vtksysProcess_Disown(gp); 162 | 163 | switch (vtksysProcess_GetState(gp)) 164 | { 165 | case vtksysProcess_State_Disowned: 166 | // This is the success case 167 | std::cout << "Successfully detached from the started Matlab process" <ConnectToServer(hostname.c_str(), port); 220 | if (connectErrorCode!=0) 221 | { 222 | // Maybe Matlab server has not been started, try to start it 223 | if (StartMatlabServer()) 224 | { 225 | // process start requested, try to connect 226 | for (int retryAttempts=0; retryAttemptsConnectToServer(hostname.c_str(), port); 229 | if (connectErrorCode==0) 230 | { 231 | // success 232 | break; 233 | } 234 | // Failed to connect, wait some more and retry 235 | vtksys::SystemTools::Delay(1000); // msec 236 | std::cerr << "Waiting for Matlab startup ... " << retryAttempts << "sec" << std::endl; 237 | } 238 | } 239 | else 240 | { 241 | std::cerr << "ERROR: Failed to start Matlab process" << std::endl; 242 | } 243 | } 244 | if (connectErrorCode != 0) 245 | { 246 | reply="ERROR: Cannot connect to the server"; 247 | return COMMAND_STATUS_FAILED; 248 | } 249 | 250 | //------------------------------------------------------------ 251 | // Send command 252 | igtl::StringMessage::Pointer stringMsg; 253 | stringMsg = igtl::StringMessage::New(); 254 | stringMsg->SetDeviceName("CMD"); 255 | std::cout << "Sending string: " << cmd << std::endl; 256 | stringMsg->SetString(cmd.c_str()); 257 | stringMsg->Pack(); 258 | socket->SetSendTimeout(5000); // timeout in msec 259 | if (!socket->Send(stringMsg->GetPackPointer(), stringMsg->GetPackSize())) 260 | { 261 | // Failed to send the message 262 | std::cerr << "Failed to send message to Matlab process" << std::endl; 263 | socket->CloseSocket(); 264 | return COMMAND_STATUS_FAILED; 265 | } 266 | 267 | //------------------------------------------------------------ 268 | // Receive reply 269 | // Create a message buffer to receive header 270 | igtl::MessageHeader::Pointer headerMsg; 271 | headerMsg = igtl::MessageHeader::New(); 272 | // Initialize receive buffer 273 | headerMsg->InitPack(); 274 | // Receive generic header from the socket 275 | if (receiveTimeoutMsec>0) 276 | { 277 | socket->SetReceiveTimeout(receiveTimeoutMsec); // timeout in msec 278 | } 279 | 280 | bool receiveTimedOut = false; 281 | int receivedBytes = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), receiveTimedOut); 282 | if (receivedBytes == 0) 283 | { 284 | reply="No reply"; 285 | socket->CloseSocket(); 286 | return COMMAND_STATUS_FAILED; 287 | } 288 | if (receivedBytes != headerMsg->GetPackSize() || receiveTimedOut) 289 | { 290 | reply = "Bad reply"; 291 | socket->CloseSocket(); 292 | return COMMAND_STATUS_FAILED; 293 | } 294 | // Deserialize the header 295 | headerMsg->Unpack(); 296 | if (strcmp(headerMsg->GetDeviceType(), "STRING") != 0) 297 | { 298 | reply = std::string("Receiving unsupported message type: ") + headerMsg->GetDeviceType(); 299 | socket->Skip(headerMsg->GetBodySizeToRead(), 0); 300 | socket->CloseSocket(); 301 | return COMMAND_STATUS_FAILED; 302 | } 303 | // Get the reply string 304 | reply=ReceiveString(socket, headerMsg); 305 | 306 | //------------------------------------------------------------ 307 | // Close connection 308 | socket->CloseSocket(); 309 | 310 | return COMMAND_STATUS_SUCCESS; 311 | } 312 | 313 | int ExitMatlab() 314 | { 315 | igtl::ClientSocket::Pointer socket = igtl::ClientSocket::New(); 316 | int connectErrorCode = socket->ConnectToServer(MATLAB_DEFAULT_HOST.c_str(), MATLAB_DEFAULT_PORT); 317 | if (connectErrorCode!=0) 318 | { 319 | // The server has not been started, nothing to do 320 | std::cout << "Matlab process is already stopped" << std::endl; 321 | return EXIT_SUCCESS; 322 | } 323 | 324 | std::string cmd = "exit"; 325 | 326 | //------------------------------------------------------------ 327 | // Send command 328 | igtl::StringMessage::Pointer stringMsg; 329 | stringMsg = igtl::StringMessage::New(); 330 | stringMsg->SetDeviceName("CMD"); 331 | std::cout << "Sending string: " << cmd << std::endl; 332 | stringMsg->SetString(cmd.c_str()); 333 | stringMsg->Pack(); 334 | socket->SetSendTimeout(5000); // timeout in msec 335 | if (!socket->Send(stringMsg->GetPackPointer(), stringMsg->GetPackSize())) 336 | { 337 | // Failed to send the message 338 | std::cerr << "Failed to send message to Matlab process" << std::endl; 339 | socket->CloseSocket(); 340 | return COMMAND_STATUS_FAILED; 341 | } 342 | 343 | // Close connection 344 | socket->CloseSocket(); 345 | 346 | std::cout << "Matlab process exit requested" << std::endl; 347 | return EXIT_SUCCESS; 348 | } 349 | 350 | 351 | int CallMatlabFunction(int argc, char * argv []) 352 | { 353 | // Search for the --returnparameterfile argument. If it is present then arguments shall be returned. 354 | const std::string returnParameterFileArgName="--returnparameterfile"; 355 | std::string returnParameterFileArgValue; 356 | for (int argvIndex=3; argvIndex=argc) 362 | { 363 | std::cerr << "ERROR: --returnparameterfile value is not defined" << std::endl; 364 | break; 365 | } 366 | returnParameterFileArgValue=argv[argvIndex+1]; 367 | if ( returnParameterFileArgValue.at(0) == '"' ) 368 | { 369 | // this is a quoted string => remove the quotes (Matlab uses different quotes anyway) 370 | returnParameterFileArgValue.erase( 0, 1 ); // erase the first character 371 | returnParameterFileArgValue.erase( returnParameterFileArgValue.size() - 1 ); // erase the last character 372 | } 373 | break; 374 | } 375 | } 376 | 377 | std::string cmd; 378 | 379 | // Change directory to the current working directory (where the Matlab function .m file is located) 380 | cmd += "cd('"+vtksys::SystemTools::GetCurrentWorkingDirectory()+"'); "; 381 | 382 | // No return value: 383 | // myfunction( cli_argsread({"--paramName1","paramValue1",...}) ); 384 | // With return value: 385 | // cli_argswrite( myfunction( cli_argsread({"--paramName1","paramValue1",...}) ) ); 386 | 387 | if (!returnParameterFileArgValue.empty()) 388 | { 389 | // with return value 390 | cmd+="cli_argswrite('"+returnParameterFileArgValue+"',"; 391 | } 392 | std::string functionName=argv[2]; 393 | cmd+=functionName+"(cli_argsread({"; 394 | 395 | for (int argvIndex=3; argvIndex remove the quotes (Matlab uses different quotes anyway) 401 | arg.erase( 0, 1 ); // erase the first character 402 | arg.erase( arg.size() - 1 ); // erase the last character 403 | } 404 | cmd+=std::string("'")+arg+"'"; 405 | if (argvIndex+1RESPONSE_ERROR_PREFIX.size() && reply.compare(0,RESPONSE_ERROR_PREFIX.size(),RESPONSE_ERROR_PREFIX)==0) 431 | { 432 | // the response starts with "ERROR:", so the execution failed 433 | std::cerr << "Failed to execute Matlab function: " << functionName << ", received the following error message: " << std::endl; 434 | std::cerr << reply << std::endl; 435 | return EXIT_FAILURE; 436 | } 437 | 438 | std::cout << reply << std::endl; 439 | return EXIT_SUCCESS; 440 | } 441 | 442 | 443 | int CallStandardCli(int argc, char * argv []) 444 | { 445 | PARSE_ARGS; 446 | 447 | if (!cmd.empty()) 448 | { 449 | // Execute command 450 | ExecuteMatlabCommandStatus status=ExecuteMatlabCommand(hostname, port, cmd, reply); 451 | if (status==COMMAND_STATUS_SUCCESS) 452 | { 453 | std::cout << reply << std::endl; 454 | completed=true; 455 | } 456 | else 457 | { 458 | std::cerr << reply << std::endl; 459 | completed=false; 460 | } 461 | 462 | // Remove newline characters, as it would confuse the return parameter file 463 | std::replace( reply.begin(), reply.end(), '\r', ' '); 464 | std::replace( reply.begin(), reply.end(), '\n', ' '); 465 | } 466 | else 467 | { 468 | // Empty command, for example when we just want to exit Matlab 469 | reply.clear(); 470 | completed = true; 471 | } 472 | 473 | SetReturnValues(returnParameterFile,reply.c_str(),completed); 474 | 475 | // Exit Matlab 476 | if (exitmatlab == true) 477 | { 478 | return ExitMatlab(); 479 | } 480 | 481 | return EXIT_SUCCESS; // always return with EXIT_SUCCESS, otherwise Slicer ignores the return values and we cannot show the reply on the module GUI 482 | } 483 | 484 | int main (int argc, char * argv []) 485 | { 486 | if (argc>2 && CALL_MATLAB_FUNCTION_ARG.compare(argv[1])==0) 487 | { 488 | // MatlabCommander is called with arguments: --call-matlab-function function_name parameter1 parameter2 ... 489 | return CallMatlabFunction(argc, argv); 490 | } 491 | else if (argc==2 && EXIT_MATLAB_ARG.compare(argv[1])==0) 492 | { 493 | // MatlabCommander is called with arguments: --exit-matlab 494 | return ExitMatlab(); 495 | } 496 | else 497 | { 498 | // MatlabCommander is called as a standard CLI modul 499 | return CallStandardCli(argc, argv); 500 | } 501 | } 502 | -------------------------------------------------------------------------------- /MatlabCommander/MatlabCommander.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Developer Tools.Matlab 4 | Matlab Commander 5 | 6 | 0.8 7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge 8 | Slicer license 9 | Andras Lasso (PerkLab, Queen's University), Jean-Christophe Fillion-Robin (Kitware), Kevin Wang (Radiation Medicine Program, Princess Margaret Hospital, University Health Network Toronto) 10 | 11 | 12 | 13 | Matlab command input 14 | 15 | cmd 16 | 17 | input 18 | 19 | 20 | -c 21 | --command 22 | 23 | 24 | 25 | 26 | Matlab command output 27 | 28 | reply 29 | 30 | output 31 | 32 | 33 | 34 | 35 | completed 36 | 37 | output 38 | false 39 | 40 | 41 | 42 | 43 | 44 | Options for specifying the Matlab command server's network address 45 | 46 | hostname 47 | 48 | 127.0.0.1 49 | 50 | --host 51 | 52 | 53 | port 54 | 55 | 56 | 4100 57 | --port 58 | 59 | 60 | exitmatlab 61 | 62 | 63 | False 64 | --q 65 | --exitmatlab 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_argsread.m: -------------------------------------------------------------------------------- 1 | function params=cli_argsread(args) 2 | % Retrieve parameters in a structure from a list of command-line arguments 3 | % The output structure contains all the named arguments (field name is the command-line argument name) 4 | % and an "unnamed" argument containing the list of unnamed arguments in a cell. 5 | 6 | args=fixupArgumentList(args); 7 | 8 | params={}; 9 | params.unnamed={}; 10 | 11 | curArgName=''; 12 | curArgValue=''; 13 | for curArgIndex=1:length(args) 14 | if (regexp(args{curArgIndex},'^-[-]?[a-zA-Z]')==1) 15 | % This is an argument name (as it starts with - or -- followed by letters) 16 | % There may be an argument name without a value (flag parameter) or value 17 | % without a name (unnamed parameter) => save it before we start 18 | % processing the new argument 19 | params=saveParam(params,curArgName,curArgValue); 20 | curArgName=''; 21 | curArgValue=''; 22 | % Save the new argument name (but don't store it yet, it may be 23 | % followed by an argument value) 24 | % Strip the - or -- from the argument name 25 | [tokens matches]=regexp(args{curArgIndex},'^-[-]?([^-]+)','tokens','match'); 26 | curArgName=tokens{1}{1}; 27 | else 28 | % This is an argument value 29 | curArgValue=getValueFromString(args{curArgIndex}); 30 | % We have a pair of argument name and value => save it 31 | params=saveParam(params,curArgName,curArgValue); 32 | curArgName=''; 33 | curArgValue=''; 34 | end 35 | end 36 | 37 | % If there is an argument that has not yet stored, store it 38 | params=saveParam(params,curArgName,curArgValue); 39 | 40 | end 41 | 42 | %% Helper functions 43 | 44 | % Fixing up the parameter list 45 | % Fiducial point name and value is stored in one argument: 46 | % '--somefiducial 12.3,14.6, 18.7' 47 | % Detect this case and convert it to 48 | % '--somefiducial' '12.3,14.6, 18.7' 49 | function updatedArgs=fixupArgumentList(originalArgs) 50 | updatedArgs={}; 51 | for curArgIndex=1:length(originalArgs) 52 | if (regexp(originalArgs{curArgIndex},'^-[-]?[a-zA-Z].*[ ].+')==1) 53 | % Detected a space in an argument name, e.g., '--somefiducial 12.3,14.6,18.7' 54 | [matchedTokens matchedString]=regexp(originalArgs{curArgIndex},'^(-[-]?[a-zA-Z]+[^ ]*)[ ](.+)','tokens','match'); 55 | argName=matchedTokens{1}{1}; % '--somefiducial' 56 | argValue=matchedTokens{1}{2}; % '12.3,14.6,18.7' 57 | % Insert the split argName and argValue in the argument list 58 | updatedArgs=[updatedArgs {argName} {argValue}]; 59 | else 60 | updatedArgs=[updatedArgs {originalArgs{curArgIndex}}]; 61 | end 62 | end 63 | end 64 | 65 | function paramValue=getValueFromString(paramString) 66 | % Store numerical values as numbers (to don't require the user to call str2num to get a numerical parameter from a string) 67 | [paramValue paramCount paramError]=sscanf(paramString,'%f,'); % reads one or more comma-separated floating point values 68 | if (isempty(paramError)) 69 | % No error, so it was a number or vector of numbers 70 | return; 71 | end 72 | % There was an error, so we interpret this value as a string 73 | paramValue=paramString; 74 | end 75 | 76 | function updatedParams=saveParam(originalParams,curArgName,curArgValue) 77 | updatedParams=originalParams; 78 | if (isempty(curArgName)) 79 | if (~isempty(curArgValue)) 80 | updatedParams.unnamed{length(updatedParams.unnamed)+1}=curArgValue; 81 | end 82 | else 83 | if (isfield(updatedParams, curArgName)) 84 | % This field exists already, so add the value 85 | updatedParams.(curArgName)=[updatedParams.(curArgName) {curArgValue}]; 86 | else 87 | updatedParams.(curArgName)=curArgValue; 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_argswrite.m: -------------------------------------------------------------------------------- 1 | function argswrite(returnParameterFilename, args) 2 | % Write return values specified in the args structure to the return parameter text file 3 | 4 | % open file for writing text file (create new) 5 | fid=fopen(returnParameterFilename, 'wt+'); 6 | assert(fid > 0, ['Could not open output file:' returnParameterFilename]); 7 | 8 | argsCellArr = struct2cell(args); 9 | 10 | % Get string names for each field in the meta data 11 | fields = fieldnames(args); 12 | 13 | % Print the header data to the output file 14 | for i=1:numel(fields) 15 | fprintf(fid,fields{i}); 16 | fprintf(fid,' = '); 17 | % Print as a row vector (scalar vectors are not written correctly if they are stored in a column vector) 18 | [valueRows valueColumns]=size(argsCellArr{i}); 19 | if (valueRows==1) 20 | value=argsCellArr{i}; 21 | else 22 | value=argsCellArr{i}'; 23 | end 24 | fprintf(fid,num2str(value)); 25 | fprintf(fid,'\n'); 26 | end 27 | 28 | fclose(fid); 29 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_commandserver.m: -------------------------------------------------------------------------------- 1 | % OpenIGTLink server that executes the received string commands 2 | function cli_commandserver(port) 3 | 4 | global OPENIGTLINK_SERVER_SOCKET 5 | 6 | import java.net.Socket 7 | import java.io.* 8 | import java.net.ServerSocket 9 | 10 | % Add current directory to the path so that all cli_* functions will be available even when the current working directory is changed 11 | addpath(pwd); 12 | 13 | serverSocketInfo.port=4100; 14 | serverSocketInfo.timeout=1000; 15 | 16 | if (nargin>0) 17 | serverSocketInfo.port=port; 18 | end 19 | 20 | disp(['Starting OpenIGTLink command server at port ' num2str(serverSocketInfo.port)]); 21 | 22 | % Open a TCP Server Port 23 | if (exist('OPENIGTLINK_SERVER_SOCKET','var')) 24 | if (not(isempty(OPENIGTLINK_SERVER_SOCKET))) 25 | % Socket has not been closed last time 26 | disp('Socket has not been closed properly last time. Closing it now.'); 27 | OPENIGTLINK_SERVER_SOCKET.close; 28 | OPENIGTLINK_SERVER_SOCKET=[]; 29 | end 30 | end 31 | 32 | try 33 | serverSocketInfo.socket = ServerSocket(serverSocketInfo.port); 34 | OPENIGTLINK_SERVER_SOCKET=serverSocketInfo.socket; 35 | catch 36 | error('Failed to open server port. Make sure the port is not open already or blocked by firewall.'); 37 | end 38 | serverSocketInfo.socket.setSoTimeout(serverSocketInfo.timeout); 39 | 40 | disp('Waiting for client connections...'); 41 | 42 | % Handle client connections 43 | while(true) 44 | 45 | % Wait for client connection 46 | drawNowCounter=0; 47 | while(true), 48 | try 49 | clientSocketInfo.socket = serverSocketInfo.socket.accept; 50 | break; 51 | catch 52 | end 53 | if (drawNowCounter>10) 54 | drawnow 55 | drawNowCounter=0; 56 | end; 57 | drawNowCounter=drawNowCounter+1; 58 | pause(0.5); 59 | end 60 | 61 | % Client connected 62 | disp('Client connected') 63 | % Rehash forces re-reading of all Matlab functions from files 64 | rehash 65 | 66 | clientSocketInfo.remoteHost = char(clientSocketInfo.socket.getInetAddress); 67 | clientSocketInfo.outputStream = clientSocketInfo.socket.getOutputStream; 68 | clientSocketInfo.inputStream = clientSocketInfo.socket.getInputStream; 69 | clientSocketInfo.messageHeaderReceiveTimeoutSec=5; 70 | clientSocketInfo.messageBodyReceiveTimeoutSec=25; 71 | 72 | % Read command 73 | receivedMsg=ReadOpenIGTLinkStringMessage(clientSocketInfo); 74 | if(~isempty(receivedMsg) && ~isempty(receivedMsg.string)) 75 | dataType=deblank(char(receivedMsg.dataTypeName)); 76 | deviceName=deblank(char(receivedMsg.deviceName)); 77 | cmd=deblank(char(receivedMsg.string)); 78 | replyDeviceName='ACK'; 79 | if (~strcmp(dataType,'STRING')) 80 | response=['ERROR: Expected STRING data type, received data type: [',dataType,']']; 81 | elseif (length(deviceName)<3 || ~strcmp(deviceName(1:3),'CMD')) 82 | response=['ERROR: Expected device name starting with CMD. Received device name: [',deviceName,']']; 83 | elseif (isempty(cmd)) 84 | response='ERROR: Received empty command string'; 85 | else 86 | % Reply device name for CMD is ACQ, for CMD_someuid is ACK_someuid 87 | replyDeviceName=deviceName; 88 | replyDeviceName(1:3)='ACK'; 89 | try 90 | disp([' Execute command: ',cmd]); 91 | response=evalc(cmd); 92 | if (isempty(response)) 93 | % Replace empty response by OK to indicate success 94 | response='OK'; 95 | end 96 | disp(' Command execution completed successfully'); 97 | catch ME 98 | response=['ERROR: Command execution failed. ',ME.getReport('extended','hyperlinks','off')]; 99 | end 100 | end 101 | else 102 | response='ERROR: Error while receiving the command'; 103 | end 104 | 105 | % Send reply 106 | responseStr=num2str(response); 107 | disp([' Response (sent to device ',replyDeviceName,'): ', responseStr]); 108 | WriteOpenIGTLinkStringMessage(clientSocketInfo, responseStr, replyDeviceName); 109 | 110 | % Close connection 111 | clientSocketInfo.socket.close; 112 | clientSocketInfo.socket=[]; 113 | disp('Client connection closed'); 114 | 115 | end 116 | 117 | % Close server socket 118 | serverSocketInfo.socket.close; 119 | serverSocketInfo.socket=[]; 120 | 121 | end 122 | 123 | function msg=ReadOpenIGTLinkStringMessage(clientSocket) 124 | msg=ReadOpenIGTLinkMessage(clientSocket); 125 | if (length(msg.body)<5) 126 | disp('Error: STRING message received with incomplete contents') 127 | msg.string=''; 128 | return 129 | end 130 | strMsgEncoding=convertFromUint8VectorToUint16(msg.body(1:2)); 131 | if (strMsgEncoding~=3) 132 | disp(['Warning: STRING message received with unknown encoding ',num2str(strMsgEncoding)]) 133 | end 134 | strMsgLength=convertFromUint8VectorToUint16(msg.body(3:4)); 135 | msg.string=char(msg.body(5:4+strMsgLength)); 136 | end 137 | 138 | function msg=ReadOpenIGTLinkMessage(clientSocket) 139 | openIGTLinkHeaderLength=58; 140 | headerData=ReadWithTimeout(clientSocket, openIGTLinkHeaderLength, clientSocket.messageHeaderReceiveTimeoutSec); 141 | if (length(headerData)==openIGTLinkHeaderLength) 142 | msg=ParseOpenIGTLinkMessageHeader(headerData); 143 | msg.body=ReadWithTimeout(clientSocket, msg.bodySize, clientSocket.messageBodyReceiveTimeoutSec); 144 | else 145 | error('ERROR: Timeout while waiting receiving OpenIGTLink message header') 146 | end 147 | end 148 | 149 | function result=WriteOpenIGTLinkStringMessage(clientSocket, msgString, deviceName) 150 | msg.dataTypeName='STRING'; 151 | msg.deviceName=deviceName; 152 | msg.timestamp=0; 153 | msgString=[uint8(msgString) uint8(0)]; % Convert string to uint8 vector and add terminator character 154 | msg.body=[convertFromUint16ToUint8Vector(3),convertFromUint16ToUint8Vector(length(msgString)),msgString]; 155 | result=WriteOpenIGTLinkMessage(clientSocket, msg); 156 | end 157 | 158 | % Returns 1 if successful, 0 if failed 159 | function result=WriteOpenIGTLinkMessage(clientSocket, msg) 160 | import java.net.Socket 161 | import java.io.* 162 | import java.net.ServerSocket 163 | % Add constant fields values 164 | msg.versionNumber=1; 165 | msg.bodySize=length(msg.body); 166 | msg.bodyCrc=0; % TODO: compute this 167 | % Pack message 168 | data=[]; 169 | data=[data, convertFromUint16ToUint8Vector(msg.versionNumber)]; 170 | data=[data, padString(msg.dataTypeName,12)]; 171 | data=[data, padString(msg.deviceName,20)]; 172 | data=[data, convertFromInt64ToUint8Vector(msg.timestamp)]; 173 | data=[data, convertFromInt64ToUint8Vector(msg.bodySize)]; 174 | data=[data, convertFromInt64ToUint8Vector(msg.bodyCrc)]; 175 | data=[data, uint8(msg.body)]; 176 | result=1; 177 | try 178 | DataOutputStream(clientSocket.outputStream).write(uint8(data),0,length(data)); 179 | catch ME 180 | disp(ME.message) 181 | result=0; 182 | end 183 | try 184 | DataOutputStream(clientSocket.outputStream).flush; 185 | catch ME 186 | disp(ME.message) 187 | result=0; 188 | end 189 | if (result==0) 190 | disp('Sending OpenIGTLink message failed'); 191 | end 192 | end 193 | 194 | function data=ReadWithTimeout(clientSocket, requestedDataLength, timeoutSec) 195 | import java.net.Socket 196 | import java.io.* 197 | import java.net.ServerSocket 198 | 199 | % preallocate to improve performance 200 | data=zeros(1,requestedDataLength,'uint8'); 201 | signedDataByte=int8(0); 202 | bytesRead=0; 203 | while(bytesRead0) 214 | % starting to read message header 215 | tstart=tic; 216 | end 217 | for i = bytesRead+1:bytesRead+bytesToRead 218 | signedDataByte = DataInputStream(clientSocket.inputStream).readByte; 219 | if signedDataByte>=0 220 | data(i) = signedDataByte; 221 | else 222 | data(i) = typecast(int8(signedDataByte),'uint8'); 223 | end 224 | end 225 | bytesRead=bytesRead+bytesToRead; 226 | if (bytesRead>0 && bytesReadtimeoutSec) 230 | % timeout, it should not happen 231 | % remove the unnecessary preallocated elements 232 | data=data(1:bytesRead); 233 | break 234 | end 235 | end 236 | end 237 | end 238 | 239 | %% Parse OpenIGTLink messag header 240 | % http://openigtlink.org/protocols/v2_header.html 241 | function parsedMsg=ParseOpenIGTLinkMessageHeader(rawMsg) 242 | parsedMsg.versionNumber=convertFromUint8VectorToUint16(rawMsg(1:2)); 243 | parsedMsg.dataTypeName=char(rawMsg(3:14)); 244 | parsedMsg.deviceName=char(rawMsg(15:34)); 245 | parsedMsg.timestamp=convertFromUint8VectorToInt64(rawMsg(35:42)); 246 | parsedMsg.bodySize=convertFromUint8VectorToInt64(rawMsg(43:50)); 247 | parsedMsg.bodyCrc=convertFromUint8VectorToInt64(rawMsg(51:58)); 248 | end 249 | 250 | function result=convertFromUint8VectorToUint16(uint8Vector) 251 | result=int32(uint8Vector(1))*256+int32(uint8Vector(2)); 252 | end 253 | 254 | function result=convertFromUint8VectorToInt64(uint8Vector) 255 | multipliers = [256^7 256^6 256^5 256^4 256^3 256^2 256^1 1]; 256 | % Matlab R2009 and earlier versions don't support int64 arithmetics. 257 | int64arithmeticsSupported=~isempty(find(strcmp(methods('int64'),'mtimes'))); 258 | if int64arithmeticsSupported 259 | % Full 64-bit arithmetics 260 | result = sum(int64(uint8Vector).*int64(multipliers)); 261 | else 262 | % Fall back to floating point arithmetics: compute result with floating 263 | % point type and convert the end result to int64 264 | % (it should be precise enough for realistic file sizes) 265 | result = int64(sum(double(uint8Vector).*multipliers)); 266 | end 267 | end 268 | 269 | function selectedByte=getNthByte(multibyte, n) 270 | selectedByte=uint8(mod(floor(multibyte/256^n),256)); 271 | end 272 | 273 | function result=convertFromUint16ToUint8Vector(uint16Value) 274 | result=[getNthByte(uint16Value,1) getNthByte(uint16Value,0)]; 275 | end 276 | 277 | function result=convertFromInt64ToUint8Vector(int64Value) 278 | result=zeros(1,8,'uint8'); 279 | result(1)=getNthByte(int64Value,7); 280 | result(2)=getNthByte(int64Value,6); 281 | result(3)=getNthByte(int64Value,5); 282 | result(4)=getNthByte(int64Value,4); 283 | result(5)=getNthByte(int64Value,3); 284 | result(6)=getNthByte(int64Value,2); 285 | result(7)=getNthByte(int64Value,1); 286 | result(8)=getNthByte(int64Value,0); 287 | end 288 | 289 | function paddedStr=padString(str,strLen) 290 | paddedStr=str(1:min(length(str),strLen)); 291 | paddingLength=strLen-length(paddedStr); 292 | if (paddingLength>0) 293 | paddedStr=[paddedStr,zeros(1,paddingLength,'uint8')]; 294 | end 295 | end 296 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_geometryread.m: -------------------------------------------------------------------------------- 1 | function geometry = cli_geometryread(filename) 2 | %cli_geometryread Read geometry for the command-line interface module from file (in PLY or STL format) into LPS coordinate system 3 | % 4 | % geometry = cli_geometryread(filename) reads the mesh 5 | % 6 | % geometry.vertices contains the vertices for all triangles in LPS coordinate system [3*n x 3]. 7 | % geometry.faces contains the vertex lists defining each triangle face [n x 3]. 8 | % 9 | % Current limitations/caveats: 10 | % * Only triangle mesh geometry is supported. 11 | % 12 | % Example: 13 | % g=cli_geometryread('SimpleGeom.stl'); 14 | % patch(g, 'FaceColor', 'red'); 15 | % 16 | 17 | [pathstr,name,ext] = fileparts(filename); 18 | if (strcmpi(ext,'.stl')) 19 | [v, f, n, c, stltitle] = stlread(filename); 20 | else 21 | [v, f] = read_ply(filename); 22 | end 23 | 24 | geometry.vertices = v; 25 | geometry.faces = f; 26 | 27 | % Slicer writes mesh points in RAS coordinate system by default, convert to LPS now 28 | geometry.vertices(:,1:2) = -1*geometry.vertices(:,1:2) 29 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_geometrywrite.m: -------------------------------------------------------------------------------- 1 | function cli_geometrywrite(outputFilename, geometry) 2 | % Function for writing mesh data to PLY or STL file 3 | % 4 | % geometry.vertices contains the vertices for all triangles in LPS coordinate system [3*n x 3]. 5 | % geometry.faces contains the vertex lists defining each triangle face [n x 3]. 6 | % 7 | % Current limitations/caveats: 8 | % * Only triangle mesh geometry is supported. 9 | 10 | % Slicer expects mesh points in RAS coordinate system by default, convert from LPS now 11 | geometry.vertices(:,1:2) = -1*geometry.vertices(:,1:2) 12 | 13 | [pathstr,name,ext] = fileparts(outputFilename); 14 | if (strcmpi(ext,'.stl')) 15 | stlwrite(outputFilename, geometry); 16 | else 17 | write_ply(geometry.vertices, geometry.faces, outputFilename); 18 | end 19 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_imageread.m: -------------------------------------------------------------------------------- 1 | function img = cli_imageread(filename) 2 | %cli_imageread Read images for the command-line interface module from file (in NRRD format, see http://teem.sourceforge.net/nrrd/format.html) 3 | % img = cli_imageread(filename) reads the image volume and associated metadata 4 | % 5 | % See detailed description of the img structure in nrrdread.m 6 | % 7 | 8 | img = nrrdread(filename); 9 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_imagewrite.m: -------------------------------------------------------------------------------- 1 | function cli_imagewrite(outputFilename, img) 2 | % Function for writing pixel and meta data struct to a NRRD file 3 | % 4 | % See detailed description of the input data format description in nrrdwrite.m 5 | % 6 | 7 | nrrdwrite(outputFilename, img); 8 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_lineartransformread.m: -------------------------------------------------------------------------------- 1 | function transform = cli_lineartransformread(filename, transformType) 2 | %cli_transformread Read a single 4x4 linear transformation matrix from an "Insight Transform File V1.0" text file 3 | % 4 | % By default the output transform is in LPS anatomical coordinate sytem and 5 | % defined according to ITK ("image processing") convention. 6 | % If transformType is set to 'slicer' then the output transform is in RAS 7 | % coordinate system and defined according to Slicer ("computer graphics") 8 | % convention. 9 | % See more details at: http://www.slicer.org/slicerWiki/index.php/Documentation/4.2/FAQ#The_registration_transform_file_saved_by_Slicer_does_not_seem_to_match_what_is_shown 10 | % 11 | 12 | if nargin < 2 13 | transformType = 'itk'; 14 | end 15 | 16 | allTransforms=cli_transformread(filename); 17 | 18 | assert(length(allTransforms)==1, 'The transform file should contain exactly one transform'); 19 | assert(strcmpi(allTransforms{1}.Transform,'AffineTransform_double_3_3'), 'The transform file should contain an AffineTransform_double_3_3 transform'); 20 | 21 | params=str2num(allTransforms{1}.Parameters); 22 | 23 | transform_lps=[[reshape(params(1:9),3,3)' params(10:12)']; 0 0 0 1]; 24 | 25 | if (strcmpi(transformType,'itk')) 26 | transform=transform_lps; 27 | elseif (strcmpi(transformType, 'slicer')) 28 | lps2ras=diag([-1 -1 1 1]); 29 | ras2lps=diag([-1 -1 1 1]); 30 | transform=lps2ras*inv(transform_lps)*ras2lps; 31 | else 32 | error('Unknown transformType: %s',transformType); 33 | end 34 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_lineartransformwrite.m: -------------------------------------------------------------------------------- 1 | function cli_lineartransformwrite(outputfilename, transformMatrix, transformType) 2 | %cli_transformwrite Write a single 4x4 linear transformation matrix to an "Insight Transform File V1.0" text file 3 | % 4 | % By default the output transform is in LPS anatomical coordinate sytem and 5 | % defined according to ITK ("image processing") convention. 6 | % If transformType is set to 'slicer' then the output transform is in RAS 7 | % coordinate system and defined according to Slicer ("computer graphics") 8 | % convention. 9 | % See more details at: http://www.slicer.org/slicerWiki/index.php/Documentation/4.2/FAQ#The_registration_transform_file_saved_by_Slicer_does_not_seem_to_match_what_is_shown 10 | % 11 | 12 | if nargin < 3 13 | transformType = 'itk'; 14 | end 15 | 16 | assert(isequal(size(transformMatrix),[4 4]), 'transformMatrix size must be 4x4'); 17 | 18 | if (strcmpi(transformType,'itk')) 19 | transform_lps=transformMatrix; 20 | elseif (strcmpi(transformType, 'slicer')) 21 | lps2ras=diag([-1 -1 1 1]); 22 | ras2lps=diag([-1 -1 1 1]); 23 | transform_lps=ras2lps*inv(transformMatrix)*lps2ras; 24 | else 25 | error('Unknown transformType: %s',transformType); 26 | end 27 | 28 | allTransforms{1}.Transform='AffineTransform_double_3_3'; 29 | allTransforms{1}.Parameters=[reshape(transform_lps(1:3,1:3)',1,9) transform_lps(1:3,4)']; 30 | allTransforms{1}.FixedParameters=[0 0 0]; 31 | 32 | cli_transformwrite(outputfilename, allTransforms); 33 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_measurementread.m: -------------------------------------------------------------------------------- 1 | function measurement = cli_measurementread(filename) 2 | %cli_measurementread Read measurement table from Slicer measurement CSV file 3 | % 4 | 5 | % Sample file contents: 6 | % 7 | % # measurement file C:/Users/someuser/AppData/Local/Temp/FBGA_vtkMRMLDoubleArrayNodeB.csv 8 | % # columns = x,y,yerr 9 | % 2.0,4.0,0.002 10 | % 5.2,1.5,0.001 11 | % 5.1,2.5,0.005 12 | % 13 | 14 | try 15 | measurement=csvread(filename,2); 16 | catch ME 17 | % failed with and without an output, the command must be invalid 18 | disp(['Could not retrieve any measurement values from: ' filename]); 19 | measurement=[]; 20 | end 21 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_measurementwrite.m: -------------------------------------------------------------------------------- 1 | function cli_measurementwrite(outputfilename, measurements) 2 | %cli_measurementwrite Write a list of measurements to a "Insight Transform File V1.0" text file 3 | % 4 | 5 | % Sample file contents: 6 | % 7 | % # measurement file C:/Users/someuser/AppData/Local/Temp/FBGA_vtkMRMLDoubleArrayNodeB.csv 8 | % # columns = x,y,yerr 9 | % 2.0,4.0,0.002 10 | % 5.2,1.5,0.001 11 | % 5.1,2.5,0.005 12 | % 13 | 14 | [rows columns] = size(measurements); 15 | assert(rows>0, 'The measurement matrix is empty'); 16 | assert(columns==3, 'The measurement matrix must have 3 columns'); 17 | 18 | % Write header 19 | fid=fopen(outputfilename, 'w'); 20 | assert(fid > 0, 'Could not open file %s', outputfilename); 21 | fprintf(fid,'# measurement file %s\n', outputfilename); 22 | fprintf(fid,'# columns = x,y,yerr\n'); 23 | fclose(fid); 24 | 25 | dlmwrite(outputfilename,measurements,'-append','delimiter',','); 26 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_pointfileread.m: -------------------------------------------------------------------------------- 1 | function points = cli_pointfileread(filename) 2 | % Read image markups from a Slicer fcsv file 3 | % points = cli_pointfileread(filename) reads the image volume and associated metadata 4 | % 5 | % points.position: point positions (Nx3) 6 | % points.orientation: point orientations as quaternion (Nx4) 7 | % points.id: point identifiers 8 | % points.visibility: non-zero if point is visible 9 | % points.selected: non-zero if point is selected 10 | % points.locked: non-zero if point is protected from editing by the user 11 | % points.label: displayed label string 12 | % points.description: description of the point 13 | % points.associatedNodeID: ID od te node where the point was marked on 14 | % 15 | % points.headerVersion: first header line 16 | % points.headerCoordinateSystem: second header line 17 | % points.headerColumns: third header line 18 | % 19 | % Sample file contents: 20 | % 21 | % # Markups fiducial file version = 4.7 22 | % # CoordinateSystem = 1 23 | % # columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID 24 | % vtkMRMLMarkupsFiducialNode_122,-31.27,-28.3827,40.0248,0,0,0,1,1,0,0,,, 25 | % vtkMRMLMarkupsFiducialNode_123,-30.7427,-28.8846,40.7103,0,0,0,1,1,0,0,,, 26 | % vtkMRMLMarkupsFiducialNode_124,-30.2028,-29.4316,41.3501,0,0,0,1,1,0,0,,, 27 | % vtkMRMLMarkupsFiducialNode_125,-29.6359,-30.022,41.9246,0,0,0,1,1,0,0,,, 28 | % 29 | 30 | points = {} 31 | 32 | fid = fopen(filename, 'r'); 33 | assert(fid > 0, 'Could not open file.'); 34 | cleaner = onCleanup(@() fclose(fid)); 35 | 36 | % Ignore the first 3 lines, they are just headers 37 | % (it may be useful to parse these lines in the future to improve robustnes 38 | % and compatibility) 39 | points.headerVersion = fgetl(fid); 40 | points.headerCoordinateSystem = fgetl(fid); 41 | points.headerColumns = fgetl(fid); 42 | 43 | columns = textscan(fid, '%s %f%f%f %f%f%f%f %d%d%d %s %s %s','delimiter',',') 44 | 45 | points.id = columns{1} 46 | points.position = [columns{2}, columns{3}, columns{4}] 47 | points.orientation = [columns{5}, columns{6}, columns{7}, columns{8}] 48 | points.visibility = columns{9} 49 | points.selected = columns{10} 50 | points.locked = columns{11} 51 | points.label = columns{12} 52 | points.description = columns{13} 53 | points.associatedNodeID = columns{14} 54 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_pointfilewrite.m: -------------------------------------------------------------------------------- 1 | function cli_pointfilewrite(outputfilename, points) 2 | %cli_measurementwrite Write a list of measurements to a Slicer fcsv text file 3 | % 4 | % See more details at cli_pointfileread 5 | % 6 | % Sample file contents: 7 | % 8 | % # Markups fiducial file version = 4.7 9 | % # CoordinateSystem = 1 10 | % # columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID 11 | % vtkMRMLMarkupsFiducialNode_122,-31.27,-28.3827,40.0248,0,0,0,1,1,0,0,,, 12 | % vtkMRMLMarkupsFiducialNode_123,-30.7427,-28.8846,40.7103,0,0,0,1,1,0,0,,, 13 | % vtkMRMLMarkupsFiducialNode_124,-30.2028,-29.4316,41.3501,0,0,0,1,1,0,0,,, 14 | % vtkMRMLMarkupsFiducialNode_125,-29.6359,-30.022,41.9246,0,0,0,1,1,0,0,,, 15 | % 16 | 17 | % Write header 18 | fid=fopen(outputfilename, 'w'); 19 | assert(fid > 0, 'Could not open file %s', outputfilename); 20 | fprintf(fid,'%s\n', points.headerVersion); 21 | fprintf(fid,'%s\n', points.headerCoordinateSystem); 22 | fprintf(fid,'%s\n', points.headerColumns); 23 | numOfPoints = size(points.position,1); 24 | for k = 1:numOfPoints 25 | % Retrieve optional properties 26 | label = ''; 27 | if k <= size(points.label,1) 28 | label = points.label(k); 29 | end 30 | description = ''; 31 | if k <= size(points.description,1) 32 | description = points.description(k); 33 | end 34 | associatedNodeID = ''; 35 | if k <= size(points.associatedNodeID,1) 36 | associatedNodeID = points.associatedNodeID(k); 37 | end 38 | % Write to file 39 | fprintf(fid,'%s,%g,%g,%g,%g,%g,%g,%g,%d,%d,%d,%s,%s,%s\n',... 40 | points.id(k,:),... 41 | points.position(k,1), points.position(k,2), points.position(k,3),... 42 | points.orientation(k,1), points.orientation(k,2), points.orientation(k,3), points.orientation(k,4),... 43 | points.visibility(k), points.selected(k), points.locked(k),... 44 | label, description, associatedNodeID); 45 | end 46 | fclose(fid); 47 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_pointvectordecode.m: -------------------------------------------------------------------------------- 1 | function points=cli_pointvectordecode(paramValue) 2 | % Creates a [3xN] matrix with the point positions in LPS coordinate system 3 | 4 | if (iscell(paramValue)) 5 | points=cell2mat(paramValue); 6 | else 7 | % Single fiducial point, it's not stored in a cell 8 | points=paramValue; 9 | end 10 | 11 | % Point coordinates are provided by Slicer in RAS coordinate system 12 | % Multiply the first two components by -1 to obtain points in LPS coordinate system 13 | points(1:2,:)=-1*points(1:2,:); 14 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_stringvectordecode.m: -------------------------------------------------------------------------------- 1 | function stringlist=cli_stringvectordecode(paramValue) 2 | % Creates a string cell array from the string-vector parameter value 3 | % (which is a comma-separated string). 4 | % More recent Matlab versions can return the value simply by using the 5 | % strsplit function. 6 | 7 | stringcellarray=regexp(paramValue,'([^,]*)','tokens') 8 | stringlist=cat(2,stringcellarray{:}) 9 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_transformread.m: -------------------------------------------------------------------------------- 1 | function transforms = cli_transformread(filename) 2 | %cli_transformread Read transforms from a "Insight Transform File V1.0" text file 3 | % 4 | % The output is a cell that contains a structure for each transform in 5 | % the file. 6 | % The structure contains the properties of each transform (typically 7 | % Transform, Parameters, and FixedParameters field). 8 | % 9 | 10 | fid = fopen(filename, 'rt'); 11 | assert(fid > 0, 'Could not open file.'); 12 | cleaner = onCleanup(@() fclose(fid)); 13 | 14 | % Transform files are expected to start with a specific first line 15 | expectedFirstLine='#Insight Transform File V1.0'; 16 | theLine = fgetl(fid); 17 | assert(strcmpi(theLine,expectedFirstLine), 'The first line of the transform file expected to be #Insight Transform File V1.0') 18 | 19 | % The contents of a linear transform file: 20 | % 21 | % #Insight Transform File V1.0 22 | % #Transform 0 23 | % Transform: AffineTransform_double_3_3 24 | % Parameters: 0.9961969233988567 0.05233595624294384 -0.0696608749212155 -0.041992154494529144 0.9889109407697044 0.14244932497869228 0.07634362299210169 -0.13898236906210146 0.9873477362704213 6.995316014085823 -9.993983402051885 0.021204305831741033 25 | % FixedParameters: 0 0 0 26 | % 27 | 28 | transforms = {}; 29 | latestTransform={}; 30 | 31 | % Parse the file a line at a time. 32 | while (~feof(fid)) 33 | theLine = fgetl(fid); 34 | if (isempty(theLine)) 35 | % End of the header. 36 | break; 37 | end 38 | if (isequal(theLine(1), '#')) 39 | % Comment line. 40 | continue; 41 | end 42 | 43 | % "fieldname:= value" or "fieldname: value" or "fieldname:value" 44 | parsedLine = regexp(theLine, ':=?\s*', 'split','once'); 45 | 46 | assert(numel(parsedLine) == 2, 'Parsing error') 47 | 48 | field = parsedLine{1}; 49 | value = parsedLine{2}; 50 | 51 | if (strcmpi(field,'Transform')) 52 | % This is a new transform 53 | if (isfield(latestTransform,'Transform')) 54 | % We already have some transform info, so save it 55 | transforms{length(transforms)+1}=latestTransform; 56 | latestTransform={}; 57 | end 58 | latestTransform.Transform=value; 59 | else 60 | % This is a new field for the latest transform 61 | latestTransform.(field)=value; 62 | end 63 | end 64 | 65 | % Save the latestTransform 66 | if (isfield(latestTransform,'Transform')) 67 | % We already have some transform info, so save it 68 | transforms{length(transforms)+1}=latestTransform; 69 | end 70 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_transformwrite.m: -------------------------------------------------------------------------------- 1 | function cli_transformwrite(outputfilename, transforms) 2 | %cli_transformwrite Write transforms to a "Insight Transform File V1.0" text file 3 | % 4 | 5 | % Open file for writing 6 | fid=fopen(outputfilename, 'w'); 7 | 8 | assert(fid > 0, 'Could not open file %s', outputfilename); 9 | cleaner = onCleanup(@() fclose(fid)); 10 | 11 | fprintf(fid,'#Insight Transform File V1.0\n'); 12 | 13 | for transformIndex=1:length(transforms) 14 | % Get string names for each field in transform descriptor 15 | fields = fieldnames(transforms{transformIndex}); 16 | metaDataCellArr = struct2cell(transforms{transformIndex}); 17 | for i=1:numel(fields) 18 | fprintf(fid,fields{i}); 19 | writeDataByType(fid,metaDataCellArr{i}); 20 | end 21 | end 22 | 23 | fprintf(fid,'\n'); 24 | 25 | %fclose(fid); 26 | 27 | function writeDataByType(fid, data) 28 | % Function that writes the header data to file based on the type of data 29 | % params: - fid of file to write to 30 | % - data from header to write 31 | if ischar(data) 32 | fprintf(fid,': %s\n',data); 33 | else 34 | fprintf(fid,': '); 35 | fprintf(fid,'%d ',data); 36 | fprintf(fid,'\n'); 37 | end 38 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/cli_version.m.in: -------------------------------------------------------------------------------- 1 | function [major minor patch]=cli_version() 2 | % Returns MatlabBridge module version 3 | 4 | major = @MATLABBRIDGE_VERSION_MAJOR@ 5 | minor = @MATLABBRIDGE_VERSION_MINOR@ 6 | patch = @MATLABBRIDGE_VERSION_PATCH@ 7 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/fcsvwrite.m: -------------------------------------------------------------------------------- 1 | function fcsvwrite(outputfilename, position, id, visibile, selected, locked, label, description, orientation) 2 | %fcsvwrite Write a list of fiducial markups to Slicer fcsv file 3 | % 4 | 5 | % Sample file contents: 6 | % 7 | % # Markups fiducial file version = 4.5 8 | % # CoordinateSystem = 0 9 | % # columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID 10 | % vtkMRMLMarkupsFiducialNode_0,-2.49926,8.41401,78.7389,0,0,0,1,1,1,0,F-1,,vtkMRMLModelNode5 11 | % vtkMRMLMarkupsFiducialNode_1,-7.29697,13.0602,74.4859,0,0,0,1,1,1,0,F-2,,vtkMRMLModelNode5 12 | % vtkMRMLMarkupsFiducialNode_2,-5.4786,10.4094,76.1044,0,0,0,1,1,1,0,F-3,,vtkMRMLModelNode5 13 | % 14 | 15 | [rows columns] = size(position); 16 | if rows>0 17 | assert(columns==3, 'Position matrix must have 3 columns'); 18 | end 19 | 20 | if nargin < 3 21 | id = strtrim(cellstr(num2str([1:rows]'))'); 22 | end 23 | if nargin < 4 24 | visible = ones(rows,1); 25 | end 26 | if nargin < 5 27 | selected = ones(rows,1); 28 | end 29 | if nargin < 6 30 | locked = zeros(rows,1); 31 | end 32 | if nargin < 7 33 | label = cell(rows,1); 34 | end 35 | if nargin < 8 36 | description = cell(rows,1); 37 | end 38 | if nargin < 9 39 | orientation = [zeros(rows,3) ones(rows,1)]; 40 | else 41 | [orientationRows orientationColumns] = size(orientation) 42 | assert(orientationRows==rows, 'Orientation matrix must the same number of rows as the position matrix'); 43 | assert(orientationColumns==4, 'Orientation matrix must have 4 columns'); 44 | end 45 | 46 | associatedNodeID = ''; % use just a constant empty associated node ID for all points 47 | 48 | % Write header 49 | fid=fopen(outputfilename, 'w'); 50 | assert(fid > 0, 'Could not open file %s', outputfilename); 51 | fprintf(fid,'# Markups fiducial file version = 4.5\n'); 52 | fprintf(fid,'# CoordinateSystem = 0\n'); 53 | fprintf(fid,'# columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID\n'); 54 | for rowIndex=1:rows 55 | fprintf(fid,'%s,%f,%f,%f,%f,%f,%f,%f,%d,%d,%d,%s,%s,%s\n',char(id(rowIndex)), 56 | position(rowIndex,1),position(rowIndex,2),position(rowIndex,3), 57 | orientation(rowIndex,1),orientation(rowIndex,2),orientation(rowIndex,3),orientation(rowIndex,4), 58 | visible(rowIndex),selected(rowIndex),locked(rowIndex), 59 | char(label(rowIndex)),char(description(rowIndex)),associatedNodeID); 60 | end 61 | fclose(fid); 62 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/nrrdaddmetafield.m: -------------------------------------------------------------------------------- 1 | function img = nrrdaddmetafield(img, fullFieldName, fieldValue) 2 | % Add a metadata field to an image 3 | % 4 | % Example: 5 | % 6 | % img = nrrdaddmetafield(img, 'MultiVolume.DICOM.EchoTime', 1.348); 7 | 8 | fieldName=regexprep(fullFieldName,'\W','_'); 9 | if ~strcmp(fieldName,fullFieldName) 10 | img.metaDataFieldNames.(fieldName) = fullFieldName; 11 | end 12 | img.metaData.(fieldName) = fieldValue; 13 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/nrrdread.m: -------------------------------------------------------------------------------- 1 | function img = nrrdread(filename) 2 | % Read image and metadata from a NRRD file (see http://teem.sourceforge.net/nrrd/format.html) 3 | % img = cli_imageread(filename) reads the image volume and associated metadata 4 | % 5 | % img.pixelData: pixel data array 6 | % img.ijkToLpsTransform: pixel (IJK) to physical (LPS, assuming 'space' is 'left-posterior-superior') 7 | % coordinate system transformation, the origin of the IJK coordinate system is (1,1,1) to match Matlab matrix indexing 8 | % img.metaData: contains all the descriptive information in the image header 9 | % img.metaDataFieldNames: Contains full names of metadata fields that cannot be used as Matlab field names because they contains 10 | % special characters (space, dot, etc). Special characters in field names are replaced by underscore by default when the NRRD 11 | % file is read. Full field names are used when writing the image to NRRD file. 12 | % 13 | % Supports reading of 3D and 4D volumes. 14 | % 15 | % Current limitations/caveats: 16 | % * Block datatype is not supported. 17 | % * Only tested with "gzip" and "raw" file encodings. 18 | % 19 | % Partly based on the nrrdread.m function with copyright 2012 The MathWorks, Inc. 20 | 21 | fid = fopen(filename, 'rb'); 22 | assert(fid > 0, 'Could not open file.'); 23 | cleaner = onCleanup(@() fclose(fid)); 24 | 25 | % NRRD files must start with the NRRD word and a version number 26 | theLine = fgetl(fid); 27 | assert(numel(theLine) >= 4, 'Bad signature in file.') 28 | assert(isequal(theLine(1:4), 'NRRD'), 'Bad signature in file.') 29 | 30 | % The general format of a NRRD file (with attached header) is: 31 | % 32 | % NRRD000X 33 | % : 34 | % : 35 | % # 36 | % ... 37 | % : 38 | % := 39 | % := 40 | % := 41 | % # 42 | % 43 | % ... 44 | 45 | img.metaData = {}; 46 | img.metaDataFieldNames = {}; 47 | % Parse the file a line at a time. 48 | while (true) 49 | 50 | theLine = fgetl(fid); 51 | 52 | if (isempty(theLine) || feof(fid)) 53 | % End of the header. 54 | break; 55 | end 56 | 57 | if (isequal(theLine(1), '#')) 58 | % Comment line. 59 | continue; 60 | end 61 | 62 | % "fieldname:= value" or "fieldname: value" or "fieldname:value" 63 | parsedLine = regexp(theLine, ':=?\s*', 'split','once'); 64 | 65 | assert(numel(parsedLine) == 2, 'Parsing error') 66 | 67 | field = parsedLine{1}; 68 | value = parsedLine{2}; 69 | 70 | % Cannot use special characters in field names, so replace them by underscore 71 | % and store the original field name in img.metaDataFieldNames so that it can be 72 | % restored when writing the data. 73 | fieldName=regexprep(field,'\W','_'); 74 | if ~strcmp(fieldName,field) 75 | img.metaDataFieldNames.(fieldName) = field; 76 | end 77 | 78 | img.metaData(1).(fieldName) = value; 79 | 80 | end 81 | 82 | datatype = getDatatype(img.metaData.type); 83 | 84 | % Get the size of the data. 85 | assert(isfield(img.metaData, 'sizes') && ... 86 | isfield(img.metaData, 'dimension') && ... 87 | isfield(img.metaData, 'encoding'), ... 88 | 'Missing required metadata fields (sizes, dimension, or encoding).') 89 | 90 | dims = sscanf(img.metaData.sizes, '%d'); 91 | ndims = sscanf(img.metaData.dimension, '%d'); 92 | assert(numel(dims) == ndims); 93 | 94 | data = readData(fid, img.metaData, datatype); 95 | if isfield(img.metaData, 'endian') 96 | data = adjustEndian(data, img.metaData); 97 | end 98 | 99 | img.pixelData = reshape(data, dims'); 100 | 101 | % For convenience, compute the transformation matrix between physical and pixel coordinates 102 | switch (ndims) 103 | case {3} 104 | axes_directions=reshape(sscanf(img.metaData.space_directions,'(%f,%f,%f) (%f,%f,%f) (%f,%f,%f)'),3,3); 105 | case {4} 106 | axes_directions=reshape(sscanf(img.metaData.space_directions,'none (%f,%f,%f) (%f,%f,%f) (%f,%f,%f)'),3,3); 107 | otherwise 108 | assert(false, 'Unsupported pixel data dimension') 109 | end 110 | axes_origin=sscanf(img.metaData.space_origin,'(%f,%f,%f)'); 111 | ijkZeroBasedToLpsTransform=[[axes_directions, axes_origin]; [0 0 0 1]]; 112 | ijkOneBasedToIjkZeroBasedTransform=[[eye(3), [-1;-1;-1] ]; [0 0 0 1]]; 113 | ijkOneBasedToLpsTransform=ijkZeroBasedToLpsTransform*ijkOneBasedToIjkZeroBasedTransform; 114 | % Use the one-based IJK transform (origin is at [1,1,1]) 115 | img.ijkToLpsTransform=ijkOneBasedToLpsTransform; 116 | 117 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118 | function datatype = getDatatype(metaType) 119 | % Determine the datatype 120 | switch (metaType) 121 | case {'signed char', 'int8', 'int8_t'} 122 | datatype = 'int8'; 123 | case {'uchar', 'unsigned char', 'uint8', 'uint8_t'} 124 | datatype = 'uint8'; 125 | case {'short', 'short int', 'signed short', 'signed short int', ... 126 | 'int16', 'int16_t'} 127 | datatype = 'int16'; 128 | case {'ushort', 'unsigned short', 'unsigned short int', 'uint16', ... 129 | 'uint16_t'} 130 | datatype = 'uint16'; 131 | case {'int', 'signed int', 'int32', 'int32_t'} 132 | datatype = 'int32'; 133 | case {'uint', 'unsigned int', 'uint32', 'uint32_t'} 134 | datatype = 'uint32'; 135 | case {'longlong', 'long long', 'long long int', 'signed long long', ... 136 | 'signed long long int', 'int64', 'int64_t'} 137 | datatype = 'int64'; 138 | case {'ulonglong', 'unsigned long long', 'unsigned long long int', ... 139 | 'uint64', 'uint64_t'} 140 | datatype = 'uint64'; 141 | case {'float'} 142 | datatype = 'single'; 143 | case {'double'} 144 | datatype = 'double'; 145 | otherwise 146 | assert(false, 'Unknown datatype') 147 | end 148 | 149 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 150 | function data = readData(fidIn, meta, datatype) 151 | 152 | switch (meta.encoding) 153 | case {'raw'} 154 | data = fread(fidIn, inf, [datatype '=>' datatype]); 155 | case {'gzip', 'gz'} 156 | compressedData = fread(fidIn, inf, 'uchar=>uint8'); 157 | try 158 | data = zlib_decompress(compressedData,datatype); 159 | catch noMemory 160 | error('Not enough Java heap space (it can be increased in Matlab preferences)'); 161 | return; 162 | end 163 | case {'txt', 'text', 'ascii'} 164 | data = fscanf(fidIn, '%f'); 165 | data = cast(data, datatype); 166 | otherwise 167 | assert(false, 'Unsupported encoding') 168 | end 169 | 170 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 171 | function data = adjustEndian(data, meta) 172 | % For ignoring unused parameters dummy variables (dummy1 and dummy2) are 173 | % used instead of ~ to maintain compatibility with Matlab R2009b version 174 | [dummy1,dummy2,endian] = computer(); 175 | needToSwap = (isequal(endian, 'B') && isequal(lower(meta.endian), 'little')) || ... 176 | (isequal(endian, 'L') && isequal(lower(meta.endian), 'big')); 177 | if (needToSwap) 178 | data = swapbytes(data); 179 | end 180 | 181 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 182 | function M = zlib_decompress(Z,DataType) 183 | % Function for decompressing pixel data 184 | % Z: pixel data to decompress (from uchar to uint8) 185 | % DataType: data type of the volume 186 | % Returns: decompressed pixel data 187 | % Examples: 188 | % pixelData = zlib_decompress(Z,int32); 189 | 190 | import com.mathworks.mlwidgets.io.InterruptibleStreamCopier 191 | a=java.io.ByteArrayInputStream(Z); 192 | b=java.util.zip.GZIPInputStream(a); 193 | isc = InterruptibleStreamCopier.getInterruptibleStreamCopier; 194 | c = java.io.ByteArrayOutputStream; 195 | isc.copyStream(b,c); 196 | M=typecast(c.toByteArray,DataType); 197 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/nrrdwrite.m: -------------------------------------------------------------------------------- 1 | function nrrdwrite(outputFilename, img) 2 | % Write image and metadata to a NRRD file (see http://teem.sourceforge.net/nrrd/format.html) 3 | % img.pixelData: pixel data array 4 | % img.ijkToLpsTransform: pixel (IJK) to physical (LPS, assuming 'space' is 'left-posterior-superior') 5 | % coordinate system transformation, the origin of the IJK coordinate system is (1,1,1) to match Matlab matrix indexing 6 | % img.metaData: Contains all the descriptive information in the image header. The following fields are ignored: 7 | % sizes: computed to match size of img.pixelData 8 | % type: computed to match type of img.pixelData 9 | % kinds: computed to match dimension of img.pixelData 10 | % dimension: computed to match dimension of img.pixelData 11 | % space_directions: ignored if img.ijkToLpsTransform is defined 12 | % space_origin: ignored if img.ijkToLpsTransform is defined 13 | % img.metaData: Contains the list of full NRRD field names for each 14 | % metaData field name. All fields should be listed here that have a 15 | % special character in their name (such as dot or space). 16 | % img.metaDataFieldNames: Contains full names of metadata fields that cannot be used as Matlab field names because they contains 17 | % special characters (space, dot, etc). Full field names are used for determining the field name to be used in the NRRD file 18 | % from the Matlab metadata field name. 19 | % 20 | % Supports writing of 3D and 4D volumes. 21 | % 2D pixelData is written as single-slice 3D volume. 22 | % 23 | % Examples: 24 | % 25 | % 1. Using output from nrrdread: 26 | % 27 | % img = nrrdread('testData\MRHeadRot.nrrd') 28 | % nrrdwrite('testOutput.nrrd', img) 29 | % 30 | % 2. Creating volume from scratch - minimal example 31 | % 32 | % [x,y,z] = meshgrid([-10:10],[-12:15],[-8:6]); 33 | % img.pixelData = x/3+y/4+z/2; 34 | % 35 | % nrrdwrite('testOutput.nrrd', img); 36 | % 37 | % 3. Creating volume from scratch 38 | % 39 | % % Set pixel data 40 | % [x,y,z] = meshgrid([-10:10],[-12:15],[-8:6]); 41 | % img.pixelData = x/3+y/4+z/2; 42 | % 43 | % % Define origin, spacing, axis directions by a homogeneous transformation matrix: 44 | % img.ijkToLpsTransform = [ 1.2 0 0 10; 0 1.2 0 12; 0 0 3.0 -22; 0 0 0 1]; 45 | % 46 | % % Enable compression 47 | % img.metaData.encoding='gzip'; 48 | % 49 | % nrrdwrite('testOutput.nrrd', img); 50 | % 51 | 52 | % Open file for writing 53 | fid=fopen(outputFilename, 'w'); 54 | if(fid<=0) 55 | fprintf('Could not open file: %s\n', outputFilename); 56 | end 57 | 58 | standardFieldNames = { 'type', 'dimension', 'space', 'sizes', 'space directions', 'kinds', 'endian', 'encoding', 'space origin', 'measurement frame' }; 59 | 60 | fprintf(fid,'NRRD0005\n'); 61 | fprintf(fid,'# Complete NRRD file format specification at:\n'); 62 | fprintf(fid,'# http://teem.sourceforge.net/nrrd/format.html\n'); 63 | 64 | % Create/override mandatory fields 65 | 66 | img.metaData.type = getMetaType(class(img.pixelData)); 67 | 68 | if ~isfield(img.metaData,'space') 69 | img.metaData.space = 'left-posterior-superior'; 70 | end 71 | 72 | img.metaData.dimension = length(size(img.pixelData)); % ndim is not defined for int16 arrays 73 | 74 | % 2D image is be written as single-slice 3D volume 75 | if img.metaData.dimension == 2 76 | img.metaData.dimension = 3; 77 | img.metaData.sizes=num2str([size(img.pixelData), 1]); 78 | else 79 | img.metaData.sizes=num2str(size(img.pixelData)); 80 | end 81 | 82 | if isfield(img,'ijkToLpsTransform') 83 | % Write zero-based IJK transform (origin is at [0,0,0]) to the image header 84 | ijkOneBasedToLpsTransform=img.ijkToLpsTransform; 85 | ijkOneBasedToIjkZeroBasedTransform=[[eye(3), [-1;-1;-1] ]; [0 0 0 1]]; 86 | ijkZeroBasedToLpsTransform=ijkOneBasedToLpsTransform*inv(ijkOneBasedToIjkZeroBasedTransform); 87 | axes_origin=ijkZeroBasedToLpsTransform(1:3,4); 88 | img.metaData.space_origin=sprintf('(%f,%f,%f)',reshape(axes_origin,1,3)); 89 | axes_directions=ijkZeroBasedToLpsTransform(1:3,1:3); 90 | switch (img.metaData.dimension) 91 | case {3} 92 | img.metaData.space_directions=sprintf('(%f,%f,%f) (%f,%f,%f) (%f,%f,%f)',reshape(axes_directions,1,9)); 93 | case {4} 94 | img.metaData.space_directions=sprintf('none (%f,%f,%f) (%f,%f,%f) (%f,%f,%f)',reshape(axes_directions,1,9)); 95 | otherwise 96 | assert(false, 'Unsupported pixel data dimension') 97 | end 98 | end 99 | 100 | if ~isfield(img.metaData,'space_directions') 101 | switch (img.metaData.dimension) 102 | case {3} 103 | img.metaData.space_directions = '(1,0,0) (0,1,0) (0,0,1)'; 104 | case {4} 105 | img.metaData.space_directions = 'none (1,0,0) (0,1,0) (0,0,1)'; 106 | otherwise 107 | assert(false, 'Unsupported pixel data dimension') 108 | end 109 | end 110 | 111 | switch (img.metaData.dimension) 112 | case {3} 113 | img.metaData.kinds='domain domain domain'; 114 | case {4} 115 | img.metaData.kinds='list domain domain domain'; 116 | % Add a custom field to make the volume load into 3D Slicer as a MultiVolume 117 | img = nrrdaddmetafield(img,'MultiVolume.NumberOfFrames',size(img.pixelData,4)); 118 | otherwise 119 | assert(false, 'Unsupported pixel data dimension') 120 | end 121 | 122 | if ~isfield(img.metaData,'endian') 123 | img.metaData.endian='little'; 124 | end 125 | 126 | if ~isfield(img.metaData,'encoding') 127 | img.metaData.encoding='raw'; 128 | end 129 | 130 | % Make sure that standard field names that contain special 131 | % characters have their full field names defined. 132 | for k=1:length(standardFieldNames) 133 | fullFieldName=standardFieldNames{k}; 134 | fieldName=regexprep(fullFieldName,'\W','_'); 135 | if ~strcmp(fieldName,fullFieldName) 136 | img.metaDataFieldNames.(fieldName)=fullFieldName; 137 | end 138 | end 139 | 140 | % Print the header data to the output file 141 | metaDataCellArr = struct2cell(img.metaData); 142 | fields = fieldnames(img.metaData); 143 | for i=1:numel(fields) 144 | writeFieldName(fid, fields{i}, img.metaDataFieldNames, standardFieldNames); 145 | writeDataByType(fid,metaDataCellArr{i}); 146 | end 147 | 148 | fprintf(fid,'\n'); 149 | 150 | % Write pixel data 151 | switch (img.metaData.encoding) 152 | case {'raw'} 153 | fwrite(fid, img.pixelData, class(img.pixelData)); 154 | case {'gzip', 'gz'} 155 | try 156 | compressedPixelData = zlib_compress(img.pixelData, class(img.pixelData)); 157 | catch noMemory 158 | disp('Not enough Java heap space (it can be increased in Matlab preferences)'); 159 | return; 160 | end 161 | fwrite(fid, compressedPixelData, class(compressedPixelData)); 162 | otherwise 163 | assert(false, 'Unsupported encoding') 164 | end 165 | 166 | fclose('all'); 167 | 168 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 169 | function writeFieldName(fid, fieldName, fullFieldNames, standardFieldNames) 170 | % If full field name is listed in img.metaDataFieldNames then use that 171 | % instead of the Matlab field name. 172 | if isfield(fullFieldNames,fieldName) 173 | fullFieldName = fullFieldNames.(fieldName); 174 | else 175 | fullFieldName = fieldName; 176 | end 177 | 178 | isStandardFieldName = ~isempty(find(strcmp(fullFieldName, standardFieldNames), 1)); 179 | if isStandardFieldName 180 | % Standard field names are separated by : 181 | fprintf(fid,'%s: ',fullFieldName); 182 | else 183 | % Custom field names are separated by := 184 | fprintf(fid,'%s:= ',fullFieldName); 185 | end 186 | 187 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 188 | function writeDataByType(fid, data) 189 | % Function that writes the header data to file based on the type of data 190 | % params: - fid of file to write to 191 | % - data from header to write 192 | if ischar(data) 193 | fprintf(fid,'%s\n',data); 194 | else 195 | fprintf(fid,'%d ',data); 196 | fprintf(fid,'\n'); 197 | end 198 | 199 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 200 | function metaType = getMetaType(matlabType) 201 | % Determine the metadata type from the Matlab type 202 | switch (matlabType) 203 | case {'int8'} 204 | metaType = 'int8'; 205 | case {'uint8'} 206 | metaType = 'uint8'; 207 | case {'int16'} 208 | metaType = 'int16'; 209 | case {'uint16'} 210 | metaType = 'uint16'; 211 | case {'int32'} 212 | metaType = 'int32'; 213 | case {'uint32'} 214 | metaType = 'uint32'; 215 | case {'int64'} 216 | metaType = 'int64'; 217 | case {'uint64'} 218 | metaType = 'uint64'; 219 | case {'single'} 220 | metaType = 'float'; 221 | case {'double'} 222 | metaType = 'double'; 223 | otherwise 224 | assert(false, 'Unsupported Matlab data type') 225 | end 226 | 227 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 228 | function compressedPixelData = zlib_compress(pixelData,DataType) 229 | % Function for compressing pixel data 230 | % pixelData: pixel data to be compressed 231 | % DataType: data type of volume 232 | % Returns: compressed data 233 | % Examples: 234 | % compressedPixelData = zlib_compress(pixelData,int32) 235 | 236 | cn = strmatch(DataType,{'double','single','logical','char','int8','uint8',... 237 | 'int16','uint16','int32','uint32','int64','uint64'}); 238 | 239 | if cn == 3 || cn == 4 240 | pixelData=uint8(pixelData); 241 | end 242 | pixelData=typecast(pixelData(:),'uint8'); 243 | a=java.io.ByteArrayOutputStream(); 244 | b=java.util.zip.GZIPOutputStream(a); 245 | b.write(pixelData); 246 | b.close; 247 | compressedPixelData=typecast(a.toByteArray,'uint8'); 248 | a.close; 249 | -------------------------------------------------------------------------------- /MatlabCommander/commandserver/read_ply.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabCommander/commandserver/read_ply.m -------------------------------------------------------------------------------- /MatlabCommander/commandserver/stlread.m: -------------------------------------------------------------------------------- 1 | function [v, f, n, c, stltitle] = stlread(filename, verbose) 2 | % This function reads an STL file in binary format into vertex and face 3 | % matrices v and f. 4 | % 5 | % USAGE: [v, f, n, c, stltitle] = stlread(filename, verbose); 6 | % 7 | % verbose is an optional logical argument for displaying some loading 8 | % information (default is false). 9 | % 10 | % v contains the vertices for all triangles [3*n x 3]. 11 | % f contains the vertex lists defining each triangle face [n x 3]. 12 | % n contains the normals for each triangle face [n x 3]. 13 | % c is optional and contains color rgb data in 5 bits [n x 3]. 14 | % if C is not specified, the item is determined to be of uniform temp 15 | % if color is specified, a max and min temp are specified and blue is 16 | % used to range the temperature from min to max in 32 steps 17 | % Valid - (15) - 1 color is used, 0 color is not used 18 | % Red - (10:14) - 0:31 - Reserved 19 | % Green - (5:9) - 0:31 - Reserved 20 | % Blue - (0:4) - 0:31 - Used for temperature scaling 21 | 22 | % stltitle contains the title of the specified stl file [1 x 80]. 23 | % 24 | % To see plot the 3D surface use: 25 | % patch('Faces',f,'Vertices',v,'FaceVertexCData',c); 26 | % or 27 | % plot3(v(:,1),v(:,2),v(:,3),'.'); 28 | % 29 | % Duplicate vertices can be removed using: 30 | % [v, f]=patchslim(v, f); 31 | % 32 | % =================================================== 33 | % 34 | % For more information see: 35 | % http://www.esmonde-white.com/home/diversions/matlab-program-for-loading-stl-files 36 | % 37 | % Based on code originally written by: 38 | % Doron Harlev 39 | % and combined with some code by: 40 | % Eric C. Johnson, 11-Dec-2008 41 | % Copyright 1999-2008 The MathWorks, Inc. 42 | % 43 | % Re-written and optimized by Francis Esmonde-White, May 2010. 44 | % 45 | % =================================================== 46 | % Minor Bugfix. 47 | % Bug in color algorithm fixed by William Grant Lohsen, May 2012. 48 | % 49 | % NOTE: Color implementation is compatible with VisCAM and SolidView 50 | % From Wikipedia: 51 | % The VisCAM and SolidView software packages use the two 'attribute byte count' 52 | % bytes at the end of every triangle to store a 15 bit RGB colour: 53 | % bit 0 to 4 are the intensity level for blue (0 to 31) 54 | % bits 5 to 9 are the intensity level for green (0 to 31) 55 | % bits 10 to 14 are the intensity level for red (0 to 31) 56 | % bit 15 is 1 if the colour is valid 57 | % bit 15 is 0 if the colour is not valid (as with normal STL files) 58 | % 59 | 60 | use_color=(nargout>=4); 61 | 62 | fid=fopen(filename, 'r'); %Open the file, assumes STL Binary format. 63 | if fid == -1 64 | error('File could not be opened, check name or path.') 65 | end 66 | 67 | if ~exist('verbose','var') 68 | verbose = false; 69 | end 70 | 71 | ftitle=fread(fid,80,'uchar=>schar'); % Read file title 72 | numFaces=fread(fid,1,'int32'); % Read number of Faces 73 | 74 | T = fread(fid,inf,'uint8=>uint8'); % read the remaining values 75 | fclose(fid); 76 | 77 | stltitle = char(ftitle'); 78 | 79 | if verbose 80 | fprintf('\nTitle: %s\n', stltitle); 81 | fprintf('Number of Faces: %d\n', numFaces); 82 | disp('Please wait...'); 83 | end 84 | 85 | % Each facet is 50 bytes 86 | % - Three single precision values specifying the face normal vector 87 | % - Three single precision values specifying the first vertex (XYZ) 88 | % - Three single precision values specifying the second vertex (XYZ) 89 | % - Three single precision values specifying the third vertex (XYZ) 90 | % - Two color bytes (possibly zeroed) 91 | 92 | % 3 dimensions x 4 bytes x 4 vertices = 48 bytes for triangle vertices 93 | % 2 bytes = color (if color is specified) 94 | 95 | trilist = 1:48; 96 | 97 | ind = reshape(repmat(50*(0:(numFaces-1)),[48,1]),[1,48*numFaces])+repmat(trilist,[1,numFaces]); 98 | Tri = reshape(typecast(T(ind),'single'),[3,4,numFaces]); 99 | 100 | n=squeeze(Tri(:,1,:))'; 101 | n=double(n); 102 | 103 | v=Tri(:,2:4,:); 104 | v = reshape(v,[3,3*numFaces]); 105 | v = double(v)'; 106 | 107 | f = reshape(1:3*numFaces,[3,numFaces])'; 108 | 109 | if use_color 110 | c0 = typecast(T(49:50),'uint16'); 111 | if (bitget(c0(1),16)==1) 112 | trilist = 49:50; 113 | ind = reshape(repmat(50*(0:(numFaces-1)),[2,1]),[1,2*numFaces])+repmat(trilist,[1,numFaces]); 114 | c0 = reshape(typecast(T(ind),'uint16'),[1,numFaces]); 115 | 116 | %modified by WGL 117 | r=bitshift(bitand(2^15-1, c0),-10); 118 | g=bitshift(bitand(2^10-1, c0),-5); 119 | b=bitand(2^5-1, c0); 120 | %end modification 121 | c=[r; g; b]'; 122 | 123 | else 124 | c = zeros(numFaces,3); 125 | end 126 | end 127 | 128 | if verbose 129 | disp('Done!'); 130 | end -------------------------------------------------------------------------------- /MatlabCommander/commandserver/stlwrite.m: -------------------------------------------------------------------------------- 1 | function stlwrite(filename, varargin) 2 | %STLWRITE Write STL file from patch or surface data. 3 | % 4 | % STLWRITE(FILE, FV) writes a stereolithography (STL) file to FILE for a 5 | % triangulated patch defined by FV (a structure with fields 'vertices' 6 | % and 'faces'). 7 | % 8 | % STLWRITE(FILE, FACES, VERTICES) takes faces and vertices separately, 9 | % rather than in an FV struct 10 | % 11 | % STLWRITE(FILE, X, Y, Z) creates an STL file from surface data in X, Y, 12 | % and Z. STLWRITE triangulates this gridded data into a triangulated 13 | % surface using triangulation options specified below. X, Y and Z can be 14 | % two-dimensional arrays with the same size. If X and Y are vectors with 15 | % length equal to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed 16 | % through MESHGRID to create gridded data. If X or Y are scalar values, 17 | % they are used to specify the X and Y spacing between grid points. 18 | % 19 | % STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an 20 | % STL file using the following property values: 21 | % 22 | % MODE - File is written using 'binary' (default) or 'ascii'. 23 | % 24 | % TITLE - Header text (max 80 chars) written to the STL file. 25 | % 26 | % TRIANGULATION - When used with gridded data, TRIANGULATION is either: 27 | % 'delaunay' - (default) Delaunay triangulation of X, Y 28 | % 'f' - Forward slash division of grid quads 29 | % 'b' - Back slash division of quadrilaterals 30 | % 'x' - Cross division of quadrilaterals 31 | % Note that 'f', 'b', or 't' triangulations now use an 32 | % inbuilt version of FEX entry 28327, "mesh2tri". 33 | % 34 | % FACECOLOR - Single colour (1-by-3) or one-colour-per-face (N-by-3) 35 | % vector of RGB colours, for face/vertex input. RGB range 36 | % is 5 bits (0:31), stored in VisCAM/SolidView format 37 | % (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL) 38 | % 39 | % Example 1: 40 | % % Write binary STL from face/vertex data 41 | % tmpvol = zeros(20,20,20); % Empty voxel volume 42 | % tmpvol(8:12,8:12,5:15) = 1; % Turn some voxels on 43 | % fv = isosurface(tmpvol, 0.99); % Create the patch object 44 | % stlwrite('test.stl',fv) % Save to binary .stl 45 | % 46 | % Example 2: 47 | % % Write ascii STL from gridded data 48 | % [X,Y] = deal(1:40); % Create grid reference 49 | % Z = peaks(40); % Create grid height 50 | % stlwrite('test.stl',X,Y,Z,'mode','ascii') 51 | 52 | % Original idea adapted from surf2stl by Bill McDonald. Huge speed 53 | % improvements implemented by Oliver Woodford. Non-Delaunay triangulation 54 | % of quadrilateral surface courtesy of Kevin Moerman. FaceColor 55 | % implementation by Grant Lohsen. 56 | % 57 | % Author: Sven Holcombe, 11-24-11 58 | 59 | 60 | % Check valid filename path 61 | path = fileparts(filename); 62 | if ~isempty(path) && ~exist(path,'dir') 63 | error('Directory "%s" does not exist.',path); 64 | end 65 | 66 | % Get faces, vertices, and user-defined options for writing 67 | [faces, vertices, options] = parseInputs(varargin{:}); 68 | asciiMode = strcmp( options.mode ,'ascii'); 69 | 70 | % Create the facets 71 | facets = single(vertices'); 72 | facets = reshape(facets(:,faces'), 3, 3, []); 73 | 74 | % Compute their normals 75 | V1 = squeeze(facets(:,2,:) - facets(:,1,:)); 76 | V2 = squeeze(facets(:,3,:) - facets(:,1,:)); 77 | normals = V1([2 3 1],:) .* V2([3 1 2],:) - V2([2 3 1],:) .* V1([3 1 2],:); 78 | clear V1 V2 79 | normals = bsxfun(@times, normals, 1 ./ sqrt(sum(normals .* normals, 1))); 80 | facets = cat(2, reshape(normals, 3, 1, []), facets); 81 | clear normals 82 | 83 | % Open the file for writing 84 | permissions = {'w','wb+'}; 85 | fid = fopen(filename, permissions{asciiMode+1}); 86 | if (fid == -1) 87 | error('stlwrite:cannotWriteFile', 'Unable to write to %s', filename); 88 | end 89 | 90 | % Write the file contents 91 | if asciiMode 92 | % Write HEADER 93 | fprintf(fid,'solid %s\r\n',options.title); 94 | % Write DATA 95 | fprintf(fid,[... 96 | 'facet normal %.7E %.7E %.7E\r\n' ... 97 | 'outer loop\r\n' ... 98 | 'vertex %.7E %.7E %.7E\r\n' ... 99 | 'vertex %.7E %.7E %.7E\r\n' ... 100 | 'vertex %.7E %.7E %.7E\r\n' ... 101 | 'endloop\r\n' ... 102 | 'endfacet\r\n'], facets); 103 | % Write FOOTER 104 | fprintf(fid,'endsolid %s\r\n',options.title); 105 | 106 | else % BINARY 107 | % Write HEADER 108 | fprintf(fid, '%-80s', options.title); % Title 109 | fwrite(fid, size(facets, 3), 'uint32'); % Number of facets 110 | % Write DATA 111 | % Add one uint16(0) to the end of each facet using a typecasting trick 112 | facets = reshape(typecast(facets(:), 'uint16'), 12*2, []); 113 | % Set the last bit to 0 (default) or supplied RGB 114 | facets(end+1,:) = options.facecolor; 115 | fwrite(fid, facets, 'uint16'); 116 | end 117 | 118 | % Close the file 119 | fclose(fid); 120 | fprintf('Wrote %d facets\n',size(facets, 3)); 121 | 122 | 123 | %% Input handling subfunctions 124 | function [faces, vertices, options] = parseInputs(varargin) 125 | % Determine input type 126 | if isstruct(varargin{1}) % stlwrite('file', FVstruct, ...) 127 | if ~all(isfield(varargin{1},{'vertices','faces'})) 128 | error( 'Variable p must be a faces/vertices structure' ); 129 | end 130 | faces = varargin{1}.faces; 131 | vertices = varargin{1}.vertices; 132 | options = parseOptions(varargin{2:end}); 133 | 134 | elseif isnumeric(varargin{1}) 135 | firstNumInput = cellfun(@isnumeric,varargin); 136 | firstNumInput(find(~firstNumInput,1):end) = 0; % Only consider numerical input PRIOR to the first non-numeric 137 | numericInputCnt = nnz(firstNumInput); 138 | 139 | options = parseOptions(varargin{numericInputCnt+1:end}); 140 | switch numericInputCnt 141 | case 3 % stlwrite('file', X, Y, Z, ...) 142 | % Extract the matrix Z 143 | Z = varargin{3}; 144 | 145 | % Convert scalar XY to vectors 146 | ZsizeXY = fliplr(size(Z)); 147 | for i = 1:2 148 | if isscalar(varargin{i}) 149 | varargin{i} = (0:ZsizeXY(i)-1) * varargin{i}; 150 | end 151 | end 152 | 153 | % Extract X and Y 154 | if isequal(size(Z), size(varargin{1}), size(varargin{2})) 155 | % X,Y,Z were all provided as matrices 156 | [X,Y] = varargin{1:2}; 157 | elseif numel(varargin{1})==ZsizeXY(1) && numel(varargin{2})==ZsizeXY(2) 158 | % Convert vector XY to meshgrid 159 | [X,Y] = meshgrid(varargin{1}, varargin{2}); 160 | else 161 | error('stlwrite:badinput', 'Unable to resolve X and Y variables'); 162 | end 163 | 164 | % Convert to faces/vertices 165 | if strcmp(options.triangulation,'delaunay') 166 | faces = delaunay(X,Y); 167 | vertices = [X(:) Y(:) Z(:)]; 168 | else 169 | if ~exist('mesh2tri','file') 170 | error('stlwrite:missing', '"mesh2tri" is required to convert X,Y,Z matrices to STL. It can be downloaded from:\n%s\n',... 171 | 'http://www.mathworks.com/matlabcentral/fileexchange/28327') 172 | end 173 | [faces, vertices] = mesh2tri(X, Y, Z, options.triangulation); 174 | end 175 | 176 | case 2 % stlwrite('file', FACES, VERTICES, ...) 177 | faces = varargin{1}; 178 | vertices = varargin{2}; 179 | 180 | otherwise 181 | error('stlwrite:badinput', 'Unable to resolve input types.'); 182 | end 183 | end 184 | 185 | if ~isempty(options.facecolor) % Handle colour preparation 186 | facecolor = uint16(options.facecolor); 187 | %Set the Valid Color bit (bit 15) 188 | c0 = bitshift(ones(size(faces,1),1,'uint16'),15); 189 | %Red color (10:15), Blue color (5:9), Green color (0:4) 190 | c0 = bitor(bitshift(bitand(2^6-1, facecolor(:,1)),10),c0); 191 | c0 = bitor(bitshift(bitand(2^11-1, facecolor(:,2)),5),c0); 192 | c0 = bitor(bitand(2^6-1, facecolor(:,3)),c0); 193 | options.facecolor = c0; 194 | else 195 | options.facecolor = 0; 196 | end 197 | 198 | function options = parseOptions(varargin) 199 | IP = inputParser; 200 | IP.addParamValue('mode', 'binary', @ischar) 201 | IP.addParamValue('title', sprintf('Created by stlwrite.m %s',datestr(now)), @ischar); 202 | IP.addParamValue('triangulation', 'delaunay', @ischar); 203 | IP.addParamValue('facecolor',[], @isnumeric) 204 | IP.parse(varargin{:}); 205 | options = IP.Results; 206 | 207 | function [F,V]=mesh2tri(X,Y,Z,tri_type) 208 | % function [F,V]=mesh2tri(X,Y,Z,tri_type) 209 | % 210 | % Available from http://www.mathworks.com/matlabcentral/fileexchange/28327 211 | % Included here for convenience. Many thanks to Kevin Mattheus Moerman 212 | % kevinmoerman@hotmail.com 213 | % 15/07/2010 214 | %------------------------------------------------------------------------ 215 | 216 | [J,I]=meshgrid(1:1:size(X,2)-1,1:1:size(X,1)-1); 217 | 218 | switch tri_type 219 | case 'f'%Forward slash 220 | TRI_I=[I(:),I(:)+1,I(:)+1; I(:),I(:),I(:)+1]; 221 | TRI_J=[J(:),J(:)+1,J(:); J(:),J(:)+1,J(:)+1]; 222 | F = sub2ind(size(X),TRI_I,TRI_J); 223 | case 'b'%Back slash 224 | TRI_I=[I(:),I(:)+1,I(:); I(:)+1,I(:)+1,I(:)]; 225 | TRI_J=[J(:)+1,J(:),J(:); J(:)+1,J(:),J(:)+1]; 226 | F = sub2ind(size(X),TRI_I,TRI_J); 227 | case 'x'%Cross 228 | TRI_I=[I(:)+1,I(:); I(:)+1,I(:)+1; I(:),I(:)+1; I(:),I(:)]; 229 | TRI_J=[J(:),J(:); J(:)+1,J(:); J(:)+1,J(:)+1; J(:),J(:)+1]; 230 | IND=((numel(X)+1):numel(X)+prod(size(X)-1))'; 231 | F = sub2ind(size(X),TRI_I,TRI_J); 232 | F(:,3)=repmat(IND,[4,1]); 233 | Fe_I=[I(:),I(:)+1,I(:)+1,I(:)]; Fe_J=[J(:),J(:),J(:)+1,J(:)+1]; 234 | Fe = sub2ind(size(X),Fe_I,Fe_J); 235 | Xe=mean(X(Fe),2); Ye=mean(Y(Fe),2); Ze=mean(Z(Fe),2); 236 | X=[X(:);Xe(:)]; Y=[Y(:);Ye(:)]; Z=[Z(:);Ze(:)]; 237 | end 238 | 239 | V=[X(:),Y(:),Z(:)]; -------------------------------------------------------------------------------- /MatlabCommander/commandserver/write_ply.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabCommander/commandserver/write_ply.m -------------------------------------------------------------------------------- /MatlabModuleGenerator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | #----------------------------------------------------------------------------- 3 | set(MODULE_NAME MatlabModuleGenerator) 4 | set(MODULE_TITLE "Matlab Module Generator") 5 | 6 | string(TOUPPER ${MODULE_NAME} MODULE_NAME_UPPER) 7 | 8 | #----------------------------------------------------------------------------- 9 | add_subdirectory(Logic) 10 | 11 | #----------------------------------------------------------------------------- 12 | set(MODULE_EXPORT_DIRECTIVE "Q_SLICER_QTMODULES_${MODULE_NAME_UPPER}_EXPORT") 13 | 14 | # Current_{source,binary} and Slicer_{Libs,Base} already included 15 | set(MODULE_INCLUDE_DIRECTORIES 16 | ${CMAKE_CURRENT_SOURCE_DIR}/Logic 17 | ${CMAKE_CURRENT_BINARY_DIR}/Logic 18 | ) 19 | 20 | set(MODULE_SRCS 21 | qSlicer${MODULE_NAME}Module.cxx 22 | qSlicer${MODULE_NAME}Module.h 23 | qSlicer${MODULE_NAME}ModuleWidget.cxx 24 | qSlicer${MODULE_NAME}ModuleWidget.h 25 | ) 26 | 27 | set(MODULE_MOC_SRCS 28 | qSlicer${MODULE_NAME}Module.h 29 | qSlicer${MODULE_NAME}ModuleWidget.h 30 | ) 31 | 32 | set(MODULE_UI_SRCS 33 | Resources/UI/qSlicer${MODULE_NAME}ModuleWidget.ui 34 | ) 35 | 36 | set(MODULE_TARGET_LIBRARIES 37 | vtkSlicer${MODULE_NAME}ModuleLogic 38 | ) 39 | 40 | set(MODULE_RESOURCES 41 | Resources/qSlicer${MODULE_NAME}Module.qrc 42 | ) 43 | 44 | #----------------------------------------------------------------------------- 45 | slicerMacroBuildQtModule( 46 | NAME ${MODULE_NAME} 47 | TITLE ${MODULE_TITLE} 48 | EXPORT_DIRECTIVE ${MODULE_EXPORT_DIRECTIVE} 49 | INCLUDE_DIRECTORIES ${MODULE_INCLUDE_DIRECTORIES} 50 | SRCS ${MODULE_SRCS} 51 | MOC_SRCS ${MODULE_MOC_SRCS} 52 | UI_SRCS ${MODULE_UI_SRCS} 53 | TARGET_LIBRARIES ${MODULE_TARGET_LIBRARIES} 54 | RESOURCES ${MODULE_RESOURCES} 55 | WITH_GENERIC_TESTS 56 | ) 57 | 58 | #----------------------------------------------------------------------------- 59 | if(BUILD_TESTING) 60 | add_subdirectory(Testing) 61 | endif() 62 | 63 | #----------------------------------------------------------------------------- 64 | set(TEMPLATE_FILES 65 | MatlabModuleTemplate.m 66 | MatlabModuleTemplate.xml 67 | ) 68 | 69 | IF (WIN32) 70 | set(TEMPLATE_FILES ${TEMPLATE_FILES} MatlabModuleTemplate.bat) 71 | ELSE() 72 | set(TEMPLATE_FILES ${TEMPLATE_FILES} MatlabModuleTemplate) 73 | ENDIF() 74 | 75 | foreach(TEMPLATE_FILE ${TEMPLATE_FILES}) 76 | configure_file( 77 | ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Templates/${TEMPLATE_FILE} 78 | ${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_SHARE_DIR}/${MODULE_NAME}/${TEMPLATE_FILE} 79 | COPYONLY) 80 | install( 81 | FILES ${CMAKE_BINARY_DIR}/${Slicer_QTLOADABLEMODULES_SHARE_DIR}/${MODULE_NAME}/${TEMPLATE_FILE} 82 | DESTINATION ${Slicer_INSTALL_QTLOADABLEMODULES_SHARE_DIR}/${MODULE_NAME} COMPONENT Runtime) 83 | endforeach() 84 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Logic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(vtkSlicer${MODULE_NAME}ModuleLogic) 2 | 3 | set(KIT ${PROJECT_NAME}) 4 | 5 | set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_LOGIC_EXPORT") 6 | 7 | set(${KIT}_INCLUDE_DIRECTORIES 8 | ) 9 | 10 | set(${KIT}_SRCS 11 | vtkSlicer${MODULE_NAME}Logic.cxx 12 | vtkSlicer${MODULE_NAME}Logic.h 13 | ) 14 | 15 | set(${KIT}_TARGET_LIBRARIES 16 | ${ITK_LIBRARIES} 17 | ) 18 | 19 | #----------------------------------------------------------------------------- 20 | SlicerMacroBuildModuleLogic( 21 | NAME ${KIT} 22 | EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE} 23 | INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES} 24 | SRCS ${${KIT}_SRCS} 25 | TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES} 26 | ) 27 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Logic/vtkSlicerMatlabModuleGeneratorLogic.cxx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: 3D Slicer 4 | 5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | // MatlabModuleGenerator Logic includes 19 | #include "vtkSlicerMatlabModuleGeneratorLogic.h" 20 | 21 | // MRML includes 22 | #include "vtkMRMLScene.h" 23 | 24 | // VTK includes 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | // STD includes 31 | #include 32 | #include // for std::remove 33 | 34 | // Slicer includes 35 | #include "vtkSlicerConfigure.h" // For Slicer_CLIMODULES_SUBDIR 36 | 37 | static const std::string TEMPLATE_NAME="MatlabModuleTemplate"; 38 | /* Define case insensitive string compare for all supported platforms. */ 39 | #if defined( _WIN32 ) && !defined(__CYGWIN__) 40 | static const std::string MODULE_PROXY_TEMPLATE_EXTENSION=".bat"; 41 | static const std::string MATLAB_COMMANDER_EXECUTABLE_NAME="MatlabCommander.exe"; 42 | #else 43 | static const std::string MODULE_PROXY_TEMPLATE_EXTENSION=""; 44 | static const std::string MATLAB_COMMANDER_EXECUTABLE_NAME="MatlabCommander"; 45 | #include 46 | #endif 47 | static const std::string MODULE_SCRIPT_TEMPLATE_EXTENSION=".m"; 48 | static const std::string MODULE_DEFINITION_TEMPLATE_EXTENSION=".xml"; 49 | 50 | 51 | //---------------------------------------------------------------------------- 52 | vtkStandardNewMacro(vtkSlicerMatlabModuleGeneratorLogic); 53 | 54 | //---------------------------------------------------------------------------- 55 | vtkSlicerMatlabModuleGeneratorLogic::vtkSlicerMatlabModuleGeneratorLogic() 56 | { 57 | } 58 | 59 | //---------------------------------------------------------------------------- 60 | vtkSlicerMatlabModuleGeneratorLogic::~vtkSlicerMatlabModuleGeneratorLogic() 61 | { 62 | } 63 | 64 | //---------------------------------------------------------------------------- 65 | void vtkSlicerMatlabModuleGeneratorLogic::PrintSelf(ostream& os, vtkIndent indent) 66 | { 67 | this->Superclass::PrintSelf(os, indent); 68 | } 69 | 70 | //--------------------------------------------------------------------------- 71 | void vtkSlicerMatlabModuleGeneratorLogic::SetMRMLSceneInternal(vtkMRMLScene * newScene) 72 | { 73 | vtkNew events; 74 | events->InsertNextValue(vtkMRMLScene::NodeAddedEvent); 75 | events->InsertNextValue(vtkMRMLScene::NodeRemovedEvent); 76 | events->InsertNextValue(vtkMRMLScene::EndBatchProcessEvent); 77 | this->SetAndObserveMRMLSceneEventsInternal(newScene, events.GetPointer()); 78 | } 79 | 80 | //----------------------------------------------------------------------------- 81 | void vtkSlicerMatlabModuleGeneratorLogic::RegisterNodes() 82 | { 83 | assert(this->GetMRMLScene() != 0); 84 | } 85 | 86 | //--------------------------------------------------------------------------- 87 | void vtkSlicerMatlabModuleGeneratorLogic::UpdateFromMRMLScene() 88 | { 89 | assert(this->GetMRMLScene() != 0); 90 | } 91 | 92 | //--------------------------------------------------------------------------- 93 | void vtkSlicerMatlabModuleGeneratorLogic 94 | ::OnMRMLSceneNodeAdded(vtkMRMLNode* vtkNotUsed(node)) 95 | { 96 | } 97 | 98 | //--------------------------------------------------------------------------- 99 | void vtkSlicerMatlabModuleGeneratorLogic 100 | ::OnMRMLSceneNodeRemoved(vtkMRMLNode* vtkNotUsed(node)) 101 | { 102 | } 103 | 104 | //--------------------------------------------------------------------------- 105 | const char* vtkSlicerMatlabModuleGeneratorLogic 106 | ::GetMatlabModuleDirectory() 107 | { 108 | // Find out where the generated Matlab modules are 109 | std::string dir=this->GetModuleShareDirectory()+"/../../../../../MatlabModules"; 110 | this->MatlabModuleDirectory=vtksys::SystemTools::CollapseFullPath(dir.c_str()); 111 | return this->MatlabModuleDirectory.c_str(); 112 | } 113 | 114 | //--------------------------------------------------------------------------- 115 | const char* vtkSlicerMatlabModuleGeneratorLogic 116 | ::GetMatlabCommandServerDirectory() 117 | { 118 | // Find out where the commandserver Matlab files are 119 | std::string dir=this->GetModuleShareDirectory()+"/../../../../"+Slicer_CLIMODULES_BIN_DIR+"/commandserver"; 120 | this->MatlabCommandServerDirectory=vtksys::SystemTools::CollapseFullPath(dir.c_str()); 121 | return this->MatlabCommandServerDirectory.c_str(); 122 | } 123 | 124 | //--------------------------------------------------------------------------- 125 | const char* vtkSlicerMatlabModuleGeneratorLogic 126 | ::GetMatlabCommanderPath() 127 | { 128 | // Find out where the MatlabCommander CLI is 129 | // Retrieve the bin directory from the known path of the share directory 130 | std::string climodulesDir=this->GetModuleShareDirectory()+"/../../../../"+Slicer_CLIMODULES_BIN_DIR; 131 | climodulesDir=vtksys::SystemTools::CollapseFullPath(climodulesDir.c_str()); 132 | this->MatlabCommanderPath=climodulesDir+"/"+MATLAB_COMMANDER_EXECUTABLE_NAME; 133 | #if defined( _WIN32 ) && !defined(__CYGWIN__) 134 | if (!vtksys::SystemTools::FileExists(this->MatlabCommanderPath.c_str(),true)) 135 | { 136 | // The executable does not exist at the expected location, so probably it is a Windows build tree 137 | // where executables are in the Debug or Release subdirectory 138 | #ifdef _DEBUG 139 | this->MatlabCommanderPath=climodulesDir+"/Debug/"+MATLAB_COMMANDER_EXECUTABLE_NAME; 140 | #else 141 | this->MatlabCommanderPath=climodulesDir+"/Release/"+MATLAB_COMMANDER_EXECUTABLE_NAME; 142 | #endif 143 | } 144 | #endif 145 | return this->MatlabCommanderPath.c_str(); 146 | } 147 | 148 | //--------------------------------------------------------------------------- 149 | const char* vtkSlicerMatlabModuleGeneratorLogic 150 | ::GenerateModule(const char* inputModuleName, vtkStdString& interfaceDefinitionFilename, vtkStdString& matlabFunctionFilename) 151 | { 152 | this->GenerateModuleResult.clear(); 153 | interfaceDefinitionFilename.clear(); 154 | matlabFunctionFilename.clear(); 155 | 156 | std::string fullModuleName=inputModuleName; // module name, including spaces 157 | std::string moduleNameNoSpaces=inputModuleName; // module name without spaces 158 | moduleNameNoSpaces.erase(std::remove(moduleNameNoSpaces.begin(), moduleNameNoSpaces.end(), ' '), moduleNameNoSpaces.end()); 159 | 160 | vtkStdString result; 161 | bool success=true; 162 | 163 | std::string targetDir=GetMatlabModuleDirectory(); 164 | 165 | if (! vtksys::SystemTools::MakeDirectory(targetDir.c_str())) 166 | { 167 | this->GenerateModuleResult+="ERROR: Unable to create Matlab module directory '"+targetDir+"'\n"; 168 | success=false; 169 | } 170 | 171 | // Matlab .m file 172 | 173 | matlabFunctionFilename = targetDir+"/"+moduleNameNoSpaces+MODULE_SCRIPT_TEMPLATE_EXTENSION; 174 | if (!CreateFileFromTemplate(this->GetModuleShareDirectory()+"/"+TEMPLATE_NAME+MODULE_SCRIPT_TEMPLATE_EXTENSION, 175 | matlabFunctionFilename, TEMPLATE_NAME, moduleNameNoSpaces, result)) 176 | { 177 | success=false; 178 | matlabFunctionFilename.clear(); 179 | } 180 | this->GenerateModuleResult+=result+"\n"; 181 | 182 | // Module description .xml file 183 | interfaceDefinitionFilename = targetDir+"/"+moduleNameNoSpaces+MODULE_DEFINITION_TEMPLATE_EXTENSION; 184 | if (!CreateFileFromTemplate(this->GetModuleShareDirectory()+"/"+TEMPLATE_NAME+MODULE_DEFINITION_TEMPLATE_EXTENSION, 185 | interfaceDefinitionFilename, TEMPLATE_NAME, fullModuleName, result)) 186 | { 187 | success=false; 188 | interfaceDefinitionFilename.clear(); 189 | } 190 | this->GenerateModuleResult+=result+"\n"; 191 | 192 | // Proxy .bat or .sh file 193 | std::string proxyTargetFilePath=targetDir+"/"+moduleNameNoSpaces+MODULE_PROXY_TEMPLATE_EXTENSION; 194 | if (!CreateFileFromTemplate(this->GetModuleShareDirectory()+"/"+TEMPLATE_NAME+MODULE_PROXY_TEMPLATE_EXTENSION, 195 | proxyTargetFilePath, TEMPLATE_NAME, moduleNameNoSpaces, result)) 196 | { 197 | success=false; 198 | } 199 | else 200 | { 201 | #if defined( _WIN32 ) && !defined(__CYGWIN__) 202 | // no need to change file attributes to make the proxy executable 203 | #else 204 | mode_t mode=S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH; 205 | vtksys::SystemTools::GetPermissions(proxyTargetFilePath.c_str(), mode); 206 | mode |= S_IXUSR|S_IXGRP|S_IXOTH; // set executable permission for user, group, and others 207 | if (!vtksys::SystemTools::SetPermissions(proxyTargetFilePath.c_str(),mode)) 208 | { 209 | result+=" Failed to set the file permission to allow execution - Slicer may not discover this module until the file permission is set allow execution."; 210 | } 211 | #endif 212 | } 213 | this->GenerateModuleResult+=result+"\n"; 214 | 215 | if (success) 216 | { 217 | this->GenerateModuleResult+="\nModule generation was successful.\nEdit the module descriptor .xml and the .m file then restart Slicer."; 218 | } 219 | else 220 | { 221 | this->GenerateModuleResult+="\nModule generation failed"; 222 | } 223 | return this->GenerateModuleResult.c_str(); 224 | } 225 | 226 | //--------------------------------------------------------------------------- 227 | bool vtkSlicerMatlabModuleGeneratorLogic 228 | ::CreateFileFromTemplate(const vtkStdString& templateFilename, const vtkStdString& targetFilename, const vtkStdString& originalString, const vtkStdString& modifiedString, vtkStdString &result) 229 | { 230 | result.clear(); 231 | 232 | if (vtksys::SystemTools::FileExists(targetFilename.c_str(),true)) 233 | { 234 | // Prevent accidental overwriting of existing valuable file with auto-generated file 235 | result="Cannot create file, it already exists:\n "+targetFilename; 236 | return false; 237 | } 238 | 239 | // Open input file 240 | fstream templateFile; 241 | templateFile.open(templateFilename.c_str(), fstream::in); 242 | if (!templateFile.is_open()) 243 | { 244 | result="Template file not found:\n "+templateFilename; 245 | return false; 246 | } 247 | 248 | // Open output file 249 | std::ofstream targetFile; 250 | targetFile.open(targetFilename.c_str() ); 251 | if (!targetFile.is_open()) 252 | { 253 | result="Target file cannot be opened for writing:\n "+targetFilename; 254 | templateFile.close(); 255 | return false; 256 | } 257 | 258 | // Copy line-by-line while replacing the original string with the modified string 259 | for (std::string line; std::getline(templateFile, line); ) 260 | { 261 | if (line.length()>0 && originalString.length()) 262 | { 263 | // search and replace 264 | size_t idx = 0; 265 | for (;;) 266 | { 267 | idx = line.find( originalString, idx); 268 | if (idx == std::string::npos) break; 269 | line.replace( idx, originalString.length(), modifiedString); 270 | idx += modifiedString.length(); 271 | } 272 | } 273 | targetFile << line << std::endl; 274 | } 275 | 276 | // Close input and output files 277 | templateFile.close(); 278 | targetFile.close(); 279 | 280 | result="File created:\n "+targetFilename; 281 | return true; 282 | } 283 | 284 | //--------------------------------------------------------------------------- 285 | void vtkSlicerMatlabModuleGeneratorLogic 286 | ::SetMatlabExecutablePath(const char* matlabExePath) 287 | { 288 | this->MatlabExecutablePath = (matlabExePath==NULL)?"":matlabExePath; 289 | 290 | std::string matlabEnvVar=std::string("SLICER_MATLAB_EXECUTABLE_PATH=")+this->MatlabExecutablePath; 291 | vtksys::SystemTools::PutEnv(matlabEnvVar.c_str()); 292 | } 293 | 294 | 295 | //--------------------------------------------------------------------------- 296 | const char* vtkSlicerMatlabModuleGeneratorLogic 297 | ::GetMatlabExecutablePath() 298 | { 299 | return this->MatlabExecutablePath.c_str(); 300 | } 301 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Logic/vtkSlicerMatlabModuleGeneratorLogic.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: 3D Slicer 4 | 5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | // .NAME vtkSlicerMatlabModuleGeneratorLogic - slicer logic class for volumes manipulation 19 | // .SECTION Description 20 | // This class manages the logic associated with reading, saving, 21 | // and changing propertied of the volumes 22 | 23 | 24 | #ifndef __vtkSlicerMatlabModuleGeneratorLogic_h 25 | #define __vtkSlicerMatlabModuleGeneratorLogic_h 26 | 27 | // Slicer includes 28 | #include "vtkSlicerModuleLogic.h" 29 | 30 | // MRML includes 31 | 32 | // STD includes 33 | #include 34 | 35 | #include "vtkSlicerMatlabModuleGeneratorModuleLogicExport.h" 36 | 37 | 38 | /// \ingroup Slicer_QtModules_ExtensionTemplate 39 | class VTK_SLICER_MATLABMODULEGENERATOR_MODULE_LOGIC_EXPORT vtkSlicerMatlabModuleGeneratorLogic : 40 | public vtkSlicerModuleLogic 41 | { 42 | public: 43 | 44 | static vtkSlicerMatlabModuleGeneratorLogic *New(); 45 | vtkTypeMacro(vtkSlicerMatlabModuleGeneratorLogic, vtkSlicerModuleLogic); 46 | void PrintSelf(ostream& os, vtkIndent indent); 47 | 48 | /// Get the directory where the generated Matlab script (and corresponding proxy shell script and XML description) files are stored 49 | /// Typically: Extensions-NNN/MatlabModules 50 | const char* GetMatlabModuleDirectory(); 51 | 52 | /// Get the directory where the cli_commandserver.m and other cli_*.m helper files are stored 53 | /// Typically: Extensions-NNN/MatlabBridge/lib/Slicer-4.2/cli-modules/commandserver 54 | const char* GetMatlabCommandServerDirectory(); 55 | 56 | /// Get the path to the MatlabCommander CLI executable 57 | /// Typically: Extensions-NNN/MatlabBridge/lib/Slicer-4.2/cli-modules/MatlabCommander.exe) 58 | const char* GetMatlabCommanderPath(); 59 | 60 | /// Get path to Matlab.exe 61 | const char* GetMatlabExecutablePath(); 62 | 63 | /// Set path to Matlab.exe 64 | void SetMatlabExecutablePath(const char* matlabExePath); 65 | 66 | /// Generates and installs a Matlab module and returns the status 67 | const char* GenerateModule(const char* moduleName, vtkStdString& interfaceDefinitionFilename, vtkStdString& matlabFunctionFilename); 68 | 69 | protected: 70 | vtkSlicerMatlabModuleGeneratorLogic(); 71 | virtual ~vtkSlicerMatlabModuleGeneratorLogic(); 72 | 73 | virtual void SetMRMLSceneInternal(vtkMRMLScene* newScene); 74 | /// Register MRML Node classes to Scene. Gets called automatically when the MRMLScene is attached to this logic class. 75 | virtual void RegisterNodes(); 76 | virtual void UpdateFromMRMLScene(); 77 | virtual void OnMRMLSceneNodeAdded(vtkMRMLNode* node); 78 | virtual void OnMRMLSceneNodeRemoved(vtkMRMLNode* node); 79 | 80 | /// return true if successful 81 | bool CreateFileFromTemplate(const vtkStdString& templateFilename, const vtkStdString& targetFilename, const vtkStdString& originalString, const vtkStdString& modifiedString, vtkStdString &result); 82 | 83 | private: 84 | 85 | std::string MatlabModuleDirectory; 86 | std::string MatlabCommandServerDirectory; 87 | std::string MatlabCommanderPath; 88 | std::string MatlabExecutablePath; 89 | std::string GenerateModuleResult; 90 | 91 | vtkSlicerMatlabModuleGeneratorLogic(const vtkSlicerMatlabModuleGeneratorLogic&); // Not implemented 92 | void operator=(const vtkSlicerMatlabModuleGeneratorLogic&); // Not implemented 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Resources/Icons/MatlabModuleGenerator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PerkLab/SlicerMatlabBridge/e9b297dbb6248be91a44013a85e21ff0fd8d13fd/MatlabModuleGenerator/Resources/Icons/MatlabModuleGenerator.png -------------------------------------------------------------------------------- /MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # If this proxy is called with the --xml parameter then just return the module decriptor XML file, 3 | # otherwise run the associated Matlab script. 4 | # MatlabBridge proxy version: 1.1 5 | 6 | MODULE_NAME="MatlabModuleTemplate" 7 | 8 | if [ $1 = "--xml" ]; then 9 | cat $MODULE_NAME.xml 10 | exit 0 11 | fi 12 | 13 | # Make this proxy file location to be the working directory (this is where the .m file is located; in Matlab the current directory will be changed to this directory) 14 | cd "$( dirname "$0" )" 15 | 16 | # Forward parameters to the Matlab CLI 17 | if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then 18 | # Linux: use Slicer launcher 19 | "$SLICER_HOME/Slicer" --launcher-no-splash --launch "$SLICER_MATLAB_COMMANDER_PATH" --call-matlab-function $MODULE_NAME $* 20 | exit $? 21 | else 22 | # Mac OS X: there is no launcher, so run the commander directly 23 | "$SLICER_MATLAB_COMMANDER_PATH" --call-matlab-function $MODULE_NAME $* 24 | exit $? 25 | fi 26 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate.bat: -------------------------------------------------------------------------------- 1 | @set MODULE_NAME=MatlabModuleTemplate 2 | @rem MatlabBridge proxy version: 1.0 3 | 4 | @echo off 5 | if not "%~1"=="--xml" goto :launch_module 6 | 7 | :print_xml 8 | rem Print CLI descriptor XML 9 | type %MODULE_NAME%.xml 10 | rem Return with success 11 | exit /b 0 12 | 13 | :launch_module 14 | rem Print error messages if any of the required environment variables are not set 15 | if not defined SLICER_MATLAB_COMMANDER_PATH echo ERROR: SLICER_MATLAB_COMMANDER_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 16 | if not defined SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH echo ERROR: SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension. 17 | if not defined SLICER_MATLAB_EXECUTABLE_PATH echo ERROR: SLICER_MATLAB_EXECUTABLE_PATH environment variable is not defined. Make sure you installed the MatlabBridge extension and set the path to the Matlab executable. 18 | rem Make the .bat file location to be the working directory (this is where the .m file is located; in Matlab the current directory will be changed to this directory) 19 | pushd "%~dp0" 20 | rem Forward parameters to the Matlab CLI 21 | "%SLICER_HOME%/Slicer.exe" --launcher-no-splash --launch "%SLICER_MATLAB_COMMANDER_PATH%" --call-matlab-function %MODULE_NAME% %* 22 | if errorlevel 1 exit /b 1 23 | rem Return with success 24 | exit /b 0 25 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate.m: -------------------------------------------------------------------------------- 1 | function outputParams=MatlabModuleTemplate(inputParams) 2 | % Example function that returns the minimum and maximum voxel value in a volume 3 | % and performs thresholding operation on the volume. 4 | % 5 | % Parameters: 6 | % inputParams.threshold: threshold value 7 | % inputParams.inputvolume: input image filename 8 | % inputParams.outputvolume: output image filename, result of the processing 9 | % outputParams.min: image minimum value 10 | % outputParams.max: image maximum value 11 | % 12 | 13 | img=cli_imageread(inputParams.inputvolume); 14 | 15 | outputParams.min=min(min(min(img.pixelData))); 16 | outputParams.max=max(max(max(img.pixelData))); 17 | 18 | img.pixelData=(double(img.pixelData)>inputParams.threshold)*100; 19 | 20 | cli_imagewrite(inputParams.outputvolume, img); 21 | 22 | %% Help for reading/writing parameters 23 | % 24 | % Reading input parameters 25 | % 26 | % integer, integer-vector, float, float-vector, double, double-vector, string, string-enumeration, file: 27 | % value=inputParams.name; 28 | % string-vector: 29 | % value=cli_stringvectordecode(inputParams.name); 30 | % point-vector: 31 | % value=cli_pointvectordecode(inputParams.name); 32 | % boolean: 33 | % value=isfield(inputParams,'name'); 34 | % image: 35 | % value=cli_imageread(inputParams.name); 36 | % transform: 37 | % value=cli_lineartransformread(inputParams.name); 38 | % or (for generic transforms): 39 | % value=cli_transformread(inputParams.name); 40 | % pointfile: 41 | % points=cli_pointfileread(inputParams.name); 42 | % [pointDim pointCount]=size(points.position); 43 | % Difference between pointfile and point is that pointfile can transfer point properties, such as visibility and 44 | % selected state and works faster and more reliably if there are many points. 45 | % point: 46 | % values_LPS=cli_pointvectordecode(inputParams.name); 47 | % [pointDim pointCount]=size(values_LPS); 48 | % region: 49 | % values=cli_pointvectordecode(inputParams.name); 50 | % [regionDim regionCount]=size(values_LPS); 51 | % center_LPS=[values(1:3,regionIndex); 1]; 52 | % radius_LPS=abs([values(4:6,regionIndex); 1]); 53 | % measurement: 54 | % value=cli_measurementread(inputParams.name); 55 | % geometry: 56 | % value=cli_geometryread(inputParams.name); 57 | % Important: in the CLI definition file the following attribute shall be added to the geometry element: fileExtensions=".ply" 58 | % See https://github.com/PerkLab/SlicerMatlabBridge/tree/master/Examples/MeshScale for a complete example. 59 | % 60 | % Notes: 61 | % - Input and file (image, transform, measurement, geometry) parameter names are defined by the element in the XML file 62 | % - Output parameter names are defined by the element in the XML file 63 | % - For retrieving index-th unnamed parameter use inputParams.unnamed{index+1} instead of inputParams.name 64 | % 65 | % 66 | % Writing output parameters 67 | % 68 | % integer, integer-vector, float, float-vector, double, double-vector, string, string-enumeration, file: 69 | % outputParams.name=value; 70 | % image: 71 | % cli_imagewrite(inputParams.name, value); 72 | % transform: 73 | % cli_lineartransformwrite(inputParams.name, value); 74 | % or (for generic transforms): 75 | % cli_transformwrite(inputParams.name, value); 76 | % measurement: 77 | % cli_measurementwrite(inputParams.name, value); 78 | % pointfile: 79 | % cli_pointfilewrite(inputParams.name, points); 80 | % geometry: 81 | % cli_geometrywrite(inputParams.name, value); 82 | % Important: in the CLI definition file the following attribute shall be added to the geometry element: fileExtensions=".stl" 83 | % See https://github.com/PerkLab/SlicerMatlabBridge/tree/master/Examples/MeshScale for a complete example. 84 | % 85 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Resources/Templates/MatlabModuleTemplate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Matlab 4 | MatlabModuleTemplate 5 | 6 | 0.0.0.1 7 | http://www.slicer.org/slicerWiki/index.php/Documentation/Nightly/Extensions/MatlabBridge 8 | 9 | Andras Lasso (PerkLab) 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | threshold 18 | 50 19 | 20 | -2000 21 | 5000 22 | 5 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | inputvolume 33 | input 34 | 35 | 36 | 37 | 38 | outputvolume 39 | output 40 | 41 | 42 | 43 | 44 | Matlab command output 45 | 46 | 47 | 48 | min 49 | output 50 | 51 | 52 | 53 | 54 | 55 | max 56 | output 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Resources/UI/qSlicerMatlabModuleGeneratorModuleWidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | qSlicerMatlabModuleGeneratorModuleWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 525 10 | 503 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Matlab configuration 21 | 22 | 23 | 24 | 25 | 26 | Matlab executable 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Exit Matlab on Application Exit 37 | 38 | 39 | 40 | 41 | 42 | 43 | Matlab script directory 44 | 45 | 46 | lineEdit_MatlabScriptDirectory 47 | 48 | 49 | 50 | 51 | 52 | 53 | true 54 | 55 | 56 | 57 | true 58 | 59 | 60 | 61 | false 62 | 63 | 64 | true 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Matlab module generation 75 | 76 | 77 | QFrame::NoFrame 78 | 79 | 80 | 81 | 82 | 83 | Module name 84 | 85 | 86 | lineEdit_GeneratorModuleName 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | Generate module 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 0 107 | 108 | 109 | 110 | 111 | false 112 | 113 | 114 | Edit interface definition 115 | 116 | 117 | 118 | 119 | 120 | 121 | false 122 | 123 | 124 | Edit Matlab function 125 | 126 | 127 | 128 | 129 | 130 | 131 | Restart application 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | Qt::Vertical 144 | 145 | 146 | 147 | 0 148 | 0 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | qSlicerWidget 158 | QWidget 159 |
qSlicerWidget.h
160 | 1 161 |
162 | 163 | ctkCollapsibleButton 164 | QWidget 165 |
ctkCollapsibleButton.h
166 | 1 167 |
168 | 169 | ctkPathLineEdit 170 | QWidget 171 |
ctkPathLineEdit.h
172 |
173 |
174 | 175 | 176 |
177 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Resources/qSlicerMatlabModuleGeneratorModule.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Icons/MatlabModuleGenerator.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Testing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Cxx) 2 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/Testing/Cxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(KIT qSlicer${MODULE_NAME}Module) 2 | 3 | #----------------------------------------------------------------------------- 4 | set(KIT_TEST_SRCS 5 | #qSlicer${MODULE_NAME}ModuleTest.cxx 6 | ) 7 | 8 | #----------------------------------------------------------------------------- 9 | slicerMacroConfigureModuleCxxTestDriver( 10 | NAME ${KIT} 11 | SOURCES ${KIT_TEST_SRCS} 12 | WITH_VTK_DEBUG_LEAKS_CHECK 13 | ) 14 | 15 | #----------------------------------------------------------------------------- 16 | #simple_test(qSlicer${MODULE_NAME}ModuleTest) 17 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModule.cxx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: 3D Slicer 4 | 5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | // Qt includes 19 | #include 20 | #include 21 | #include 22 | 23 | // VTK includes 24 | #include "vtksys/SystemTools.hxx" 25 | 26 | // SlicerQt includes 27 | #include 28 | 29 | // MatlabModuleGenerator Logic includes 30 | #include 31 | 32 | // MatlabModuleGenerator includes 33 | #include "qSlicerMatlabModuleGeneratorModule.h" 34 | #include "qSlicerMatlabModuleGeneratorModuleWidget.h" 35 | 36 | const std::string MATLAB_COMMAND_SERVER_SCRIPT_NAME="cli_commandserver.m"; 37 | 38 | #if defined( _WIN32 ) && !defined(__CYGWIN__) 39 | // Windows 40 | static const std::string DEFAULT_MATLAB_PROCESS_PATH="matlab.exe"; 41 | #elif defined(__APPLE__) 42 | // Mac OS X 43 | static const std::string DEFAULT_MATLAB_PROCESS_PATH="/Applications/MATLAB_XXXXX.app/bin/matlab"; 44 | #else 45 | // Linux 46 | static const std::string DEFAULT_MATLAB_PROCESS_PATH="/usr/local/bin/matlab"; 47 | #endif 48 | 49 | //----------------------------------------------------------------------------- 50 | 51 | #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) 52 | #include 53 | Q_EXPORT_PLUGIN2(qSlicerMatlabModuleGeneratorModule, qSlicerMatlabModuleGeneratorModule); 54 | #endif 55 | 56 | //----------------------------------------------------------------------------- 57 | /// \ingroup Slicer_QtModules_ExtensionTemplate 58 | class qSlicerMatlabModuleGeneratorModulePrivate 59 | { 60 | public: 61 | qSlicerMatlabModuleGeneratorModulePrivate(); 62 | }; 63 | 64 | //----------------------------------------------------------------------------- 65 | // qSlicerMatlabModuleGeneratorModulePrivate methods 66 | 67 | //----------------------------------------------------------------------------- 68 | qSlicerMatlabModuleGeneratorModulePrivate 69 | ::qSlicerMatlabModuleGeneratorModulePrivate() 70 | { 71 | } 72 | 73 | //----------------------------------------------------------------------------- 74 | // qSlicerMatlabModuleGeneratorModule methods 75 | 76 | //----------------------------------------------------------------------------- 77 | qSlicerMatlabModuleGeneratorModule 78 | ::qSlicerMatlabModuleGeneratorModule(QObject* _parent) 79 | : Superclass(_parent) 80 | , d_ptr(new qSlicerMatlabModuleGeneratorModulePrivate) 81 | { 82 | } 83 | 84 | //----------------------------------------------------------------------------- 85 | qSlicerMatlabModuleGeneratorModule::~qSlicerMatlabModuleGeneratorModule() 86 | { 87 | } 88 | 89 | //----------------------------------------------------------------------------- 90 | QString qSlicerMatlabModuleGeneratorModule::helpText()const 91 | { 92 | return "The MatlabModuleGenerator module is used for generating a skeleton Matlab module that the user can further customize to implement the intended functionality. The module also allows the user to specify the location of the Matlab executable."; 93 | } 94 | 95 | //----------------------------------------------------------------------------- 96 | QString qSlicerMatlabModuleGeneratorModule::acknowledgementText()const 97 | { 98 | return "This work is part of the SparKit project, funded by An Applied Cancer Research Unit of Cancer Care Ontario with funds provided by the Ministry of Health and Long-Term Care and the Ontario Consortium for Adaptive Interventions in Radiation Oncology (OCAIRO) to provide free, open-source toolset for radiotherapy and related image-guided interventions."; 99 | } 100 | 101 | //----------------------------------------------------------------------------- 102 | QStringList qSlicerMatlabModuleGeneratorModule::contributors()const 103 | { 104 | QStringList moduleContributors; 105 | moduleContributors << QString("Andras Lasso (PerkLab, Queen's University)"); 106 | moduleContributors << QString("Jean-Christophe Fillion-Robin (Kitware)"); 107 | moduleContributors << QString("Kevin Wang (Radiation Medicine Program, Princess Margaret Hospital, University Health Network Toronto)"); 108 | return moduleContributors; 109 | } 110 | 111 | //----------------------------------------------------------------------------- 112 | QIcon qSlicerMatlabModuleGeneratorModule::icon()const 113 | { 114 | return QIcon(":/Icons/MatlabModuleGenerator.png"); 115 | } 116 | 117 | //----------------------------------------------------------------------------- 118 | QStringList qSlicerMatlabModuleGeneratorModule::categories() const 119 | { 120 | return QStringList() << "Developer Tools.Matlab"; 121 | } 122 | 123 | //----------------------------------------------------------------------------- 124 | QStringList qSlicerMatlabModuleGeneratorModule::dependencies() const 125 | { 126 | return QStringList(); 127 | } 128 | 129 | QString qSlicerMatlabModuleGeneratorModule::getMatlabExecutablePath() const 130 | { 131 | // 1. Slicer.ini application settings 132 | // If the Matlab path is defined in the Slicer settings then use that 133 | QSettings settings; 134 | QString matlabExecutablePath = settings.value("Matlab/MatlabExecutablePath","").toString(); 135 | if (!matlabExecutablePath.isEmpty()) 136 | { 137 | QFileInfo checkFile(matlabExecutablePath); 138 | if (checkFile.exists() && checkFile.isFile()) 139 | { 140 | qDebug("Matlab executable found in Slicer settings: %s", qPrintable(matlabExecutablePath)); 141 | return matlabExecutablePath; 142 | } 143 | qDebug("Matlab executable is defined in Slicer settings (%s), but the file is not found.", qPrintable(matlabExecutablePath)); 144 | } 145 | 146 | // 2. SLICER_MATLAB_EXECUTABLE_PATH environment variable 147 | // If the Matlab path is defined in an environment variable then use that 148 | const char* matlabExePathEnvValue=getenv("SLICER_MATLAB_EXECUTABLE_PATH"); 149 | if (matlabExePathEnvValue && strlen(matlabExePathEnvValue)>0) 150 | { 151 | qDebug("Matlab executable found in environment at %s", qPrintable(matlabExePathEnvValue)); 152 | return QString(matlabExePathEnvValue); 153 | } 154 | 155 | // 3. App Paths 156 | #if defined( _WIN32 ) && !defined(__CYGWIN__) 157 | QSettings matlabExePathRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\matlab.exe",QSettings::NativeFormat); 158 | QString matlabExePathWin=matlabExePathRegistryKey.value(".", NULL).toString(); // "." reads the (Default) value 159 | if (!matlabExePathWin.isEmpty()) 160 | { 161 | qDebug("Matlab executable found on system at %s", qPrintable(matlabExePathWin)); 162 | return matlabExePathWin; 163 | } 164 | #elif defined(__APPLE__) 165 | QString appPath("/Applications"); 166 | QDir appDir(appPath); 167 | QStringList nameFilter("MATLAB*.app"); 168 | QStringList matlabAppPaths = appDir.entryList(nameFilter); 169 | if(!matlabAppPaths.isEmpty()) 170 | { 171 | QString matlabAppPath = matlabAppPaths.at(0); //take the first one found 172 | QString matlabExePathMac = appPath + "/" + matlabAppPath + "/bin/matlab"; 173 | QFileInfo matlabExeFileMac(matlabExePathMac); 174 | if (matlabExeFileMac.exists() && matlabExeFileMac.isFile()) 175 | { 176 | qDebug() << "Matlab executable found on system at : " << matlabExePathMac; 177 | return matlabExePathMac; 178 | } 179 | } 180 | #else 181 | std::vector hints; 182 | std::string matlabExePathUnix = vtksys::SystemTools::FindProgram("matlab", hints, false); // false: search system path 183 | if (!matlabExePathUnix.empty()) 184 | { 185 | qDebug("Matlab executable found on system at %s", qPrintable(matlabExePathUnix.c_str())); 186 | return QString(matlabExePathUnix.c_str()); 187 | } 188 | #endif 189 | 190 | // 4. Hardcoded default string 191 | qDebug("MatlabExecutablePath not found, default path used: %s", qPrintable(DEFAULT_MATLAB_PROCESS_PATH.c_str())); 192 | return QString(DEFAULT_MATLAB_PROCESS_PATH.c_str()); 193 | } 194 | 195 | //----------------------------------------------------------------------------- 196 | void qSlicerMatlabModuleGeneratorModule::setup() 197 | { 198 | this->Superclass::setup(); 199 | 200 | qSlicerApplication * app = qSlicerApplication::application(); 201 | if (!app) 202 | { 203 | qCritical() << "Fail to initalize qSlicerMatlabModuleGeneratorModule module: application is invalid"; 204 | return; 205 | } 206 | vtkSlicerMatlabModuleGeneratorLogic* moduleGeneratorLogic= vtkSlicerMatlabModuleGeneratorLogic::SafeDownCast(this->logic()); 207 | if (moduleGeneratorLogic == 0) 208 | { 209 | qCritical() << "Fail to initalize qSlicerMatlabModuleGeneratorModule module: logic is invalid"; 210 | return; 211 | } 212 | 213 | //Uncomment this to allow some time to attach the debugger 214 | //vtksys::SystemTools::Delay(10000); 215 | 216 | // Get Matlab executable path and store in the logic 217 | QString matlabExecutablePath = getMatlabExecutablePath(); 218 | moduleGeneratorLogic->SetMatlabExecutablePath(matlabExecutablePath.toLatin1()); 219 | 220 | // Append Matlab module path to the additional paths 221 | QStringList additionalPaths = app->revisionUserSettings()->value("Modules/AdditionalPaths").toStringList(); 222 | QString pathToAppend=moduleGeneratorLogic->GetMatlabModuleDirectory(); 223 | QDir dirToCheck(pathToAppend); 224 | bool isPathToAppendAlreadyInAdditionalPaths=false; 225 | foreach(const QString& path, additionalPaths) 226 | { 227 | if (dirToCheck == QDir(path)) 228 | { 229 | isPathToAppendAlreadyInAdditionalPaths=true; 230 | break; 231 | } 232 | } 233 | if (!isPathToAppendAlreadyInAdditionalPaths) 234 | { 235 | additionalPaths << pathToAppend; 236 | app->revisionUserSettings()->setValue("Modules/AdditionalPaths",additionalPaths); 237 | } 238 | 239 | // Set Matlab executable and commandserver script paths in environment variables 240 | // for MatlabCommander CLI module 241 | // Ideally, the app->setEnvironmentVariable method should be used, but somehow app->setEnvironmentVariable 242 | // causes failure in the sample data volume (and probably in other modules, too, as Python cannot find the "os" symbol) 243 | std::string matlabEnvVar=std::string("SLICER_MATLAB_EXECUTABLE_PATH=")+std::string(matlabExecutablePath.toLatin1()); 244 | vtksys::SystemTools::PutEnv(matlabEnvVar.c_str()); 245 | std::string scriptEnvVar=std::string("SLICER_MATLAB_COMMAND_SERVER_SCRIPT_PATH=")+moduleGeneratorLogic->GetMatlabCommandServerDirectory()+"/"+MATLAB_COMMAND_SERVER_SCRIPT_NAME; 246 | vtksys::SystemTools::PutEnv(scriptEnvVar.c_str()); 247 | std::string commanderEnvVar=std::string("SLICER_MATLAB_COMMANDER_PATH=")+moduleGeneratorLogic->GetMatlabCommanderPath(); 248 | vtksys::SystemTools::PutEnv(commanderEnvVar.c_str()); 249 | } 250 | 251 | //----------------------------------------------------------------------------- 252 | qSlicerAbstractModuleRepresentation * qSlicerMatlabModuleGeneratorModule 253 | ::createWidgetRepresentation() 254 | { 255 | return new qSlicerMatlabModuleGeneratorModuleWidget; 256 | } 257 | 258 | //----------------------------------------------------------------------------- 259 | vtkMRMLAbstractLogic* qSlicerMatlabModuleGeneratorModule::createLogic() 260 | { 261 | return vtkSlicerMatlabModuleGeneratorLogic::New(); 262 | } 263 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModule.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: 3D Slicer 4 | 5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef __qSlicerMatlabModuleGeneratorModule_h 19 | #define __qSlicerMatlabModuleGeneratorModule_h 20 | 21 | // SlicerQt includes 22 | #include "qSlicerLoadableModule.h" 23 | 24 | #include "qSlicerMatlabModuleGeneratorModuleExport.h" 25 | 26 | class qSlicerMatlabModuleGeneratorModulePrivate; 27 | 28 | /// \ingroup Slicer_QtModules_ExtensionTemplate 29 | class Q_SLICER_QTMODULES_MATLABMODULEGENERATOR_EXPORT 30 | qSlicerMatlabModuleGeneratorModule 31 | : public qSlicerLoadableModule 32 | { 33 | Q_OBJECT 34 | #ifdef Slicer_HAVE_QT5 35 | Q_PLUGIN_METADATA(IID "org.slicer.modules.loadable.qSlicerLoadableModule/1.0"); 36 | #endif 37 | Q_INTERFACES(qSlicerLoadableModule); 38 | 39 | public: 40 | 41 | typedef qSlicerLoadableModule Superclass; 42 | explicit qSlicerMatlabModuleGeneratorModule(QObject *parent=0); 43 | virtual ~qSlicerMatlabModuleGeneratorModule(); 44 | 45 | qSlicerGetTitleMacro(QTMODULE_TITLE); 46 | 47 | virtual QString helpText()const; 48 | virtual QString acknowledgementText()const; 49 | virtual QStringList contributors()const; 50 | 51 | virtual QIcon icon()const; 52 | 53 | virtual QStringList categories()const; 54 | virtual QStringList dependencies() const; 55 | 56 | protected: 57 | 58 | /// Get location of the Matlab executable. 59 | /// Search order: 60 | /// \li Slicer.ini application settings 61 | /// \li SLICER_MATLAB_EXECUTABLE_PATH environment variable 62 | /// \li Path or App Paths 63 | /// \li Hardcoded default location 64 | QString getMatlabExecutablePath() const; 65 | 66 | /// Initialize the module. Register the volumes reader/writer 67 | virtual void setup(); 68 | 69 | /// Create and return the widget representation associated to this module 70 | virtual qSlicerAbstractModuleRepresentation * createWidgetRepresentation(); 71 | 72 | /// Create and return the logic associated to this module 73 | virtual vtkMRMLAbstractLogic* createLogic(); 74 | 75 | protected: 76 | QScopedPointer d_ptr; 77 | 78 | private: 79 | Q_DECLARE_PRIVATE(qSlicerMatlabModuleGeneratorModule); 80 | Q_DISABLE_COPY(qSlicerMatlabModuleGeneratorModule); 81 | 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModuleWidget.cxx: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: 3D Slicer 4 | 5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | // Qt includes 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | // VTK includes 25 | #include 26 | 27 | // SlicerQt includes 28 | #include "qSlicerMatlabModuleGeneratorModuleWidget.h" 29 | #include "ui_qSlicerMatlabModuleGeneratorModuleWidget.h" 30 | #include "qSlicerApplication.h" 31 | #include "qSlicerModuleManager.h" 32 | #include "qSlicerAbstractCoreModule.h" 33 | #include 34 | 35 | // Module includes 36 | #include "vtkSlicerMatlabModuleGeneratorLogic.h" 37 | 38 | 39 | //----------------------------------------------------------------------------- 40 | /// \ingroup Slicer_QtModules_ExtensionTemplate 41 | class qSlicerMatlabModuleGeneratorModuleWidgetPrivate: public Ui_qSlicerMatlabModuleGeneratorModuleWidget 42 | { 43 | Q_DECLARE_PUBLIC(qSlicerMatlabModuleGeneratorModuleWidget); 44 | protected: 45 | qSlicerMatlabModuleGeneratorModuleWidget* const q_ptr; 46 | vtkStdString lastInterfaceDefinitionFilename; 47 | vtkStdString lastMatlabFunctionFilename; 48 | public: 49 | qSlicerMatlabModuleGeneratorModuleWidgetPrivate(qSlicerMatlabModuleGeneratorModuleWidget& object); 50 | vtkSlicerMatlabModuleGeneratorLogic* logic() const; 51 | }; 52 | 53 | //----------------------------------------------------------------------------- 54 | // qSlicerMatlabModuleGeneratorModuleWidgetPrivate methods 55 | 56 | //----------------------------------------------------------------------------- 57 | qSlicerMatlabModuleGeneratorModuleWidgetPrivate::qSlicerMatlabModuleGeneratorModuleWidgetPrivate(qSlicerMatlabModuleGeneratorModuleWidget& object) 58 | : q_ptr(&object) 59 | { 60 | } 61 | 62 | //----------------------------------------------------------------------------- 63 | vtkSlicerMatlabModuleGeneratorLogic* 64 | qSlicerMatlabModuleGeneratorModuleWidgetPrivate::logic() const 65 | { 66 | Q_Q(const qSlicerMatlabModuleGeneratorModuleWidget); 67 | return vtkSlicerMatlabModuleGeneratorLogic::SafeDownCast(q->logic()); 68 | } 69 | 70 | //----------------------------------------------------------------------------- 71 | // qSlicerMatlabModuleGeneratorModuleWidget methods 72 | 73 | //----------------------------------------------------------------------------- 74 | qSlicerMatlabModuleGeneratorModuleWidget::qSlicerMatlabModuleGeneratorModuleWidget(QWidget* _parent) 75 | : Superclass( _parent ) 76 | , d_ptr( new qSlicerMatlabModuleGeneratorModuleWidgetPrivate(*this) ) 77 | { 78 | } 79 | 80 | //----------------------------------------------------------------------------- 81 | qSlicerMatlabModuleGeneratorModuleWidget::~qSlicerMatlabModuleGeneratorModuleWidget() 82 | { 83 | } 84 | 85 | //----------------------------------------------------------------------------- 86 | void qSlicerMatlabModuleGeneratorModuleWidget::setup() 87 | { 88 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget); 89 | d->setupUi(this); 90 | this->Superclass::setup(); 91 | 92 | // Determine the value of Matlab/ExitMatlab in QSettings 93 | // and set checkbox_ExitMatlab accordingly 94 | QSettings settings; 95 | if (settings.contains("Matlab/ExitMatlabOnApplicationExit")) 96 | { 97 | bool exitMatlab = settings.value("Matlab/ExitMatlabOnApplicationExit").toBool(); 98 | d->checkBox_ExitMatlab->setChecked(exitMatlab); 99 | } 100 | else 101 | { 102 | d->checkBox_ExitMatlab->setChecked(true); 103 | settings.setValue("Matlab/ExitMatlabOnApplicationExit",true); 104 | } 105 | 106 | connect( QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(applicationAboutToQuit()) ); 107 | 108 | connect( d->lineEdit_MatlabExecutablePath, SIGNAL(currentPathChanged(QString)), this, SLOT(matlabExecutablePathChanged(QString)) ); 109 | connect( d->checkBox_ExitMatlab, SIGNAL(stateChanged(int)), this, SLOT(exitMatlabChanged(int)) ); 110 | 111 | connect( d->pushButton_GenerateModule, SIGNAL(clicked()), this, SLOT(generateModuleClicked()) ); 112 | 113 | connect( d->pushButton_EditInterfaceDefinition, SIGNAL(clicked()), this, SLOT(editInterfaceDefinitionClicked()) ); 114 | connect( d->pushButton_EditMatlabFunction, SIGNAL(clicked()), this, SLOT(editMatlabFunctionClicked()) ); 115 | connect( d->pushButton_RestartApplication, SIGNAL(clicked()), this, SLOT(restartApplicationClicked()) ); 116 | 117 | d->lineEdit_MatlabExecutablePath->setCurrentPath(d->logic()->GetMatlabExecutablePath()); 118 | d->lineEdit_MatlabScriptDirectory->setText(d->logic()->GetMatlabModuleDirectory()); 119 | } 120 | 121 | //----------------------------------------------------------------------------- 122 | void qSlicerMatlabModuleGeneratorModuleWidget::applicationAboutToQuit() 123 | { 124 | bool exitMatlab = true; 125 | QSettings settings; 126 | if (settings.contains("Matlab/ExitMatlabOnApplicationExit")) 127 | { 128 | exitMatlab = settings.value("Matlab/ExitMatlabOnApplicationExit").toBool(); 129 | } 130 | if (exitMatlab) 131 | { 132 | qDebug("Shutting down Matlab"); 133 | qSlicerModuleManager* moduleManager = qSlicerApplication::application()->moduleManager(); 134 | qSlicerAbstractCoreModule* matlabCommanderModule = moduleManager->module("MatlabCommander"); 135 | if (matlabCommanderModule) 136 | { 137 | vtkSlicerCLIModuleLogic* matlabCommanderLogic = vtkSlicerCLIModuleLogic::SafeDownCast(matlabCommanderModule->logic()); 138 | vtkMRMLCommandLineModuleNode* cmdNode = matlabCommanderLogic->CreateNodeInScene(); 139 | cmdNode->SetParameterAsBool("exitmatlab", true); 140 | matlabCommanderLogic->ApplyAndWait(cmdNode); 141 | } 142 | else 143 | { 144 | qWarning("MatlabCommander module is not found"); 145 | } 146 | } 147 | } 148 | 149 | //----------------------------------------------------------------------------- 150 | void qSlicerMatlabModuleGeneratorModuleWidget::matlabExecutablePathChanged(QString path) 151 | { 152 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget); 153 | 154 | QSettings settings; 155 | settings.setValue("Matlab/MatlabExecutablePath",path); 156 | 157 | d->logic()->SetMatlabExecutablePath(path.toLatin1()); 158 | } 159 | 160 | //----------------------------------------------------------------------------- 161 | void qSlicerMatlabModuleGeneratorModuleWidget::exitMatlabChanged(int state) 162 | { 163 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget); 164 | QSettings settings; 165 | settings.setValue("Matlab/ExitMatlabOnApplicationExit",state==Qt::Checked); 166 | } 167 | 168 | //----------------------------------------------------------------------------- 169 | void qSlicerMatlabModuleGeneratorModuleWidget::generateModuleClicked() 170 | { 171 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget); 172 | QString moduleName=d->lineEdit_GeneratorModuleName->text(); 173 | vtkStdString result=d->logic()->GenerateModule(moduleName.toLatin1(), d->lastInterfaceDefinitionFilename, d->lastMatlabFunctionFilename); 174 | d->textEdit_GeneratorResults->setText(QString(result)); 175 | 176 | d->pushButton_EditInterfaceDefinition->setEnabled(!d->lastInterfaceDefinitionFilename.empty()); 177 | d->pushButton_EditMatlabFunction->setEnabled(!d->lastMatlabFunctionFilename.empty()); 178 | } 179 | 180 | //----------------------------------------------------------------------------- 181 | void qSlicerMatlabModuleGeneratorModuleWidget::editInterfaceDefinitionClicked() 182 | { 183 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget); 184 | QString filename = QString::fromLatin1("file:///")+QString::fromLatin1(d->lastInterfaceDefinitionFilename); 185 | QDesktopServices::openUrl(QUrl(filename, QUrl::TolerantMode)); 186 | } 187 | 188 | //----------------------------------------------------------------------------- 189 | void qSlicerMatlabModuleGeneratorModuleWidget::editMatlabFunctionClicked() 190 | { 191 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget); 192 | QString filename = QString::fromLatin1("file:///")+QString::fromLatin1(d->lastMatlabFunctionFilename); 193 | QDesktopServices::openUrl(QUrl(filename, QUrl::TolerantMode)); 194 | } 195 | 196 | //----------------------------------------------------------------------------- 197 | void qSlicerMatlabModuleGeneratorModuleWidget::restartApplicationClicked() 198 | { 199 | Q_D(qSlicerMatlabModuleGeneratorModuleWidget); 200 | qSlicerApplication::application()->confirmRestart(); 201 | } 202 | -------------------------------------------------------------------------------- /MatlabModuleGenerator/qSlicerMatlabModuleGeneratorModuleWidget.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | 3 | Program: 3D Slicer 4 | 5 | Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved. 6 | 7 | See COPYRIGHT.txt 8 | or http://www.slicer.org/copyright/copyright.txt for details. 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | ==============================================================================*/ 17 | 18 | #ifndef __qSlicerMatlabModuleGeneratorModuleWidget_h 19 | #define __qSlicerMatlabModuleGeneratorModuleWidget_h 20 | 21 | // SlicerQt includes 22 | #include "qSlicerAbstractModuleWidget.h" 23 | 24 | #include "qSlicerMatlabModuleGeneratorModuleExport.h" 25 | 26 | class qSlicerMatlabModuleGeneratorModuleWidgetPrivate; 27 | class vtkMRMLNode; 28 | 29 | /// \ingroup Slicer_QtModules_ExtensionTemplate 30 | class Q_SLICER_QTMODULES_MATLABMODULEGENERATOR_EXPORT qSlicerMatlabModuleGeneratorModuleWidget : 31 | public qSlicerAbstractModuleWidget 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | 37 | typedef qSlicerAbstractModuleWidget Superclass; 38 | qSlicerMatlabModuleGeneratorModuleWidget(QWidget *parent=0); 39 | virtual ~qSlicerMatlabModuleGeneratorModuleWidget(); 40 | 41 | public slots: 42 | 43 | protected slots: 44 | 45 | void applicationAboutToQuit(); 46 | 47 | void matlabExecutablePathChanged(QString path); 48 | void exitMatlabChanged(int state); 49 | void generateModuleClicked(); 50 | 51 | void editInterfaceDefinitionClicked(); 52 | void editMatlabFunctionClicked(); 53 | void restartApplicationClicked(); 54 | 55 | protected: 56 | QScopedPointer d_ptr; 57 | 58 | virtual void setup(); 59 | 60 | private: 61 | Q_DECLARE_PRIVATE(qSlicerMatlabModuleGeneratorModuleWidget); 62 | Q_DISABLE_COPY(qSlicerMatlabModuleGeneratorModuleWidget); 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # SlicerMatlabBridge 3 | MatlabBridge extension for 3D Slicer 4 | 5 | More information: https://www.slicer.org/wiki/Documentation/Nightly/Extensions/MatlabBridge 6 | --------------------------------------------------------------------------------