MK_LUNG_IMAGE create an image with lung and heart contrasts from a model MK_LUNG_IMAGE defines the lungs, heart and diaphragm as ellipsoids and creates an image with these organs out of the supplied eidors fwd_model. Typical usage: IMG = MK_LUNG_IMAGE(MDL) uses default options for shape, position and contrast. IMG = MK_LUNG_IMAGE(MDL, OPT) uses the specified options (see below). IMG = MK_LUNG_IMAGE(MDL, OPT, 'show') also generate a figure with 4 views of the produced image Additional utilities: OPT = MK_LUNG_IMAGE(MDL,'options') returns the default options for the given model, and does not generate an image. MK_LUNG_IMAGE(MDL, OPT, 'diagnostic') shows the supplied model together with the organ ellipsoids as defined by the supplied options. This usage has no return parameters. The options input OPT is a struct with the following fields and defaults: bkgnd_val: 1 - image value for the background lung_val: 0.2000 - image value for the lungs heart_val: 1.5000 - image value for the hearts left_lung_center: ctr + [ .24 0 -1/3]*scale right_lung_center: ctr + [ -.24 0 -1/3]*scale heart_center: ctr + [ 0.07 -1/6 0]*scale diaphragm_center: ctr + [ 0 -1/4 -2/3]*scale heart_axes: [ 1/6 1/5 1/4 ]*scale left_lung_axes: [ 8/30 1/3 25/30]*scale right_lung_axes: [ 8/30 1/3 25/30]*scale diaphragm_axes: [22/30 19/30 2/5]*scale where ctr is the center of the bounding box of the model, and scale is the smaller of the bounding box's x dimension divided by 7/6 and its y dimension. Each organ is an ellipsoid with the corresponding center and axes. NOTE that only options that deviate from defaults need be specified. Example: mdl = mk_thorax_model('female'); % female thorax img = mk_lung_image(mdl); subplot(131) show_fem(img) % it seems that the heart definition goes outside the model % let's correct the default options opt = mk_lung_image(mdl, 'options'); % get default options corr = 20; opt.heart_center(2) = opt.heart_center(2) + corr; opt.left_lung_center(2) = opt.left_lung_center(2) + corr; opt.right_lung_center(2) = opt.right_lung_center(2) + corr; opt.diaphragm_center(2) = opt.diaphragm_center(2) + corr; img = mk_lung_image(mdl, opt); subplot(132) show_fem(img) % it's hard to tell because the model has very big elements. % let's make a diagnostic plot to verify the organ definitions fit inside % the model (independent of model maxh) subplot(133) mk_lung_image(mdl,opt,'diagnostic'); CITATION_REQUEST: AUTHOR: Bartlomiej Grychtol, Beat Müller and Andy Adler TITLE: 3D EIT image reconstruction with GREIT JOURNAL: Physiological Measurement VOL: 37 YEAR: 2016 See also: ELEM_SELECT, MK_THORAX_MODEL
0001 function img = mk_lung_image(mdl, opt, cmd) 0002 %MK_LUNG_IMAGE create an image with lung and heart contrasts from a model 0003 % MK_LUNG_IMAGE defines the lungs, heart and diaphragm as ellipsoids and 0004 % creates an image with these organs out of the supplied eidors fwd_model. 0005 % 0006 % Typical usage: 0007 % 0008 % IMG = MK_LUNG_IMAGE(MDL) uses default options for shape, position and 0009 % contrast. 0010 % IMG = MK_LUNG_IMAGE(MDL, OPT) uses the specified options (see below). 0011 % IMG = MK_LUNG_IMAGE(MDL, OPT, 'show') also generate a figure with 4 views 0012 % of the produced image 0013 % 0014 % Additional utilities: 0015 % 0016 % OPT = MK_LUNG_IMAGE(MDL,'options') returns the default options for the 0017 % given model, and does not generate an image. 0018 % MK_LUNG_IMAGE(MDL, OPT, 'diagnostic') shows the supplied model together 0019 % with the organ ellipsoids as defined by the supplied options. This usage 0020 % has no return parameters. 0021 % 0022 % The options input OPT is a struct with the following fields and defaults: 0023 % bkgnd_val: 1 - image value for the background 0024 % lung_val: 0.2000 - image value for the lungs 0025 % heart_val: 1.5000 - image value for the hearts 0026 % left_lung_center: ctr + [ .24 0 -1/3]*scale 0027 % right_lung_center: ctr + [ -.24 0 -1/3]*scale 0028 % heart_center: ctr + [ 0.07 -1/6 0]*scale 0029 % diaphragm_center: ctr + [ 0 -1/4 -2/3]*scale 0030 % heart_axes: [ 1/6 1/5 1/4 ]*scale 0031 % left_lung_axes: [ 8/30 1/3 25/30]*scale 0032 % right_lung_axes: [ 8/30 1/3 25/30]*scale 0033 % diaphragm_axes: [22/30 19/30 2/5]*scale 0034 % where ctr is the center of the bounding box of the model, and scale is 0035 % the smaller of the bounding box's x dimension divided by 7/6 and its y 0036 % dimension. Each organ is an ellipsoid with the corresponding center and 0037 % axes. 0038 % NOTE that only options that deviate from defaults need be specified. 0039 % 0040 % Example: 0041 % mdl = mk_thorax_model('female'); % female thorax 0042 % img = mk_lung_image(mdl); 0043 % subplot(131) 0044 % show_fem(img) 0045 % % it seems that the heart definition goes outside the model 0046 % % let's correct the default options 0047 % opt = mk_lung_image(mdl, 'options'); % get default options 0048 % corr = 20; 0049 % opt.heart_center(2) = opt.heart_center(2) + corr; 0050 % opt.left_lung_center(2) = opt.left_lung_center(2) + corr; 0051 % opt.right_lung_center(2) = opt.right_lung_center(2) + corr; 0052 % opt.diaphragm_center(2) = opt.diaphragm_center(2) + corr; 0053 % img = mk_lung_image(mdl, opt); 0054 % subplot(132) 0055 % show_fem(img) 0056 % % it's hard to tell because the model has very big elements. 0057 % % let's make a diagnostic plot to verify the organ definitions fit inside 0058 % % the model (independent of model maxh) 0059 % subplot(133) 0060 % mk_lung_image(mdl,opt,'diagnostic'); 0061 % 0062 % CITATION_REQUEST: 0063 % AUTHOR: Bartlomiej Grychtol, Beat Müller and Andy Adler 0064 % TITLE: 3D EIT image reconstruction with GREIT 0065 % JOURNAL: Physiological Measurement 0066 % VOL: 37 0067 % YEAR: 2016 0068 % 0069 % See also: ELEM_SELECT, MK_THORAX_MODEL 0070 0071 % (C) 2015-2016 Bartlomiej Grychtol. License: GPL version 2 or 3 0072 % $Id: mk_lung_image.m 6485 2022-12-28 14:34:32Z aadler $ 0073 0074 citeme(mfilename); 0075 0076 if nargin>0 && ischar(mdl) && strcmp(mdl,'UNIT_TEST') 0077 do_unit_test; return; 0078 end 0079 0080 if nargin == 1, opt = struct; end 0081 returnopt = false; 0082 if nargin == 2 && ischar(opt) && strcmp(opt,'options') 0083 returnopt = true; 0084 clear opt; 0085 opt = struct; 0086 end 0087 opt = parse_opt(mdl,opt); 0088 if returnopt 0089 img = opt; 0090 return 0091 end 0092 0093 if nargin == 3 && ischar(cmd) && strcmp(cmd, 'diagnostic') 0094 show_organs(mdl,opt); 0095 return 0096 end 0097 0098 elem_data = define_elem_data(mdl, opt); 0099 0100 img = mk_image(mdl,elem_data); 0101 0102 if nargin==3 && ischar(cmd) && strcmp(cmd, 'show') 0103 show4views(img); 0104 end 0105 end 0106 0107 function elem_data = define_elem_data(mdl, opt) 0108 0109 el_str = '(x- %f).^2/%f^2 + (y- %f).^2/%f^2 + (z- %f).^2/%f^2 <= 1'; 0110 pack = @(x,y) mat2cell(reshape([x' y']',1,[])',ones(1, 2*numel(x)))'; 0111 0112 0113 args = pack(opt.left_lung_center, opt.left_lung_axes); 0114 ll_str = sprintf(el_str, args{:}); 0115 ll_fcn = inline(ll_str,'x','y','z'); 0116 left_lung = elem_select(mdl,ll_fcn); 0117 0118 args = pack(opt.right_lung_center, opt.right_lung_axes); 0119 rl_str = sprintf(el_str, args{:}); 0120 rl_fcn = inline(rl_str,'x','y','z'); 0121 right_lung = elem_select(mdl,rl_fcn); 0122 0123 lung = min(1,left_lung + right_lung); 0124 0125 args = pack(opt.diaphragm_center, opt.diaphragm_axes); 0126 dia_str = sprintf(el_str, args{:}); 0127 dia_fcn = inline(dia_str,'x','y','z'); 0128 diaphragm = elem_select(mdl,dia_fcn); 0129 0130 lung = max(0,lung - diaphragm); 0131 0132 args = pack(opt.heart_center, opt.heart_axes); 0133 hrt_str = sprintf(el_str, args{:}); 0134 hrt_fcn = inline(hrt_str,'x','y','z'); 0135 heart = elem_select(mdl, hrt_fcn); 0136 0137 lung = max(0, lung - heart); 0138 0139 elem_data = ... 0140 opt.bkgnd_val ... 0141 - (opt.bkgnd_val-opt.lung_val)*lung ... 0142 - (opt.bkgnd_val-opt.heart_val)*heart; 0143 end 0144 0145 function show_organs(mdl, opt) 0146 show_fem(mdl) 0147 hold on 0148 pack = @(x) mat2cell(x',ones(1,numel(x)))'; 0149 args = pack([opt.left_lung_center opt.left_lung_axes]); 0150 [x y z] = ellipsoid(args{:}); 0151 surf(x,y,z,'FaceColor','b'); 0152 0153 args = pack([opt.right_lung_center opt.right_lung_axes]); 0154 [x y z] = ellipsoid(args{:}); 0155 surf(x,y,z,'FaceColor','b'); 0156 0157 args = pack([opt.heart_center opt.heart_axes]); 0158 [x y z] = ellipsoid(args{:}); 0159 surf(x,y,z,'FaceColor','r'); 0160 0161 0162 args = pack([opt.diaphragm_center opt.diaphragm_axes]); 0163 [x y z] = ellipsoid(args{:}); 0164 surf(x,y,z,'FaceColor','g'); 0165 hold off 0166 end 0167 0168 function show4views(img) 0169 subplot(221) 0170 h = show_fem(img); 0171 set(h,'linewidth',.1) 0172 subplot(222) 0173 h = show_fem(img); 0174 set(h,'linewidth',.1) 0175 view([0 90]) 0176 subplot(223) 0177 h = show_fem(img); 0178 set(h,'linewidth',.1) 0179 view([90,0]) 0180 subplot(224) 0181 h = show_fem(img); 0182 set(h,'linewidth',.1) 0183 view([0 0]) 0184 end 0185 0186 function opt = parse_opt(fmdl,opt) 0187 minnode = min(fmdl.nodes); 0188 maxnode = max(fmdl.nodes); 0189 bb = maxnode-minnode; 0190 scale = min( bb(1:2) ./ [7/6 1]); % the default values below fit a model of these proportions best 0191 ctr = minnode + bb/2; 0192 0193 opt = set_default(opt, 'bkgnd_val', 1 ); 0194 opt = set_default(opt, 'lung_val' , .2); 0195 opt = set_default(opt, 'heart_val', 1.5); 0196 0197 opt = set_default(opt, 'left_lung_center', ctr + [ .24 0 -1/3]*scale); 0198 opt = set_default(opt, 'right_lung_center', ctr + [ -.24 0 -1/3]*scale); 0199 opt = set_default(opt, 'heart_center', ctr + [ 0.07 -1/6 0]*scale); 0200 opt = set_default(opt, 'diaphragm_center', ctr + [ 0 -1/4 -2/3]*scale); 0201 0202 opt = set_default(opt, 'heart_axes', [ 1/6 1/5 1/4 ]*scale); 0203 opt = set_default(opt, 'left_lung_axes' , [ 8/30 1/3 25/30]*scale); 0204 opt = set_default(opt, 'right_lung_axes', [ 8/30 1/3 25/30]*scale); 0205 opt = set_default(opt, 'diaphragm_axes', [22/30 19/30 2/5]*scale); 0206 end 0207 0208 function s = set_default(s, fname, defval) 0209 if ~isfield(s,fname) 0210 s.(fname) = defval; 0211 end 0212 end 0213 0214 0215 function do_unit_test 0216 mdl = ng_mk_ellip_models([400 180 150 10],4,10); 0217 img = mk_lung_image(mdl); 0218 subplot(231) 0219 show_fem(img); 0220 0221 % sclaing should have no effect 0222 mdl.nodes = 3*mdl.nodes; 0223 img = mk_lung_image(mdl); 0224 subplot(232) 0225 show_fem(img); 0226 0227 % shorter model should show a "slice" 0228 mdl = ng_mk_ellip_models([200 180 150 10],4,10); 0229 img = mk_lung_image(mdl); 0230 subplot(233) 0231 show_fem(img); 0232 0233 % it should still fit into the male torso 0234 mdl = mk_thorax_model('male'); 0235 img = mk_lung_image(mdl); 0236 subplot(234) 0237 show_fem(img); 0238 0239 % the female model seems to need adjustements 0240 mdl = mk_thorax_model('female'); % female thorax 0241 opt = mk_lung_image(mdl, 'options'); % 0242 corr = 20; 0243 opt.heart_center(2) = opt.heart_center(2) + corr; 0244 opt.left_lung_center(2) = opt.left_lung_center(2) + corr; 0245 opt.right_lung_center(2) = opt.right_lung_center(2) + corr; 0246 opt.diaphragm_center(2) = opt.diaphragm_center(2) + corr; 0247 subplot(235) 0248 % make a diagnostic plot to verify the organ definitions fit inside the 0249 % model (independent of model maxh) 0250 mk_lung_image(mdl,opt,'diagnostic'); 0251 % show_fem(img); 0252 0253 return 0254 0255 mdl = mk_thorax_model('grychtol2016a_male_thorax'); 0256 img = mk_lung_image(mdl); 0257 subplot(236) 0258 show_fem(img); 0259 0260 end