├── ROIs2Regions.m ├── ellipse2mask.m └── ReadImageJROI.m /ROIs2Regions.m: -------------------------------------------------------------------------------- 1 | function [sRegions] = ROIs2Regions(cvsROIs, vnImageSize) 2 | 3 | % ROIs2Regions - FUNCTION Convert a set of imported ImageJ ROIs into a Matlab regions structure 4 | % 5 | % Usage: [sRegions] = ROIs2Regions(cvsROIs, vnImageSize) 6 | % 7 | % 'cvsROIs' is a cell array of ImageJ ROI structures, as imported by 8 | % ReadImageJROI. 'vnImageSize' is a vector [M N] containing the size of the 9 | % image in pixels. 10 | % 11 | % 'sRegions' will be a structure compatible with the Matlab regions 12 | % structure format, as returned by bwconncomp. It will contain one region 13 | % for each compatible ROI in 'cvsROIs'. 14 | % 15 | % Only a subset of ImageJ ROI types is supported for conversion: 16 | % 'rectangle', oval', 'polygon' and 'freehand'. 17 | 18 | % Author: Dylan Muir 19 | % Created: 2011 20 | 21 | % - Check arguments 22 | 23 | if (nargin < 2) 24 | disp('*** ROIs2Regions: Incorrect usage.'); 25 | help ROIs2Regions; 26 | return; 27 | end 28 | 29 | % - Build a regions structure 30 | sRegions.Connectivity = 8; 31 | sRegions.ImageSize = vnImageSize; 32 | sRegions.NumObjects = numel(cvsROIs); 33 | sRegions.PixelIdxList = {}; 34 | 35 | for (nROIIndex = numel(cvsROIs):-1:1) 36 | sThisROI = cvsROIs{nROIIndex}; 37 | 38 | switch (lower(sThisROI.strType)) 39 | case 'rectangle' 40 | if (isfield(sThisROI, 'strSubtype') && isequal(lower(sThisROI.strSubtype), 'shape')) 41 | % - Skip this one 42 | continue; 43 | 44 | else 45 | % - Make a rectangular mask 46 | mbThisMask = false(vnImageSize); 47 | sThisROI.vnRectBounds = sThisROI.vnRectBounds + 1; 48 | mbThisMask(sThisROI.vnRectBounds(1):sThisROI.vnRectBounds(3), sThisROI.vnRectBounds(2):sThisROI.vnRectBounds(4)) = true; 49 | sRegions.PixelIdxList{nROIIndex} = find(mbThisMask'); 50 | end 51 | 52 | case 'oval' 53 | % - Draw an oval inside the bounding box 54 | mbThisMask = ellipse2mask('bounds', vnImageSize, sThisROI.vnRectBounds+1); 55 | sRegions.PixelIdxList{nROIIndex} = find(mbThisMask'); 56 | 57 | case {'polygon'; 'freehand'} 58 | % - Draw a polygonal mask 59 | mbThisMask = poly2mask(sThisROI.mnCoordinates(:, 1)+1, sThisROI.mnCoordinates(:, 2)+1, vnImageSize(1), vnImageSize(2)); 60 | sRegions.PixelIdxList{nROIIndex} = find(mbThisMask'); 61 | 62 | otherwise 63 | warning( 'ROIs2Regions:unsupported', ... 64 | '--- ROIs2Regions: Warning: Unsupported ROI type.'); 65 | end 66 | end 67 | 68 | % --- END of ROIs2Regions.m --- 69 | -------------------------------------------------------------------------------- /ellipse2mask.m: -------------------------------------------------------------------------------- 1 | function [mbMask] = ellipse2mask(strType, vnImageSize, varargin) 2 | 3 | % ellipse2mask - FUNCTION Make an ellipse mask 4 | % 5 | % Usage: [mbMask] = ellipse2mask('bounds', vnImageSize, [fX1 fY1 fX2 fY2]) 6 | % ellipse2mask('majoraxis', vnImageSize, [fX1 fY1 fX2 fY2], fAspectRatio) 7 | % ellipse2mask('center', vnImageSize, [fCx fCy], [fMajorAxisLength fMinorAxisLength], fThetaRad) 8 | % ellipse2mask('axes', vnImageSize, Major:[fX1 fY1 fX2 fY2], Minor:[fX1 fY1 fX2 fY2]) 9 | % 10 | % 'vnImageSize' is the size of the desired output mask, with the format [nRows 11 | % nColumns]. 12 | % 13 | % 'bounds': Define an ellipse within a rectangle aligned with the X and Y axis. 14 | % The bounds of the rectangle are defined with the vector [fX1 fY1 fX2 fY2]. 15 | % 16 | % 'majoraxis': Define an ellipse to fit within a defined major axis, along the 17 | % line defined by [fX1 fY1 fX2 fY2], with a specified major:minor axis length 18 | % aspect ratio 'fAspectRatio'. 19 | % 20 | % 'center': Define an ellipse by providing a center [fCx fCy], a major and minor 21 | % axis length [fMajorAxisLength fMinorAxisLength] and a rotation of the major 22 | % axis from the X axis, in radians. 23 | % 24 | % 'axes': Define an ellipse by providing the major and minor axis lines, 25 | % Major:[fX1 fY1 fX2 fY2], Minor:[fX1 fY1 fX2 fY2]. WARNING: ellipse2mask will 26 | % not fix your incorrectly defined axes! The major and minor axes should 27 | % intersect at their middles, and be orthogonal. 28 | 29 | % Author: Dylan Muir 30 | % Created: 10th August, 2011 31 | 32 | % -- Check arguments 33 | 34 | if (nargin == 0) 35 | disp('*** ellipse2mask: Incorrect usage.'); 36 | help ellipse2mask; 37 | return; 38 | end 39 | 40 | % - Is the image size a 2-element vector? 41 | if (numel(vnImageSize) ~= 2) 42 | error('ellipse2mask:arguments', ... 43 | '''vnImageSize'' must have two elements.'); 44 | end 45 | 46 | % - Was the function call reasonable? 47 | bIncorrectCall = false; 48 | switch lower(strType) 49 | case 'bounds' 50 | if (nargin < 3) 51 | bIncorrectCall = true; 52 | end 53 | 54 | % - Extract arguments and check 55 | vfRectBounds = varargin{1}; 56 | 57 | if (numel(vfRectBounds) ~= 4) 58 | bIncorrectCall = true; 59 | end 60 | 61 | case 'majoraxis' 62 | if (nargin < 4) 63 | bIncorrectCall = true; 64 | end 65 | 66 | % - Extract arguments and check 67 | vfMajorAxis = varargin{1}; 68 | fAspectRatio = varargin{2}; 69 | 70 | if ((numel(vfMajorAxis) ~= 4) || ~isscalar(fAspectRatio)) 71 | bIncorrectCall = true; 72 | end 73 | 74 | case 'center' 75 | if (nargin < 5) 76 | bIncorrectCall = true; 77 | end 78 | 79 | % - Extract arguments and check 80 | vfCenter = varargin{1}; 81 | vfAxes = varargin{2}; 82 | fTheta = varargin{3}; 83 | 84 | if ((numel(vfCenter) ~= 2) || (numel(vfAxes) ~= 2) || ~isscalar(fTheta)) 85 | bIncorrectCall = true; 86 | end 87 | 88 | 89 | case 'axes' 90 | if (nargin < 4) 91 | bIncorrectCall = true; 92 | end 93 | 94 | % - Extract arguments and check 95 | vfAAxisLine = varargin{1}; 96 | vfBAxisLine = varargin{2}; 97 | 98 | if ((numel(vfAAxisLine) ~= 4) || (numel(vfBAxisLine) ~= 4)) 99 | bIncorrectCall = true; 100 | end 101 | 102 | otherwise 103 | error('ellipse2mask:unknown_type', ... 104 | '*** ellipse2mask: Unknown ellipse definition type.'); 105 | end 106 | 107 | % - No, so generate an error 108 | if (bIncorrectCall) 109 | error('ellipse2mask:arguments', ... 110 | '*** ellipse2mask: Incorrect usage.'); 111 | end 112 | 113 | 114 | % -- Convert parameters to center plus semi-axes vectors and lengths 115 | % vfCenter: [fCX fCY] 116 | % vfAAxis: Unit vector along major axis 117 | % cfBAxis: Unit vector along minor axis 118 | % fA: Semi-major axis length 119 | % fB: Semi-minor axis length 120 | 121 | switch lower(strType) 122 | case 'bounds' 123 | % - Make an ellipse that fits inside an axis-aligned rectangle 124 | vfCenter = [vfRectBounds(1) + vfRectBounds(3) vfRectBounds(2) + vfRectBounds(4)] / 2; 125 | vfAAxis = [1 0]; 126 | % - Make fA and fB one unit bigger, to fit nicely in bounds 127 | fA = abs(vfRectBounds(3) - vfCenter(1)) + 1; 128 | fB = abs(vfRectBounds(4) - vfCenter(2)) + 1; 129 | 130 | case 'majoraxis' 131 | % - Make an ellipse that fits along a defined major axis, with a specified 132 | % major:minor axis ratio 133 | vfCenter = [vfMajorAxis(1) + vfMajorAxis(3) vfMajorAxis(2) + vfMajorAxis(4)] / 2; 134 | vfAAxis = vfMajorAxis(3:4) - vfCenter; 135 | fA = sqrt(sum(vfAAxis.^2)); 136 | vfAAxis = vfAAxis ./ fA; 137 | fB = fA ./ fAspectRatio; 138 | 139 | case 'center' 140 | % - Make an ellipse defined by a center point, two axis lengths (major and 141 | % minor) and a rotation 142 | fA = vfAxes(1)/2; 143 | fB = vfAxes(2)/2; 144 | vfAAxis = [cos(fTheta) sin(fTheta)]; 145 | 146 | case 'axes' 147 | % - Make an ellipse defined by the major and minor axis lines. 148 | vfCenter = [vfAAxisLine(1) + vfAAxisLine(3) vfAAxisLine(2) + vfAAxisLine(4)] / 2; 149 | vfCenterB = [vfBAxisLine(1) + vfBAxisLine(3) vfBAxisLine(2) + vfBAxisLine(4)] / 2; 150 | vfAAxis = vfAAxisLine(3:4) - vfAAxisLine(1:2); 151 | vfBAxis = vfBAxisLine(3:4) - vfBAxisLine(1:2); 152 | fA = sqrt(sum(vfAAxis.^2))/2; 153 | fB = sqrt(sum(vfBAxis.^2))/2; 154 | vfAAxis = vfAAxis ./ fA; 155 | vfBAxis = vfBAxis ./ fB; 156 | 157 | % - Check to see if the axis definitions match 158 | if (sum(vfBAxis - [-vfAAxis(2) vfAAxis(1)]) > 2*eps) 159 | warning( 'ellipse2mask:axismismatch', ... 160 | '--- ellipse2mask: Warning: The major and minor axes are not orthogonal. The output is undetermined.'); 161 | end 162 | 163 | if (sum(vfCenter - vfCenterB) > 2*eps) 164 | warning( 'ellipse2mask:axismismatch', ... 165 | '--- ellipse2mask: Warning: The major and minor axes do not intersect at their middles. The output is undetermined.'); 166 | end 167 | end 168 | 169 | 170 | % -- Find points within the ellipse 171 | 172 | % - Make a mesh of points 173 | [mnY, mnX] = meshgrid(1:vnImageSize(1), 1:vnImageSize(2)); 174 | 175 | % - Transform points 176 | mnXT = (mnX - vfCenter(1)).*vfAAxis(1) + (mnY - vfCenter(2)).*vfAAxis(2); 177 | mnYT = -(mnX - vfCenter(1)).*vfAAxis(2) + (mnY - vfCenter(2)).*vfAAxis(1); 178 | 179 | % - Find points inside the ellipse 180 | mbMask = (mnXT.^2 / fA^2 + mnYT.^2 / fB^2) < 1; 181 | 182 | % --- END of ellipse2mask.m --- 183 | -------------------------------------------------------------------------------- /ReadImageJROI.m: -------------------------------------------------------------------------------- 1 | function [sROI] = ReadImageJROI(cstrFilenames) 2 | 3 | % ReadImageJROI - FUNCTION Read an ImageJ ROI into a matlab structure 4 | % 5 | % Usage: [sROI] = ReadImageJROI(strFilename) 6 | % [cvsROIs] = ReadImageJROI(cstrFilenames) 7 | % [cvsROIs] = ReadImageJROI(strROIArchiveFilename) 8 | % 9 | % This function reads the ImageJ binary ROI file format. 10 | % 11 | % 'strFilename' is the full path to a '.roi' file. A list of ROI files can be 12 | % passed as a cell array of filenames, in 'cstrFilenames'. An ImageJ ROI 13 | % archive can be access by providing a '.zip' filename in 14 | % 'strROIArchiveFilename'. Single ROIs are returned as matlab structures, with 15 | % variable fields depending on the ROI type. Multiple ROIs are returned as a 16 | % cell array of ROI structures. 17 | % 18 | % The field '.strName' is guaranteed to exist, and contains the ROI name (the 19 | % filename minus '.roi', or the name set for the ROI). 20 | % 21 | % The field '.strType' is guaranteed to exist, and defines the ROI type: 22 | % {'Rectangle', 'Oval', Line', 'Polygon', 'Freehand', 'Traced', 'PolyLine', 23 | % 'FreeLine', 'Angle', 'Point', 'NoROI'}. 24 | % 25 | % The field '.vnRectBounds' is guaranteed to exist, and defines the rectangular 26 | % bounds of the ROI: ['nTop', 'nLeft', 'nBottom', 'nRight']. 27 | % 28 | % The field '.nVersion' is guaranteed to exist, and defines the version number 29 | % of the ROI format. 30 | % 31 | % The field '.vnPosition' is guaranteed to exist. If the information is 32 | % defined within the ROI, this field will be a three-element vector 33 | % [nCPosition nZPosition nTPosition]. 34 | % 35 | % ROI types: 36 | % Rectangle: 37 | % .strType = 'Rectangle'; 38 | % .nArcSize - The arc size of the rectangle's rounded corners 39 | % 40 | % For a composite, 'shape' ROI: 41 | % .strSubtype = 'Shape'; 42 | % .vfShapeSegments - A long, complicated vector of complicated shape 43 | % segments. This vector is in the format passed to the 44 | % ImageJ ShapeROI constructor. I won't decode this for 45 | % you! :( 46 | % 47 | % Oval: 48 | % .strType = 'Oval'; 49 | % 50 | % Line: 51 | % .strType = 'Line'; 52 | % .vnLinePoints - The end points of the line ['nX1', 'nY1', 'nX2', 'nY2'] 53 | % 54 | % With arrow: 55 | % .strSubtype = 'Arrow'; 56 | % .bDoubleHeaded - Does the line have two arrowheads? 57 | % .bOutlined - Is the arrow outlined? 58 | % .nArrowStyle - The ImageJ style of the arrow (unknown interpretation) 59 | % .nArrowHeadSize - The size of the arrowhead (unknown units) 60 | % 61 | % Polygon: 62 | % .strType = 'Polygon'; 63 | % .mnCoordinates - An [Nx2] matrix, specifying the coordinates of 64 | % the polygon vertices. Each row is [nX nY]. 65 | % 66 | % Freehand: 67 | % .strType = 'Freehand'; 68 | % .mnCoordinates - An [Nx2] matrix, specifying the coordinates of 69 | % the polygon vertices. Each row is [nX nY]. 70 | % 71 | % Ellipse subtype: 72 | % .strSubtype = 'Ellipse'; 73 | % .vfEllipsePoints - A vector containing the ellipse control points: 74 | % [fX1 fY1 fX2 fY2]. 75 | % .fAspectRatio - The aspect ratio of the ellipse. 76 | % 77 | % Traced: 78 | % .strType = 'Traced'; 79 | % .mnCoordinates - An [Nx2] matrix, specifying the coordinates of 80 | % the line vertices. Each row is [nX nY]. 81 | % 82 | % PolyLine: 83 | % .strType = 'PolyLine'; 84 | % .mnCoordinates - An [Nx2] matrix, specifying the coordinates of 85 | % the line vertices. Each row is [nX nY]. 86 | % 87 | % FreeLine: 88 | % .strType = 'FreeLine'; 89 | % .mnCoordinates - An [Nx2] matrix, specifying the coordinates of 90 | % the line vertices. Each row is [nX nY]. 91 | % 92 | % Angle: 93 | % .strType = 'Angle'; 94 | % .mnCoordinates - An [Nx2] matrix, specifying the coordinates of 95 | % the angle vertices. Each row is [nX nY]. 96 | % 97 | % Point: 98 | % .strType = 'Point'; 99 | % .mfCoordinates - An [Nx2] matrix, specifying the coordinates of 100 | % the points. Each row is [fX fY]. 101 | % .vnCounters - An [Nx1] vector, specifying which counter is 102 | % associated with each point. May be empty. 103 | % .vnSlices - An [Nx1] vector, specifying on which plane each 104 | % point is on. These are specified as linear 105 | % indices, with the hyperstack arranged as 106 | % [Channels Z-slices T-slices]. If empty, then all 107 | % points are placed on the first slice. 108 | % 109 | % NoROI: 110 | % .strType = 'NoROI'; 111 | % 112 | % Additionally, ROIs from later versions (.nVersion >= 218) may have the 113 | % following fields: 114 | % 115 | % .nStrokeWidth - The width of the line stroke 116 | % .nStrokeColor - The encoded color of the stroke (ImageJ color format) 117 | % .nFillColor - The encoded fill color for the ROI (ImageJ color 118 | % format) 119 | % 120 | % If the ROI contains text: 121 | % .strSubtype = 'Text'; 122 | % .nFontSize - The desired font size 123 | % .nFontStyle - The style of the font (unknown format) 124 | % .strFontName - The name of the font to render the text with 125 | % .strText - A string containing the text 126 | 127 | % Author: Dylan Muir 128 | % Created: 9th August, 2011 129 | % 130 | % 20170118 Added code to read slice position for point ROIs 131 | % 20141020 Added code to read 'header 2' fields; thanks to Luca Nocetti 132 | % 20140602 Bug report contributed by Samuel Barnes and Yousef Mazaheri 133 | % 20110810 Bug report contributed by Jean-Yves Tinevez 134 | % 20110829 Bug fix contributed by Benjamin Ricca 135 | % 20120622 Order of ROIs in a ROI set is now preserved 136 | % 20120703 Different way of reading zip file contents guarantees that ROI order 137 | % is preserved 138 | % 139 | % Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Dylan Muir 140 | % 141 | % This program is free software; you can redistribute it and/or 142 | % modify it under the terms of the GNU General Public License 143 | % as published by the Free Software Foundation; either version 3 144 | % of the License, or (at your option) any later version. 145 | % 146 | % This program is distributed in the hope that it will be useful, 147 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 148 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149 | % GNU General Public License for more details. 150 | 151 | % -- Constants 152 | 153 | bOpt_SubPixelResolution = 128; 154 | 155 | 156 | % -- Check arguments 157 | 158 | if (nargin < 1) 159 | disp('*** ReadImageJROI: Incorrect usage'); 160 | help ReadImageJROI; 161 | return; 162 | end 163 | 164 | 165 | % -- Check for a cell array of ROI filenames 166 | 167 | if (iscell(cstrFilenames)) 168 | % - Read each ROI in turn 169 | cvsROI = cellfun(@ReadImageJROI, CellFlatten(cstrFilenames), 'UniformOutput', false); 170 | 171 | % - Return all ROIs 172 | sROI = cvsROI; 173 | return; 174 | 175 | else 176 | % - This is not a cell string 177 | strFilename = cstrFilenames; 178 | clear cstrFilenames; 179 | end 180 | 181 | 182 | % -- Check for a zip file 183 | 184 | [nul, nul, strExt] = fileparts(strFilename); %#ok 185 | if (isequal(lower(strExt), '.zip')) 186 | % - get zp file contents 187 | cstrFilenames_short = listzipcontents_rois(strFilename); 188 | 189 | % - Unzip the file into a temporary directory 190 | strROIDir = tempname; 191 | unzip(strFilename, strROIDir); 192 | 193 | for (nFileIndex = 1:length(cstrFilenames_short)) 194 | cstrFilenames{1, nFileIndex} = [strROIDir '/' char(cstrFilenames_short(nFileIndex, 1))]; 195 | end 196 | 197 | % - Build ROIs for each file 198 | cvsROIs = ReadImageJROI(cstrFilenames); 199 | 200 | % - Clean up temporary directory 201 | rmdir(strROIDir, 's'); 202 | 203 | % - Return ROIs 204 | sROI = cvsROIs; 205 | return; 206 | end 207 | 208 | 209 | % -- Read ROI 210 | 211 | % -- Check file and open 212 | if (~exist(strFilename, 'file')) 213 | error('ReadImageJROI:FileNotFound', ... 214 | '*** ReadImageJROI: The file [%s] was not found.', strFilename); 215 | end 216 | 217 | fidROI = fopen(strFilename, 'r', 'ieee-be'); 218 | 219 | % -- Check file magic code 220 | strMagic = fread(fidROI, [1 4], '*char'); 221 | 222 | if (~isequal(strMagic, 'Iout')) 223 | error('ReadImageJROI:FormatError', ... 224 | '*** ReadImageJROI: The file was not an ImageJ ROI format.'); 225 | end 226 | 227 | % -- Read version 228 | sROI.nVersion = fread(fidROI, 1, 'int16'); 229 | 230 | % -- Read ROI type 231 | nTypeID = fread(fidROI, 1, 'uint8'); 232 | fseek(fidROI, 1, 'cof'); % Skip a byte 233 | 234 | % -- Read rectangular bounds 235 | sROI.vnRectBounds = fread(fidROI, [1 4], 'int16'); 236 | 237 | % -- Read number of coordinates 238 | nNumCoords = fread(fidROI, 1, 'uint16'); 239 | 240 | % -- Read the rest of the header 241 | vfLinePoints = fread(fidROI, 4, 'float32'); 242 | nStrokeWidth = fread(fidROI, 1, 'int16'); 243 | nShapeROISize = fread(fidROI, 1, 'uint32'); 244 | nStrokeColor = fread(fidROI, 1, 'uint32'); 245 | nFillColor = fread(fidROI, 1, 'uint32'); 246 | nROISubtype = fread(fidROI, 1, 'int16'); 247 | nOptions = fread(fidROI, 1, 'int16'); 248 | nArrowStyle = fread(fidROI, 1, 'uint8'); 249 | nArrowHeadSize = fread(fidROI, 1, 'uint8'); 250 | nRoundedRectArcSize = fread(fidROI, 1, 'int16'); 251 | sROI.nPosition = fread(fidROI, 1, 'uint32'); 252 | 253 | 254 | % -- Read the 'header 2' fields 255 | nHeader2Offset = fread(fidROI, 1, 'uint32'); 256 | 257 | if (nHeader2Offset > 0) && ~fseek(fidROI, nHeader2Offset+32+4, 'bof') 258 | % - Seek to start of header 2 259 | fseek(fidROI, nHeader2Offset+4, 'bof'); 260 | 261 | % - Read fields 262 | sROI.vnPosition = fread(fidROI, 3, 'uint32')'; 263 | vnNameParams = fread(fidROI, 2, 'uint32')'; 264 | nOverlayLabelColor = fread(fidROI, 1, 'uint32'); %#ok 265 | nOverlayFontSize = fread(fidROI, 1, 'int16'); %#ok 266 | fseek(fidROI, 1, 'cof'); % Skip a byte 267 | nOpacity = fread(fidROI, 1, 'uint8'); %#ok 268 | nImageSize = fread(fidROI, 1, 'uint32'); %#ok 269 | fStrokeWidth = fread(fidROI, 1, 'float32'); %#ok 270 | vnROIPropertiesParams = fread(fidROI, 2, 'uint32')'; %#ok 271 | nCountersOffset = fread(fidROI, 1, 'uint32'); 272 | 273 | else 274 | sROI.vnPosition = []; 275 | vnNameParams = [0 0]; 276 | nOverlayLabelColor = []; %#ok 277 | nOverlayFontSize = []; %#ok 278 | nOpacity = []; %#ok 279 | nImageSize = []; %#ok 280 | fStrokeWidth = []; %#ok 281 | vnROIPropertiesParams = [0 0]; %#ok 282 | nCountersOffset = 0; 283 | end 284 | 285 | 286 | % -- Set ROI name 287 | if (isempty(vnNameParams) || any(vnNameParams == 0) || fseek(fidROI, sum(vnNameParams), 'bof')) 288 | [nul, sROI.strName] = fileparts(strFilename); %#ok 289 | 290 | else 291 | % - Try to read ROI name from header 292 | fseek(fidROI, vnNameParams(1), 'bof'); 293 | sROI.strName = fread(fidROI, vnNameParams(2), 'int16=>char')'; 294 | end 295 | 296 | 297 | % - Seek to get aspect ratio 298 | fseek(fidROI, 52, 'bof'); 299 | fAspectRatio = fread(fidROI, 1, 'float32'); 300 | 301 | % - Seek to after header 302 | fseek(fidROI, 64, 'bof'); 303 | 304 | 305 | % -- Build ROI 306 | 307 | switch nTypeID 308 | case 1 309 | % - Rectangle 310 | sROI.strType = 'Rectangle'; 311 | sROI.nArcSize = nRoundedRectArcSize; 312 | 313 | if (nShapeROISize > 0) 314 | % - This is a composite shape ROI 315 | sROI.strSubtype = 'Shape'; 316 | if (nTypeID ~= 1) 317 | error('ReadImageJROI:FormatError', ... 318 | '*** ReadImageJROI: A composite ROI must be a Rectangle type.'); 319 | end 320 | 321 | % - Read shapes 322 | sROI.vfShapes = fread(fidROI, nShapeROISize, 'float32'); 323 | end 324 | 325 | 326 | case 2 327 | % - Oval 328 | sROI.strType = 'Oval'; 329 | 330 | case 3 331 | % - Line 332 | sROI.strType = 'Line'; 333 | sROI.vnLinePoints = round(vfLinePoints); 334 | 335 | if (nROISubtype == 2) 336 | % - This is an arrow line 337 | sROI.strSubtype = 'Arrow'; 338 | sROI.bDoubleHeaded = nOptions & 2; 339 | sROI.bOutlined = nOptions & 4; 340 | sROI.nArrowStyle = nArrowStyle; 341 | sROI.nArrowHeadSize = nArrowHeadSize; 342 | end 343 | 344 | 345 | case 0 346 | % - Polygon 347 | sROI.strType = 'Polygon'; 348 | sROI.mnCoordinates = read_coordinates; 349 | 350 | case 7 351 | % - Freehand 352 | sROI.strType = 'Freehand'; 353 | sROI.mnCoordinates = read_coordinates; 354 | 355 | if (nROISubtype == 3) 356 | % - This is an ellipse 357 | sROI.strSubtype = 'Ellipse'; 358 | sROI.vfEllipsePoints = vfLinePoints; 359 | sROI.fAspectRatio = fAspectRatio; 360 | end 361 | 362 | case 8 363 | % - Traced 364 | sROI.strType = 'Traced'; 365 | sROI.mnCoordinates = read_coordinates; 366 | 367 | case 5 368 | % - PolyLine 369 | sROI.strType = 'PolyLine'; 370 | sROI.mnCoordinates = read_coordinates; 371 | 372 | case 4 373 | % - FreeLine 374 | sROI.strType = 'FreeLine'; 375 | sROI.mnCoordinates = read_coordinates; 376 | 377 | case 9 378 | % - Angle 379 | sROI.strType = 'Angle'; 380 | sROI.mnCoordinates = read_coordinates; 381 | 382 | case 10 383 | % - Point 384 | sROI.strType = 'Point'; 385 | [sROI.mfCoordinates, vnCounters] = read_coordinates; 386 | 387 | % - Set counters and [C Z T] positions 388 | if (isempty(vnCounters)) 389 | sROI.vnCounters = zeros(nNumCoords, 1); 390 | sROI.vnSlices = ones(nNumCoords, 1); 391 | else 392 | sROI.vnCounters = bitand(vnCounters, 255); 393 | sROI.vnSlices = bitshift(vnCounters, -8, 'uint32'); 394 | end 395 | 396 | case 6 397 | sROI.strType = 'NoROI'; 398 | 399 | otherwise 400 | error('ReadImageJROI:FormatError', ... 401 | '--- ReadImageJROI: The ROI file contains an unknown ROI type.'); 402 | end 403 | 404 | 405 | % -- Handle version >= 218 406 | 407 | if (sROI.nVersion >= 218) 408 | sROI.nStrokeWidth = nStrokeWidth; 409 | sROI.nStrokeColor = nStrokeColor; 410 | sROI.nFillColor = nFillColor; 411 | sROI.bSplineFit = nOptions & 1; 412 | 413 | if (nROISubtype == 1) 414 | % - This is a text ROI 415 | sROI.strSubtype = 'Text'; 416 | 417 | % - Seek to after header 418 | fseek(fidROI, 64, 'bof'); 419 | 420 | sROI.nFontSize = fread(fidROI, 1, 'uint32'); 421 | sROI.nFontStyle = fread(fidROI, 1, 'uint32'); 422 | nNameLength = fread(fidROI, 1, 'uint32'); 423 | nTextLength = fread(fidROI, 1, 'uint32'); 424 | 425 | % - Read font name 426 | sROI.strFontName = fread(fidROI, nNameLength, 'uint16=>char'); 427 | 428 | % - Read text 429 | sROI.strText = fread(fidROI, nTextLength, 'uint16=>char'); 430 | end 431 | end 432 | 433 | % - Close the file 434 | fclose(fidROI); 435 | 436 | 437 | % --- END of ReadImageJROI FUNCTION --- 438 | 439 | function [mnCoordinates, vnCounters] = read_coordinates 440 | 441 | % - Check for sub-pixel resolution 442 | if bitand(nOptions, bOpt_SubPixelResolution) 443 | fseek(fidROI, 64 + 4*nNumCoords, 'bof'); 444 | 445 | % - Read X and Y coordinates 446 | vnX = fread(fidROI, [nNumCoords 1], 'single'); 447 | vnY = fread(fidROI, [nNumCoords 1], 'single'); 448 | 449 | else 450 | % - Read X and Y coords 451 | vnX = fread(fidROI, [nNumCoords 1], 'int16'); 452 | vnY = fread(fidROI, [nNumCoords 1], 'int16'); 453 | 454 | % - Trim at zero 455 | vnX(vnX < 0) = 0; 456 | vnY(vnY < 0) = 0; 457 | 458 | % - Offset by top left ROI bound 459 | vnX = vnX + sROI.vnRectBounds(2); 460 | vnY = vnY + sROI.vnRectBounds(1); 461 | end 462 | 463 | mnCoordinates = [vnX vnY]; 464 | 465 | % - Read counters, if present 466 | if (nCountersOffset ~= 0) 467 | fseek(fidROI, nCountersOffset, 'bof'); 468 | vnCounters = fread(fidROI, [nNumCoords 1], 'uint32'); 469 | else 470 | vnCounters = []; 471 | end 472 | end 473 | 474 | function [filelist] = listzipcontents_rois(zipFilename) 475 | 476 | % listzipcontents_rois - FUNCTION Read the file names in a zip file 477 | % 478 | % Usage: [filelist] = listzipcontents_rois(zipFilename) 479 | 480 | % - Import java libraries 481 | import java.util.zip.*; 482 | import java.io.*; 483 | 484 | % - Read file list via JAVA object 485 | filelist={}; 486 | in = ZipInputStream(FileInputStream(zipFilename)); 487 | entry = in.getNextEntry(); 488 | 489 | % - Filter ROI files 490 | while (entry~=0) 491 | name = entry.getName; 492 | if (name.endsWith('.roi')) && (~name.startsWith('__MACOSX')) 493 | filelist = cat(1,filelist,char(name)); 494 | end; 495 | entry = in.getNextEntry(); 496 | end; 497 | 498 | % - Close zip file 499 | in.close(); 500 | end 501 | 502 | 503 | function [cellArray] = CellFlatten(varargin) 504 | 505 | % CellFlatten - FUNCTION Convert a list of items to a single level cell array 506 | % 507 | % Usage: [cellArray] = CellFlatten(arg1, arg2, ...) 508 | % 509 | % CellFlatten will convert a list of arguments into a single-level cell array. 510 | % If any argument is already a cell array, each cell will be concatenated to 511 | % 'cellArray' in a list. The result of this function is a single-dimensioned 512 | % cell array containing a cell for each individual item passed to CellFlatten. 513 | % The order of cell elements in the argument list is guaranteed to be 514 | % preserved. 515 | % 516 | % This function is useful when dealing with variable-length argument lists, 517 | % each item of which can also be a cell array of items. 518 | 519 | % Author: Dylan Muir 520 | % Created: 14th May, 2004 521 | 522 | % -- Check arguments 523 | 524 | if (nargin == 0) 525 | disp('*** CellFlatten: Incorrect usage'); 526 | help CellFlatten; 527 | return; 528 | end 529 | 530 | % -- Convert arguments 531 | 532 | % - Which elements contain cell subarrays? 533 | vbIsCellSubarray = cellfun(@iscell, varargin, 'UniformOutput', true); 534 | 535 | % - Skip if no cell subarrays 536 | if ~any(vbIsCellSubarray) 537 | cellArray = varargin; 538 | return; 539 | end 540 | 541 | % - Recursively flatten subarrays 542 | varargin(vbIsCellSubarray) = cellfun(@(c)CellFlatten(c{:}), varargin(vbIsCellSubarray), 'UniformOutput', false); 543 | 544 | % - Count the total number of arguments 545 | vnArgSizes(nargin) = nan; 546 | vnArgSizes(~vbIsCellSubarray) = 1; 547 | vnArgSizes(vbIsCellSubarray) = cellfun(@numel, varargin(vbIsCellSubarray), 'UniformOutput', true); 548 | vnArgEnds = cumsum(vnArgSizes); 549 | vnArgStarts = [1 vnArgEnds(1:end-1)+1]; 550 | nNumArgs = vnArgEnds(end); 551 | 552 | % - Preallocate return array 553 | cellArray = cell(1, nNumArgs); 554 | 555 | % - Deal out non-cell subarray arguments 556 | cellArray(vnArgEnds(~vbIsCellSubarray)) = varargin(~vbIsCellSubarray); 557 | 558 | % - Deal out arguments into return array 559 | for nIndexArg = find(vbIsCellSubarray) 560 | cellArray(vnArgStarts(nIndexArg):vnArgEnds(nIndexArg)) = varargin{nIndexArg}; 561 | end 562 | 563 | % --- END of CellFlatten.m --- 564 | 565 | end 566 | 567 | end 568 | % --- END of ReadImageJROI.m --- 569 | --------------------------------------------------------------------------------