diff --git a/source/+bruker/brukerreader.p b/source/+bruker/brukerreader.p
index b59535f..7daf731 100644
Binary files a/source/+bruker/brukerreader.p and b/source/+bruker/brukerreader.p differ
diff --git a/source/+corelab/corelab.fig b/source/+corelab/corelab.fig
index cb5d91b..5816ff9 100644
Binary files a/source/+corelab/corelab.fig and b/source/+corelab/corelab.fig differ
diff --git a/source/+corelab/corelab.p b/source/+corelab/corelab.p
index f03f9a6..cf03752 100644
Binary files a/source/+corelab/corelab.p and b/source/+corelab/corelab.p differ
diff --git a/source/+ct/CTBoneSegmentation.p b/source/+ct/CTBoneSegmentation.p
deleted file mode 100644
index 46d91be..0000000
Binary files a/source/+ct/CTBoneSegmentation.p and /dev/null differ
diff --git a/source/+ct/CTLVSegmentation.p b/source/+ct/CTLVSegmentation.p
index e563869..42efbd5 100644
Binary files a/source/+ct/CTLVSegmentation.p and b/source/+ct/CTLVSegmentation.p differ
diff --git a/source/+ct/CTWholeHeartSegmentation.p b/source/+ct/CTWholeHeartSegmentation.p
deleted file mode 100644
index 6e279ae..0000000
Binary files a/source/+ct/CTWholeHeartSegmentation.p and /dev/null differ
diff --git a/source/+ct/WholeHeartCT.oldprototype b/source/+ct/WholeHeartCT.oldprototype
deleted file mode 100644
index 1cd445c..0000000
Binary files a/source/+ct/WholeHeartCT.oldprototype and /dev/null differ
diff --git a/source/+ct/WholeHeartIntensityMap.mat b/source/+ct/WholeHeartIntensityMap.mat
deleted file mode 100644
index 1a3d3ff..0000000
Binary files a/source/+ct/WholeHeartIntensityMap.mat and /dev/null differ
diff --git a/source/+ct/autogeneratesax.p b/source/+ct/autogeneratesax.p
new file mode 100644
index 0000000..06e5e99
Binary files /dev/null and b/source/+ct/autogeneratesax.p differ
diff --git a/source/+ct/coronaryOstiaSearch.p b/source/+ct/coronaryOstiaSearch.p
deleted file mode 100644
index 516441e..0000000
Binary files a/source/+ct/coronaryOstiaSearch.p and /dev/null differ
diff --git a/source/+ct/ctautocontrast.m b/source/+ct/ctautocontrast.m
index 35ae14a..913bc03 100644
--- a/source/+ct/ctautocontrast.m
+++ b/source/+ct/ctautocontrast.m
@@ -20,8 +20,6 @@ function autocontrastcardiac(no)
global SET NO DATA
-set(DATA.Handles.autocontrasticon,'state','off');
-
if nargin == 0
no = NO;
end
@@ -116,7 +114,12 @@ function autocontrastcardiac(no)
SET(no).IntensityMapping.Brightness=brightness;
%update image
-drawfunctions('drawcontrastimage',no);
+for p = find(DATA.ViewPanels==no)
+ DATA.ViewIM{p} = [];
+ drawfunctions('drawimages',p)
+ createfunctions('addcolorbar',p)
+end
+
myworkoff;
@@ -128,8 +131,6 @@ function autocontrastcardiac(no)
global SET DATA
-set(DATA.Handles.autocontrastallicon,'state','off');
-
h = mywaitbarstart(length(SET)*2,'Auto contrast in process',0,DATA.GUI.Segment);
for no = 1:length(SET)
h = mywaitbarupdate(h);
diff --git a/source/+ct/ctlicensecheck.p b/source/+ct/ctlicensecheck.p
index 39ac5c1..6ea07a6 100644
Binary files a/source/+ct/ctlicensecheck.p and b/source/+ct/ctlicensecheck.p differ
diff --git a/source/+ct/ctperfusion.p b/source/+ct/ctperfusion.p
index d2df797..727696a 100644
Binary files a/source/+ct/ctperfusion.p and b/source/+ct/ctperfusion.p differ
diff --git a/source/+ct/imagestacksct.p b/source/+ct/imagestacksct.p
index 7837de8..6028a18 100644
Binary files a/source/+ct/imagestacksct.p and b/source/+ct/imagestacksct.p differ
diff --git a/source/+ct/newfischerclassification.mat b/source/+ct/newfischerclassification.mat
deleted file mode 100644
index b8373e9..0000000
Binary files a/source/+ct/newfischerclassification.mat and /dev/null differ
diff --git a/source/+ct/showSegmentation.fig b/source/+ct/showSegmentation.fig
deleted file mode 100644
index 9f2979f..0000000
Binary files a/source/+ct/showSegmentation.fig and /dev/null differ
diff --git a/source/+ct/showSegmentation.m b/source/+ct/showSegmentation.m
deleted file mode 100644
index 060224c..0000000
--- a/source/+ct/showSegmentation.m
+++ /dev/null
@@ -1,836 +0,0 @@
-function showSegmentation(call,arg1,arg2)
-
-global setCell helpVar handles
-
-if nargin==0
- %open GUI
- figName=['+ct' filesep 'showSegmentation.fig'];
- fig=openfig(figName,'reuse');
- handles=guihandles(fig);
- handles.fig=fig;
-
- set(fig,'renderer','zbuffer')
-
- %Set keypress for entire GUI
- segment('recursekeypressfcn',handles.fig,@showSegmentationkeypressed);
-
- helpVar.XSize=setCell{helpVar.showLevel}.size(1);
- helpVar.YSize=setCell{helpVar.showLevel}.size(2);
- helpVar.ZSize=setCell{helpVar.showLevel}.size(3);
-
- helpVar.rslice = round(helpVar.ZSize/2);
- helpVar.gslice = round(helpVar.YSize/2);
- helpVar.bslice = round(helpVar.XSize/2);
-
- warning('off','MATLAB:contour:ConstantData'); %Ignore warning messages from contour.
-
- %Install icons
- try
- load('icons.mat','icon');
- catch
- myfailed('Critical error: Could not read icons.');
- return;
- end;
-
- mytoolbar = uitoolbar(handles.fig);
-
- %Selection icon
- props.ClickedCallback = 'ct.showSegmentation(''selecttool'')';
- props.ToolTip = 'Pointer tool.';
- props.CData = icon.selectslices;
- props.Tag = 'selecticon';
- props.separator = 'off';
- handles.selecticon = uitoggletool(mytoolbar,props);
-
- %zoom in icon
- props.ClickedCallback = 'ct.showSegmentation(''zoomin'')';
- props.ToolTip = 'Zoom in';
- props.CData = icon.zoomin;
- props.Tag = 'zoominicon';
- props.separator = 'off';
- handles.zoominicon = uitoggletool(mytoolbar,props);
-
- %zoom out icon
- props.ClickedCallback = 'ct.showSegmentation(''zoomout'')';
- props.ToolTip = 'Zoom out';
- props.CData = icon.zoomout;
- props.Tag = 'zoomouticon';
- props.separator = 'off';
- handles.zoomouticon = uitoggletool(mytoolbar,props);
-
- %refresh
- props.ClickedCallback = 'ct.showSegmentation(''refresh'')';
- props.ToolTip = 'Refresh image';
- props.CData = icon.refresh;
- props.Tag = 'refreshicon';
- props.separator = 'on';
- handles.refreshicon = uitoggletool(mytoolbar,props);
-
-
- %set default values
- showSegmentationDefault
- %set buttons default
- ct.showSegmentation('updatebuttons','default');
- %set sliders
- ct.showSegmentation('updatesliders');
- %update image
- ct.showSegmentation('update');
-
-else
- switch call
- case 'updatebuttons'
- switch arg1
- case 'CTWholeHeartSegmentation'
- set(handles.wholeheartpushbutton,'visible', 'on', 'enable', 'on');
- set(handles.coronaryostiapushbutton,'visible','off','enable', 'off');
- set(handles.bonesegmentationpushbutton,'visible','off','enable','off');
- set(handles.runoffpushbutton,'visible','off','enable','off');
- set(handles.carotidrenalpushbutton,'visible','off','enable','off');
- set(handles.bonethreshslider,'visible','off','enable','off');
- set(handles.bonethreshtext,'visible','off');
- case 'coronaryOstiaSearch'
- switch arg2
- case 'init'
- set(handles.wholeheartpushbutton,'visible', 'on', 'enable', 'off');
- set(handles.coronaryostiapushbutton,'visible','on','enable', 'off');
- case 'segmentation done'
- set(handles.wholeheartpushbutton,'visible', 'on', 'enable', 'on');
- set(handles.coronaryostiapushbutton,'visible','on','enable', 'on');
- end
- set(handles.bonesegmentationpushbutton,'visible','off','enable','off');
- set(handles.runoffpushbutton,'visible','off','enable','off');
- set(handles.carotidrenalpushbutton,'visible','off','enable','off');
- set(handles.bonethreshslider,'visible','off','enable','off');
- set(handles.bonethreshtext,'visible','off');
- case 'CTBoneSegmentation'
- set(handles.wholeheartpushbutton,'visible', 'off', 'enable', 'off');
- set(handles.coronaryostiapushbutton,'visible','off','enable', 'off');
- set(handles.bonesegmentationpushbutton,'visible','on','enable','on');
- set(handles.runoffpushbutton,'visible','off','enable','off');
- set(handles.carotidrenalpushbutton,'visible','off','enable','off');
- set(handles.bonethreshslider,'visible','on','enable','on');
- set(handles.bonethreshtext,'visible','on');
- set(handles.bonethreshslider,'min',-0.5,'max',1.5,'value',0.5,...
- 'sliderstep',[0.05 0.1]);
- case 'CTARunOff'
- set(handles.wholeheartpushbutton,'visible', 'off', 'enable', 'off');
- set(handles.coronaryostiapushbutton,'visible','off','enable', 'off');
- set(handles.bonesegmentationpushbutton,'visible','off','enable','off');
- set(handles.runoffpushbutton,'visible','on','enable','on');
- set(handles.carotidrenalpushbutton,'visible','off','enable','off');
- set(handles.bonethreshslider,'visible','off','enable','off');
- set(handles.bonethreshtext,'visible','off');
- case 'CTACarotidRenal'
- set(handles.wholeheartpushbutton,'visible', 'off', 'enable', 'off');
- set(handles.coronaryostiapushbutton,'visible','off','enable', 'off');
- set(handles.bonesegmentationpushbutton,'visible','off','enable','off');
- set(handles.runoffpushbutton,'visible','off','enable','off');
- set(handles.carotidrenalpushbutton,'visible','on','enable','on');
- set(handles.bonethreshslider,'visible','off','enable','off');
- set(handles.bonethreshtext,'visible','off');
- case 'default'
- ct.showSegmentation('updatebuttons','CTWholeHeartSegmentation');
- otherwise
- set(handles.wholeheartpushbutton,'visible', 'on', 'enable', 'off');
- set(handles.coronaryostiapushbutton,'visible','on','enable', 'off');
- set(handles.bonesegmentationpushbutton,'visible','on','enable','off');
- set(handles.runoffpushbutton,'visible','on','enable','off');
- set(handles.carotidrenalpushbutton,'visible','on','enable','off');
- set(handles.bonethreshslider,'visible','off','enable','off');
- set(handles.bonethreshtext,'visible','off');
- end
- case 'updatesliders'
- set(handles.rslider,'min',1,'max',helpVar.ZSize,'value',helpVar.ZSize-helpVar.rslice+1,...
- 'sliderstep',[1/helpVar.ZSize 3/helpVar.ZSize]);
- set(handles.gslider,'min',1,'max',helpVar.YSize,'value',helpVar.gslice,...
- 'sliderstep',[1/helpVar.YSize 3/helpVar.YSize]);
- set(handles.bslider,'min',1,'max',helpVar.XSize,'value',helpVar.bslice,...
- 'sliderstep',[1/helpVar.XSize 3/helpVar.XSize]);
- case 'slice'
- switch arg1
- case 'r'
- helpVar.rslice = max(min(helpVar.rslice-arg2,helpVar.ZSize),1);
- case 'g'
- helpVar.gslice = max(min(helpVar.gslice+arg2,helpVar.YSize),1);
- case 'b'
- helpVar.bslice = max(min(helpVar.bslice+arg2,helpVar.XSize),1);
- end;
- ct.showSegmentation('update');
- case 'rslider'
- helpVar.rslice = 1+helpVar.ZSize-min(helpVar.ZSize,max(round(mygetslider(handles.rslider)),1));
- set(handles.rslider,'Value',helpVar.ZSize-helpVar.rslice+1);
- ct.showSegmentation('rdraw');
- ct.showSegmentation('sdraw');
- ct.showSegmentation('lineupdate');
- case 'gslider'
- helpVar.gslice = min(helpVar.YSize,max(round(mygetslider(handles.gslider)),1));
- set(handles.gslider,'Value',helpVar.gslice);
- ct.showSegmentation('gdraw');
- ct.showSegmentation('lineupdate');
- case 'bslider'
- helpVar.bslice = min(helpVar.XSize,max(round(mygetslider(handles.bslider)),1));
- set(handles.bslider,'Value',helpVar.bslice);
- ct.showSegmentation('bdraw');
- ct.showSegmentation('lineupdate');
- case 'bonethreshslider'
- thresh=mygetslider(handles.bonethreshslider);
- ct.CTBoneSegmentation('adjustthreshhold',thresh);
- case 'overviewzoom'
- figure(12);
- handles.overviewaxes = gca;
- ct.showSegmentation('update');
- ct.showSegmentation('isosurface');
- axis off image;
- cameratoolbar(12);
- case 'isosurface'
- if isempty(setCell{helpVar.showLevel}.segmentation)
- myfailed('No segmentation exists');
- return;
- end
- fv = isosurface(double(...
- setCell{helpVar.showLevel}.segmentation),...
- 0.5);
-
- if get(handles.reducecheckbox,'value')
- fv = reducepatch(fv,0.2);
- end;
-
- %Flip in z-direction and xy
- fv.vertices(:,3) = (helpVar.ZSize+1)-fv.vertices(:,3);
- temp = fv.vertices(:,2);
- fv.vertices(:,2) = fv.vertices(:,1);
- fv.vertices(:,1) = temp;
-
- %--- Display
- hold(handles.overviewaxes,'on');
- h = patch(fv,'parent',handles.overviewaxes);
- hold(handles.overviewaxes,'off');
- set(h,'facecolor',[1 0 0],'edgecolor',[1 1 0],'facealpha',0.5);
- if not(get(handles.polygonscheckbox,'value'))
- set(h,'edgealpha',0);
- end;
- case 'update'
- ct.showSegmentation('rdraw');
- ct.showSegmentation('gdraw');
- ct.showSegmentation('bdraw');
-
- ct.showSegmentation('lineupdate');
- ct.showSegmentation('updatesliders');
- case 'selection'
- helpVar.ViewSelection = get(handles.selectioncheckbox,'value');
- ct.showSegmentation('update');
- case 'outline'
- helpVar.ViewOutline = get(handles.outlinecheckbox,'value');
- ct.showSegmentation('update');
- case 'mip'
- helpVar.ViewMIP = get(handles.mipcheckbox,'value');
- ct.showSegmentation('update');
- case 'lineupdate'
- set(handles.grline,'ydata',[helpVar.rslice helpVar.rslice]);
- set(handles.brline,'ydata',[helpVar.rslice helpVar.rslice]);
-
- set(handles.rgline,'xdata',[helpVar.gslice helpVar.gslice]);
- set(handles.bgline,'xdata',[helpVar.gslice helpVar.gslice]);
-
- set(handles.rbline,'ydata',[helpVar.bslice helpVar.bslice]);
- set(handles.gbline,'xdata',[helpVar.bslice helpVar.bslice]);
- case 'rdraw'
- %--- Red image
- handles.rimage = image(squeeze(setCell{helpVar.showLevel}.IM(:,:,helpVar.rslice)),'parent',handles.raxes);
-
- %Add objects
- hold(handles.raxes,'on');
- handles.rbline = plot(handles.raxes,[0 helpVar.YSize],[helpVar.bslice helpVar.bslice],'b-');
- handles.rgline = plot(handles.raxes,[helpVar.gslice helpVar.gslice],[0 helpVar.XSize],'g-');
- x1 = helpVar.RZoomState(1)+0.5;
- x2 = helpVar.RZoomState(2)-0.5;
- y1 = helpVar.RZoomState(3)+0.5;
- y2 = helpVar.RZoomState(4)-0.5;
- handles.rimagebox = plot(handles.raxes,[x1 x2 x2 x1 x1],[y1 y1 y2 y2 y1],'r-');
- set(handles.rimagebox,'linewidth',2);
-
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- [c,h] = contour(...
- handles.raxes,...
- double(squeeze(setCell{helpVar.showLevel}.segmentation(:,:,helpVar.rslice))),...
- [0.5 0.5]);
- set(h,'ButtonDownFcn','ct.showSegmentation(''click'',''r'')');
- children = get(h,'children');
- set(children,'edgecolor',[1 1 0]);
- if helpVar.ViewOutline
- set(children,'visible','on');
- else
- set(children,'visible','off');
- end;
- end
-
-
- %show landmarks
- if ~isempty(setCell{helpVar.showLevel}.landmarks.X)
- for loop=1:length(setCell{helpVar.showLevel}.landmarks.X)
- if round(setCell{helpVar.showLevel}.landmarks.Z(loop))==helpVar.rslice
- handles.pointp(loop) = plot(handles.raxes,...
- setCell{helpVar.showLevel}.landmarks.Y(loop),setCell{helpVar.showLevel}.landmarks.X(loop),'w+');
- handles.pointo(loop) = plot(handles.raxes,...
- setCell{helpVar.showLevel}.landmarks.Y(loop),setCell{helpVar.showLevel}.landmarks.X(loop),'wo');
- handles.pointtext(loop) = text(...
- 'position',[setCell{helpVar.showLevel}.landmarks.Y(loop)+2 setCell{helpVar.showLevel}.landmarks.X(loop)],...
- 'string',setCell{helpVar.showLevel}.landmarks.Label{loop},...
- 'parent',handles.raxes,...
- 'color',[1 1 1]);
- end
- end
- end
-
- hold(handles.raxes,'off');
-
- %Aspect ratio
- axis(handles.raxes,'off');
- set(handles.raxes,'Clim',[0 1],'dataaspectratio',...
- [1/setCell{helpVar.showLevel}.resolution(2) ...
- 1/setCell{helpVar.showLevel}.resolution(1) 1]);
-
- set(handles.rimage,'ButtonDownFcn','ct.showSegmentation(''click'',''r'')');
- set([handles.rbline handles.rgline],'ButtonDownFcn','ct.showSegmentation(''click'',''r'')');
- ct.showSegmentation('rupdate');
-
- case 'gdraw'
- %--- Green image
- temp = squeeze(setCell{helpVar.showLevel}.IM(:,helpVar.gslice,:))';
- handles.gimage = image(temp,'parent',handles.gaxes);
-
- %Add objects
- hold(handles.gaxes,'on');
-
- handles.grline = plot(handles.gaxes,[0 helpVar.YSize],[helpVar.rslice helpVar.rslice],'r-');
- handles.gbline = plot(handles.gaxes,[helpVar.bslice helpVar.bslice],[0 helpVar.ZSize],'b-');
-
- x1 = helpVar.GZoomState(1)+0.5;
- x2 = helpVar.GZoomState(2)-0.5;
- y1 = helpVar.GZoomState(3)+0.5;
- y2 = helpVar.GZoomState(4)-0.5;
- handles.gimagebox = plot(handles.gaxes,[x1 x2 x2 x1 x1],[y1 y1 y2 y2 y1],'g-');
- set(handles.gimagebox,'linewidth',2);
-
- set(handles.gaxes,'Clim',[0 1],'dataaspectratio',...
- [1/setCell{helpVar.showLevel}.resolution(2) ...
- 1/setCell{helpVar.showLevel}.resolution(3) 1]);
-
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- %show segmentation
- [c,h] = contour(...
- handles.gaxes,...
- double(squeeze(setCell{helpVar.showLevel}.segmentation(:,helpVar.gslice,:)))',...
- [0.5 0.5]);
- set(h,'ButtonDownFcn','ct.showSegmentation(''click'',''g'')');
- children = get(h,'children');
- set(children,'edgecolor',[1 1 0]);
- if helpVar.ViewOutline
- set(children,'visible','on');
- else
- set(children,'visible','off');
- end;
- end
-
-
- %show landmarks
- if ~isempty(setCell{helpVar.showLevel}.landmarks.X)
- for loop=1:length(setCell{helpVar.showLevel}.landmarks.X)
- if round(setCell{helpVar.showLevel}.landmarks.Y(loop))==helpVar.gslice
- handles.pointp(loop) = plot(handles.gaxes,...
- setCell{helpVar.showLevel}.landmarks.X(loop),setCell{helpVar.showLevel}.landmarks.Z(loop),'w+');
- handles.pointo(loop) = plot(handles.gaxes,...
- setCell{helpVar.showLevel}.landmarks.X(loop),setCell{helpVar.showLevel}.landmarks.Z(loop),'wo');
- handles.pointtext(loop) = text(...
- 'position',[setCell{helpVar.showLevel}.landmarks.X(loop)+2 setCell{helpVar.showLevel}.landmarks.Z(loop)],...
- 'string',setCell{helpVar.showLevel}.landmarks.Label{loop},...
- 'parent',handles.gaxes,...
- 'color',[1 1 1]);
- end
- end
- end
-
- hold(handles.gaxes,'off');
- axis(handles.gaxes,'off');
- set(handles.gimage,'ButtonDownFcn','ct.showSegmentation(''click'',''g'')');
- set([handles.grline handles.gbline],'ButtonDownFcn','ct.showSegmentation(''click'',''g'')');
-
- set(handles.gaxes,'Clim',[0 1],'dataaspectratio',...
- [1/setCell{helpVar.showLevel}.resolution(2) ...
- 1/setCell{helpVar.showLevel}.resolution(3) 1]);
- ct.showSegmentation('gupdate');
- case 'bdraw'
-
- %--- Blue image
- temp = squeeze(setCell{helpVar.showLevel}.IM(helpVar.bslice,:,:))';
- handles.bimage = image(temp,'parent',handles.baxes);
-
- %Add objects
- hold(handles.baxes,'on');
- handles.brline = plot(handles.baxes,[0 helpVar.XSize],[helpVar.rslice helpVar.rslice],'r-');
- handles.bgline = plot(handles.baxes,[helpVar.gslice helpVar.gslice],[0 helpVar.ZSize],'g-');
- x1 = helpVar.BZoomState(1)+0.5;
- x2 = helpVar.BZoomState(2)-0.5;
- y1 = helpVar.BZoomState(3)+0.5;
- y2 = helpVar.BZoomState(4)-0.5;
- handles.bimagebox = plot(handles.baxes,[x1 x2 x2 x1 x1],[y1 y1 y2 y2 y1],'b-');
- set(handles.bimagebox,'linewidth',2);
-
- %Add objects
- hold(handles.raxes,'on');
- handles.rbline = plot(handles.raxes,[0 helpVar.YSize],[helpVar.bslice helpVar.bslice],'b-');
- handles.rgline = plot(handles.raxes,[helpVar.gslice helpVar.gslice],[0 helpVar.XSize],'g-');
- x1 = helpVar.RZoomState(1)+0.5;
- x2 = helpVar.RZoomState(2)-0.5;
- y1 = helpVar.RZoomState(3)+0.5;
- y2 = helpVar.RZoomState(4)-0.5;
- handles.rimagebox = plot(handles.raxes,[x1 x2 x2 x1 x1],[y1 y1 y2 y2 y1],'r-');
- set(handles.rimagebox,'linewidth',2);
-
- %show segmentation
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- [c,h] = contour(...
- handles.baxes,...
- double(squeeze(setCell{helpVar.showLevel}.segmentation(helpVar.bslice,:,:)))',...
- [0.5 0.5]);
- set(h,'ButtonDownFcn','ct.showSegmentation(''click'',''b'')');
- children = get(h,'children');
- set(children,'edgecolor',[1 1 0]);
- if helpVar.ViewOutline
- set(children,'visible','on');
- else
- set(children,'visible','off');
- end;
- end
-
- %show landmarks
- if ~isempty(setCell{helpVar.showLevel}.landmarks.X)
- for loop=1:length(setCell{helpVar.showLevel}.landmarks.X)
- if round(setCell{helpVar.showLevel}.landmarks.X(loop))==helpVar.bslice
- handles.pointp(loop) = plot(handles.baxes,...
- setCell{helpVar.showLevel}.landmarks.Y(loop),setCell{helpVar.showLevel}.landmarks.Z(loop),'w+');
- handles.pointo(loop) = plot(handles.baxes,...
- setCell{helpVar.showLevel}.landmarks.Y(loop),setCell{helpVar.showLevel}.landmarks.Z(loop),'wo');
- handles.pointtext(loop) = text(...
- 'position',[setCell{helpVar.showLevel}.landmarks.Y(loop)+2 setCell{helpVar.showLevel}.landmarks.Z(loop)],...
- 'string',setCell{helpVar.showLevel}.landmarks.Label{loop},...
- 'parent',handles.baxes,...
- 'color',[1 1 1]);
- end
- end
- end
-
- hold(handles.baxes,'off');
- axis(handles.baxes,'off');
- set(handles.bimage,'ButtonDownFcn','ct.showSegmentation(''click'',''b'')');
- set([handles.brline handles.bgline],'ButtonDownFcn','ct.showSegmentation(''click'',''b'')');
-
- set(handles.baxes,'Clim',[0 1],'dataaspectratio',...
- [1/setCell{helpVar.showLevel}.resolution(1) ...
- 1/setCell{helpVar.showLevel}.resolution(3) 1]);
- ct.showSegmentation('bupdate');
-
- case 'rupdate'
- %--- Update 'red' image
- if helpVar.ViewMIP
- %MIP
- temp = squeeze(max(setCell{helpVar.showLevel}.IM,[],3));
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- overlaySegmentation = squeeze(max(setCell{helpVar.showLevel}.segmentation,[],3))>0.5;
- else
- overlaySegmentation=[];
- end
- else
- %Slice
- temp = squeeze(setCell{helpVar.showLevel}.IM(:,:,helpVar.rslice));
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- overlaySegmentation = squeeze(setCell{helpVar.showLevel}.segmentation(:,:,helpVar.rslice))>0.5;
- else
- overlaySegmentation=[];
- end
- end;
- %Update image
-
- set(handles.rimage,'cdata',...
- remapandoverlaySegmentation(temp,overlaySegmentation));
-
- %zoom state
- if isempty(helpVar.RZoomState)
- helpVar.RZoomState = [0.5;size(temp,2)-0.5;0.5;size(temp,1)-0.5];
- end;
- set(handles.raxes,...
- 'xlim',helpVar.RZoomState(1:2),...
- 'ylim',helpVar.RZoomState(3:4));
-
- x1 = helpVar.RZoomState(1);
- x2 = helpVar.RZoomState(2);
- y1 = helpVar.RZoomState(3);
- y2 = helpVar.RZoomState(4);
- set(handles.rimagebox,'xdata',[x1 x2 x2 x1 x1],'ydata',[y1 y1 y2 y2 y1]);
-
- case 'gupdate'
- %--- Green image
- if helpVar.ViewMIP
- %MIP
- temp = squeeze(max(setCell{helpVar.showLevel}.IM,[],2))';
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- overlaySegmentation = squeeze(max(setCell{helpVar.showLevel}.segmentation,[],2))'>0.5;
- else
- overlaySegmentation=[];
- end
- else
- %Slice
- temp = squeeze(setCell{helpVar.showLevel}.IM(:,helpVar.gslice,:))';
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- overlaySegmentation = squeeze(setCell{helpVar.showLevel}.segmentation(:,helpVar.gslice,:))'>0.5;
- else
- overlaySegmentation=[];
- end
- end;
- %Update image
- set(handles.gimage,'cdata',...
- remapandoverlaySegmentation(temp,overlaySegmentation));
-
- %zoom state
- if isempty(helpVar.GZoomState)
- helpVar.GZoomState = [0.5;size(temp,2)-0.5;0.5;size(temp,1)-0.5];
- end;
- set(handles.gaxes,...
- 'xlim',helpVar.GZoomState(1:2),...
- 'ylim',helpVar.GZoomState(3:4));
-
- x1 = helpVar.GZoomState(1);
- x2 = helpVar.GZoomState(2);
- y1 = helpVar.GZoomState(3);
- y2 = helpVar.GZoomState(4);
- set(handles.gimagebox,'xdata',[x1 x2 x2 x1 x1],'ydata',[y1 y1 y2 y2 y1]);
-
- case 'bupdate'
- if helpVar.ViewMIP
- %MIP
- temp = squeeze(max(setCell{helpVar.showLevel}.IM,[],1))';
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- overlaySegmentation = squeeze(max(setCell{helpVar.showLevel}.segmentation,[],1))'>0.5;
- else
- overlaySegmentation=[];
- end
- else
- %Slice
- temp = squeeze(setCell{helpVar.showLevel}.IM(helpVar.bslice,:,:))';
- if ~isempty(setCell{helpVar.showLevel}.segmentation)
- overlaySegmentation = squeeze(setCell{helpVar.showLevel}.segmentation(helpVar.bslice,:,:))'>0.5;
- else
- overlaySegmentation=[];
- end
- end;
- %Update image
- set(handles.bimage,'cdata',...
- remapandoverlaySegmentation(temp,overlaySegmentation));
- %zoom state
- if isempty(helpVar.BZoomState)
- helpVar.BZoomState = [0.5;size(temp,2)-0.5;0.5;size(temp,1)-0.5];
- end;
- set(handles.baxes,...
- 'xlim',helpVar.BZoomState(1:2),...
- 'ylim',helpVar.BZoomState(3:4));
-
- x1 = helpVar.BZoomState(1);
- x2 = helpVar.BZoomState(2);
- y1 = helpVar.BZoomState(3);
- y2 = helpVar.BZoomState(4);
- set(handles.bimagebox,'xdata',[x1 x2 x2 x1 x1],'ydata',[y1 y1 y2 y2 y1]);
-
- case 'volume'
- if isempty(setCell{helpVar.showLevel}.segmentation)
- myfailed('No segmentation exists');
- return
- end
- num=sum(sum(sum(setCell{helpVar.showLevel}.segmentation>0.5)));
- voxel = cumprod(setCell{helpVar.showLevel}.resolution);
- num = num*voxel(end);
- num = num/1000; %convert to ml == cm^3
-
- msgbox(dprintf('Totalvolume of object is %0.5g [ml]',num));
- case 'zoomin'
- set(handles.zoominicon,'state','off');
- helpVar.Zoom = helpVar.Zoom*1.2;
- helpVar.RZoomState = zoomhelper(helpVar.RZoomState,1.2,...
- [helpVar.YSize helpVar.XSize]);
- helpVar.GZoomState = zoomhelper(helpVar.GZoomState,1.2,...
- [helpVar.XSize helpVar.ZSize]);
- helpVar.BZoomState = zoomhelper(helpVar.BZoomState,1.2,...
- [helpVar.YSize helpVar.ZSize]);
-
- ct.showSegmentation('rupdate');
- ct.showSegmentation('gupdate');
- ct.showSegmentation('bupdate');
- case 'zoomout'
- set(handles.zoomouticon,'state','off');
- helpVar.Zoom = helpVar.Zoom/1.2;
- helpVar.Zoom = helpVar.Zoom*1.2;
- helpVar.RZoomState = zoomhelper(helpVar.RZoomState,1/1.2,[helpVar.YSize helpVar.XSize]);
- helpVar.GZoomState = zoomhelper(helpVar.GZoomState,1/1.2,[helpVar.XSize helpVar.ZSize]);
- helpVar.BZoomState = zoomhelper(helpVar.BZoomState,1/1.2,[helpVar.YSize helpVar.ZSize]);
-
- ct.showSegmentation('rupdate');
- ct.showSegmentation('gupdate');
- ct.showSegmentation('bupdate');
- case 'selecttool'
- helpVar.CurrentTool = 'select';
- ct.showSegmentation('update');
- case 'click'
- %Called when mouse pressed
- [x,y] = mygetcurrentpoint(gca);
-
- type = get(gcf,'SelectionType');
- switch helpVar.CurrentTool
- case 'select'
- %--- Selection tool
- switch type
- case 'normal'
- %Mark pen/window
- helpVar.pencolor = arg1;
- selectmotion; %Call once to update
-
- %Start selection tool if kept down
- set(gcf,'WindowButtonMotionFcn','ct.showSegmentation(''selectmotion'')');
- set(gcf,'WindowButtonUpFcn','ct.showSegmentation(''selectbuttonup'')');
- case 'extend'
- %Start paning tool
- helpVar.pencolor = arg1;
- set(gcf,'WindowButtonMotionFcn','ct.showSegmentation(''panmotion'')');
- set(gcf,'WindowButtonUpFcn','ct.showSegmentation(''panbuttonup'')');
- end;
-
- end; %switch clause
- case 'refresh'
- set(handles.refreshicon,'state','off');
- helpVar.RZoomState = [0.5 helpVar.XSize-0.5 0.5 helpVar.YSize-0.5];
- helpVar.GZoomState = [0.5 helpVar.YSize-0.5 0.5 helpVar.ZSize-0.5];
- helpVar.BZoomState = [0.5 helpVar.XSize-0.5 0.5 helpVar.ZSize-0.5];
- helpVar.LevelSet.Zoom = 1;
- ct.showSegmentation('update');
- end
-end
-
-%---------------------------------------
-function showSegmentationkeypressed(fignum,evnt)
-%---------------------------------------
-global setCell helpVar
-
-key = getkey(evnt);
-
-switch key
- case 'z'
- %Zoom in (z)
- ct.showSegmentation('zoomin');
- case 'x'
- %Zoom out (x)
- ct.showSegmentation('zoomout');
- case 'uparrow'
- switch helpVar.pencolor
- case 'r'
- ct.showSegmentation('slice','r',1)
- case 'g'
- ct.showSegmentation('slice','g',1)
- case 'b'
- ct.showSegmentation('slice','b',1)
- end
- case 'downarrow'
- switch helpVar.pencolor
- case 'r'
- ct.showSegmentation('slice','r',-1)
- case 'g'
- ct.showSegmentation('slice','g',-1)
- case 'b'
- ct.showSegmentation('slice','b',-1)
- end
-end;
-
-%------------------------------------------------------------------
-function im = remapandoverlaySegmentation(temp,overlaySegmentation)
-%------------------------------------------------------------------
-global setCell helpVar
-
-%Remap to correct colorscale and add overlay if user wants that.
-
-%Remap data
-if isequal(helpVar.ViewIm,'magnitude')
- tempr = calcfunctions('remapuint8',temp);
- tempg = tempr;
- tempb = tempr;
-else
- temp = temp/4+0.5;
- tempr = segment('remap',temp,helpVar.Colormap(:,1));
- tempg = segment('remap',temp,helpVar.Colormap(:,2));
- tempb = segment('remap',temp,helpVar.Colormap(:,3));
-end;
-%Add overlay
-if helpVar.ViewSelection
- tempr(overlaySegmentation)=1;
- %tempg(overlaybw)=0;
- %tempb(overlaybw)=0; %red
-end;
-im = cat(3,tempr,tempg,tempb);
-
-%-------------------------------
-function showSegmentationDefault
-%-------------------------------
-global helpVar setCell
-
-helpVar.pencolor = ''; %contains r,g,b depending which window drawing in
-helpVar.RZoomState = [0.5 helpVar.XSize-0.5 0.5 helpVar.YSize-0.5];
-helpVar.GZoomState = [0.5 helpVar.YSize-0.5 0.5 helpVar.ZSize-0.5];
-helpVar.BZoomState = [0.5 helpVar.XSize-0.5 0.5 helpVar.ZSize-0.5];
-helpVar.Zoom = 1;
-helpVar.CurrentTool = 'select';
-helpVar.ViewIm = 'magnitude'; %can also be speed
-helpVar.ViewMIP = false; %view mip image
-helpVar.ViewInteraction = true; %View manual interaction
-helpVar.ViewSelection = false; %View selection
-helpVar.ViewOutline = true; %View outline
-
-%-----------------------------------------------------
-function [zoomstate] = zoomhelper(zoomstate,f,sz)
-%-----------------------------------------------------
-%imagesize
-xsize=sz(1);
-ysize=sz(2);
-%Get old position
-temp = zoomstate;
-oldxspan=temp(2)-temp(1);
-oldyspan=temp(4)-temp(3);
-
-xlim = [...
- 0.5*(temp(1)+temp(2))-0.5*(temp(2)-temp(1))/f ...
- 0.5*(temp(1)+temp(2))+0.5*(temp(2)-temp(1))/f];
-%f = f*0.5;
-ylim = [...
- 0.5*(temp(3)+temp(4))-0.5*(temp(4)-temp(3))/f ...
- 0.5*(temp(3)+temp(4))+0.5*(temp(4)-temp(3))/f];
-
-xspan=(xlim(2)-xlim(1));
-yspan=(ylim(2)-ylim(1));
-if f>1
- if xsize>ysize
- if xspan>oldyspan
- ylim=[0.5 ysize-0.5];
- elseif oldyspan>xspan
- ylim=[0.5*(temp(3)+temp(4)) - 0.5*(xlim(2)-xlim(1))...
- 0.5*(temp(3)+temp(4)) + 0.5*(xlim(2)-xlim(1))];
- end
- else
- if yspan>oldxspan
- xlim=[0.5 xsize-0.5];
- elseif oldxspan>yspan
- xlim=[0.5*(temp(1)+temp(2)) - 0.5*(ylim(2)-ylim(1))...
- 0.5*(temp(1)+temp(2)) + 0.5*(ylim(2)-ylim(1))];
- end
- end
-else
- if xsize>ysize
- if xspan<=xsize
- if oldxspan>yspan || yspan>=ysize
- ylim=[0.5 ysize-0.5];
- elseif yspan>oldxspan
- ylim=[0.5*(temp(3)+temp(4)) - 0.5*(xlim(2)-xlim(1))...
- 0.5*(temp(3)+temp(4)) + 0.5*(xlim(2)-xlim(1))];
- end
- end
- else
- if yspan<=ysize
- if oldyspan>xspan ||xspan>=xsize
- xlim=[0.5 xsize-0.5];
- elseif xspan>oldyspan
- xlim=[0.5*(temp(1)+temp(2)) - 0.5*(ylim(2)-ylim(1))...
- 0.5*(temp(1)+temp(2)) + 0.5*(ylim(2)-ylim(1))];
- end
- end
- end
-end
-
-zoomstate = [xlim(:);ylim(:)];
-%------------------------------
-function selectbuttonup
-%------------------------------
-
-set(gcf,'WindowButtonMotionFcn','');
-set(gcf,'WindowButtonUpFcn','');
-ct.showSegmentation('update');
-
-%----------------------------
-function selectmotion
-%----------------------------
-global helpVar
-%rewritten to be able to use in timeresolve volumes (JS)
-
-[x,y] = mygetcurrentpoint(gca);
-
-
-switch helpVar.pencolor
- case 'r'
- helpVar.gslice = round(x);
- helpVar.bslice = round(y);
- case 'g'
- helpVar.bslice = round(x);
- helpVar.rslice = round(y);
- case 'b'
- helpVar.gslice = round(x);
- helpVar.rslice = round(y);
-end;
-
-%Move the line
-ct.showSegmentation('update')
-
-
-%---------------------------
-function panbuttonup
-%---------------------------
-global helpVar
-
-test='i panbuttonup'
-
-set(gcf,'WindowButtonMotionFcn','');
-set(gcf,'WindowButtonUpFcn','');
-
-ax = gca;
-xlim = get(ax,'xlim');
-ylim = get(ax,'ylim');
-
-switch helpVar.pencolor
- case 'r'
- helpVar.RZoomState = [xlim ylim];
- case 'g'
- helpVar.GZoomState = [xlim ylim];
- case 'b'
- helpVar.BZoomState = [xlim ylim];
-end;
-ct.showSegmentation('update');
-panmotion('reset'); %Reset for next time
-
-%--------------------------------
-function panmotion(reset)
-%--------------------------------
-persistent startpos
-
-test='i panmotion'
-
-if nargin==1
- startpos = [];
- return;
-end;
-
-%Get mouse position
-[p(1),p(2)] = mygetcurrentpoint(gca);
-
-if isempty(startpos)
- startpos = p;
-end;
-
-xlim = get(gca,'xlim');
-ylim = get(gca,'ylim');
-set(gca,...
- 'xlim',xlim+startpos(1)-p(1),...
- 'ylim',ylim+startpos(2)-p(2));
-
-
diff --git a/source/+ct/whichstackct.fig b/source/+ct/whichstackct.fig
deleted file mode 100644
index 91d1ec7..0000000
Binary files a/source/+ct/whichstackct.fig and /dev/null differ
diff --git a/source/+perfusion/perfusion.fig b/source/+perfusion/perfusion.fig
index 96cba57..d05df1f 100644
Binary files a/source/+perfusion/perfusion.fig and b/source/+perfusion/perfusion.fig differ
diff --git a/source/+perfusion/perfusion.p b/source/+perfusion/perfusion.p
index 4192486..4d7d9da 100644
Binary files a/source/+perfusion/perfusion.p and b/source/+perfusion/perfusion.p differ
diff --git a/source/+perfusion/perfusionscoring.fig b/source/+perfusion/perfusionscoring.fig
index 6706538..8f9cf7f 100644
Binary files a/source/+perfusion/perfusionscoring.fig and b/source/+perfusion/perfusionscoring.fig differ
diff --git a/source/+perfusion/perfusionscoring.m b/source/+perfusion/perfusionscoring.m
deleted file mode 100644
index 96dfb20..0000000
--- a/source/+perfusion/perfusionscoring.m
+++ /dev/null
@@ -1,1695 +0,0 @@
-function varargout = perfusionscoring(varargin)
-%GUI for fast MR perfusion analysis
-macro_helper(varargin{:});
-if nargin == 0 || isempty(varargin{1})
- varargin{1} = 'init';
-end
-[varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
-
-%------------
-function init %#ok
-%------------
-%Initiate GUI
-global DATA SET
-
-
-% Add no and scoringedit array to mygui properties
-allnos = 1:numel(SET);
-stressnos = find(strcmp({SET.ImageType},'Perfusion Stress Aligned'));
-if isempty(stressnos)
- stressnos = find(strcmp({SET.ImageType},'Perfusion Stress'));
- hasalignedstress = false;
-else
- hasalignedstress = true;
-end
-
-restnos = find(strcmp({SET.ImageType},'Perfusion Rest Aligned'));
-if isempty(restnos)
- restnos = find(strcmp({SET.ImageType},'Perfusion Rest'));
- hasalignedrest = false;
-else
- hasalignedrest = true;
-end
-
-restonly = false;
-stressonly = false;
-if hasalignedstress && hasalignedrest
-elseif hasalignedstress
- if yesno(['Found only Perfusion Stress Aligned image stack. Proceed ' ...
- 'using only one stack for perfusion analysis?'])
- stressonly = true;
- else
- return
- end
-
-
-elseif hasalignedrest
- if yesno(['Found only Perfusion Rest Aligned image stack. Proceed ' ...
- 'using only one stack for perfusion analysis?'])
- %analysed = true;
- restonly = true;
- %stressnos = restnos;
- else
- return
- end
-end
-
-scarnos = findfunctions('findscarshortaxisno');
-
-if (numel(restnos) ~= 1 || numel(stressnos) ~= 1)
- if isempty(restnos) && isempty(stressnos)
- myfailed(['Could not find either of stress/rest image stacks. Please ' ...
- 'set image description of two stacks to Perfusion Stress and ' ...
- 'Perfusion Rest before launching Perfusion module']);
- return
- elseif isempty(restnos) && ~hasalignedstress
- if yesno(['Found only Perfusion Stress image stack. Proceed ' ...
- 'using only one stack for perfusion analysis?'])
- %restnos = stressnos;
- stressonly = true;
- else
- return
- end
- elseif isempty(stressnos) && ~hasalignedrest
- if yesno(['Found only Perfusion Rest image stack. Proceed ' ...
- 'using only one stack for perfusion analysis?'])
- %stressnos = restnos;
- restonly = true;
- else
- return
- end
- else %none is empty
- mywarning(['Found more than one rest or stress image stack. ' ...
- 'Taking first (arbitrary decision).']);
- end
-end
-
-DATA.GUI.PerfusionScoring = mygui('+perfusion/perfusionscoring.fig');
-gui=DATA.GUI.PerfusionScoring;
-gui.currenttag='stress';
-gui.stressonly = stressonly;
-gui.restonly = restonly;
-gui.hidelv=0;
-
-
-if stressonly
- set(gui.handles.stresstimebaraxes,'visible','on')
-elseif restonly
- set(gui.handles.resttimebaraxes,'visible','on')
-else
- set(gui.handles.stresstimebaraxes,'visible','on')
- set(gui.handles.resttimebaraxes,'visible','on')
-end
-
-if ~isempty(stressnos)
- gui.stressno = stressnos(1);
-else
- gui.stressno = [];
-end
-if ~isempty(restnos)
- gui.restno = restnos(1);
-else
- gui.restno = [];
-end
-
-if ~isempty(scarnos)
- gui.scarno = scarnos(1);
-else
- gui.scarno = [];
- set(gui.handles.scaraxes, 'Visible', 'off')
-end
-
-%Determine which slices to use
-inds=[gui.stressno, gui.restno];
-[~,nslicestack]=min([SET(inds).ZSize]);
-nslicestack = inds(nslicestack);
-gui.stressslices=[];
-gui.restslices=[];
-gui.scarslices=[];
-
-if gui.stressonly
- gui.stressslices=1:SET(gui.stressno).ZSize;
-
- gui.mrest = zeros(24,4);
- if isfield(SET(gui.stressno).PerfusionScoring,'mstress') && ~isempty(SET(gui.stressno).PerfusionScoring.mstress)
- gui.mstress = SET(gui.stressno).PerfusionScoring.mstress;
- else
- gui.mstress = zeros(24,4);
- end
-
-elseif gui.restonly;
- gui.restslices=1:SET(gui.restno).ZSize;
-
- gui.mstress = zeros(24,4);
-
- if isfield(SET(gui.restno).PerfusionScoring,'mrest') && ~isempty(SET(gui.restno).PerfusionScoring.mrest)
- gui.mrest = SET(gui.restno).PerfusionScoring.mrest;
- else
- gui.mrest = zeros(24,4);
- end
-
-else
- gui.stressslices=1:SET(nslicestack).ZSize;
- gui.restslices=1:SET(nslicestack).ZSize;
-
- [gui.stressslices,~,~,~,~,~] = segmentation('findmatchingslices', ...
- nslicestack,gui.stressno,0,0,0,0,0,0);
- [gui.restslices,~,~,~,~,~] = segmentation('findmatchingslices', ...
- nslicestack,gui.restno,0,0,0,0,0,0);
-
- if isfield(SET(gui.stressno).PerfusionScoring,'mstress') && ~isempty(SET(gui.stressno).PerfusionScoring.mstress)
- gui.mstress = SET(gui.stressno).PerfusionScoring.mstress;
- else
- gui.mstress = zeros(24,4);
- end
-
- if isfield(SET(gui.restno).PerfusionScoring,'mrest') && ~isempty(SET(gui.restno).PerfusionScoring.mrest)
- gui.mrest = SET(gui.restno).PerfusionScoring.mrest;
- else
- gui.mrest = zeros(24,4);
- end
-
-end
-
-if ~isempty(gui.scarno)
- [gui.scarslices,~,~,~,~,~] = segmentation('findmatchingslices', ...
- nslicestack,gui.scarno,0,0,0,0,0,0);
-end
-
-if ~isrow(gui.stressslices)
- gui.stressslices=gui.stressslices';
-end
-if ~isrow(gui.restslices)
- gui.restslices=gui.restslices';
-end
-if ~isrow(gui.scarslices)
- gui.scarslices=gui.scarslices';
-end
-
-if ~isempty(gui.scarno)
- if isfield(SET(gui.scarno).PerfusionScoring,'mscar') && ~isempty(SET(gui.scarno).PerfusionScoring.mscar)
- gui.mscar=SET(gui.scarno).PerfusionScoring.mscar;
- else
- gui.mscar = zeros(24,4);
- end
-else
- gui.mscar = zeros(24,4);
-end
-
-gui.mdiff = gui.mstress-gui.mrest;
-
-fcn = @(hObject,eventdata)perfusion.perfusionscoring('timebaraxes_ButtonDownFcn',hObject,eventdata);
-set(gui.fig,'WindowButtonDownFcn',fcn);
-
-segment('recursekeypressfcn',gui.fig,@(hObject,eventdata)perfusion.perfusionscoring('keypress_Callback',eventdata))
-load('newicons.mat','newicons')
-
-gui.Icons=newicons;
-gui.iconholder = myiconplaceholder(gui.handles.iconaxes,0,1,gui.fig);
-initiconholder;
-
-%indent autozoom
-indent(gui.iconholder,'autozoom',0);
-
-% %estimate rotation;
-% impos1 = SET(gui.stressno).ImagePosition;
-% impos2 = SET(gui.restno).ImagePosition;
-% imo1 = SET(gui.stressno).ImageOrientation(1:3);
-% imo2 = SET(gui.restno).ImageOrientation(1:3);
-%
-% theta = acos(imo1/norm(imo1)*imo2'/norm(imo2))/pi*180;
-%
-% im1 = SET(gui.stressno).IM(:,:,1,1);
-% im2 = SET(gui.restno).IM(:,:,1,1);
-% im3 = SET(gui.scarno).IM(:,:,1,1);
-
-% fig = figure;
-% subplot(121)
-% imagesc(im1);
-% subplot(122)
-% imagesc(imrotate(im2,rad))
- gui.autozoom=1;
-
-set(gui.fig,'WindowButtonMotionFcn','perfusion.perfusionscoring(''motionfunc'')');
-gui.resttf=1;
-gui.stresstf=1;
-gui.scartf=1;
-gui.restn=[];
-gui.stressn=[];
-gui.scarn=[];
-%gui.cinetf=1;
-
-if ~isempty(gui.restno)
- gui.restn=SET(gui.restno).TSize;
-end
-if ~isempty(gui.stressno)
- gui.stressn=SET(gui.stressno).TSize;
-end
-if ~isempty(gui.scarno)
- gui.scarn=SET(gui.scarno).TSize;
-end
-% if ~isempty(gui.cineno)
-% gui.cinen=SET(gui.cineno).TSize;
-% end
-
-%gui.cineplay=0;
-gui.restplay=0;
-gui.stressplay=0;
-gui.play=0;
-
-% for type={'stress','rest','scar'}
-% generateimages(type{1});
-% end
-
-
-%Initiate imageaxis and timebar
-for imname = {'stress','rest'}
- autozoom(imname{1});
- generateimages(imname{1});
- initimageaxis(imname{:});
- inittimebar(imname{1})
- settimeframe('currenttime',1,imname{1})
- %inittimebar(imname{:},analysed);
-end
-
-autozoom('scar');
-generateimages('scar');
-initimageaxis('scar');
-generatebullseye('stress')
-generatebullseye('rest')
-%generatebullseye('scar')
-generatebullseye('diff')
-
-% for type={'Stress','Rest'}
-% title(gui.handles.(['bullseyeaxes',lower(type{1})]),['\fontsize{14}',type{1}])
-% end
-% title(gui.handles.diffaxes,['\fontsize{14}','Diff'])
-
-save2set
-
-
-%---------------------------
-function generateimages(type)
-%---------------------------
-
-global SET DATA
-gui = DATA.GUI.PerfusionScoring;
-no = gui.([type,'no']);
-if isempty(no)
- return;
-end
-
-
-xsz=SET(no).XSize;
-ysz=SET(no).YSize;
-T = gui.([type,'n']);
-slices = gui.([type,'slices']);
-%this was taken from a really nicely orientated cine SAX
-% 0.7598 0.6030 -0.2431 -0.4615 0.2369 -0.8549
-imoref = [0.7598, 0.6030, -0.2431];
-imorefn= [-0.4579 0.7617 0.4583];
-imo = SET(no).ImageOrientation(1:3)/norm(SET(no).ImageOrientation(1:3));
-
-
-% figure;
-% plot3([0 imo(1)],[0 imo(2)],[0 imo(3)],'r');
-imo=imo-(imorefn*imo')*imorefn;
-% hold on;
-% plot3([0 imo(1)],[0 imo(2)],[0 imo(3)],'c');
-%
-% plot3([0 imorefn(1)],[0 imorefn(2)],[0 imorefn(3)],'g')
-
-
-theta= acos(imoref/norm(imoref)*imo'/norm(imo))/pi*180;
-xlim = gui.([type, 'xlim']);
-ylim = gui.([type, 'ylim']);
-% xscale=gui.([type,'xscale']);
-% yscale=gui.([type,'yscale']);
-scale =gui.([type,'scale']);
-im=[];
-for tf=1:T
- tmp=[];
- for i = slices
- tmp= cat(2,tmp, imresize(imrotate(squeeze(SET(no).IM(xlim,ylim,tf,i)),theta,'bilinear','crop'),scale*[xsz ysz],'bilinear'));
- end
- im=cat(3,im,tmp);
-end
-
-% for slice = slices
-% im=imresize(imrotate(SET(no).IM(xlim,ylim,:,slice),theta),[]);
-% end
- gui.([type 'im'])=im;
-% figure;subplot(121)
-% imagesc(im(:,:,1))
-% subplot(122)
-% imagesc(SET(1).IM(:,:,8,1))
-
-%---------------------
-function resize_fcn
-%---------------------
-
-try
- global DATA
- persistent chk
-
- if ~isempty(chk)
- return
- else
- chk=1;
- end
-
- if isfield(DATA.GUI,'PerfusionScoring')
- gui = DATA.GUI.PerfusionScoring;
- try
- render(gui.iconholder);
- drawnow
- catch
- %it wasnt there
- end
- end
-
- chk=[];
-catch
-%no data loaded
-end
-
-%---------------------
-function motionfunc
-%-----------------------
-%motion function in the perfusionscoring gui.
-global DATA
-
-gui = DATA.GUI.PerfusionScoring;
-motion(gui.iconholder);
-
-%---------------------
-function initiconholder
-%-----------------------
-%initiates the iconholder in the perfusionscoring interface
-global DATA
-gui = DATA.GUI.PerfusionScoring;
-
-iconcell={};
-iconcell{1,end+1}=myicon('playstress',gui.iconholder,gui.Icons.playstress,'Play stress stack',@() perfusion.perfusionscoring('play','stress'),2,1);
-iconcell{1,end+1}=myicon('playrest',gui.iconholder,gui.Icons.playrest,'Play rest stack',@() perfusion.perfusionscoring('play','rest'),2,1);
-iconcell{1,end+1}=myicon('playall',gui.iconholder,gui.Icons.play,'Play all stacks',@() perfusion.perfusionscoring('playall'),2,1);
-%iconcell{1,end+1}=myicon('hidesegmentation',gui.iconholder,gui.Icons.hidelv,'Hide icons',@() perfusion.perfusionscoring('hidecontour'),2);
-iconcell{1,end+1}=myicon('autozoom',gui.iconholder,gui.Icons.autozoom,'Auto zoom',@() perfusion.perfusionscoring('autozoomtoggle'),2);
-add(gui.iconholder,iconcell)%gui.iconholder.add(iconcell);
-%render(gui.iconholder)
-
-%----------------------------
-function autozoomtoggle
-%---------------------- --
- global DATA SET
- gui = DATA.GUI.PerfusionScoring;
-
- if gui.autozoom
- gui.autozoom=0;
- if ~isempty(gui.scarno)
- gui.scarxlim=1:SET(gui.scarno).XSize;
- gui.scarylim=1:SET(gui.scarno).YSize;
- else
- gui.scarxlim=[];
- gui.scarylim=[];
- end
-
- if ~isempty(gui.stressno)
- gui.stressxlim=1:SET(gui.stressno).XSize;
- gui.stressylim=1:SET(gui.stressno).YSize;
- else
- gui.stressxlim=[];
- gui.stressylim=[];
- end
-
- if ~isempty(gui.restno)
- gui.restxlim=1:SET(gui.restno).XSize;
- gui.restylim=1:SET(gui.restno).YSize;
- else
- gui.restxlim=[];
- gui.restylim=[];
- end
-
- for type = {'scar', 'rest', 'stress'}
- generateimages(type{1});
- initimageaxis(type{1})
- end
-
- else
-
- gui.autozoom=1;
- for type = {'scar', 'rest', 'stress'}
- autozoom(type{1});
- generateimages(type{1});
- initimageaxis(type{1});
- end
- end
- colormap([153/255 204/255 1;1 0.95 0;1 0 0])
-%----------------------------
- function autozoom(type)
-%-----------------------
-%function which finds larges epicardial contour and crops image a fixed
-%distance from it.
-global DATA %SET
-
-gui = DATA.GUI.PerfusionScoring;
-
-no=gui.([type,'no']);
-
-if isempty(no)
- return
-end
-cinesaxno = findfunctions('findcineshortaxisno');
-if ~isempty(cinesaxno)
- %[~,xlim,ylim] = segment('getbox',cinesaxno,no);
- [xlim,ylim] = segment('getbox',cinesaxno,no,1);
-else
- [xlim,ylim] = segment('getbox',no,no,1);
-end
-gui.([type,'xlim']) = xlim(1):xlim(end);
-gui.([type,'ylim']) = ylim(1):ylim(end);
-if ylim(end)-ylim(1)>=xlim(end)-xlim(1)
- gui.([type,'scale']) = 180/(ylim(end)-ylim(1)+1);
- else
- gui.([type,'scale']) = 180/(xlim(end)-xlim(1)+1);
- end
-
-%
-% slices=gui.([type,'slices']);
-% xsz=SET(no).XSize;
-% ysz=SET(no).YSize;
-%
-% if ~isempty(SET(no).EpiX) && ~all(all(all(isnan(SET(no).EpiX(:,:,slices)))))
-%
-% epix = SET(no).EpiX(:,:,slices);
-% epiy = SET(no).EpiY(:,:,slices);
-%
-% xmin = floor(min(epix(:)));
-% ymin = floor(min(epiy(:)));
-% xmax = ceil(max(epix(:)));
-% ymax = ceil(max(epiy(:)));
-%
-% dia = round(norm([xmax,ymax]-[xmin,ymin])/2*0.75);
-% xmin=xmin-dia;
-% ymin=ymin-dia;
-% xmax=xmax+dia;
-% ymax=ymax+dia;
-%
-% %make square cut?
-% %min(abs([xmin-xmax,ymin-ymax]))
-%
-% if xmin<1
-% xmin=1;
-% end
-%
-% if ymin<1
-% ymin=1;
-% end
-%
-% if xmax>xsz
-% xmax=xsz;
-% end
-%
-% if ymax>ysz
-% ymax=ysz;
-% end
-%
-% %this catches segmentation blow ups
-% if ymax-ymin<20
-% ymin=1;
-% ymax=ysz;
-% end
-%
-% if xmax-xmin<20
-% xmin=1;
-% xmax=xsz;
-% end
-%
-% if ymax-ymin>=xmax-xmin
-% gui.([type,'yscale']) = 180/(ymax-ymin+1);
-% gui.([type,'xscale']) = gui.([type,'yscale']);%*(ymax-ymin+1)/(xmax-xmin+1);%120/(ymax-ymin+1);
-% else
-% gui.([type,'xscale']) = 180/(xmax-xmin+1);
-% gui.([type,'yscale']) = gui.([type,'xscale']);%*(xmax-xmin+1)/(ymax-ymin+1);
-% end
-% gui.([type,'xlim']) = xmin:xmax;
-% gui.([type,'ylim']) = ymin:ymax;
-%
-% else
-% im= SET(no).IM(:,:,:,slices);
-% [xlim,ylim] = autocrop(im);
-%
-% if isempty(xlim)
-% xmin=1;
-% xmax=xsz;
-% else
-% xmin=xlim(1);
-% xmax=xlim(end);
-% end
-%
-% if isempty(ylim)
-% ymin=1;
-% ymax=ysz;
-% else
-% ymin=ylim(1);
-% ymax=ylim(end);
-% end
-%
-% if ymax-ymin>=xmax-xmin
-% gui.([type,'yscale']) = 180/(ymax-ymin+1);
-% gui.([type,'xscale']) = gui.([type,'yscale']);%*(ymax-ymin+1)/(xmax-xmin+1);%120/(ymax-ymin+1);
-% else
-% gui.([type,'xscale']) = 180/(xmax-xmin+1);
-% gui.([type,'yscale']) = gui.([type,'xscale']);%*(xmax-xmin+1)/(ymax-ymin+1);
-% end
-%
-% gui.([type,'xlim']) = xmin:xmax;
-% gui.([type,'ylim']) = ymin:ymax;
-% end
-
-%---------------------------------------
-function togglemode(type)
-%---------------------------------------
-global DATA
-gui = DATA.GUI.PerfusionScoring;
-gui.currenttag=type;
-
-
-
-%----------------------------
-function initimageaxis(field)
-%----------------------------
-%Initiate image axis with images from current stack
-global DATA SET
-gui = DATA.GUI.PerfusionScoring;
-handles = gui.handles;
-h = handles.([field 'axes']);
-no = gui.([field 'no']);
-tf = gui.([field 'tf']);
-slices = gui.([field,'slices']);
-
-cla(h)
-
-if isempty(no)
- return
-end
-
-for hloop = h'
- hold(hloop,'on');
- %axis(hloop,[0 1 0 1]);
- axis(hloop,'ij');%'equal'
- if ~isempty(SET(no).Colormap)
- colormap(hloop,SET(no).Colormap)
- else
- colormap(hloop,'gray')
- end
-end
-
-% xlim = gui.([field, 'xlim']);
-% ylim = gui.([field, 'ylim']);
-% xsz=xlim(end)-xlim(1);
-% ysz=ylim(end)-ylim(1);
-%
-% xscale=gui.([field,'xscale']);
-% yscale=gui.([field,'yscale']);
-% %gui.([field,'im'])=[];
-% im=[];
-%for i = slices
- %im = [im, imresize(squeeze(SET(no).IM(xlim,ylim,tf,i)),[xscale*xsz yscale*ysz],'bilinear')];
-%end
-im = gui.([field, 'im']);
-im=im(:,:,tf);
-%plot images
-cmap = gray(256);
-c = SET(no).IntensityMapping.Contrast;
-b = SET(no).IntensityMapping.Brightness;
-rim = segment('remap',im,cmap(:,1),c,b);
-gim = segment('remap',im,cmap(:,2),c,b);
-bim = segment('remap',im,cmap(:,3),c,b);
-im = cat(3,rim, gim, bim);
- gui.([field,'imhandle']) = image(im,'parent',h);
- set(gui.([field,'imhandle']),'buttondownfcn',sprintf('perfusion.perfusionscoring(''togglemode'',''%s'')',field))
- axis(h,'image')
-% xlim(h,gui.([field,'xlim']))
-% ylim(h,gui.([field,'ylim']))
-
-if ~strcmp('scar',field)
-pos = plotboxpos(gui.handles.([field,'axes']));
-set(gui.handles.([field,'timebaraxes']),'position',[pos(1)+pos(3)/5,pos(2)-0.027,3*pos(3)/5,0.02])
-end
-
-%initcontours
- %zsz = SET(gui.([field,'no'])).ZSize;
-% xsz = SET(no).XSize;
-% ysz = SET(gui.([field,'no'])).YSize;
-% xres = SET(gui.([field,'no'])).ResolutionX;
-% yres = SET(gui.([field,'no'])).ResolutionY;
-% set(gui.handles.([field,'axes']),'plotboxaspectratio',[zsz*ysz*yres xsz*xres 1]);
-% xlim = gui.([field,'xlim']);
-% ylim = gui.([field,'ylim']);
-% xmin = xlim(1);
-% ymin = ylim(1);
-% ymax = ylim(end);
-%
-% xscale = gui.([field,'xscale']);
-% yscale = gui.([field,'yscale']);
-% if ~isempty(SET(no).EndoX)
-% x=[];
-% y=[];
-% for i = 1:length(slices)
-% x = [x;nan;xscale*(SET(no).EndoX(:,tf,slices(i))-xmin)+1];
-% y = [y;nan;yscale*(SET(no).EndoY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
-% end
-% gui.([field,'endoseghandle']) = plot(h,y,x,'r');
-% else
-% gui.([field,'endoseghandle']) = plot(h,nan,nan,'r');
-% end
-%
-% if ~isempty(SET(no).EpiX)
-% x=[];
-% y=[];
-% for i = 1:length(slices)
-% x = [x;nan;xscale*(SET(no).EpiX(:,tf,slices(i))-xmin)+1];
-% y = [y;nan;yscale*(SET(no).EpiY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
-% end
-% gui.([field,'episeghandle']) = plot(h,y,x,'g');
-% else
-% gui.([field,'episeghandle']) = plot(h,nan,nan,'g');
-% end
-%
-% if ~isempty(SET(no).RVEndoX)
-% x=[];
-% y=[];
-% for i = 1:length(slices)
-% x = [x;nan;xscale*(SET(no).RVEndoX(:,tf,slices(i))-xmin)+1];
-% y = [y;nan;yscale*(SET(no).RVEndoY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
-% end
-% gui.([field,'rvendoseghandle']) = plot(h,y,x,'m');
-% else
-% gui.([field,'rvendoseghandle']) = plot(h,nan,nan,'m');
-% end
-%
-% if ~isempty(SET(no).RVEpiX)
-% x=[];
-% y=[];
-% for i = 1:length(slices)
-% x = [x;nan;xscale*(SET(no).RVEpiX(:,tf,slices(i))-xmin)+1];
-% y = [y;nan;yscale*(SET(no).RVEpiY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
-% end
-% gui.([field,'rvepiseghandle']) = plot(h,y,x,'c');
-% else
-% gui.([field,'rvepiseghandle']) = plot(h,nan,nan,'c');
-% end
-
-
- %drawimages(field);
-%-----------------------------------------
-function autodetectstartstop
-%------------------------------------
-global DATA SET
-
-gui = DATA.GUI.PerfusionScoring;
-
-activation = zeros(1,gui.stressn);
-
-for t=1:gui.stressn
- activation(t) = sum(sum(sum(squeeze(SET(gui.stressno).IM(:,:,t,gui.stressslices)))));
-end
-
-%-----------------------------------
-function inittimebar(field)
-%-----------------------------------
-%Initiate timebar axis for image specified by input parameter 'field'.
-global DATA SET
-gui = DATA.GUI.PerfusionScoring;
-h = gui.handles.([field 'timebaraxes']);
-no = gui.([field 'no']);
-
-if isempty(no)
- return
-end
-
-if gui.stressonly && strcmp(field,'rest')
-return
-end
-
-if gui.restonly && strcmp(field,'stress')
-return
-end
-
-delete(get(h,'Children'));
-
-tvec = SET(no).TimeVector;
-
-hold(h,'on');
-fcn = @(hObject,eventdata)perfusion.perfusionscoring('timebar_ButtonDownFcn',hObject,eventdata,field);
-
-%Draw timebar (red) and set its buttondown fcn
-timebar = plot(h,tvec(SET(no).CurrentTimeFrame)*[1 1],[0 1],'r','Tag','currenttime','linewidth',2);
-set(timebar,'ButtonDownFcn',fcn);
-set(h,'fontsize',14)
-%Draw start and end bars (blue) and set buttondown fcns
-
-% endtime = tvec(SET(no).EndAnalysis);
-% plot(h,endtime*[1 1],[0 1],'b','Tag','endtime','ButtonDownFcn',fcn,'linewidth',2);
-% text(endtime,0.9,'End','Parent',h,'Tag','endtext','ButtonDownFcn',fcn);
-%
-% starttime = tvec(SET(no).StartAnalysis);
-% plot(h,starttime*[1 1],[0 1],'b','Tag','starttime','ButtonDownFcn',fcn,'linewidth',2);
-% text(starttime,0.9,'Start','Parent',h,'Tag','starttext',...
-% 'ButtonDownFcn',fcn,'HorizontalAlignment','right');
-
-
-updatetimebar(field);
-
-%----------------------------------
-function settimeframe(tag,tf,field)
-%----------------------------------
-%Sets current/start/end timeframe for image stack specified by input
-%parameter 'field'
-global DATA SET
-gui = DATA.GUI.PerfusionScoring;
-no = gui.([field 'no']);
-
-if isempty(no)
- return
-end
-
-switch tag
- case 'currenttime'
- SET(no).CurrentTimeFrame = max(min(tf,SET(no).TSize),1);
- gui.([field,'tf']) = SET(no).CurrentTimeFrame;
- case {'starttime','starttext'}
- SET(no).StartAnalysis = max(min(tf,SET(no).EndAnalysis),1);
- case {'endtime','endtext'}
- SET(no).EndAnalysis = max(min(tf,SET(no).TSize),SET(no).StartAnalysis);
-end
-drawimages(field);
-updatetimebar(field);
-
-
-%----------------------------------------------------
- function keypress_Callback(evnt)
- %---------------------------------------------------
- global DATA
- gui = DATA.GUI.PerfusionScoring;
- currenttag = get(get(gui.fig,'currentaxes'),'tag');
-
- if isempty(currenttag) || ~strcmp(currenttag,'iconaxes')
- currenttag=gui.currenttag;
- end
-
- key=getkey(evnt);
-
- switch key
- case 'rightarrow'
-
- if regexp(currenttag,'stress')
-
- tf = gui.stresstf+1;
- if tf>gui.stressn
- tf=1;
- end
- settimeframe('currenttime',tf,'stress')
- end
-
- if regexp(currenttag,'rest')
- tf=gui.resttf+1;
- if tf>gui.restn
- tf=1;
- end
- settimeframe('currenttime',tf,'rest')
- end
-
- case 'leftarrow'
-
- if regexp(currenttag,'stress')
- tf = gui.stresstf-1;
- if tf<1
- tf=gui.stressn;
- end
- settimeframe('currenttime',tf,'stress')
- end
-
- if regexp(currenttag,'rest')
- tf=gui.resttf-1;
- if tf<1
- tf=gui.restn;
- end
- settimeframe('currenttime',tf,'rest')
- end
-
- case 'shift-rightarrow'
- if gui.restonly
- ref_tf=(gui.resttf+1)/gui.restn;
-
- if ref_tf>1;
- ref_tf=1/gui.restn;
- end
-
- else
- ref_tf=(gui.stresstf+1)/gui.stressn;
-
- if ref_tf>1;
- ref_tf=1/gui.stressn;
- end
- end
- for type = {'stress','rest'}%,'cine'}
- % pick tf closest to current stress or rest if restonly frame
- T=gui.([type{1}, 'n']);
- [~,tf] = min(abs(ref_tf-(1:T)/T));
- settimeframe('currenttime',tf,type{1})
- end
- case 'shift-leftarrow'
- if gui.restonly
- ref_tf=(gui.resttf-1)/gui.restn;
-
- if ref_tf<1/gui.restn;
- ref_tf=1;
- end
-
- else
- ref_tf=(gui.stresstf-1)/gui.stressn;
-
- if ref_tf<1/gui.stressn;
- ref_tf=1;
- end
- end
- for type = {'stress','rest'}%,'cine'}
- % pick tf closest to current stress or rest if restonly frame
- T=gui.([type{1}, 'n']);
- [~,tf] = min(abs(ref_tf-(1:T)/T));
- settimeframe('currenttime',tf,type{1})
- end
- case 'p'
- if ~gui.play
- indent(gui.iconholder,'playall',1)
- else
- undent(gui.iconholder,'playall',1)
- end
- end
-
-%----------------------------------------------------
-function timebaraxes_ButtonDownFcn(hObject, ~)
-%----------------------------------------------------
-%Buttondown function for timebar axes of image specified by input
-%parameter 'field'. Changes current timeframe to the one closest to
-%position of clicked point
-global DATA SET
-gui = DATA.GUI.PerfusionScoring;
-handleAddress=hittest(hObject);
-try
-switch get(handleAddress,'tag')
- case 'stresstimebaraxes'
- field='stress';
- case 'resttimebaraxes'
- field='rest';
- otherwise
- return
-end
-catch
-return;
-end
-gui.currenttag=field;
-no = gui.([field 'no']);
-[x,y] = mygetcurrentpoint(handleAddress);
-[~,tvix] = min(abs(SET(no).TimeVector-x));
-settimeframe('currenttime',tvix,field);
-kids=get(handleAddress,'children');
-obj=kids(strcmp('currenttime',get(kids,'tag')));
-
-if isempty(obj)
- return
-end
-
-motionfcn = @(hObject,eventdata)perfusion.perfusionscoring('timebaraxes_MotionFcn',hObject,eventdata,obj,no,field,1);
-set(gui.fig,'WindowButtonMotionFcn',motionfcn);
-buttonupfcn = @(hObject,eventdata)perfusion.perfusionscoring('timebaraxes_ButtonUpFcn',hObject,eventdata);
-set(gui.fig,'WindowButtonUpFcn', buttonupfcn);
-
-%------------------------------------------------
-function timebar_ButtonDownFcn(hObject, ~, field)
-%------------------------------------------------
-%Buttondown function for graphical timebar object of image specified
-%by input parameter 'field'. Activates dragging of timebars.
-global DATA
-gui = DATA.GUI.PerfusionScoring;
-no = gui.([field 'no']);
-obj = hObject;
-motionfcn = @(hObject,eventdata)perfusion.perfusionscoring('timebaraxes_MotionFcn',hObject,eventdata,obj,no,field);
-set(gui.fig,'WindowButtonMotionFcn',motionfcn);
-buttonupfcn = @(hObject,eventdata)perfusion.perfusionscoring('timebaraxes_ButtonUpFcn',hObject,eventdata);
-set(gui.fig,'WindowButtonUpFcn', buttonupfcn);
-
-
-%-----------------------------------------------------------
-function timebaraxes_MotionFcn(hObject, ~, tbobj, no, field,axesclick)
-%-----------------------------------------------------------
-%Mouse motion function for timebar axes of image specified by input
-%parameter 'field'. Used for dragging timebars to change current
-%timeframe or start/end points of timeframes in which to align images.
-global SET
-
-if nargin<6
- axesclick=0;
-end
-
-x = mygetcurrentpoint(get(tbobj,'Parent'));
-[~,tvix] = min(abs(SET(no).TimeVector-x));
-settimeframe(get(tbobj,'Tag'),tvix,field);
-
-%-------------------------------------------
-function timebaraxes_ButtonUpFcn(hObject, ~)
-%-------------------------------------------
-%Buttonup function for timebar axes of image specified by input
-%parameter 'field'. Deactivates dragging of timebar.
-set(hObject,'WindowButtonMotionFcn',[],'WindowButtonUpFcn',[]);
-
-
-
-%---------------------------
-function updatetimebar(field)
-%---------------------------
-%Update timebar axis specified by handle 'h' from input arguments
-global DATA SET
-gui = DATA.GUI.PerfusionScoring;
-h = gui.handles.([field 'timebaraxes']);
-no = gui.([field,'no']);
-
-fcn = get(h,'ButtonDownFcn');
-tvec = SET(no).TimeVector;
-tmin = tvec(1);
-tmax = tvec(end);
-
-starttime = tvec(SET(no).StartAnalysis);
-endtime = tvec(SET(no).EndAnalysis);
-currenttime = tvec(SET(no).CurrentTimeFrame); %#ok
-
-%Update timebars
-for kid = get(h,'Children')'
- tag = get(kid,'Tag');
- switch tag
- case {'starttime','endtime','currenttime'}
- eval(sprintf('set(kid,''XData'',%s*[1 1])',tag));
- case 'starttext'
- set(kid,'Position',[starttime 0.9 0]);
- case 'endtext'
- set(kid,'Position',[endtime 0.9 0]);
- end
-end
-
-%Set axes options
-marg = (tmax-tmin)/100;
-axis(h,[tmin-marg tmax+marg 0 1]);
-tstep = 5*ceil((tmax-tmin)/40);
-tickvec = [ceil(tmin/tstep)*tstep:tstep:floor(tmax/tstep)*tstep];
-set(h, 'Xtick', tickvec,'YTick',[],'XMinorTick','on');
-set(h,'ButtonDownFcn',fcn);
-
-%-------------------------
-function drawimages(field)
-%-------------------------
-%Do an update of all image axes
-global DATA SET
-gui = DATA.GUI.PerfusionScoring;
-no = gui.([field 'no']);
-tf=gui.([field,'tf']);
-
-if isempty(no)
- return
-end
-
-if strcmp(field,'stress') && gui.restonly || ...
- strcmp(field,'rest') && gui.stressonly
- return
-end
-
-h = gui.handles.([field 'axes']);
-
-%gui.([field,'im'])=[];
-
-xlim = gui.([field, 'xlim']);
-ylim = gui.([field, 'ylim']);
-% xsz=xlim(end)-xlim(1);
-% ysz=ylim(end)-ylim(1);
-
-% xscale=gui.([field,'xscale']);
-% yscale=gui.([field,'yscale']);
-
-% for i = gui.([field,'slices'])
-% gui.([field,'im']) = [gui.([field,'im']), imresize(squeeze(SET(no).IM(gui.([field,'xlim']),gui.([field,'ylim']),tf,i)),[xscale*xsz yscale*ysz],'bilinear')];%squeeze(SET(gui.([field,'no'])).IM(xlim,ylim,tf,i))];
-% end
-im=gui.([field,'im']);
-im=im(:,:,tf);
-
-%plot images
-cmap = gray(256);
-c = SET(gui.([field,'no'])).IntensityMapping.Contrast;
-b = SET(gui.([field,'no'])).IntensityMapping.Brightness;
-rim = segment('remap',im,cmap(:,1),c,b);
-gim = segment('remap',im,cmap(:,2),c,b);
-bim = segment('remap',im,cmap(:,3),c,b);
-im = cat(3,rim, gim, bim);
- set(gui.([field,'imhandle']),'Cdata', im)
-% xlim(h,gui.([field,'xlim']))
-% ylim(h,gui.([field,'ylim']))
- %hidelv button indented
-
- %drawcontours(field)
-% gui.endoseghandle = plot(SET(gui.([field,'no'])).EndoX,SET(gui.([field,'no'])).EndoY);
-% gui.episeghandle = plot(SET(gui.([field,'no'])).EpiX,SET(gui.([field,'no'])).EpiY);
-% gui.rvendoseghandle = plot(SET(gui.([field,'no'])).RVEndoX,SET(gui.([field,'no'])).RVEndoY);
-% gui.rvepiseghandle = plot(SET(gui.([field,'no'])).RVEpiX,SET(gui.([field,'no'])).RVEpiY);
-% end
- %--------------------------------------
- function drawcontours(field)
- %-----------------------------------
- global DATA SET
-
- gui = DATA.GUI.PerfusionScoring;
- no = gui.([field 'no']);
- tf = gui.([field 'tf']);
- slices = gui.([field, 'slices']);
- xlim = gui.([field,'xlim']);
- ylim = gui.([field,'ylim']);
- xmin = xlim(1);
- ymin = ylim(1);
- ymax = ylim(end);
-
- scale = gui.([field,'scale']);
-
- if ~isempty(SET(no).EndoX) && ~gui.hidelv
- x=[];
- y=[];
- for i = 1:length(slices)
- x = [x;nan;scale*(SET(no).EndoX(:,tf,slices(i))-xmin)+1];
- y = [y;nan;scale*(SET(no).EndoY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
- end
- set(gui.([field,'endoseghandle']),'XData',y,'YData',x)%plot(h,x,y);
- else
- set(gui.([field,'endoseghandle']), 'XData',nan,'YData',nan)
- end
-
- if ~isempty(SET(no).EpiX) && ~gui.hidelv
- x=[];
- y=[];
- for i = 1:length(slices)
- x = [x;nan;scale*(SET(no).EpiX(:,tf,slices(i))-xmin)+1];
- y = [y;nan;scale*(SET(no).EpiY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
- end
- set(gui.([field,'episeghandle']),'XData',y,'YData',x)%plot(h,x,y);
- else
- set(gui.([field,'episeghandle']), 'XData',nan,'YData',nan)
- end
-
- if ~isempty(SET(no).RVEndoX) && ~gui.hidelv
- x=[];
- y=[];
- for i = 1:length(slices)
- x = [x;nan;scale*(SET(no).RVEndoX(:,tf,slices(i))-xmin)+1];
- y = [y;nan;scale*(SET(no).RVEndoY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
- end
- set(gui.([field,'rvendoseghandle']),'XData',y,'YData',x)%plot(h,x,y);
- else
- set(gui.([field,'rvendoseghandle']), 'XData',nan,'YData',nan)
- end
-
- if ~isempty(SET(no).RVEpiX) && ~gui.hidelv
- x=[];
- y=[];
- for i = 1:length(slices)
- x = [x;nan;scale*(SET(no).RVEpiX(:,tf,slices(i))-xmin)+1];
- y = [y;nan;scale*(SET(no).RVEpiY(:,tf,slices(i))+(ymax-ymin)*(i-1)-ymin)+1+(i-1)];
- end
- set(gui.([field,'rvepiseghandle']),'XData',y,'YData',x)%plot(h,x,y);
- else
- set(gui.([field,'rvepiseghandle']), 'XData',nan,'YData',nan)
- end
-
- %-------------------
- function playcheck(type)
- %-----------------
- global DATA
- gui = DATA.GUI.PerfusionScoring;
-
- if ~strcmp(type,'rest') && gui.restplay
- %undent and stop rest play
- gui.restplay=0;
- undent(gui.iconholder.iconCell{2})
- render(gui.iconholder)
- end
-
- if ~strcmp(type,'stress') && gui.stressplay
- gui.stressplay=0;
- undent(gui.iconholder.iconCell{1})
- render(gui.iconholder)
- end
-
- if ~strcmp(type,'play') && gui.play
- gui.play=0;
- undent(gui.iconholder.iconCell{3})
- render(gui.iconholder)
- end
-
- %---------------------------------
- function play(type)
- %--------------------------------
- global DATA SET
-
- gui = DATA.GUI.PerfusionScoring;
- no=gui.([type, 'no']);
-
- gui.([type,'play'])=~gui.([type,'play']);
-
- gui.currenttag=type;
- playcheck(type)
-
- if isempty(no)
- return
- end
-
- try
- while gui.([type,'play'])
- gui.([type, 'tf']) = gui.([type, 'tf'])+1;
-
- if gui.([type, 'tf'])>gui.([type, 'n'])
- gui.([type, 'tf'])=1;
- end
-
- SET(no).CurrentTimeFrame=gui.([type, 'tf']);
-
- drawimages(type);
- updatetimebar(type);
- drawnow
- %pause(0.001)
- end
- catch
- %gui has been closed.
-
- mydisp('closed while playing')
- return
- end
-
-%---------------------------------
-function playall
-%--------------------------------
-global DATA SET
-
-gui = DATA.GUI.PerfusionScoring;
-
-% if gui.stressonly
-% play('stress')
-% return
-% end
-%
-% if gui.restonly
-% play('rest')
-% return
-% end
-
-gui.play=~gui.play;
-
-playcheck('play')
-
-try
-while gui.play
- if gui.restonly
- ref_tf=(gui.resttf+1)/gui.restn;
-
- if ref_tf>1;
- ref_tf=1/gui.restn;
- end
-
- else
- ref_tf=(gui.stresstf+1)/gui.stressn;
-
- if ref_tf>1;
- ref_tf=1/gui.stressn;
- end
- end
-
- if gui.stressonly
- types = {'stress'};
- elseif gui.restonly
- types={'rest'};
- else
- types={'stress','rest'};
- end
-
- for type = types%,'cine'}
- % pick tf closest to current stress or rest if restonly frame
- T=gui.([type{1}, 'n']);
- [~,gui.([type{1}, 'tf'])] = min(abs(ref_tf-(1:T)/T));%SET(gui.([type{1}, 'no'])).TSize));
- SET(gui.([type{1}, 'no'])).CurrentTimeFrame=gui.([type{1}, 'tf']);
- drawimages(type{1});
- updatetimebar(type{1});
- end
- drawnow
- %pause(0.001)
-end
-catch
- %closed while playing
- mydisp('closed while playing')
-end
-
-%--------------------
-function score(type)
-%--------------
-%Updates perfusion scoring bullseye according to click
-global DATA
-
-gui=DATA.GUI.PerfusionScoring;
-
-switch type
- case 'stress'
- gui.currenttag=type;
- bullseyehandle=gui.handles.bullseyeaxesstress;
- case 'rest'
- gui.currenttag=type;
- bullseyehandle=gui.handles.bullseyeaxesrest;
- case 'scar'
- return
- %bullseyehandle=gui.handles.bullseyeaxesscar;
-end
-%first identify which region was clicked then update the correct m values
-[x,y] = mygetcurrentpoint(bullseyehandle);
-
-xc=x-gui.center;
-yc=y-gui.center;
-
-[theta,rho] = cart2pol(xc,yc);
-
-%determine slice
-
-%apex case completely handled here
-if rho < 50
- %apex adjust m(1:4) then return
- region=1;
- sector='apex';
-end
-
-if rho >50 && rho <100
- region=2;
-end
-
-if rho >100 && rho <150
-region=3;
-end
-
-if rho >150 && rho <200
- region=4;
-end
-
-if rho>200
- return
-end
-
-%apical
-if region == 2
- if abs(theta)pi/4 && theta <3*pi/4
- %inferior
- sector = 'inferior';
- end
-
- if abs(theta) > 3*pi/4% || (theta >-pi/4 && theta < 0)
- %septal
- sector = 'septal';
- end
-
- if theta <-pi/4 && theta >-3*pi/4
- %anterior
- sector ='anterior';
- end
-end
-
-
-%basal mid
-if region >2
- if theta0
- %inferolateral
- sector = 'inferolateral';
- end
-
- if theta >pi/3 && theta <2*pi/3
- %inferior
- sector = 'inferior';
- end
-
- if theta >2*pi/3 && theta -pi/3
- %anteroseptal
- sector = 'anterolateral';
- end
-
- if theta < -pi/3 && theta >-2*pi/3
- %anterior
- sector = 'anterior';
- end
-
- if theta < -2*pi/3 && theta >-pi
- %anterolateral
- sector = 'anteroseptal';
- end
-end
-
-clicktype = get(get(bullseyehandle,'parent'),'selectiontype');
-
-switch clicktype
- case 'open'
- setsectionscore(type,region,sector,2)
- case 'normal' %ordinary mouseclick add
- setsectionscore(type,region,sector,1)
- case {'alt','extend'}
- setsectionscore(type,region,sector,0)
-end
-
-generatebullseye(type)
-gui.mdiff = gui.mstress - gui.mrest;
-generatebullseye('diff')
-save2set
-
-%-------------------------------
-function setsectionscore(type,region,sector, incr)
-%-----------------------------
-global DATA
- %Unpack vector to matrix
-
- gui=DATA.GUI.PerfusionScoring;
-
- switch sector
- case 'anterior'
- if region==2
- inds=[1, 2, 21, 22, 23, 24];
- else
- inds=1:4;
- end
-
- case 'anteroseptal'
- inds=5:8;
-
- case 'inferoseptal'
- inds=9:12;
-
- case 'inferior'
- if region==2
- inds = 9:14;
- else
- inds = 13:16;
- end
-
- case 'inferolateral'
- inds=17:20;
-
- case 'anterolateral'
- inds=21:24;
-
- case 'septal'
- inds=3:8;
-
- case 'lateral'
- inds=15:20;
-
- case 'apex'
- inds=1:24;
- end
-
- m = gui.(['m',type]);
- if m(inds(1),region)==1 && incr==1
- incr=2;
- elseif m(inds(1),region)==2 && incr==1
- incr=0;
- end
-
- switch type
- case 'rest'
- gui.mrest(inds,region)=incr;%gui.mrest(inds(1),region)+incr;
- case 'stress'
- gui.mstress(inds,region)=incr;%gui.mstress(inds(1),region)+incr;
- case 'scar'
- gui.mscar(inds,region)=incr;%gui.mscar(inds(1),region)+incr;
- end
-
- %---------------------
- function save2set
- %---------------------
- global DATA SET
-
- gui=DATA.GUI.PerfusionScoring;
-
- outdata=cell(3,17);
- for loop=1:17
- [stri,pos] = reportbullseye('aha17nameandpos',loop); %Get name and position of export
- outdata{1,loop+1}=stri;
- end
-
- counter=1;
- for type={'stress','rest','diff'}
- m=gui.(['m',type{1}]);
- counter=counter+1;
- outdata{counter,1}=type{1};
- outdata{counter,2} = mynanmean(m(1:4,4));
- outdata{counter,3} = mynanmean(m(5:8,4));
- outdata{counter,4} = mynanmean(m(9:12,4));
- outdata{counter,5} = mynanmean(m(13:16,4));
- outdata{counter,6} = mynanmean(m(17:20,4));
- outdata{counter,8} = mynanmean(m(21:24,4));
- %mid
- outdata{counter,8} = mynanmean(m(1:4,3));
- outdata{counter,9} = mynanmean(m(5:8,3));
- outdata{counter,10} = mynanmean(m(9:12,3));
- outdata{counter,11} = mynanmean(m(13:16,3));
- outdata{counter,12} = mynanmean(m(17:20,3));
- outdata{counter,13} = mynanmean(m(21:24,3));
- %apical
- outdata{counter,14} = mynanmean([m(1:2,2) ; m(21:24,2)]);
- outdata{counter,15} = mynanmean(m(3:8,2));
- outdata{counter,16} = mynanmean(m(9:14,2));
- outdata{counter,17} = mynanmean(m(15:20,2));
- %apex
- outdata{counter,18} = mynanmean(m(:,1));
- end
- for type = {'stress','rest','scar'}
- no=gui.([type{1},'no']);
- if ~isempty(no)
- SET(no).PerfusionScoring.export=outdata;
- SET(no).PerfusionScoring.(['m',type{1}])=gui.(['m',type{1}]);
- if any(strcmp(type{1},{'stress','rest'}))
- SET(no).PerfusionScoring.mdiff=gui.mdiff;
- end
- SET(no).PerfusionScoring.stressno=gui.stressno;
- SET(no).PerfusionScoring.restno=gui.restno;
- SET(no).PerfusionScoring.scarno=gui.scarno;
- end
- end
-
-
- %---------------------------
- function reset(type)
- %------------------------
-global DATA
-gui=DATA.GUI.PerfusionScoring;
-gui.(['m',type])= zeros(24,4);
-generatebullseye(type);
-
-gui.mdiff = gui.mstress - gui.mrest;
-generatebullseye('diff');
-save2set
-
- %-----------
-function generatebullseye(type,handle,no)
-%-----------
-global DATA
-
-
-%Set up
-ahanumslices = 3;
-n = 200;
-scale = n/(ahanumslices+1);
-numsectors = 24;
-
-if nargin == 1;
-gui=DATA.GUI.PerfusionScoring;
-switch type
- case 'rest'
- m = gui.mrest;
- bullseyehandle=gui.handles.bullseyeaxesrest;
- case 'stress'
- m=gui.mstress;
- bullseyehandle=gui.handles.bullseyeaxesstress;
- case 'diff'
- m=gui.mdiff;
- bullseyehandle=gui.handles.diffaxes;
- case 'scar'
- m=gui.mscar;
- bullseyehandle=gui.handles.bullseyeaxesscar;
-end
-gui.center=n+1;
-else
- global SET
- try
- m=SET(no).PerfusionScoring.(['m',type]);
- bullseyehandle=handle;
- catch
- mydisp('Perfusion Scoring not available')
- return;
- end
-end
-
-set(bullseyehandle,'Color',[0 0 0],'Visible','on');
-[x,y] = ndgrid(...
- linspace(-ahanumslices-1,ahanumslices+1,2*n+1),...
- linspace(-ahanumslices-1,ahanumslices+1,2*n+1));
-rad = sqrt(x.*x+y.*y);
-
-%Createidx outer
-ang = angle(complex(y,x))+pi;
-ang = numsectors*ang/(2*pi);
-ang = mod(-(ang-numsectors/3),numsectors); %orient it iaccording to sectors in AHA 17-segment model
-idxouter = 1+min(floor(ang),(numsectors-1))+(numsectors)*min(floor(rad),ahanumslices);
-
-%Createidx inner
-ang = mod(angle(complex(y,x))+pi+pi/4,2*pi);
-ang = numsectors*ang/(2*pi);
-ang = mod(-(ang-numsectors/3),numsectors); %orient it iaccording to sectors in AHA 17-segment model
-idxinner = 1+min(floor(ang),(numsectors-1))+(numsectors)*min(floor(rad),ahanumslices);
-
-idx = idxouter;
-idx(rad<2) = idxinner(rad<2);
-
-im = m(idx);
-im(rad>(ahanumslices+1)) = NaN;
-%im = rad;
-
-%View data
-alpha = double(not(isnan(im)));
-im(isnan(im)) = 0;
-h = imagesc(im,'parent',bullseyehandle);
-
-set(h,'alphadata',alpha,'AlphaDataMapping','scaled');
-axis(bullseyehandle,'image','off');
-%cmap=[0.4259 0.2759 0.2759; 0.6045 0.3935 0.3935; 0.7412 0.4833 0.4833];
-%a=pink;
-%cmap = [a(90,:);a(140,:);a(190,:)];
-
-%pink one
-%cmap=[0.7412 0.4833 0.4833; 0.8356 0.7230 0.6040;0.9107 0.9107 0.7043];
-cmap=[153/255 204/255 1;1 0.95 0;1 0 0];
-%cmap=[0.0598 0.6841 0.7247; 0.9696 0.7300 0.2706; 1 0 0];
-colormap(bullseyehandle,cmap);
-caxis(bullseyehandle,[0 2])
-
-if nargin == 1
- set(h,'ButtonDownFcn',sprintf('perfusion.perfusionscoring(''score'',''%s'')',type));
-end
-
-%Draw circles
-om = linspace(0,2*pi,100);
-xc = sin(om);
-yc = cos(om);
-hold(bullseyehandle,'on');
-for loop=1:(ahanumslices+1)
- h = plot(bullseyehandle,n+1+scale*loop*xc,n+1+scale*loop*yc,'w-');
- set(h,'linewidth',2);
-end;
-hold(bullseyehandle,'off');
-
-%Draw lines
-hold(bullseyehandle,'on');
-b = sqrt(0.75);
-a = 0.5;
-c = 1/sqrt(2);
-h = plot(bullseyehandle,scale*[0 2],scale*[4 4],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[6 8],scale*[4 4],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4-c 4-2*c],scale*[4-c 4-2*c],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4+c 4+2*c],scale*[4+c 4+2*c],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4-c 4-2*c],scale*[4+c 4+2*c],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4+c 4+2*c],scale*[4-c 4-2*c],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4-4*a 4-2*a],scale*[4-4*b 4-2*b],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4-4*a 4-2*a],scale*[4+4*b 4+2*b],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4+4*a 4+2*a],scale*[4+4*b 4+2*b],'w-'); set(h,'linewidth',2);
-h = plot(bullseyehandle,scale*[4+4*a 4+2*a],scale*[4-4*b 4-2*b],'w-'); set(h,'linewidth',2);
-hold(bullseyehandle,'off');
-
-%print out the strain values in the bullseye
-rloops = [1 4 6 6];
-for cloop=1:(ahanumslices+1)
- for rloop = 1:rloops(cloop)
- if cloop > 2 %basal and mid
- r = max(1,mod(round(rloop*length(xc)/rloops(cloop)+2/6*length(xc)),length(xc)));
- else
- r = max(1,mod(round(rloop*length(xc)/rloops(cloop)+1/2*length(xc)),length(xc)));
- end
- if rloops(cloop) == 6 %basal and mid
- mx = 1+(rloop-1)*4:4+(rloop-1)*4;
- elseif rloops(cloop) == 4 %apical
- if rloop == 4
- mx = [1:2 21:24];
- else
- mx = 3+(rloop-1)*6:8+(rloop-1)*6;
- end
- else %apex
- mx = 1:24;
- end
- value = (mynanmean(m(mx,cloop)));
- if ~isnan(value)
- text_handle=text(n+1+(scale/2*min(1,max(0,cloop-1))+scale*(cloop-1))*xc(r), ...
- n+1+(scale/2*min(1,max(0,cloop-1))+scale*(cloop-1))*yc(r), ...
- sprintf('%0.3g',value),'Parent',bullseyehandle,'HorizontalAlignment','center','fontweight','bold');
-
- if nargin == 1
- set(text_handle,'ButtonDownFcn',sprintf('perfusion.perfusionscoring(''score'',''%s'')',type));
- end
-
- end
- end
-end;
-
-switch type
- case 'stress'
- title(bullseyehandle,dprintf('Stress'),'FontSize',14)
- case 'rest'
- title(bullseyehandle,dprintf('Rest/LGE'),'FontSize',14)
- case 'diff'
- title(bullseyehandle,dprintf('Diff'),'FontSize',14)
-end
-% colorbar('peer',gui.handles.bullseyeaxes);
-% maxvalue = max(max(m(:)),abs(min(m(:))));
-% if isnan(maxvalue) || maxvalue==0
-% maxvalue = 1;
-% end;
-% set(gui.handles.bullseyeaxes,'clim',[-maxvalue maxvalue]);
-
-
-%--------------------------------------------
-function close_Callback
-%--------------------------------------------
-global DATA SET
-try
-gui=DATA.GUI.PerfusionScoring;
-gui.play=0;
-gui.stressplay=0;
-gui.restplay=0;
-
-for type = {'stress' 'rest'}
- SET(gui.([type{1},'no'])).PerfusionScoring.diffbullseye=frame2im(mygetframe(gui.handles.diffaxes));
-end
-
-for type = {'stress' 'rest' 'scar'}
- SET(gui.([type{1},'no'])).PerfusionScoring.([type{1}, 'bullseye'])=frame2im(mygetframe(gui.handles.(['bullseyeaxes',type{1}])));
-end
-
-save2set
-
-close(gui)
-catch
-close(gcf)
-end
\ No newline at end of file
diff --git a/source/+perfusion/perfusionscoring.p b/source/+perfusion/perfusionscoring.p
new file mode 100644
index 0000000..767130d
Binary files /dev/null and b/source/+perfusion/perfusionscoring.p differ
diff --git a/source/+pwv/pulsewavevelocity.fig b/source/+pwv/pulsewavevelocity.fig
index a0b10da..2d0c436 100644
Binary files a/source/+pwv/pulsewavevelocity.fig and b/source/+pwv/pulsewavevelocity.fig differ
diff --git a/source/+pwv/pulsewavevelocity.p b/source/+pwv/pulsewavevelocity.p
index 279a1bc..422ebe9 100644
Binary files a/source/+pwv/pulsewavevelocity.p and b/source/+pwv/pulsewavevelocity.p differ
diff --git a/source/+reporter/figgenerator.m b/source/+reporter/figgenerator.m
deleted file mode 100644
index 6fe7da2..0000000
--- a/source/+reporter/figgenerator.m
+++ /dev/null
@@ -1,363 +0,0 @@
-%FIGGENERATOR Class for generating figures containing text documents
-%Position: [vänsterkant underkant bredd höjd]
-
-classdef figgenerator < handle
-
- properties
- filename = '';
- pathname = '';
- title = '';
- allfigs = [];
- figno = [];
- lineht = 0;
- pos = 0;
- pagewidth = 0;
- stf = struct;
- end
-
- methods
-
- %---------------------------------------------------
- function fg = figgenerator(title, pathname, filename, pagewidth, lineht)
- %---------------------------------------------------
- %Constructor
-
- if nargin < 5
- lineht = 14;
- if nargin < 4
- pagewidth = 800;
- if nargin < 3
- filename = [title '_%04.0f.jpg'];
- if nargin < 2
- pathname = pwd;
- end
- end
- end
- end
- fg.title = title;
- fg.filename = filename;
- fg.pathname = pathname;
- fg.pagewidth = pagewidth;
- fg.lineht = lineht;
- fg.stf.fontname = 'courier new';
- end
-
- %---------------------------
- function start(fg, figtitle)
- %---------------------------
- %START Method to open a new figure
-
- fg.figno = figure;
- fg.allfigs = [fg.allfigs fg.figno];
- axis ij
- %axis off
- hold on
- figpos = get(fg.figno,'position');
- figpos(3) = fg.pagewidth;
- set(fg.figno,'position',figpos);
- fg.pos = fg.lineht/2;
- if nargin == 2
- title(figtitle);
- end
- end
-
- %----------------
- function zoom(fg)
- %----------------
- %ZOOM Zoom to current page size
- pageht = fg.pos+fg.lineht;
- axis off
- axis([0 fg.pagewidth 0 pageht]);
- figpos = get(fg.figno, 'position');
- figpos(4) = pageht + 2*fg.lineht;
- set(fg.figno, 'position', figpos);
- end
-
- %-----------------
- function hline(fg)
- %-----------------
- %HLINE Method to write a horizontal line
-
- return %Might not get this to work properly
- figure(fg.figno)
- fg.newline;
- plot([0 fg.pagewidth],[fg.pos fg.pos],'k');
- fg.newline;
-
- end
-
- %---------------------------------------------------------
- function call = table(fg, content, boldcells, width, lpos)
- %---------------------------------------------------------
- %TABLE Method to insert a table with content specified by a cell
-
- if nargin < 5
- lpos = 0;
- if nargin < 4
- width = round(0.625*fg.pagewidth);
- if nargin < 3
- boldcells = zeros(size(content));
- if nargin < 2
- myfailed('Too few input arguments.');
- end
- end
- end
- end
-
- if nargout > 0
- call = @(lpos)table(fg,content,boldcells,width,lpos);
- return
- end
-
- startpos = fg.pos;
-
- for j = 1:size(content, 2)
- maxwidth = max(cellfun(@length,content(:,j)));
- lpos = [lpos lpos(end)+(maxwidth+3)*fg.lineht*10/14];
- end
-
- tpos = startpos;
- for i = 1:size(content, 1)
- for j = 1:size(content, 2)
- if ~isempty(content{i,j})
- st = fg.stf;
- if boldcells(i, j) == 2
- st.color = [1 0 0];
- elseif boldcells(i, j)
- st.fontweight = 'bold';
- end
- if ~isempty(regexp(content{i,j},'(²)', 'once'))
- constri = regexprep(content{i,j},'(²)','^2');
- tpos = tpos + fg.lineht/4;
- text(lpos(j), tpos, constri, st);
- else
- text(lpos(j), tpos, content{i,j}, st);
- end
- end
- end
- tpos = tpos + fg.lineht;
- fg.newline;
- end
-
- end
-
- %-------------------------------------------
- function call = headline(fg, headtext, lpos)
- %-------------------------------------------
- %HEADLINE Method to write a headline in bold
- if nargin < 3
- lpos = 0;
- end
-
- if nargout > 0
- call = @(lpos)headline(fg, headtext, lpos);
- return
- end
-
- fg.newline;
- text(lpos, fg.pos, headtext, 'fontsize', 16, 'fontweight', 'bold');
- fg.newline;
- fg.newline;
- end
-
- %-----------------------------------------------------------
- function call = text(fg, paragraph, alignment, lpos, weight)
- %-----------------------------------------------------------
- %TEXT Method to write a paragraph of text
-
- if nargin < 5
- weight = 'normal';
- if nargin < 4
- lpos = 0;
- if nargin < 3
- alignment = 'left';
- end
- end
- end
-
- if nargout > 0
- call = @(lpos)text(fg, paragraph, alignment, lpos);
- return
- end
-
- st = fg.stf;
- if nargin == 3
- st.horizontalalignment = alignment;
- if strcmp(alignment,'right')
- lpos = fg.pagewidth;
- end
- end
- h = text(lpos, fg.pos, paragraph, st);
- set(h,'FontWeight',weight);
- fg.newline;
- end
-
-
- %------------
- function gsstri = ftext(fg)
- %------------
- %FTEXT Method to write a paragraph of text with formatted headlines.
- global SET
- %stri = [];
- gsstri = []; %Gensvar string (unformatted)
- cr = [];
- prow = 1; %Variable to keep track of row number in current paragraph
- %Convert from Matlab string matrix to viewable text
- for row = 1:size(SET(1).Report.Comments,1)
- crprev = cr;
- cr = deblank(SET(1).Report.Comments(row,:));
- gsstri = [gsstri cr sprintf('\n')]; %#ok
- if isempty(cr) %Insert new paragraph if a line is blank
- %stri = [stri sprintf('\n
\n\n')]; %#ok
- if ~isempty(crprev)
- fg.text(crprev);
- end
- fg.newline;
- prow = 1;
- else
- if prow == 2 %Create headline according to rules of formatting (see manual)
- if strcmp(upper(crprev),crprev)
- %stri = regexprep(stri,crprev,sprintf('%s
',crprev)); %superheadline
- fg.text(crprev,'left',0,'bold');
- %fg.text(cr);
- prow = 1;
- else
- %stri = regexprep(stri,crprev,sprintf('%s
',crprev)); %subheadline
- fg.text(crprev,'left',0,'bold');
- %fg.text(cr);
- end
- elseif prow > 2
- fg.text(crprev);
- fg.newline;
- %stri = [stri sprintf('
\n')]; %#ok
- end
- %stri = [stri sprintf('%s\n',cr)]; %#ok
- prow = prow + 1;
- end
- end
- fg.text(cr);
-
- end
-
- %--------------------------------------------------
- function call = image(fg, imgname, imgsource, lpos)
- %--------------------------------------------------
- %IMAGE Method to add an image. imgsource can be a
- %location or an image matrix.
-
- if nargout > 0
- call = @(lpos)image(fg, imgname, imgsource, lpos);
- return
- end
-
- if nargin < 4
- lpos = 0;
- end
-
- if ischar(imgsource)
- try
- imgsource = imread(imgsource);
- catch me
- mydispexception(me);
- error('Could not read image file');
- end
- end
- sz = size(imgsource);
- newpos = fg.pos + sz(1);
- fg.newline;
- imagesc([lpos lpos+sz(2)], [fg.pos newpos], imgsource);
- fg.pos = newpos;
- fg.newline;
- end
-
- %-----------------------------
- function columns(fg, varargin)
- %-----------------------------
- %COLUMNS Method for dividing input into columns
- startpos = fg.pos;
- endpos = startpos;
- nbrcols = length(varargin);
- step = fg.pagewidth / nbrcols;
- for i = 1:nbrcols
- fg.pos = startpos;
- lpos = (i-1)*step;
- if iscell(varargin{i})
- for j = 1:length(varargin{i})
- if iscell(varargin{i}{j})
- for k = 1:length(varargin{i}{j})
- feval(varargin{i}{j}{k}, lpos)
- end
- elseif ~isempty(varargin{i}{j})
- feval(varargin{i}{j}, lpos);
- end
- end
- elseif ~isempty(varargin{i})
- feval(varargin{i}, lpos)
- end
- endpos = max(fg.pos, endpos);
- end
- fg.pos = endpos;
-
- end
-
- %--------------------------
- function call = newline(fg)
- %--------------------------
- %NEWLINE Method to insert a line break
- if nargout > 0
- call = @()newline(fg);
- return
- end
-
- fg.pos = fg.pos + fg.lineht;
- end
-
- %---------------------------------------------------------
- function newpagepos = pagebreakchk(fg, pagepos, nextblock)
- %---------------------------------------------------------
- %PAGEBREAKCHK Method to insert a page break
- %Checks if it is time to insert a page break using 'pagepos' parameter
- maxpageheight = 1506; %Approximated from studies of some common browser printing defaults
- newpos = pagepos + nextblock;
- if newpos > maxpageheight
- fg.zoom;
- fg.start;
- fg.lineht=15;
- axis equal
- set(gcf,'units','normalized','outerposition',[0 0 1 1])
- %xlim([0,1000])
- newpagepos = nextblock;
- %axis equal
- else
- newpagepos = newpos;
- end
- end
-
- %----------------
- function stop(fg)
- %----------------
- %STOP Save all figures to image files, then close them
- fg.zoom;
- for i = 1:numel(fg.allfigs)
- saveas(fg.allfigs(i),fullfile(fg.pathname,sprintf(fg.filename,i)))
- end
- close(fg.allfigs)
- end
-
- end
-
- methods(Access = 'private')
-
-
- end
-
- methods(Static)
- %-------------
- function call = conc(varargin)
- %-------------
- %Concatenate two or more function calls
- call = varargin;
- end
- end
-
-end
\ No newline at end of file
diff --git a/source/+reporter/figgenerator.p b/source/+reporter/figgenerator.p
new file mode 100644
index 0000000..6e245b0
Binary files /dev/null and b/source/+reporter/figgenerator.p differ
diff --git a/source/+reporter/htmlgenerator.m b/source/+reporter/htmlgenerator.m
deleted file mode 100644
index 168ee94..0000000
--- a/source/+reporter/htmlgenerator.m
+++ /dev/null
@@ -1,357 +0,0 @@
-%HTMLGENERATOR Class for generating HTML files
-
-classdef htmlgenerator
-
- properties(SetAccess = 'private', Hidden)
- filename = '';
- pathname = '';
- fid = [];
- title = '';
- pagewidth = 0;
- end
-
- methods
-
- %-------------
- function hg = htmlgenerator(title, pathname, filename, pagewidth)
- %-------------
- %Constructor
- if nargin < 4
- pagewidth = 1024;
- if nargin < 3
- filename = [title '.htm'];
- if nargin < 2
- pathname = pwd;
- end
- end
- end
- hg.title = title;
- hg.filename = filename;
- hg.pathname = pathname;
- hg.pagewidth = pagewidth;
- end
-
- %-------------
- function hg = start(hg)
- %-------------
- %START Method to open the HTML file and write headers
- hg.fid = fopen(fullfile(hg.pathname,hg.filename), 'w', 'n', 'UTF-8');
- write(hg, html_header(hg));
- end
-
- %-------------
- function stri = hline(hg)
- %-------------
- %HLINE Method to write a horizontal line
- stri = sprintf('
\n
\n
\n');
- %These methods return a string if asked for output, otherwise write
- %to file
-
- if nargout < 1
- write(hg, stri);
- end
- end
-
- %-------------
- function stri = table(hg, content, boldcells, width, bgcolors)
- %-------------
- %TABLE Method to insert a table with content specified by a cell.
- if nargin <5
- bgcolors = zeros(size(content));
- if nargin < 4
- width = round(0.625*hg.pagewidth);
- if nargin < 3
- boldcells = zeros(size(content));
- if nargin < 2
- myfailed('Too few input arguments.');
- end
- end
- end
- end
- tdstring='';
- stri = sprintf('\n', width);
- for i = 1:size(content, 1)
- stri = [stri sprintf('\n')]; %#ok
- for j = 1:size(content, 2)
- if bgcolors(i,j) == 2
- tdstring='';
- elseif bgcolors(i,j) == 3
- tdstring=' | ';
- elseif bgcolors(i,j) == 4
- tdstring=' | ';
- else
- tdstring=' | ';
- end
-
- if boldcells(i, j) == 2
- b1 = '';
- b2 = '';
- elseif boldcells(i, j) == 3
- b1 = '';
- b2 = '';
- elseif boldcells(i, j) == 4
- b1 = '';
- b2 = '';
-
- elseif boldcells(i, j)
- b1 = '';
- b2 = '';
- else
- b1 = '';
- b2 = '';
- end
- stri = [stri sprintf('%s%s%s%s | \n',tdstring, b1, content{i,j}, b2)]; %#ok
- end
- stri = [stri sprintf(' \n')]; %#ok
- end
- stri = [stri sprintf(' \n \n')];
-
- if nargout < 1
- write(hg, stri);
- end
-
- end
-
- %-------------
- function stri = box(hg, text, width)
- %-------------
- %BOX Method to insert a text box
- if nargin < 3
- width = hg.pagewidth;
- if nargin < 2
- myfailed('Too few input arguments.');
- end
- end
- stri = sprintf(['\n'], width, text);
- if nargout < 1
- write(hg, stri);
- end
- end
-
- %-------------
- function stri = headline(hg, headtext, prio)
- %-------------
- %HEADLINE Method to write a headline in bold
- if nargin < 3
- prio = 3;
- end
- stri = sprintf('%s\n', prio, headtext, prio);
- if nargout < 1
- write(hg, stri);
- end
- end
-
- %-------------
- function stri = text(hg, paragraph, alignment)
- %-------------
- %TEXT Method to write a paragraph of text
- if nargin == 3
- alstr = sprintf(' align=%s',alignment);
- else
- alstr = '';
- end
- stri = sprintf('\n%s\n \n',alstr,paragraph);
- if nargout < 1
- write(hg, stri);
- end
- end
-
- %------------
- function gsstri = ftext(hg)
- %------------
- %FTEXT Method to write a paragraph of text with formatted headlines.
- global SET
- stri = [];
- gsstri = []; %Gensvar string (unformatted)
- cr = [];
- prow = 1; %Variable to keep track of row number in current paragraph
- %Convert from Matlab string matrix to viewable text
- comment = SET(1).Report.Comments;
- newlines = [0 regexp(comment,'(\n)') numel(comment)+1];
- for row = 2:numel(newlines)
- crprev = cr;
- if ~isempty(crprev)
- crprev = regexprep(crprev,{'\*','\.'},{'\\*','\\.'});
- end
- cr = comment(newlines(row-1)+1:newlines(row)-1);
- gsstri = [gsstri cr sprintf('\n')]; %#ok
- if isempty(cr) %Insert new paragraph if a line is blank
- stri = [stri sprintf('\n\n\n')]; %#ok
- prow = 1;
- else
- if prow == 2 %Create headline according to rules of formatting (see manual)
- if strcmp(upper(crprev),crprev)
- stri = regexprep(stri,crprev,sprintf('%s',crprev)); %superheadline
- prow = 1;
- else
- stri = regexprep(stri,crprev,sprintf('%s',crprev)); %subheadline
- end
- elseif prow > 2
- stri = [stri sprintf(' \n')]; %#ok
- end
- stri = [stri sprintf('%s\n',cr)]; %#ok
- prow = prow + 1;
- end
- end
- hg.text(stri);
- end
-
- %-------------
- function stri = image(hg, imgname, imgsource)
- %-------------
- %IMAGE Method to add an image. Also stores it to disk in
- % the same folder as the HTML file. imgsource can be a
- % location or an image matrix.
-
- if nargin < 3
- stri = sprintf('\n \n', imgname);
- else
- imgdest = [hg.pathname filesep imgname];
- if ischar(imgsource)
- try
- imgsource = imread(imgsource);
- catch me
- mydispexception(me);
- error('Could not read image file');
- end
- end
- try
- imwrite(imgsource, imgdest);
- stri = sprintf('\n \n', imgname);
- catch me
- mydispexception(me);
- error('Could not write image file');
- end
- end
-
- if nargout < 1
- write(hg, stri);
- end
- end
-
- %-------------
- function stri = columns(hg, varargin)
- %-------------
- %COLUMNS Method to insert a table without borders, used for dividing
- %input into columns
-
-% colfunix = [find(cellfun('isclass',varargin,'function_handle'))...
-% length(varargin)+1];
-% if isempty(colfunix)
-% outargs = varargin;
-% else
-% nbroffuns = length(colfunix)-1;
-% outargs = cell(1,nbroffuns);
-% for i = 1:nbroffuns
-% inargs = varargin(colfunix(i):colfunix(i+1)-1);
-% outargs{i} = feval(inargs{:});
-% end
-% end
-
- stri = sprintf('\n',hg.pagewidth);
- for i = 1:length(varargin)
- stri = [stri sprintf('%s | \n', varargin{i})]; %#ok
- end
- stri = [stri sprintf(' \n')];
-
- if nargout < 1
- write(hg, stri);
- end
- end
-
- %-------------
- function stri = link(hg, ref, text)
- %-------------
- %LINK Method to write a link to a file or URL
- if nargin < 3
- text = ref;
- end
- stri = sprintf('%s\n', ref, text);
-
- if nargout < 1
- write(hg, stri);
- end
- end
-
- %--------------------------
- function stri = newline(hg)
- %--------------------------
- %NEWLINE Method to insert a line break
- stri = ' ';
- if nargout == 0
- write(hg,stri);
- end
-
- end
-
- %-------------
- function newpagepos = pagebreakchk(hg, pagepos, nextblock)
- %-------------
- %PAGEBREAKCHK Method to insert a page break
- %Checks if it is time to insert a page break using 'pagepos' parameter
- maxpageheight = 1506; %Approximated from studies of some common browser printing defaults
- newpos = pagepos + nextblock;
- if newpos > maxpageheight
- hg.text('');
- newpagepos = nextblock;
- else
- newpagepos = newpos;
- end
- end
-
- %-------------
- function hg = stop(hg)
- %-------------
- %STOP Method to write necessary HTML footers and close file
- write(hg, html_footer(hg));
- fclose(hg.fid);
- end
-
- end %End of methods
-
- methods (Access = 'private')
-
- %-------------
- function write(hg, str)
- %-------------
- %Writes a string of characters to file
- fprintf(hg.fid, '%s', str);
- end
-
- %--------------------------
- function stri = html_header(hg)
- %--------------------------
- %Return string used as HTML header
- stri = [];
-
- stri = [stri sprintf('\n')];
- stri = [stri sprintf('\n')];
- stri = [stri sprintf('%s\n', hg.title)];
- stri = [stri sprintf('\n')];
- stri = [stri sprintf('\n')];
- stri = [stri sprintf('\n\n')];
- stri = [stri sprintf('\n', hg.pagewidth)];
-
- end
-
- %--------------------------
- function stri = html_footer(hg) %#ok
- %--------------------------
- %Return string used as HTML footer
- stri = sprintf('\n\n');
- end
-
- end %End of private methods
-
- methods(Static)
- %-------------
- function stri = conc(varargin)
- %-------------
- %Concatenate two or more function calls
- stri = [varargin{:}];
- end
- end
-
-end
-
\ No newline at end of file
diff --git a/source/+reporter/htmlgenerator.p b/source/+reporter/htmlgenerator.p
new file mode 100644
index 0000000..b0129d5
Binary files /dev/null and b/source/+reporter/htmlgenerator.p differ
diff --git a/source/+reporter/logo.png b/source/+reporter/logo.png
deleted file mode 100644
index d0a4ded..0000000
Binary files a/source/+reporter/logo.png and /dev/null differ
diff --git a/source/+reporter/pdf2dcm.exe b/source/+reporter/pdf2dcm.exe
new file mode 100644
index 0000000..bb87c29
Binary files /dev/null and b/source/+reporter/pdf2dcm.exe differ
diff --git a/source/+reporter/reference/buechel_f0018.normvalues.txt b/source/+reporter/reference/buechel_f0018.normvalues.txt
new file mode 100644
index 0000000..449f93b
--- /dev/null
+++ b/source/+reporter/reference/buechel_f0018.normvalues.txt
@@ -0,0 +1,17 @@
+Name: 'Buechel, Females, Age 0-18'
+ImagingType: 'SSFP'
+Sex: 'F'
+LowerAgeBound: 0
+UpperAgeBound: 18
+LVM: [(10^(-2*0.0475))*(45.2*(SET(1).PatientInfo.BSA^1.304)) (10^(2*0.0475))*(45.2*(SET(1).PatientInfo.BSA^1.304))]
+EDV: [(10^(-2*0.0426))*(67.8*(SET(1).PatientInfo.BSA^1.38)) (10^(2*0.0426))*(67.8*(SET(1).PatientInfo.BSA^1.38))]
+ESV: [(10^(-2*0.0647))*(26.1*(SET(1).PatientInfo.BSA^1.37)) (10^(2*0.0647))*(26.1*(SET(1).PatientInfo.BSA^1.37))]
+SV: [(10^(-2*0.05))*(41.7*(SET(1).PatientInfo.BSA^1.394)) (10^(2*0.05))*(41.7*(SET(1).PatientInfo.BSA^1.394))]
+EF: [(10^(-2*0.041))*61.3 (10^(2*0.041))*61.3]
+RVM: [(10^(-2*0.0605))*(14.9*(SET(1).PatientInfo.BSA^1.331)) (10^(2*0.0605))*(14.9*(SET(1).PatientInfo.BSA^1.331))]
+RVEDV: [(10^(-2*0.0499))*(72.7*(SET(1).PatientInfo.BSA^1.469)) (10^(2*0.0499))*(72.7*(SET(1).PatientInfo.BSA^1.469))]
+RVESV: [(10^(-2*0.0737))*(30.2*(SET(1).PatientInfo.BSA^1.559)) (10^(2*0.0737))*(30.2*(SET(1).PatientInfo.BSA^1.559))]
+RVSV: [(10^(-2*0.0524))*(42.1*(SET(1).PatientInfo.BSA^1.407)) (10^(2*0.0524))*(42.1*(SET(1).PatientInfo.BSA^1.407))]
+RVEF: [(10^(-2*0.042))*(61.8-(3.6*SET(1).PatientInfo.BSA)) (10^(2*0.042))*(61.8-(3.6*SET(1).PatientInfo.BSA))]
+CO: [(10^(-2*0.0727))*(3.622*(SET(1).PatientInfo.BSA^1.062)) (10^(2*0.0727))*(3.622*(SET(1).PatientInfo.BSA^1.062))]
+RVCO: [(10^(-2*0.0783))*(3.6583*(SET(1).PatientInfo.BSA^1.076)) (10^(2*0.0783))*(3.6583*(SET(1).PatientInfo.BSA^1.076))]
\ No newline at end of file
diff --git a/source/+reporter/reference/buechel_m0018.normvalues.txt b/source/+reporter/reference/buechel_m0018.normvalues.txt
new file mode 100644
index 0000000..9db5d6a
--- /dev/null
+++ b/source/+reporter/reference/buechel_m0018.normvalues.txt
@@ -0,0 +1,17 @@
+Name: 'Buechel, Males, Age 0-18'
+ImagingType: 'SSFP'
+Sex: 'M'
+LowerAgeBound: 0
+UpperAgeBound: 18
+LVM: [(10^(-2*0.0475))*(53*(SET(1).PatientInfo.BSA^1.304)) (10^(2*0.0475))*(53*(SET(1).PatientInfo.BSA^1.304))]
+EDV: [(10^(-2*0.0426))*(77.5*(SET(1).PatientInfo.BSA^1.38)) (10^(2*0.0426))*(77.5*(SET(1).PatientInfo.BSA^1.38))]
+ESV: [(10^(-2*0.0647))*(29.7*(SET(1).PatientInfo.BSA^1.37)) (10^(2*0.0647))*(29.7*(SET(1).PatientInfo.BSA^1.37))]
+SV: [(10^(-2*0.05))*(47.4*(SET(1).PatientInfo.BSA^1.394)) (10^(2*0.05))*(47.4*(SET(1).PatientInfo.BSA^1.394))]
+EF: [(10^(-2*0.041))*61.3 (10^(2*0.041))*61.3]
+RVM: [(10^(-2*0.0605))*(16.7*(SET(1).PatientInfo.BSA^1.331)) (10^(2*0.0605))*(16.7*(SET(1).PatientInfo.BSA^1.331))]
+RVEDV: [(10^(-2*0.0499))*(83.8*(SET(1).PatientInfo.BSA^1.469)) (10^(2*0.0499))*(83.8*(SET(1).PatientInfo.BSA^1.469))]
+RVESV: [(10^(-2*0.0737))*(35.3*(SET(1).PatientInfo.BSA^1.559)) (10^(2*0.0737))*(35.3*(SET(1).PatientInfo.BSA^1.559))]
+RVSV: [(10^(-2*0.0524))*(48.2*(SET(1).PatientInfo.BSA^1.407)) (10^(2*0.0524))*(48.2*(SET(1).PatientInfo.BSA^1.407))]
+RVEF: [(10^(-2*0.042))*(61.8-(3.6*SET(1).PatientInfo.BSA)) (10^(2*0.042))*(61.8-(3.6*SET(1).PatientInfo.BSA))]
+CO: [(10^(-2*0.0727))*(3.89*(SET(1).PatientInfo.BSA^1.062)) (10^(2*0.0727))*(3.89*(SET(1).PatientInfo.BSA^1.062))]
+RVCO: [(10^(-2*0.0783))*(3.9473*(SET(1).PatientInfo.BSA^1.076)) (10^(2*0.0783))*(3.9473*(SET(1).PatientInfo.BSA^1.076))]
\ No newline at end of file
diff --git a/source/+reporter/report2clipboard.p b/source/+reporter/report2clipboard.p
new file mode 100644
index 0000000..6c66752
Binary files /dev/null and b/source/+reporter/report2clipboard.p differ
diff --git a/source/+reporter/reportgenerator.p b/source/+reporter/reportgenerator.p
new file mode 100644
index 0000000..ef30ec0
Binary files /dev/null and b/source/+reporter/reportgenerator.p differ
diff --git a/source/+reporter/reportsheet.fig b/source/+reporter/reportsheet.fig
index 028f491..4a1aecd 100644
Binary files a/source/+reporter/reportsheet.fig and b/source/+reporter/reportsheet.fig differ
diff --git a/source/+reporter/reportsheet.p b/source/+reporter/reportsheet.p
index 1edf09d..3e8308d 100644
Binary files a/source/+reporter/reportsheet.p and b/source/+reporter/reportsheet.p differ
diff --git a/source/+reporter/sendtogensvar.m b/source/+reporter/sendtogensvar.m
deleted file mode 100644
index 7f9a0b6..0000000
--- a/source/+reporter/sendtogensvar.m
+++ /dev/null
@@ -1,39 +0,0 @@
-function resulturl = sendtogensvar(url, username, password, data)
- % This function creates a study in gensvar and returns the url of the
- % study. For a list of valid fieldnames in the data structure see
- % the function getStudyFieldGroup() in common.php.
-
- % Prepare data
- fnames = fieldnames(data);
- sdata = {};
- for i=1:numel(fnames)
- value = data.(fnames{i});
- if isa(value, 'char')
- sdata = [sdata {fnames{i}} {value}];
- continue
- end
- if isa(value, 'double') || isa(value, 'single')
- sdata = [sdata {fnames{i}} {sprintf('%f', value)}];
- continue
- end
- error('SEGMENT:ERROR', 'Bad value type in data parameter');
- end
-
- % Send
- rr = urlread([url '/api.php'], 'POST', [{'action', 'create_study', 'username', username, 'password', password} sdata]);
- r = regexp(rr, '\n', 'split');
- if(not(isequal(r{1}, 'gensvar')))
- error('SEGMENT:ERROR', ['Couldn''t connect to gensvar: ' rr]);
- end
- if(isequal(r{2}, 'ok'))
- resulturl = [url '/editstudy.php?id=' r{3}];
- return
- end
- if(isequal(r{2}, 'noaccess'))
- error('SEGMENT:ERROR', 'Bad combination of username and password');
- end
- if(isequal(r{2}, 'baddata'))
- error('SEGMENT:ERROR', ['Bad data sent. Gensvar says: ''' r{3} '''.']);
- end
- error('SEGMENT:ERROR', 'Unknown result sent from gensvar');
-end
\ No newline at end of file
diff --git a/source/+reporter/sendtogensvar.p b/source/+reporter/sendtogensvar.p
new file mode 100644
index 0000000..a0e3f7f
Binary files /dev/null and b/source/+reporter/sendtogensvar.p differ
diff --git a/source/+segment3dp/tools.m b/source/+segment3dp/tools.m
new file mode 100644
index 0000000..a10cdb3
--- /dev/null
+++ b/source/+segment3dp/tools.m
@@ -0,0 +1 @@
+function varargout = tools(varargin)
diff --git a/source/+spect/autoperfusionspect.m b/source/+spect/autoperfusionspect.m
index 44e85a0..486caf1 100644
--- a/source/+spect/autoperfusionspect.m
+++ b/source/+spect/autoperfusionspect.m
@@ -13,7 +13,7 @@
pathname = DATA.Pref.datapath;
pathname = myuigetdir(pathname,'Select a folder with .mat files');
if isequal(pathname,0)
- myfailed('Aborted.');
+% myfailed('Aborted.');
return;
end
%find the .mat files
@@ -92,12 +92,7 @@
if doanalysis
for loop = 1:length(SET)
SET(loop).Linked = loop;
- segment('switchtoimagestack',loop);
- DATA.ViewPanels(1) = NO;
- DATA.ViewIM{1} = [];
- DATA.Overlay(1) = struct('alphadata', [], 'cdata', []);
- drawfunctions('drawimageno',NO);
- DATA.switchtoimagestack(NO,true); %force
+ viewfunctions('setview',1,1,NO,{'one'})
tools('setcolormap_Callback','spect');
if SET(NO).ResolutionX > 4
tools('upsampleimage_Callback',2);
@@ -147,17 +142,8 @@
end
end
-% spect.spectperfusionsegmentation('perfusionanalyze_Callback',0);
- %viewing
-% segment('viewallimagestacks_Callback');
-% for j = 1:length(SET)
-% segment('switchtoimagestack',j);
-% DATA.switchtoimagestack(NO,true); %force
-% DATA.CurrentPanel = j;
-% segment('viewimage_Callback','montage');
-% segment('viewrefresh_Callback');
-% end
- segment('viewrefreshall_Callback');
+ viewfunctions('setview')
+
%saving file
DATA.Buffer.KeyStroke = {'ok'}; %Put ok in queue for confirm box.
filemenu('saveall_Callback')
diff --git a/source/+spect/spectlvsegmentation.p b/source/+spect/spectlvsegmentation.p
index 3ac2f3f..e27fcad 100644
Binary files a/source/+spect/spectlvsegmentation.p and b/source/+spect/spectlvsegmentation.p differ
diff --git a/source/+spect/spectmarsegmentation.p b/source/+spect/spectmarsegmentation.p
index 7aa748c..db821f5 100644
Binary files a/source/+spect/spectmarsegmentation.p and b/source/+spect/spectmarsegmentation.p differ
diff --git a/source/+spect/spectperfusionsegmentation.p b/source/+spect/spectperfusionsegmentation.p
index e8d3534..d0f786d 100644
Binary files a/source/+spect/spectperfusionsegmentation.p and b/source/+spect/spectperfusionsegmentation.p differ
diff --git a/source/+spect/spectplot2d.fig b/source/+spect/spectplot2d.fig
index 4d62f4c..dbc6f31 100644
Binary files a/source/+spect/spectplot2d.fig and b/source/+spect/spectplot2d.fig differ
diff --git a/source/+spect/spectplot2d.m b/source/+spect/spectplot2d.m
index 9da59e2..409a796 100644
--- a/source/+spect/spectplot2d.m
+++ b/source/+spect/spectplot2d.m
@@ -65,7 +65,7 @@ function init_Callback(mode,makeviewmode)
nos.stressgated = stressgatedno;
fnames = fieldnames(nos);
-h = mywaitbarstart(3,'Calculating',1,DATA.GUI.Segment);
+h = mywaitbarstart(5,'Calculating',1,DATA.GUI.Segment);
IM = [];
LVsegmentation = [];
@@ -189,7 +189,8 @@ function init_Callback(mode,makeviewmode)
VLAslice.(field),LVsegmentation.(field),EndoX.(field), ...
EndoY.(field),EpiX.(field),EpiY.(field), startslices.(field), ...
endslices.(field),isLVseg.(field),tnbr,mode,resamplexy.(field));
- end
+ end
+ h = mywaitbarupdate(h);
end
mywaitbarclose(h);
@@ -718,7 +719,7 @@ function init_Callback(mode,makeviewmode)
end
%upsample images spatially
IM = tools('upsampleslices',fsz,IM,1);
- IM = tools('upsamplevolume',fs,IM,1);
+ IM = tools('upsamplevolume2',[fs fs 1 1],IM,1);
%upsample images temporally
if ft ~= 1
IM = tools('upsampletemporal',ft,IM);
@@ -1247,7 +1248,12 @@ function init_Callback(mode,makeviewmode)
switch gui.showimagetype{1}
case {'stress','stressgated','restgated'}
+ colormap(gui.handles.axesSAapicalleft,'spect');
colormap(gui.handles.axesSAmidleft,'spect');
+ colormap(gui.handles.axesSAbasalleft,'spect');
+ colormap(gui.handles.axesHLAleft,'spect');
+ colormap(gui.handles.axesVLAleft,'spect');
+
axis(gui.handles.axesSAbasalleft,'image','off');
set(gui.handles.axesSAbasalleft,'clim',[normmincount normmaxcount]);
axis(gui.handles.axesSAmidleft,'image','off');
@@ -1345,7 +1351,11 @@ function init_Callback(mode,makeviewmode)
end
switch gui.showimagetype{2}
case {'rest','restgated'}
+ colormap(gui.handles.axesSAapicalright,'spect');
colormap(gui.handles.axesSAmidright,'spect');
+ colormap(gui.handles.axesSAbasalright,'spect');
+ colormap(gui.handles.axesHLAright,'spect');
+ colormap(gui.handles.axesVLAright,'spect');
axis(gui.handles.axesSAbasalright,'image','off');
set(gui.handles.axesSAbasalright,'clim',[normmincount normmaxcount]);
axis(gui.handles.axesSAmidright,'image','off');
@@ -1916,7 +1926,7 @@ function plotahavalues(panel)
SRS = SRS+gui.scoringvalues{3,loop};
end
set(gui.handles.textScoring,'String',['SRS: ',num2str(SRS)]);
- scoringexplanation = sprintf('%s\n%s\n%s\n%s','Scoring of presence of infarct','0: normal','1: equivocal','2: infarct');
+ scoringexplanation = sprintf('%s\n%s\n%s\n%s\n%s\n%s','Scoring of presence of infarct','0: normal','1: equivocal','2: moderate','3: severe infact','4: apparent infact');
set(gui.handles.textScoringExplanation,'String',scoringexplanation);
case 0
for loop = 1:size(gui.scoringvalues,2)
@@ -2220,6 +2230,11 @@ function plotSAintersections(panel)
set(gui.handles.textVLAleft,'String',[]);
set(gui.handles.textleft,'String',[]);
end
+ colormap(gui.handles.axesSAapicalleft,'spect');
+ colormap(gui.handles.axesSAmidleft,'spect');
+ colormap(gui.handles.axesSAbasalleft,'spect');
+ colormap(gui.handles.axesHLAleft,'spect');
+ colormap(gui.handles.axesVLAleft,'spect');
else
%no images to plot
set(gui.handles.axesSAbasalimageleft,'cdata',[]);
@@ -3241,8 +3256,8 @@ function hideSAintersections(panel)
if get(gui.handles.radiobuttonshowsegmentation,'value')
updateLVsegmentation;
if isequal(gui.mode,'scoring')
- updateahasections('both');
- hideSAintersections('both');
+ updateahasections('both');
+ updateSAintersections('left');
end
end
if isequal(gui.mode,'scoring')
@@ -3524,8 +3539,8 @@ function roundtf(roundmethod)
succeed = false;
return;
end
- if isempty(gui.scoringvalues{3,k}) || ~isnumeric(gui.scoringvalues{3,k}) || gui.scoringvalues{3,k}<0 || gui.scoringvalues{3,k}>2
- myfailed('REST Infarct: Scoring value missing, or outside the allowed range [0 2]');
+ if isempty(gui.scoringvalues{3,k}) || ~isnumeric(gui.scoringvalues{3,k}) || gui.scoringvalues{3,k}<0 || gui.scoringvalues{3,k}>4
+ myfailed('REST Infarct: Scoring value missing, or outside the allowed range [0 4]');
succeed = false;
return;
end
@@ -4534,6 +4549,7 @@ function keypressed(fignum,evnt) %#ok
SDS = 0;
pos = [17 13 16:-1:14 7 12:-1:8 1 6:-1:2];
+if isequal(currentobj.Style,'edit')
if get(gui.handles.radiobuttongated,'value')
tags = {'editHLAright', ...
'editapicalantright','editapicallatright', ...
@@ -4578,6 +4594,7 @@ function keypressed(fignum,evnt) %#ok
scoringvalues = sprintf('%s\n%s\n%s',['SSS: ',num2str(SSS)],['SRS: ',num2str(SRS)],['SDS: ',num2str(SDS)]);
set(gui.handles.textScoring,'String',scoringvalues);
end
+end
%---------------------------------------------------------------------
function lvv = calclvv(startslices,endslices,endox,endoy,t,resXY,resZ)
diff --git a/source/+spect/spectregistration.p b/source/+spect/spectregistration.p
index aa70747..379cab1 100644
Binary files a/source/+spect/spectregistration.p and b/source/+spect/spectregistration.p differ
diff --git a/source/+spect/spectsplinetoolsC.mexw32 b/source/+spect/spectsplinetoolsC.mexw32
deleted file mode 100644
index cc98cce..0000000
Binary files a/source/+spect/spectsplinetoolsC.mexw32 and /dev/null differ
diff --git a/source/+strain/strain.fig b/source/+strain/strain.fig
deleted file mode 100644
index 48e9aca..0000000
Binary files a/source/+strain/strain.fig and /dev/null differ
diff --git a/source/+strain/strain.p b/source/+strain/strain.p
deleted file mode 100644
index f4dc7fd..0000000
Binary files a/source/+strain/strain.p and /dev/null differ
diff --git a/source/+straintagging/CardiacMotion32.exe b/source/+straintagging/CardiacMotion32.exe
deleted file mode 100644
index 5d26a7f..0000000
Binary files a/source/+straintagging/CardiacMotion32.exe and /dev/null differ
diff --git a/source/+straintagging/LAXselectslices.m b/source/+straintagging/LAXselectslices.m
index 29b7330..76385e6 100644
--- a/source/+straintagging/LAXselectslices.m
+++ b/source/+straintagging/LAXselectslices.m
@@ -65,7 +65,8 @@ function init(taggroup) %#ok
case '2CH'
axh(tagno)=gui.handles.LAX2CH_axes;
colormap(axh(tagno),gray(255));
- gui.handles.im2CH=imshow(twochamber,'Parent',axh(tagno));
+ gui.handles.im2CH=image(cat(3,twochamber,twochamber,twochamber),'Parent',axh(tagno));
+ axis(axh(tagno),'off','image')
hold(axh(tagno), 'on')
set(axh(tagno),'plotboxaspectratio',[max(zsz)*...
ysz(tagno)*yres(tagno) xsz(tagno)*xres(tagno) 1]);
@@ -75,7 +76,8 @@ function init(taggroup) %#ok
case '3CH'
axh(tagno)=gui.handles.LAX3CH_axes;
colormap(axh(tagno),gray(255));
- gui.handles.im3CH=imshow(threechamber,'Parent',axh(tagno));
+ gui.handles.im3CH=image(cat(3,threechamber,threechamber,threechamber),'Parent',axh(tagno));
+ axis(axh(tagno),'off','image')
hold(axh(tagno), 'on')
set(axh(tagno),'plotboxaspectratio',[max(zsz)*...
ysz(tagno)*yres(tagno) xsz(tagno)*xres(tagno) 1]);
@@ -85,7 +87,8 @@ function init(taggroup) %#ok
case '4CH'
axh(tagno)=gui.handles.LAX4CH_axes;
colormap(axh(tagno),gray(255));
- gui.handles.im4CH=imshow(fourchamber,'Parent',axh(tagno));
+ gui.handles.im4CH=image(cat(3,fourchamber,fourchamber,fourchamber),'Parent',axh(tagno));
+ axis(axh(tagno),'off','image')
hold(axh(tagno), 'on')
set(axh(tagno),'plotboxaspectratio',[max(zsz)*...
ysz(tagno)*yres(tagno) xsz(tagno)*xres(tagno) 1]);
@@ -128,14 +131,30 @@ function init(taggroup) %#ok
%-------------------
%generates new stack then terminates the gui and start strain analysis
-global DATA
+global DATA SET
gui=DATA.GUI.LAXselectslices;
taggroup=gui.taggroup;
-strainno=LAXgenerateimagestack(taggroup);
+strainno=LAXgenerateimagestack(taggroup); %generates new image stacks
+
+%correct the taggroup, should be in order 2CH, 3CH, 4CH as they exist
+
+%find order for 2CH, 3CH, 4CH
+chamberexist(1,:)=strcmp('2CH',{SET.ImageViewPlane});
+chamberexist(2,:)=strcmp('3CH',{SET.ImageViewPlane});
+chamberexist(3,:)=strcmp('4CH',{SET.ImageViewPlane});
+taggroupnew = [];
+for chloop = 1:3
+ taggroupnew = [taggroupnew find(chamberexist(chloop,:))];
+end
+straingroup = strainno;
+straingroup(isnan(strainno)) = taggroup(isnan(strainno));
+for noloop = straingroup
+ SET(noloop).StrainTagging.taggroup = taggroupnew;
+end
close_callback;
-straintagging.straintagging('init','cine','longaxis');
+straintagging.straintagging('init','cine','longaxis',straingroup(1));
%----------------------
function close_callback
@@ -151,10 +170,12 @@ function init(taggroup) %#ok
end
%----------------------------------
-function strainno=LAXgenerateimagestack(taggroup)
+function strainnoall=LAXgenerateimagestack(taggroup)
%----------------------------------
global DATA SET
gui=DATA.GUI.LAXselectslices;
+strainnoall = [];
+ind = 1;
for tagno=taggroup
if SET(tagno).ZSize>1
@@ -219,6 +240,7 @@ function init(taggroup) %#ok
strainno = numel(SET)+1;
SET(strainno) = laxset;
SET(strainno).KeptSlices = gui.slicestouse{tagno};
+ strainnoall(ind) = strainno;
%Change some descriptors in previous making obscured for strain
%analysis
@@ -226,15 +248,13 @@ function init(taggroup) %#ok
SET(tagno).ImageViewPlane='Unspecified';
%draw new image stack and update volumes
- DATA.switchtoimagestack(strainno);
- segment_main('viewimage_Callback','montage');
+ viewfunctions('setview',1,1,strainno,{'montage'})
drawfunctions('drawthumbnails');
- drawfunctions('drawallslices');
- drawfunctions('drawimageno');
segment_main('updatevolume');
- segment_main('updatemodeldisplay');
- updatetool('select');
+ else
+ strainnoall(ind) = NaN;
end
+ ind = ind+1;
end
%-----------------------------------------
diff --git a/source/+straintagging/cm_readMhdData.p b/source/+straintagging/cm_readMhdData.p
index befcb25..672c26c 100644
Binary files a/source/+straintagging/cm_readMhdData.p and b/source/+straintagging/cm_readMhdData.p differ
diff --git a/source/+straintagging/cm_readVTKData.p b/source/+straintagging/cm_readVTKData.p
index c496640..b2191df 100644
Binary files a/source/+straintagging/cm_readVTKData.p and b/source/+straintagging/cm_readVTKData.p differ
diff --git a/source/+straintagging/cm_writeMhdData.p b/source/+straintagging/cm_writeMhdData.p
index 021939c..aae5389 100644
Binary files a/source/+straintagging/cm_writeMhdData.p and b/source/+straintagging/cm_writeMhdData.p differ
diff --git a/source/+straintagging/cm_writeVTKData.p b/source/+straintagging/cm_writeVTKData.p
index 4c14aa2..83c0218 100644
Binary files a/source/+straintagging/cm_writeVTKData.p and b/source/+straintagging/cm_writeVTKData.p differ
diff --git a/source/+straintagging/cropstraintagging.fig b/source/+straintagging/cropstraintagging.fig
index ae86150..2bcfe58 100644
Binary files a/source/+straintagging/cropstraintagging.fig and b/source/+straintagging/cropstraintagging.fig differ
diff --git a/source/+straintagging/cropstraintagging.m b/source/+straintagging/cropstraintagging.m
index 9d3d81b..e12f1c3 100644
--- a/source/+straintagging/cropstraintagging.m
+++ b/source/+straintagging/cropstraintagging.m
@@ -27,7 +27,7 @@
end
end
-gui = mygui(['straintagging' filesep 'cropstraintagging.fig']);
+gui = mygui(['+straintagging' filesep 'cropstraintagging.fig']);
DATA.GUI.CropStrainTagging = gui;
gui.state = false;
diff --git a/source/+straintagging/drawguide.fig b/source/+straintagging/drawguide.fig
index 420086e..fed0e09 100644
Binary files a/source/+straintagging/drawguide.fig and b/source/+straintagging/drawguide.fig differ
diff --git a/source/+straintagging/dyssynchrony.fig b/source/+straintagging/dyssynchrony.fig
index 764acd9..755cb54 100644
Binary files a/source/+straintagging/dyssynchrony.fig and b/source/+straintagging/dyssynchrony.fig differ
diff --git a/source/+straintagging/dyssynchrony.m b/source/+straintagging/dyssynchrony.m
index afa585a..fbdbff2 100644
--- a/source/+straintagging/dyssynchrony.m
+++ b/source/+straintagging/dyssynchrony.m
@@ -34,7 +34,11 @@ function init(taggroup,type)
.5 .5 0];
if strcmp(type,'LAX')
- set(gui.handles.typepopupmenu,'String',{'Longitudinal Peak Time';'Longitudinal Strain';'Radial Peak Time';'Radial Strain'})
+ set(gui.handles.typepopupmenu,'String',{...
+ dprintf('Longitudinal Peak Time');...
+ dprintf('Longitudinal Strain');...
+ dprintf('Radial Peak Time');...
+ dprintf('Radial Strain')})
include2ch=0;
include3ch=0;
include4ch=0;
@@ -91,7 +95,11 @@ function init(taggroup,type)
end
else
- set(gui.handles.typepopupmenu,'String',{'Circumferential Peak Time';'Circumferential Strain';'Radial Peak Time';'Radial Strain'})
+ set(gui.handles.typepopupmenu,'String',{...
+ dprintf('Circumferential Peak Time');...
+ dprintf('Circumferential Strain');...
+ dprintf('Radial Peak Time');...
+ dprintf('Radial Strain')})
no=taggroup;
T=SET(no).TSize;
@@ -585,10 +593,11 @@ function setpeakbuttonup(type,handleind)%#ok %type,ind)
strlist=get(gui.handles.typepopupmenu,'String');
ind=get(gui.handles.typepopupmenu,'Value');
str=strlist{ind};
+engstr = translation.dictionary(str,'English',DATA.Pref.Language); %ensure that it is English
hold(h,'on')
grid(h,'on');
-switch str
+switch engstr
case {'Circumferential Peak Time','Longitudinal Peak Time'}
set(h,'Ydir','reverse')
for i=gui.sections2show%1:17
@@ -598,7 +607,7 @@ function setpeakbuttonup(type,handleind)%#ok %type,ind)
set(h,'ytick',1:17)
set(h,'yticklabel',ahastri(pos))
ylim(h,[0,18])
- legend(h,gui.handles.cumplabel,'Cumulative strain peak')
+ legend(h,gui.handles.cumplabel,dprintf('Cumulative strain peak'))
ylabel(h,'')
case 'Radial Peak Time'
@@ -610,7 +619,7 @@ function setpeakbuttonup(type,handleind)%#ok %type,ind)
set(h,'ytick',1:17)
set(h,'yticklabel',ahastri(pos))
ylim(h,[0,18])
- legend(h,gui.handles.cumplabel,'Cumulative strain peak')
+ legend(h,gui.handles.cumplabel,dprintf('Cumulative strain peak'))
ylabel(h,'')
case {'Circumferential Strain','Longitudinal Strain'}
@@ -638,7 +647,7 @@ function setpeakbuttonup(type,handleind)%#ok %type,ind)
xlim(h,[0,gui.tvec(end)])
ylabel(h,'%')
end
-xlabel(h,'Heart Cycle [s/T]')
+xlabel(h,dprintf('Heart Cycle [s/T]'))
hold(h,'off')
diff --git a/source/+straintagging/runexe.p b/source/+straintagging/runexe.p
index 9fc23b1..8a9ab16 100644
Binary files a/source/+straintagging/runexe.p and b/source/+straintagging/runexe.p differ
diff --git a/source/+straintagging/strain.fig b/source/+straintagging/strain.fig
index 6303c15..1218cde 100644
Binary files a/source/+straintagging/strain.fig and b/source/+straintagging/strain.fig differ
diff --git a/source/+straintagging/strainrate.fig b/source/+straintagging/strainrate.fig
index ab783d1..260641b 100644
Binary files a/source/+straintagging/strainrate.fig and b/source/+straintagging/strainrate.fig differ
diff --git a/source/+straintagging/strainrate.m b/source/+straintagging/strainrate.m
deleted file mode 100644
index 4616b87..0000000
--- a/source/+straintagging/strainrate.m
+++ /dev/null
@@ -1,1092 +0,0 @@
-function varargout = strainrate(varargin)
-%Gives strainrate measures
-
-macro_helper(varargin{:});
-[varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
-
-
-%---------------------------------------
-function init(taggroup,type)
-%----------------------------------------
-global SET DATA
-
-gui = mygui(fullfile('+straintagging','strainrate.fig'));
-DATA.GUI.strainrate = gui;
-if strcmp(type,'LAX')
- taggrouptmp=nan(1,3);
- %sort taggroup so we can always use gui.views2show for indexes in LAX
- for tagno=taggroup
- switch SET(tagno).ImageViewPlane
- case '2CH'
- taggrouptmp(1)=tagno;
- case '3CH'
- taggrouptmp(2)=tagno;
- case '4CH'
- taggrouptmp(3)=tagno;
- end
- end
- taggrouptmp(isnan(taggrouptmp))=[];
- taggroup=taggrouptmp;
- gui.taggroup=taggroup;
-else
- gui.taggroup=taggroup;
-end
-gui.oneatatime=0;
-gui.lastpressed=[];
-gui.tvec = SET(taggroup(1)).StrainTagging.strainrateTvect;
-gui.cmap=[1 1 0;...
- 0 0 1;...
- 0 1 0;...
- 0 1 1;...
- 1 0 0;...
- 1 0 1;...
- .5 .5 0;...
- .8 .8 .8;...
- 240/255 120/255 0;...
- 64/255 0 128/255;...
- 128/255 64/255 0;...
- 0 64/255 0;...
- 128/255 128/255 128/255;...
- 128/255 128/255 1;...
- 0 128/255 128/255;...
- 128/255 0 0;...
- 1 128/255 128/255];
-
-srstack=[];
-for no = taggroup
- if isfield(SET(no).StrainTagging,'SR')
- srstack=no;
- break;
- end
-end
-
-if isempty(srstack) %|| isfield(SET(no).StrainTagging.SR,'updated')
- tmpstruct = calcstrainrate(type, taggroup);
-else
- tmpstruct=SET(srstack).StrainTagging.SR;
-end
-
-%combine structs
- f = fieldnames(tmpstruct);
- for i = 1:length(f)
- gui.(f{i}) = tmpstruct.(f{i});
- end
-
-switch type
- case 'LAX'
-
- %gui.tvec = %linspace(0,1,SET(taggroup(1)).TSize-2);
- strcell={'2CH','3CH','4CH'};
- gui.radios2show =1:sum(gui.include);%1:length(taggroup);
- set(gui.handles.typepopupmenu ,'String',{'Longitudinal Strain Rate';...
- 'Radial Strain Rate';...
- 'Mean Longitudinal Strain Rate';...
- 'Mean Radial Strain Rate';...
- 'Mean Longitudinal Strain with Tangents';...
- 'Mean Radial Strain with Tangents';...
- 'Longitudinal Strain with Tangents';...
- 'Radial Strain with Tangents'});
- used=find(gui.include);
- for i=gui.radios2show
- set(gui.handles.(['radiobutton',num2str(i)]),'String',strcell{used(i)});
- set(gui.handles.(['radiobutton',num2str(i)]),'Value',1);
- set(gui.handles.(['radiobutton',num2str(i)]),'backgroundcolor',gui.cmap(i,:))
- end
-% for i=1:length(gui.include)%gui.radios2show
-% set(gui.handles.(['radiobutton',num2str(i)]),'Value',1);
-% set(gui.handles.(['radiobutton',num2str(i)]),'backgroundcolor',gui.cmap(i,:))
-% end
- set(gui.handles.circtext,'String','Longit. [%/s]');
-
- set(gui.handles.globalcirctext,'String','Longit. [%/(s/T)]');
- set(gui.handles.globalradtext,'String','Rad. [%/(s/T)]');
- case 'SAX'
-
- %graphical
- set(gui.handles.typepopupmenu ,'String',{'Circumferential Strain Rate';...
- 'Radial Strain Rate';...
- 'Mean Circumferential Strain Rate';...
- 'Mean Radial Strain Rate';...
- 'Mean Circumferential Strain with Tangents';...
- 'Mean Radial Strain with Tangents';...
- 'Circumferential Strain with Tangents';...
- 'Radial Strain with Tangents'});
- usedslices=find(gui.include);
- gui.radios2show=1:length(usedslices);
- for i=gui.radios2show
- set(gui.handles.(['radiobutton',num2str(i)]),'Value',1);
- set(gui.handles.(['radiobutton',num2str(i)]),'String',sprintf('Slice %d',usedslices(i)))
- set(gui.handles.(['radiobutton',num2str(i)]),'backgroundcolor',gui.cmap(i,:))
- end
-
- set(gui.handles.circtext,'String','Circ. [%/s]');
-
- set(gui.handles.globalcirctext,'String','Circ. [%/s]');
- set(gui.handles.globalradtext,'String','Rad. [%/s]');
- set(gui.handles.autoviewpeakpushbutton, 'String','Auto Detect Slice Peaks')
-end
-
-%graphical
-for r = gui.radios2show(end)+1:17
- set(gui.handles.(['radiobutton' num2str(r)]),'visible', 'off')
- set(gui.handles.(['text' num2str(r)]),'visible', 'off')
- set(gui.handles.(['text' num2str(17+r)]),'visible', 'off')
- set(gui.handles.(['text' num2str(2*17+r)]),'visible', 'off')
- set(gui.handles.(['text' num2str(3*17+r)]),'visible', 'off')
-end
-
-% gui.popupind=get(gui.handles.typepopupmenu,'Value');
-
-radio_Callback;
-
-%--------------------------------------------------------------
-function resetpeaks_Callback(type)
-%--------------------------------------------------------------
-global DATA
-
-gui=DATA.GUI.strainrate;
-
-switch type
- case 'global'
- [gui.globalradup, gui.globalradupind] = max(gui.globalsrrad);
- [gui.globalraddown, gui.globalraddownind] = min(gui.globalsrrad);
- [gui.globalcircup, gui.globalcircupind] = max(gui.globalsrcirc);
- [gui.globalcircdown, gui.globalcircdownind] = min(gui.globalsrcirc);
- case 'views'
- [gui.radup, gui.radupind] = max(gui.srrad,[],2);
- [gui.raddown, gui.raddownind] = min(gui.srrad,[],2);
- [gui.circup, gui.circupind] = max(gui.srcirc,[],2);
- [gui.circdown, gui.circdownind] = min(gui.srcirc,[],2);
-end
-
-updateplot
-
-
-%---------------------------------------------------------------
-function [sr] = calcstrainrate(type, taggroup)
-%---------------------------------------------------------------
-%Calculates strainrate from stack group
-global SET
-
-
-switch type
- case 'LAX'
- sz=[3, SET(taggroup(1)).TSize-2];
- sr.srcirc =nan(sz);
- sr.srrad = nan(sz);
- sr.include=zeros(1,3);
- for i = 1:length(taggroup)
- switch SET(taggroup(i)).ImageViewPlane
- case '2CH'
- if ~all(all(isnan(SET(taggroup(i)).StrainTagging.strainratecircum)))
- sr.srcirc(1,:) = squeeze(nanmean(SET(taggroup(i)).StrainTagging.strainratecircum,2));
- sr.srrad(1,:) = squeeze(nanmean(SET(taggroup(i)).StrainTagging.strainraterad,2));
- sr.include(1)=1;
- else
- sr.include(1)=0;
- end
- case '3CH'
- if ~all(all(isnan(SET(taggroup(i)).StrainTagging.strainratecircum)))
- sr.srcirc(end-1,:) = squeeze(nanmean(SET(taggroup(i)).StrainTagging.strainratecircum,2));
- sr.srrad(end-1,:) = squeeze(nanmean(SET(taggroup(i)).StrainTagging.strainraterad,2));
- sr.include(2)=1;
- else
- sr.include(2)=0;
- end
- case '4CH'
- if ~all(all(isnan(SET(taggroup(i)).StrainTagging.strainratecircum)))
- sr.srcirc(end,:) = squeeze(nanmean(SET(taggroup(i)).StrainTagging.strainratecircum,2));
- sr.srrad(end,:) = squeeze(nanmean(SET(taggroup(i)).StrainTagging.strainraterad,2));
- sr.include(3)=1;
- else
- sr.include(3)=0;
- end
- end
- end
- sr.srcirc=sr.srcirc(find(sr.include),:);
- sr.srrad=sr.srrad(find(sr.include),:);
-
- case 'SAX'
- sr.srcirc = squeeze(nanmean(SET(taggroup(1)).StrainTagging.strainratecircum,2))';
- sr.srrad = squeeze(nanmean(SET(taggroup(1)).StrainTagging.strainraterad,2))';
-
- tmp1=[];
- tmp2=[];
- sr.include=ones(1,SET(taggroup(1)).ZSize);
- for i = 1:SET(taggroup(1)).ZSize
- if ~all(isnan(sr.srcirc(i,2:end)))
- tmp1=[tmp1;sr.srcirc(i,:)];
- tmp2=[tmp2;sr.srrad(i,:)];
- else
- sr.include(i)=0;
- end
- end
- sr.srcirc=tmp1;
- sr.srrad=tmp2;
-end
-
-%Global Strain
- if strcmp(SET(taggroup(1)).ImageViewPlane,'Short-axis')
- sr.globalsrrad = nanmean(sr.srrad,1);
- sr.globalsrcirc = nanmean(sr.srcirc,1);
- else
- %global strainrate normalised if LAX images
- normstrainratecirc=[];
- normstrainraterad =[];
-
- for tagno = taggroup
- normstrainratecirc = [normstrainratecirc, conv2([1 0 -1],1,SET(tagno).StrainTagging.globalcirc,'valid')/(2/(SET(tagno).TSize-1))];
- normstrainraterad = [normstrainraterad, conv2([1 0 -1],1,SET(tagno).StrainTagging.globalrad,'valid')/(2/(SET(tagno).TSize-1))];
- end
-
- sr.globalsrcirc=nanmean(normstrainratecirc,2);
- sr.globalsrrad=nanmean(normstrainraterad,2);
- end
-
- [sr.globalradup, sr.globalradupind] = max(sr.globalsrrad);
- [sr.globalraddown, sr.globalraddownind] = min(sr.globalsrrad);
- [sr.globalcircup, sr.globalcircupind] = max(sr.globalsrcirc);
- [sr.globalcircdown, sr.globalcircdownind] = min(sr.globalsrcirc);
-
-[sr.radup, sr.radupind] = max(sr.srrad,[],2);
-[sr.raddown, sr.raddownind] = min(sr.srrad,[],2);
-[sr.circup, sr.circupind] = max(sr.srcirc,[],2);
-[sr.circdown, sr.circdownind] = min(sr.srcirc,[],2);
-
-%---------------------------------------------------------------
-function setpeak_Callback(type,dir)
-%--------------------------------------------------------------
-global DATA
-gui = DATA.GUI.strainrate ;
-h=gui.handles.segaxes;
-
-if nargin < 2
- switch type
- case 'circ'
- tmp=[gui.handles.peakscircup,gui.handles.peakscircdown];
- case 'rad'
- tmp=[gui.handles.peaksradup,gui.handles.peaksraddown];
- case 'globalcirc'
- tmp=[gui.handles.globalpeakcircup,gui.handles.globalpeakcircdown];
- case 'globalrad'
- tmp=[gui.handles.globalpeakradup,gui.handles.globalpeakraddown];
- end
-
- if ~any(strcmp(type,{'globalrad','globalcirc'}))
- x=nan(1,gui.radios2show(end)*2);
- y=nan(1,gui.radios2show(end)*2);
-
- for i = [gui.views2show,gui.views2show+gui.radios2show(end)]
- x(i)=get(tmp(i),'Xdata');
- y(i)=get(tmp(i),'Ydata');
- end
-
- [xclick,yclick]=mygetcurrentpoint(h);
- [~,ind]=min((xclick-x).^2+(yclick-y).^2);
-
- if ind<=gui.radios2show(end)
- dir='up';
- else
- dir='down';
- end
- else
- for i = 1:2
- x(i)=get(tmp(i),'Xdata');
- y(i)=get(tmp(i),'Ydata');
- end
-
- [xclick,yclick]=mygetcurrentpoint(h);
- [~,ind]=min((xclick-x).^2+(yclick-y).^2);
-
- if ind==1
- dir = 'up';
- else
- dir = 'down';
- end
- end
-end
-
-
- switch type
- case 'circ'
- switch dir
- case 'up'
- peakhandle=gui.handles.peakscircup;
- case 'down'
- peakhandle=gui.handles.peakscircdown;
- end
- case 'rad'
- switch dir
- case 'up'
- peakhandle=gui.handles.peaksradup;
- case 'down'
- peakhandle=gui.handles.peaksraddown;
- end
- case 'globalcirc'
- switch dir
- case 'up'
- peakhandle=gui.handles.globalpeakcircup;
- case 'down'
- peakhandle=gui.handles.globalpeakcircdown;
- end
- case 'globalrad'
- switch dir
- case 'up'
- peakhandle=gui.handles.globalpeakradup;
- case 'down'
- peakhandle=gui.handles.globalpeakraddown;
- end
- end
-
- if ~strcmp(type,{'globalcirc','globalrad'})
- for i = gui.views2show
- x(i)=get(peakhandle(i),'Xdata');
- y(i)=get(peakhandle(i),'Ydata');
- end
- else
- x=get(peakhandle,'Xdata');
- y=get(peakhandle,'Ydata');
- end
-
- [xclick,yclick]=mygetcurrentpoint(h);
- [~,ind]=min((xclick-x).^2+(yclick-y).^2);
-
- switch type
- case 'circ'
- switch dir
- case 'down'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''circ'',''down'',%d)',ind));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''circ'',''down'',%d)',ind));
- case 'up'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''circ'',''up'',%d)',ind));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''circ'',''up'',%d)',ind));
- end
- case 'rad'
- switch dir
- case 'down'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''rad'',''down'',%d)',ind));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''rad'',''down'',%d)',ind));
- case 'up'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''rad'',''up'',%d)',ind));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''rad'',''up'',%d)',ind));
- end
- case 'globalcirc'
- switch dir
- case 'down'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''globalcirc'',''down'')'));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''globalcirc'',''down'')'));
- case 'up'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''globalcirc'',''up'')'));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''globalcirc'',''up'')'));
- end
- case 'globalrad'
- switch dir
- case 'down'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''globalrad'',''down'')'));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''globalrad'',''down'')'));
- case 'up'
- myset(gui.handles.fig,'windowbuttonmotionfcn',sprintf('straintagging.strainrate(''setpeakmotion'',''globalrad'',''up'')'));
- myset(gui.handles.fig,'windowbuttonupfcn',sprintf('straintagging.strainrate(''setpeakbuttonup'',''globalrad'',''up'')'));
- end
- end
-
-
-%-------------------------------------------------------
-function setpeakmotion(type,dir,handleind)%type,ind)
-%--------------------------------------------------
-global DATA
-gui = DATA.GUI.strainrate ;
-h=gui.handles.segaxes;
-
-switch type
- case 'circ'
- switch dir
- case 'up'
- peakhandle = gui.handles.peakscircup(handleind);
- case 'down'
- peakhandle = gui.handles.peakscircdown(handleind);
- end
- graphhandle=gui.handles.graphscirc(handleind);
-
- case 'rad'
- switch dir
- case 'up'
- peakhandle = gui.handles.peaksradup(handleind);
- case 'down'
- peakhandle = gui.handles.peaksraddown(handleind);
- end
- graphhandle=gui.handles.graphsrad(handleind);
-
- case 'globalcirc'
- switch dir
- case 'up'
- peakhandle = gui.handles.globalpeakcircup;
- case 'down'
- peakhandle = gui.handles.globalpeakcircdown;
- end
- graphhandle = gui.handles.globalgraphcirc;
- case 'globalrad'
- switch dir
- case 'up'
- peakhandle = gui.handles.globalpeakradup;
- case 'down'
- peakhandle = gui.handles.globalpeakraddown;
- end
- graphhandle = gui.handles.globalgraphrad;
-end
-
-[xclicked,~]=mygetcurrentpoint(h);
-x=get(graphhandle,'Xdata');
-[~,ind]=min((x-xclicked).^2);
-y=get(graphhandle,'Ydata');
-set(peakhandle,'Xdata',x(ind),'Ydata',y(ind))
-
-if get(gui.handles.typepopupmenu,'Value')>4 && ind>1
- ind=ind-1;
-end
-
-switch type
- case 'circ'
- switch dir
- case 'up'
- gui.circupind(handleind) = ind;
- gui.circup(handleind) = gui.srcirc(handleind,ind);%y(ind);
- case 'down'
- gui.circdownind(handleind) = ind;
- gui.circdown(handleind) = gui.srcirc(handleind,ind);%y(ind);
- end
- case 'rad'
- switch dir
- case 'up'
- gui.radupind(handleind) = ind;
- gui.radup(handleind) = gui.srrad(handleind,ind);%y(ind);
- case 'down'
- gui.raddownind(handleind) = ind;
- gui.raddown(handleind) = gui.srrad(handleind,ind);%y(ind);
- end
- case 'globalrad'
- switch dir
- case 'up'
- gui.globalradupind = ind;
- gui.globalradup = gui.globalsrrad(ind);
- case 'down'
- gui.globalraddownind = ind;
- gui.globalraddown = gui.globalsrrad(ind);
- end
- case 'globalcirc'
- switch dir
- case 'up'
- gui.globalcircupind = ind;
- gui.globalcircup = gui.globalsrcirc(ind);
- case 'down'
- gui.globalcircdownind = ind;
- gui.globalcircdown = gui.globalsrcirc(ind);
- end
-end
-
-for i=gui.views2show
- set(gui.handles.(['text',num2str(i)]),'String',sprintf('%0.1f',gui.circup(i)))
- set(gui.handles.(['text',num2str(17+i)]),'String',sprintf('%0.1f',gui.circdown(i)))
- set(gui.handles.(['text',num2str(2*17+i)]),'String',sprintf('%0.1f',gui.radup(i)))
- set(gui.handles.(['text',num2str(3*17+i)]),'String',sprintf('%0.1f',gui.raddown(i)))
-end
-
-
-set(gui.handles.('globalcircuptext'),'String',sprintf('%0.1f',gui.globalcircup))
-set(gui.handles.('globalcircdowntext'),'String',sprintf('%0.1f',gui.globalcircdown))
-set(gui.handles.('globalraduptext'),'String',sprintf('%0.1f',gui.globalradup))
-set(gui.handles.('globalraddowntext'),'String',sprintf('%0.1f',gui.globalraddown))
-
-
-function setpeakbuttonup(type,dir,handleind)%type,ind)
-global DATA
-gui = DATA.GUI.strainrate;
-
-if nargin<3
-setpeakmotion(type,dir)
-else
-setpeakmotion(type,dir,handleind)
-end
-set(gui.handles.fig,'windowbuttonmotionfcn',[]);
-set(gui.handles.fig,'windowbuttonupfcn',[])
-
-switch type
- case 'circ'
- myset(gui.handles.fig,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''circ'')'))
- case 'rad'
- myset(gui.handles.fig,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''rad'')'))
- case ''
-end
-
-function all_Callback
-global DATA
-gui = DATA.GUI.strainrate ;
-
-if gui.oneatatime
- val=get(gui.handles.oneatatimecheckbox,'value');
- set(gui.handles.oneatatimecheckbox,'value',~val)
- oneatatime_Callback;
-end
-
-
-for i=gui.radios2show
- myset(gui.handles.(['radiobutton',num2str(i)]),'Value',1);
-end
-
-radio_Callback
-
-
-%-----------------------------------------------
-function oneatatime_Callback
-%---------------------------------------------
-global DATA
-gui = DATA.GUI.strainrate;
-
-oneatatime=get(gui.handles.oneatatimecheckbox,'value');
-set(gui.handles.oneatatimecheckbox,'value',oneatatime);
-gui.oneatatime=oneatatime;
-
-if oneatatime
- ind=[];
- for i=1:17
- val=get(gui.handles.(['radiobutton',num2str(i)]),'Value');
- if val
- ind=i;
- break;
- end
- end
-
- if isempty(ind)
- set(gui.handles.('radiobutton1'),'Value',1)
- ind=1;
- end
-
- for i=1:17
- myset(gui.handles.(['radiobutton',num2str(i)]),'Value',0);
- end
- myset(gui.handles.(['radiobutton',num2str(ind)]),'Value',1);
- gui.lastpressed=ind;
-
- gui.views2show=ind;
-
-% %Auto detect global
-% strlist=get(gui.handles.typepopupmenu,'String');
-% ind=get(gui.handles.typepopupmenu,'Value');
-% str=strlist{ind};
-
-%if any(strcmp(str,{'Mean Longitudinal Strain Rate', 'Mean Radial Strain Rate', 'Mean Circumferential Strain Rate','Mean Longitudinal Strain with Tangents', 'Mean Radial Strain with Tangents', 'Mean Circumferential Strain with Tangents'}))
- setglobalpeaks;
-%end
-
- updateplot;
-end
-%----------------------------------------------------------------
-function radio_Callback
-%---------------------------------------------------------------
-global DATA
-gui = DATA.GUI.strainrate ;
-
-if gui.oneatatime
- myset(gui.handles.(['radiobutton',num2str(gui.lastpressed)]),'Value',0);
-end
-
-tmp=zeros(1,17);
-for i=1:17
- tmp(i)=get(gui.handles.(['radiobutton',num2str(i)]),'Value');
-end
-
-if gui.oneatatime
- lastpressed=find(tmp);
- if isempty(lastpressed)
- myset(gui.handles.(['radiobutton',num2str(gui.lastpressed)]),'Value',1);
- return;
- else
- myset(gui.handles.(['radiobutton',num2str(lastpressed)]),'Value',1);
- gui.lastpressed=lastpressed;
- end
-end
-
-gui.views2show=find(tmp);
-
-% %Auto detect global
-% strlist=get(gui.handles.typepopupmenu,'String');
-% ind=get(gui.handles.typepopupmenu,'Value');
-% str=strlist{ind};
-
-%if any(strcmp(str,{'Mean Longitudinal Strain Rate', 'Mean Radial Strain Rate', 'Mean Circumferential Strain Rate','Mean Longitudinal Strain with Tangents', 'Mean Radial Strain with Tangents', 'Mean Circumferential Strain with Tangents'}))
- setglobalpeaks;
-%end
-
-updateplot;
-
-%---------------------------------------
-function setglobalpeaks
-%---------------------------------------
-global SET DATA
-gui = DATA.GUI.strainrate;
-%Auto detect global
-
-if strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')
- gui.globalsrrad = nanmean(gui.srrad(gui.views2show,:),1);
- gui.globalsrcirc = nanmean(gui.srcirc(gui.views2show,:),1);
-else
- %global strainrate normalised if LAX images
- normstrainratecirc=[];
- normstrainraterad =[];
-
- for tagno = gui.taggroup
- normstrainratecirc = [normstrainratecirc, conv2([1 0 -1],1,SET(tagno).StrainTagging.globalcirc,'valid')/(2/(SET(tagno).TSize-1))];
- normstrainraterad = [normstrainraterad, conv2([1 0 -1],1,SET(tagno).StrainTagging.globalrad,'valid')/(2/(SET(tagno).TSize-1))];
- end
-
- gui.globalsrcirc=nanmean(normstrainratecirc(:,gui.views2show),2);
- gui.globalsrrad=nanmean(normstrainraterad(:,gui.views2show),2);
-end
-
-%change value but not time
-gui.globalradup=gui.globalsrrad(gui.globalradupind);
-gui.globalraddown=gui.globalsrrad(gui.globalraddownind);
-gui.globalcircup=gui.globalsrcirc(gui.globalcircupind);
-gui.globalcircdown=gui.globalsrcirc(gui.globalcircdownind);
-
-
-% [gui.globalradup, gui.globalradupind] = max(gui.globalsrrad);
-% [gui.globalraddown, gui.globalraddownind] = min(gui.globalsrrad);
-% [gui.globalcircup, gui.globalcircupind] = max(gui.globalsrcirc);
-% [gui.globalcircdown, gui.globalcircdownind] = min(gui.globalsrcirc);
-
-
-%----------------------------------------
-function plotNonSegmentedStrainrate(h,tvec,straincurve,type,normalizedtime)
-%----------------------------------------
-global DATA
-
-if nargin<5
- normalizedtime=0;
-end
-gui=DATA.GUI.strainrate;
-
-switch type
- case 'globalcirc'
- downslope=gui.globalcircdown;
- inddown=gui.globalcircdownind;
- upslope=gui.globalcircup;
- indup=gui.globalcircupind;
- case 'globalrad'
- downslope=gui.globalraddown;
- inddown=gui.globalraddownind;
- upslope=gui.globalradup;
- indup=gui.globalradupind;
-end
-
-plot(h,tvec,straincurve,'.-','linewidth',2,'Color','b')
-hold(h,'on')
-inddown = inddown+1;
-indup=indup+1;
-downtime = tvec(inddown);
-uptime = tvec(indup);
-plot(h,downtime,straincurve(inddown),'r+','markersize',10,'linewidth',3)
-plot(h,uptime,straincurve(indup),'k+','markersize',10,'linewidth',3)
-
-tangentplot(h,tvec,straincurve,normalizedtime,inddown,indup,downtime,uptime);
-
-% xlim(h,[tvec(1),tvec(end)])
-% ylim(h,'manual')
-% xlim(h,'manual')
-% x=-SET(gui.taggroup(1)).TSize:SET(gui.taggroup(1)).TSize;
-% if ~normalizedtime
-% uptan_t=uptime+x*SET(gui.taggroup(1)).TIncr;
-% downtan_t=downtime+x*SET(gui.taggroup(1)).TIncr;
-%
-% uptan = upslope*SET(gui.taggroup(1)).TIncr*x+straincurve(indup);
-% downtan = downslope*SET(gui.taggroup(1)).TIncr*x+straincurve(inddown);
-% else
-% uptan_t=uptime+x/(SET(gui.taggroup(1)).TSize-1);
-% downtan_t=downtime+x/(SET(gui.taggroup(1)).TSize-1);
-%
-% uptan = upslope/(SET(gui.taggroup(1)).TSize-1)*x+straincurve(indup);
-% downtan = downslope/(SET(gui.taggroup(1)).TSize-1)*x+straincurve(inddown);
-% end
-%
-% gui.handles.tup = plot(h,uptan_t,uptan,'k--');
-% gui.handles.tdown = plot(h,downtan_t,downtan,'k--');
-
-% if ~normalizedtime
-% m=straincurve(indup+1)-upslope*SET(gui.taggroup(1)).TIncr*indup;
-% else
-% m=straincurve(indup+1)-upslope/(SET(gui.taggroup(1)).TSize-1)*indup;
-% end
-%
-% xup(1)=(yl(1)-m)/upslope;
-% xup(2)=(yl(2)-m)/upslope;
-%
-% if ~normalizedtime
-% m=straincurve(inddown+1)-downslope*SET(gui.taggroup(1)).TIncr*inddown;
-% else
-% m=straincurve(inddown+1)-downslope/(SET(gui.taggroup(1)).TSize-1)*inddown;
-% end
-%
-% xdown(1)=(yl(1)-m)/downslope;
-% % xdown(2)=(yl(2)-m)/downslope;
-% gui.handles.tup = plot(h,xup,yl,'k--');
-% gui.handles.tdown = plot(h,xdown,yl,'k--');
-function tangentplot(h,tvec,straincurve,normalizedtime,inddown,indup,downtime,uptime,downslope,upslope)
-global SET DATA
-
-gui=DATA.GUI.strainrate;
-
-
-if ~strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')
- if indup~=1
- upslope = -(straincurve(indup-1)-straincurve(indup+1))/(2/(SET(gui.taggroup(1)).TSize-1));
- else
- upslope = -(straincurve(indup)-straincurve(indup+1))/(1/(SET(gui.taggroup(1)).TSize-1));
- end
- if inddown~=1
- downslope = -(straincurve(inddown-1)-straincurve(inddown+1))/(2/(SET(gui.taggroup(1)).TSize-1));
- else
- downslope = -(straincurve(inddown)-straincurve(inddown+1))/(1/(SET(gui.taggroup(1)).TSize-1));
- end
-else
- if indup~=1
- upslope = -(straincurve(indup-1)-straincurve(indup+1))/(2*SET(gui.taggroup(1)).TIncr);
- else
- upslope = -(straincurve(indup)-straincurve(indup+1))/(1*SET(gui.taggroup(1)).TIncr);
- end
- if inddown~=1
- downslope = -(straincurve(inddown-1)-straincurve(inddown+1))/(2*SET(gui.taggroup(1)).TIncr);
- else
- downslope = -(straincurve(inddown)-straincurve(inddown+1))/(1*SET(gui.taggroup(1)).TIncr);
- end
-end
-
-xlim(h,[tvec(1),tvec(end)])
-ylim(h,'manual')
-xlim(h,'manual')
-x=-SET(gui.taggroup(1)).TSize:SET(gui.taggroup(1)).TSize;
-if ~normalizedtime
- uptan_t=uptime+x*SET(gui.taggroup(1)).TIncr;
- downtan_t=downtime+x*SET(gui.taggroup(1)).TIncr;
-
- uptan = upslope*SET(gui.taggroup(1)).TIncr*x+straincurve(indup);
- downtan = downslope*SET(gui.taggroup(1)).TIncr*x+straincurve(inddown);
-else
- uptan_t=uptime+x/(SET(gui.taggroup(1)).TSize-1);
- downtan_t=downtime+x/(SET(gui.taggroup(1)).TSize-1);
-
- uptan = upslope/(SET(gui.taggroup(1)).TSize-1)*x+straincurve(indup);
- downtan = downslope/(SET(gui.taggroup(1)).TSize-1)*x+straincurve(inddown);
-end
-
-gui.handles.tup = plot(h,uptan_t,uptan,'k--');
-gui.handles.tdown = plot(h,downtan_t,downtan,'k--');
-
-function updateplot
-global DATA SET
-
-gui = DATA.GUI.strainrate ;
-myset(gui.handles.fig,'ButtonDownFcn',[])
-h=gui.handles.segaxes;
-legend(h,'off')
-
-cla(h)
-%cla(gui.handles.reportaxes)
-%changed curve choice need to redo globalpeaks
-% if gui.popupind~=get(gui.handles.typepopupmenu,'Value');
-% setglobalpeaks;
-% gui.popupind=get(gui.handles.typepopupmenu,'Value');
-% end
-
-set(h,'yticklabelmode','auto')
-set(h,'ytickmode','auto')
-
-ylim(h,'auto')
-xlim(h,'auto')
-% get names of segments
-
-strlist=get(gui.handles.typepopupmenu,'String');
-ind=get(gui.handles.typepopupmenu,'Value');
-str=strlist{ind};
-
-hold(h,'on')
-grid(h,'on');
-
-used=find(gui.include);
-
-if ~strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')
- normalizedtime=1;
- tvec=linspace(0,1,SET(gui.taggroup(1)).TSize);
- srtvec=tvec(2:end-1);
-else
- srtvec=gui.tvec;
- tvec=SET(gui.taggroup(1)).TimeVector;
- normalizedtime=0;
-end
-
-
-switch str
- case 'Mean Longitudinal Strain with Tangents'
- straincurves=[];
- counter=1;
-
- for tagno=gui.taggroup
- straincurves = [straincurves, SET(tagno).StrainTagging.globalcirc];
- end
-
- straincurve=mynanmean(straincurves(:,gui.views2show),2);
- plotNonSegmentedStrainrate(h,tvec,straincurve,'globalcirc',normalizedtime);
-
- case 'Mean Circumferential Strain with Tangents'
- straincurve=mynanmean(SET(gui.taggroup(1)).StrainTagging.globalcirc(:,used(gui.views2show)),2);
- plotNonSegmentedStrainrate(h,SET(gui.taggroup(1)).TimeVector,straincurve,'globalcirc');
-
- case 'Mean Radial Strain with Tangents'
- straincurves=[];
-
- for tagno=gui.taggroup
- straincurves = [straincurves, SET(tagno).StrainTagging.globalrad];
- end
- if strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')
- straincurve=mynanmean(straincurves(:,used(gui.views2show)),2);
- else
- straincurve=mynanmean(straincurves(:,gui.views2show),2);
- end
- plotNonSegmentedStrainrate(h,tvec,straincurve,'globalrad',normalizedtime);
-
- case {'Longitudinal Strain with Tangents','Circumferential Strain with Tangents'}
- straincurve = nan(SET(gui.taggroup(1)).TSize,length(gui.taggroup));
- used = find(gui.include);
- for i=gui.views2show
- if strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')
- straincurve(:,i)=SET(gui.taggroup(1)).StrainTagging.globalcirc(:,used(i));
- else
- straincurve(:,i)=SET(gui.taggroup(i)).StrainTagging.globalcirc;
-% switch SET(gui.taggroup(used(i))).ImageViewPlane
-% case '2CH'
-% straincurve(:,1)=SET(gui.taggroup(used(i))).StrainTagging.globalcirc;
-% case '3CH'
-% straincurve(:,end-1)=SET(gui.taggroup(i)).StrainTagging.globalcirc;
-% case '4CH'
-% straincurve(:,end)=SET(gui.taggroup(i)).StrainTagging.globalcirc;
-% end
- end
- end
- for i = gui.views2show
- gui.handles.graphscirc(i)=plot(h,tvec,straincurve(:,i),'.-','linewidth',2,'Color',gui.cmap(i,:));
- gui.handles.peakscircup(i)=plot(h,srtvec(gui.circupind(i)), straincurve(gui.circupind(i)+1,i),'k+','markersize',10,'linewidth',3);
- gui.handles.peakscircdown(i)=plot(h,srtvec(gui.circdownind(i)), straincurve(gui.circdownind(i)+1,i),'r+','markersize',10,'linewidth',3);
- myset(gui.handles.peakscircup(i),'ButtonDownFcn','');
- myset(gui.handles.peakscircdown(i),'ButtonDownFcn','');
- myset(gui.handles.graphscirc(i),'ButtonDownFcn','');
- end
-
-
- for i = gui.views2show
- tangentplot(h,tvec,straincurve(:,i),normalizedtime,gui.circdownind(i)+1,gui.circupind(i)+1,...
- srtvec(gui.circdownind(i)),srtvec(gui.circupind(i)),gui.circdown(i),gui.circup(i));
- end
-
- myset(h,'ButtonDownFcn','');
-
- case'Radial Strain with Tangents'
- straincurve = nan(SET(gui.taggroup(1)).TSize,length(gui.views2show));
- used = find(gui.include);
- for i=1:length(used)
- if strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')
- straincurve(:,i)=SET(gui.taggroup(1)).StrainTagging.globalrad(:,used(i));
- else
- straincurve(:,i)=SET(gui.taggroup(i)).StrainTagging.globalrad;
-% switch SET(gui.taggroup(i)).ImageViewPlane
-% case '2CH'
-% straincurve(:,1)=SET(gui.taggroup(i)).StrainTagging.globalrad;
-% case '3CH'
-% straincurve(:,end-1)=SET(gui.taggroup(i)).StrainTagging.globalrad;
-% case '4CH'
-% straincurve(:,end)=SET(gui.taggroup(i)).StrainTagging.globalrad;
-% end
- end
- end
- for i = gui.views2show
- gui.handles.graphsrad(i)=plot(h,tvec,straincurve(:,i),'.-','linewidth',2,'Color',gui.cmap(i,:));
- gui.handles.peaksradup(i)=plot(h,srtvec(gui.radupind(i)), straincurve(gui.radupind(i)+1,i),'k+','markersize',10,'linewidth',3);
- gui.handles.peaksraddown(i)=plot(h,srtvec(gui.raddownind(i)), straincurve(gui.raddownind(i)+1,i),'r+','markersize',10,'linewidth',3);
-
- myset(gui.handles.peakscircup(i),'ButtonDownFcn','');
- myset(gui.handles.peakscircdown(i),'ButtonDownFcn','');
- myset(gui.handles.graphscirc(i),'ButtonDownFcn','');
- end
-
- for i = gui.views2show
- tangentplot(h,tvec,straincurve(:,i),normalizedtime,gui.raddownind(i)+1,gui.radupind(i)+1,...
- srtvec(gui.raddownind(i)),srtvec(gui.radupind(i)),gui.raddown(i),gui.radup(i));
- end
- myset(h,'ButtonDownFcn','');
-
-
- case {'Circumferential Strain Rate', 'Longitudinal Strain Rate'}
- for i = gui.views2show
- gui.handles.graphscirc(i)=plot(h,srtvec,gui.srcirc(i,:),'.-','linewidth',2,'Color',gui.cmap(i,:));
- gui.handles.peakscircup(i)=plot(h,srtvec(gui.circupind(i)), gui.circup(i),'k+','markersize',10,'linewidth',3);
- gui.handles.peakscircdown(i)=plot(h,srtvec(gui.circdownind(i)), gui.circdown(i),'r+','markersize',10,'linewidth',3);
- myset(gui.handles.peakscircup(i),'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''circ'',''up'')'));
- myset(gui.handles.peakscircdown(i),'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''circ'',''down'')'));
- myset(gui.handles.graphscirc(i),'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''circ'')'));
- end
- yl=ylim;
- xl=[srtvec(1),srtvec(end)];
- set(h,'XLim',xl,'YLim',yl)
- myset(h,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''circ'')'));
-
-
- case 'Radial Strain Rate'
- for i = gui.views2show
- gui.handles.graphsrad(i)=plot(h,srtvec,gui.srrad(i,:),'.-','linewidth',2,'Color',gui.cmap(i,:));
- gui.handles.peaksradup(i)=plot(h,srtvec(gui.radupind(i)), gui.radup(i),'k+','markersize',10,'linewidth',3);
- gui.handles.peaksraddown(i)=plot(h,srtvec(gui.raddownind(i)), gui.raddown(i),'r+','markersize',10,'linewidth',3);
- myset(gui.handles.peaksradup(i),'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''rad'',''up'')'));
- myset(gui.handles.peaksraddown(i),'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''rad'',''down'')'));
- myset(gui.handles.graphsrad(i),'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''rad'')'));
- end
- yl=ylim;
- xl=[srtvec(1),srtvec(end)];
- set(h,'XLim',xl,'YLim',yl)
- myset(h,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''rad'')'));
-
- case {'Mean Circumferential Strain Rate', 'Mean Longitudinal Strain Rate'}
- gui.handles.globalgraphcirc=plot(h,srtvec,gui.globalsrcirc,'.-','linewidth',2,'Color','b');
- gui.handles.globalpeakcircup=plot(h,srtvec(gui.globalcircupind), gui.globalcircup,'k+','markersize',10,'linewidth',3);
- gui.handles.globalpeakcircdown=plot(h,srtvec(gui.globalcircdownind), gui.globalcircdown,'r+','markersize',10,'linewidth',3);
-
- myset(gui.handles.globalpeakcircup,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalcirc'',''up'')'));
- myset(gui.handles.globalpeakcircdown,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalcirc'',''down'')'));
- myset(gui.handles.globalgraphcirc,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalcirc'')'));
-
- yl=ylim;
- xl=[srtvec(1),srtvec(end)];
- set(h,'XLim',xl,'YLim',yl)
- myset(h,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalcirc'')'));
-
-
- case 'Mean Radial Strain Rate'
- gui.handles.globalgraphrad=plot(h,srtvec,gui.globalsrrad,'.-','linewidth',2,'Color','b');
- gui.handles.globalpeakradup=plot(h,srtvec(gui.globalradupind), gui.globalradup,'k+','markersize',10,'linewidth',3);
- gui.handles.globalpeakraddown=plot(h,srtvec(gui.globalraddownind), gui.globalraddown,'r+','markersize',10,'linewidth',3);
-
- myset(gui.handles.globalpeakradup,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalrad'',''up'')'));
- myset(gui.handles.globalpeakraddown,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalrad'',''down'')'));
- myset(gui.handles.globalgraphrad,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalrad'')'));
-
- yl=ylim;
- xl=[srtvec(1),srtvec(end)];
- set(h,'XLim',xl,'YLim',yl)
- myset(h,'ButtonDownFcn',sprintf('straintagging.strainrate(''setpeak_Callback'',''globalrad'')'));
-
-end
-
-if strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')%~any(strcmp(str,{'Mean Longitudinal Strain with Tangents','Mean Radial Strain with Tangents','Mean Longitudinal Strain Rate','Mean Radial Strain Rate','Mean Longitudinal Strain Rate','Radial Strain Rate'})) || strcmp(SET(gui.taggroup(1)).ImageViewPlane,'Short-axis')
- xlabel(h,'Time [s]')
-else
- xlabel(h,'Heart cycle [s/T]')
-end
-
-if ind >4
- ylabel(h,'%/s')
-else
- ylabel(h,'%')
-end
-hold(h,'off')
-
-for i=gui.views2show
- set(gui.handles.(['text',num2str(i)]),'String',sprintf('%0.1f',gui.circup(i)))
- set(gui.handles.(['text',num2str(17+i)]),'String',sprintf('%0.1f',gui.circdown(i)))
- set(gui.handles.(['text',num2str(2*17+i)]),'String',sprintf('%0.1f',gui.radup(i)))
- set(gui.handles.(['text',num2str(3*17+i)]),'String',sprintf('%0.1f',gui.raddown(i)))
-end
-
-set(gui.handles.('globalcircuptext'),'String',sprintf('%0.1f',gui.globalcircup))
-set(gui.handles.('globalcircdowntext'),'String',sprintf('%0.1f',gui.globalcircdown))
-set(gui.handles.('globalraduptext'),'String',sprintf('%0.1f',gui.globalradup))
-set(gui.handles.('globalraddowntext'),'String',sprintf('%0.1f',gui.globalraddown))
-
-function export_Callback
-global DATA SET
-gui = DATA.GUI.strainrate ;
-
-col=1;
-line=1;
-outdata{line,1} = 'Patient Name';
-outdata{line,2} = 'Patient ID';
-outdata{line,3} = 'Heart Rate';
-outdata{line,4} = 'Image Type';
-
-line=2;
-outdata{line,1} = SET(no).PatientInfo.Name;
-outdata{line,2} = SET(no).PatientInfo.ID;
-outdata{line,3} = SET(no).HeartRate;
-outdata{line,4} = sprintf('%s %s',SET(no).ImageType,SET(no).ImageViewPlane);
-%
-% %Write relevant gui parameters to outdatacell
-% out{line,5} = gui.radup;
-% sr.radupind = gui.radupind;
-% sr.raddown = gui.raddown;
-% sr.raddownind = gui.raddownind;
-% sr.circup = gui.circup;
-% sr.circupind=gui.circupind;
-% sr.circdown=gui.circdown;
-% sr.circdownind=gui.circdownind;
-% sr.srcirc = gui.srcirc;
-% sr.srrad = gui.srrad;
-% sr.include = gui.include;
-% sr.globalcircup=gui.globalcircup;
-% sr.globalcircdown=gui.globalcircdown;
-% sr.globalcircupind=gui.globalcircupind;
-% sr.globalcircdownind=gui.globalcircdownind;
-% sr.globalradup=gui.globalradup;
-% sr.globalraddown=gui.globalraddown;
-% sr.globalradupind=gui.globalradupind;
-% sr.globalraddownind=gui.globalraddownind;
-% sr.globalsrcirc=gui.globalsrcirc;
-% sr.globalsrrad=gui.globalsrrad;
-
-function save_Callback
-global DATA SET
-gui = DATA.GUI.strainrate ;
-
-%Write relevant gui parameters to SET structure
-sr.radup = gui.radup;
-sr.radupind = gui.radupind;
-sr.raddown = gui.raddown;
-sr.raddownind = gui.raddownind;
-sr.circup = gui.circup;
-sr.circupind=gui.circupind;
-sr.circdown=gui.circdown;
-sr.circdownind=gui.circdownind;
-sr.srcirc = gui.srcirc;
-sr.srrad = gui.srrad;
-sr.include = gui.include;
-sr.globalcircup=gui.globalcircup;
-sr.globalcircdown=gui.globalcircdown;
-sr.globalcircupind=gui.globalcircupind;
-sr.globalcircdownind=gui.globalcircdownind;
-sr.globalradup=gui.globalradup;
-sr.globalraddown=gui.globalraddown;
-sr.globalradupind=gui.globalradupind;
-sr.globalraddownind=gui.globalraddownind;
-sr.globalsrcirc=gui.globalsrcirc;
-sr.globalsrrad=gui.globalsrrad;
-
-for no = gui.taggroup
- SET(no).StrainTagging.SR=sr;
-end
-
-close_Callback
-
-function close_Callback
-global DATA
-
-try
- DATA.GUI.strainrate = close(DATA.GUI.strainrate );
-catch %#ok
- DATA.GUI.strainrate =[];
- delete(gcbf);
-end
diff --git a/source/+straintagging/strainrate.p b/source/+straintagging/strainrate.p
new file mode 100644
index 0000000..4984806
Binary files /dev/null and b/source/+straintagging/strainrate.p differ
diff --git a/source/+straintagging/strainselectslices.fig b/source/+straintagging/strainselectslices.fig
index e653c6b..ce5eb51 100644
Binary files a/source/+straintagging/strainselectslices.fig and b/source/+straintagging/strainselectslices.fig differ
diff --git a/source/+straintagging/strainselectslices.p b/source/+straintagging/strainselectslices.p
index a7f42cf..3b20e65 100644
Binary files a/source/+straintagging/strainselectslices.p and b/source/+straintagging/strainselectslices.p differ
diff --git a/source/+straintagging/straintagging.p b/source/+straintagging/straintagging.p
index e176b3b..d5b7ea3 100644
Binary files a/source/+straintagging/straintagging.p and b/source/+straintagging/straintagging.p differ
diff --git a/source/+straintagging/straintools.p b/source/+straintagging/straintools.p
new file mode 100644
index 0000000..d4f80d0
Binary files /dev/null and b/source/+straintagging/straintools.p differ
diff --git a/source/+t2star/t2star.fig b/source/+t2star/t2star.fig
index 4847b35..9e490f4 100644
Binary files a/source/+t2star/t2star.fig and b/source/+t2star/t2star.fig differ
diff --git a/source/+t2star/t2star.p b/source/+t2star/t2star.p
index bbcf15a..99f6a00 100644
Binary files a/source/+t2star/t2star.p and b/source/+t2star/t2star.p differ
diff --git a/source/+t2star/t2star_ADAPTS6.p b/source/+t2star/t2star_ADAPTS6.p
index 5c8b599..711fe46 100644
Binary files a/source/+t2star/t2star_ADAPTS6.p and b/source/+t2star/t2star_ADAPTS6.p differ
diff --git a/source/+transfer/addcomment.m b/source/+transfer/addcomment.m
deleted file mode 100644
index 07ea628..0000000
--- a/source/+transfer/addcomment.m
+++ /dev/null
@@ -1,39 +0,0 @@
-function addcomment
-%Add a comment to current image stack
-
-%Nils Lundahl
-global DATA SET NO
-
-if ~DATA.DataLoaded
- myfailed('No data loaded.');
- return;
-end;
-
-comment = struct('Username','Unknown','Time','','Text','');
-
-%Extract environemnt variable containing username of windows machines
-if ispc
- comment.Username = getenv('USERNAME');
-else
- comment.Username = 'Unkown'; %Added Einar
-end
-
-txt = inputdlg(comment.Username,'Enter comment',[10 80]);
-
-%Add it
-if ~isempty(txt)
- stri = '';
- for li = 1:size(txt{1},1)
- stri = [stri strtrim(txt{1}(li,:)) '\n'];
- end
- comment.Text = sprintf(stri);
- comment.Time = datestr(now,31);
- if isfield(SET,'Comment') && ~isempty(SET(NO).Comment)
- SET(NO).Comment = [SET(NO).Comment comment];
- else
- SET(NO).Comment = comment;
- end
-else
- myfailed('Empty comment. Ignored.');
-end
-
diff --git a/source/+transfer/addcomment.p b/source/+transfer/addcomment.p
new file mode 100644
index 0000000..8b44736
Binary files /dev/null and b/source/+transfer/addcomment.p differ
diff --git a/source/+transfer/base64decode.m b/source/+transfer/base64decode.m
deleted file mode 100644
index 447cfca..0000000
--- a/source/+transfer/base64decode.m
+++ /dev/null
@@ -1,103 +0,0 @@
-function y = base64decode(x)
-%BASE64DECODE Perform base64 decoding on a string.
-%
-% BASE64DECODE(STR) decodes the given base64 string STR.
-%
-% Any character not part of the 65-character base64 subset set is silently
-% ignored. Characters occuring after a '=' padding character are never
-% decoded.
-%
-% STR doesn't have to be a string. The only requirement is that it is a
-% vector containing values in the range 0-255.
-%
-% If the length of the string to decode (after ignoring non-base64 chars) is
-% not a multiple of 4, then a warning is generated.
-%
-% This function is used to decode strings from the Base64 encoding specified
-% in RFC 2045 - MIME (Multipurpose Internet Mail Extensions). The Base64
-% encoding is designed to represent arbitrary sequences of octets in a form
-% that need not be humanly readable. A 65-character subset ([A-Za-z0-9+/=])
-% of US-ASCII is used, enabling 6 bits to be represented per printable
-% character.
-%
-% See also BASE64ENCODE.
-
-% Author: Peter John Acklam
-% Time-stamp: 2004-09-20 08:20:50 +0200
-% E-mail: pjacklam@online.no
-% URL: http://home.online.no/~pjacklam
-
- % check number of input arguments
- error(nargchk(1, 1, nargin));
-
- % remove non-base64 chars
- x = x ( ( 'A' <= x & x <= 'Z' ) ...
- | ( 'a' <= x & x <= 'z' ) ...
- | ( '0' <= x & x <= '9' ) ...
- | ( x == '+' ) | ( x == '=' ) | ( x == '/' ) );
-
- if rem(length(x), 4)
- warning('Length of base64 data not a multiple of 4; padding input.');
- end
-
- k = find(x == '=');
- if ~isempty(k)
- x = x(1:k(1)-1);
- end
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Now perform the following mapping
- %
- % A-Z -> 0 - 25
- % a-z -> 26 - 51
- % 0-9 -> 52 - 61
- % + -> 62
- % / -> 63
-
- y = repmat(uint8(0), size(x));
- i = 'A' <= x & x <= 'Z'; y(i) = - 'A' + x(i);
- i = 'a' <= x & x <= 'z'; y(i) = 26 - 'a' + x(i);
- i = '0' <= x & x <= '9'; y(i) = 52 - '0' + x(i);
- i = x == '+'; y(i) = 62 - '+' + x(i);
- i = x == '/'; y(i) = 63 - '/' + x(i);
- x = y;
-
- nebytes = length(x); % number of encoded bytes
- nchunks = ceil(nebytes/4); % number of chunks/groups
-
- % add padding if necessary
- if rem(nebytes, 4)
- x(end+1 : 4*nchunks) = 0;
- end
-
- x = reshape(uint8(x), 4, nchunks);
- y = repmat(uint8(0), 3, nchunks); % for the decoded data
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Rearrange every 4 bytes into 3 bytes
- %
- % 00aaaaaa 00bbbbbb 00cccccc 00dddddd
- %
- % to form
- %
- % aaaaaabb bbbbcccc ccdddddd
-
- y(1,:) = bitshift(x(1,:), 2); % 6 highest bits of y(1,:)
- y(1,:) = bitor(y(1,:), bitshift(x(2,:), -4)); % 2 lowest bits of y(1,:)
-
- y(2,:) = bitshift(x(2,:), 4); % 4 highest bits of y(2,:)
- y(2,:) = bitor(y(2,:), bitshift(x(3,:), -2)); % 4 lowest bits of y(2,:)
-
- y(3,:) = bitshift(x(3,:), 6); % 2 highest bits of y(3,:)
- y(3,:) = bitor(y(3,:), x(4,:)); % 6 lowest bits of y(3,:)
-
- % remove padding
- switch rem(nebytes, 4)
- case 2
- y = y(1:end-2);
- case 3
- y = y(1:end-1);
- end
-
- % reshape to a row vector and make it a character array
- y = char(reshape(y, 1, numel(y)));
diff --git a/source/+transfer/base64encode.m b/source/+transfer/base64encode.m
deleted file mode 100644
index 92b41d2..0000000
--- a/source/+transfer/base64encode.m
+++ /dev/null
@@ -1,159 +0,0 @@
-function y = base64encode(x, eol)
-%BASE64ENCODE Perform base64 encoding on a string.
-%
-% BASE64ENCODE(STR, EOL) encode the given string STR. EOL is the line ending
-% sequence to use; it is optional and defaults to '\n' (ASCII decimal 10).
-% The returned encoded string is broken into lines of no more than 76
-% characters each, and each line will end with EOL unless it is empty. Let
-% EOL be empty if you do not want the encoded string broken into lines.
-%
-% STR and EOL don't have to be strings (i.e., char arrays). The only
-% requirement is that they are vectors containing values in the range 0-255.
-%
-% This function may be used to encode strings into the Base64 encoding
-% specified in RFC 2045 - MIME (Multipurpose Internet Mail Extensions). The
-% Base64 encoding is designed to represent arbitrary sequences of octets in a
-% form that need not be humanly readable. A 65-character subset
-% ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be represented per
-% printable character.
-%
-% Examples
-% --------
-%
-% If you want to encode a large file, you should encode it in chunks that are
-% a multiple of 57 bytes. This ensures that the base64 lines line up and
-% that you do not end up with padding in the middle. 57 bytes of data fills
-% one complete base64 line (76 == 57*4/3):
-%
-% If ifid and ofid are two file identifiers opened for reading and writing,
-% respectively, then you can base64 encode the data with
-%
-% while ~feof(ifid)
-% fwrite(ofid, base64encode(fread(ifid, 60*57)));
-% end
-%
-% or, if you have enough memory,
-%
-% fwrite(ofid, base64encode(fread(ifid)));
-%
-% See also BASE64DECODE.
-
-% Author: Peter John Acklam
-% Time-stamp: 2004-02-03 21:36:56 +0100
-% E-mail: pjacklam@online.no
-% URL: http://home.online.no/~pjacklam
-
- % check number of input arguments
- error(nargchk(1, 2, nargin));
-
- % make sure we have the EOL value
- if nargin < 2
- eol = sprintf('\n');
- else
- if sum(size(eol) > 1) > 1
- error('EOL must be a vector.');
- end
- if any(eol(:) > 255)
- error('EOL can not contain values larger than 255.');
- end
- end
-
- if sum(size(x) > 1) > 1
- error('STR must be a vector.');
- end
-
- x = uint8(x);
- eol = uint8(eol);
-
- ndbytes = length(x); % number of decoded bytes
- nchunks = ceil(ndbytes / 3); % number of chunks/groups
- nebytes = 4 * nchunks; % number of encoded bytes
-
- % add padding if necessary, to make the length of x a multiple of 3
- if rem(ndbytes, 3)
- x(end+1 : 3*nchunks) = 0;
- end
-
- x = reshape(x, [3, nchunks]); % reshape the data
- y = repmat(uint8(0), 4, nchunks); % for the encoded data
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Split up every 3 bytes into 4 pieces
- %
- % aaaaaabb bbbbcccc ccdddddd
- %
- % to form
- %
- % 00aaaaaa 00bbbbbb 00cccccc 00dddddd
- %
- y(1,:) = bitshift(x(1,:), -2); % 6 highest bits of x(1,:)
-
- y(2,:) = bitshift(bitand(x(1,:), 3), 4); % 2 lowest bits of x(1,:)
- y(2,:) = bitor(y(2,:), bitshift(x(2,:), -4)); % 4 highest bits of x(2,:)
-
- y(3,:) = bitshift(bitand(x(2,:), 15), 2); % 4 lowest bits of x(2,:)
- y(3,:) = bitor(y(3,:), bitshift(x(3,:), -6)); % 2 highest bits of x(3,:)
-
- y(4,:) = bitand(x(3,:), 63); % 6 lowest bits of x(3,:)
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Now perform the following mapping
- %
- % 0 - 25 -> A-Z
- % 26 - 51 -> a-z
- % 52 - 61 -> 0-9
- % 62 -> +
- % 63 -> /
- %
- % We could use a mapping vector like
- %
- % ['A':'Z', 'a':'z', '0':'9', '+/']
- %
- % but that would require an index vector of class double.
- %
- z = repmat(uint8(0), size(y));
- i = y <= 25; z(i) = 'A' + double(y(i));
- i = 26 <= y & y <= 51; z(i) = 'a' - 26 + double(y(i));
- i = 52 <= y & y <= 61; z(i) = '0' - 52 + double(y(i));
- i = y == 62; z(i) = '+';
- i = y == 63; z(i) = '/';
- y = z;
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Add padding if necessary.
- %
- npbytes = 3 * nchunks - ndbytes; % number of padding bytes
- if npbytes
- y(end-npbytes+1 : end) = '='; % '=' is used for padding
- end
-
- if isempty(eol)
-
- % reshape to a row vector
- y = reshape(y, [1, nebytes]);
-
- else
-
- nlines = ceil(nebytes / 76); % number of lines
- neolbytes = length(eol); % number of bytes in eol string
-
- % pad data so it becomes a multiple of 76 elements
- y(nebytes + 1 : 76 * nlines) = 0;
- y = reshape(y, 76, nlines);
-
- % insert eol strings
- eol = eol(:);
- y(end + 1 : end + neolbytes, :) = eol(:, ones(1, nlines));
-
- % remove padding, but keep the last eol string
- m = nebytes + neolbytes * (nlines - 1);
- n = (76+neolbytes)*nlines - neolbytes;
- y(m+1 : n) = '';
-
- % extract and reshape to row vector
- y = reshape(y, 1, m+neolbytes);
-
- end
-
- % output is a character array
- y = char(y);
diff --git a/source/+transfer/base64encode.p b/source/+transfer/base64encode.p
new file mode 100644
index 0000000..c4b8f33
Binary files /dev/null and b/source/+transfer/base64encode.p differ
diff --git a/source/+transfer/checkpattern.m b/source/+transfer/checkpattern.m
deleted file mode 100644
index b57f742..0000000
--- a/source/+transfer/checkpattern.m
+++ /dev/null
@@ -1,90 +0,0 @@
-function [ok,msg] = checkpattern(pattern,newname)
-%Check if the new name is valid according to the pattern.
-
-ok = true;
-msg = '';
-
-if isequal(newname,pattern)
- ok = false;
- msg = 'You need to change the default value. Upload aborted.';
- return;
-end;
-
-if ~isequal(length(newname),length(pattern))
- ok = false;
- msg = sprintf('Length of new name and pattern need to be same. Length of pattern is %d and length of new name is %d',...
- length(pattern),length(newname));
- return;
-end;
-
-for loop = 1:length(pattern)
-
- %If it is a dash then it should be a dash
- if isequal(pattern(loop),'-') && ~isequal(newname(loop),'-')
- ok = false;
- msg = sprintf('Need to have a dash in position %d.',loop);
- return;
- end;
-
- %If it is a colon then it should be a dash
- if isequal(pattern(loop),':') && ~isequal(newname(loop),':')
- ok = false;
- msg = sprintf('Need to have a colon in position %d.',loop);
- return;
- end;
-
- %If it is a semi-colon then it should be a
- if isequal(pattern(loop),';') && ~isequal(newname(loop),';')
- ok = false;
- msg = sprintf('Need to have a semi-colon in position %d.',loop);
- return;
- end;
-
- %If it is a point then it should be a
- if isequal(pattern(loop),'.') && ~isequal(newname(loop),'.')
- ok = false;
- msg = sprintf('Need to have a point in position %d.',loop);
- return;
- end;
-
- %If it is a space then it should be a
- if isequal(pattern(loop),' ') && ~isequal(newname(loop),' ')
- ok = false;
- msg = sprintf('Need to have a space in position %d.',loop);
- return;
- end;
-
- %If it is an underscore then it should be a
- if isequal(pattern(loop),'_') && ~isequal(newname(loop),'_')
- ok = false;
- msg = sprintf('Need to have an underscorein position %d.',loop);
- return;
- end;
-
- %It is a upper case letter => should be equal
- if isequal(pattern(loop),upper(pattern(loop)))
- if ~isequal(pattern(loop),newname(loop))
- ok = false;
- msg = sprintf('Letter number %d needs to be a ''%s''',loop,pattern(loop));
- end;
- end;
-
- %If it is a lower case n then it should be numeric
- if isequal(pattern(loop),'n') %#ok
- if ~ismember(newname(loop),'0123456789')
- ok = false;
- msg = sprintf('New name in position %d needs to be numeric.',loop);
- return;
- end;
- end;
-
- %If it is a lower case x then it should be non numeric
- if isequal(pattern(loop),'x') %#ok
- if ismember(newname(loop),'0123456789')
- ok = false;
- msg = sprintf('New name in position %d needs to be non-numeric.',loop);
- return;
- end;
- end;
-
-end;
\ No newline at end of file
diff --git a/source/+transfer/createcredentials.fig b/source/+transfer/createcredentials.fig
new file mode 100644
index 0000000..3c6b3da
Binary files /dev/null and b/source/+transfer/createcredentials.fig differ
diff --git a/source/+transfer/createcredentials.p b/source/+transfer/createcredentials.p
new file mode 100644
index 0000000..4d91be9
Binary files /dev/null and b/source/+transfer/createcredentials.p differ
diff --git a/source/+transfer/deltree.m b/source/+transfer/deltree.m
deleted file mode 100644
index 3ebe6d9..0000000
--- a/source/+transfer/deltree.m
+++ /dev/null
@@ -1,14 +0,0 @@
-function deltree(fileLocation)
-% Works like deltree /y in good old Windows.
-% You can specify files, folders, or wildcards.
-%
-% Example: deltree('C:\Temp\Administrator\*.*');
-
-if( ispc )
- executeString = sprintf('del /s /q %s', fileLocation);
- system(executeString);
- rmdir(fileLocation, 's');
-else
- executeString = sprintf('rm -Rf %s', fileLocation);
- system(executeString);
-end
diff --git a/source/+transfer/exception2str.m b/source/+transfer/exception2str.m
deleted file mode 100644
index 1d14271..0000000
--- a/source/+transfer/exception2str.m
+++ /dev/null
@@ -1,9 +0,0 @@
-function str = exception2str(e)
- str = '';
- str = [str sprintf('Error message:\n%s\n\n',e.message) ];
- str = [str sprintf('Stack trace:\n') ];
- for i=1:numel(e.stack)
- str = [str sprintf('Line %d in ''%s''\n', e.stack(i).line, e.stack(i).file) ];
- end
- str = [str sprintf('\nEnd\n') ];
-end
\ No newline at end of file
diff --git a/source/+transfer/failmessage.m b/source/+transfer/failmessage.m
deleted file mode 100644
index 1dca2c8..0000000
--- a/source/+transfer/failmessage.m
+++ /dev/null
@@ -1,29 +0,0 @@
-function failmessage
-%This throws a fail message to instruct the site on what to do.
-
-%Einar Heiberg
-global DATA
-
-% Display message
-old_dna = DATA.Pref.DoNotAsk;
-DATA.Pref.DoNotAsk = false; %Ensure that message box is displayed.
-DATA.Buffer.KeyStroke = {}; %Ensure that message box is displayed.
-
-mymsgbox(dprintf([...
- 'Something went wrong! \n\n' ...
- 'An error report will be generated after you have clicked OK on \n' ...
- 'this message. Please copy errors from the error report and send \n' ...
- 'them in an email to support@medviso.com.\n\n' ...
- 'We will then look into the source of the problem and assist you as soon as possible.']));
-
-flushlog;
-if ispc
- dos(sprintf('notepad.exe "%s" &',DATA.LogFile));
-else
- mymsgbox(dprintf('Log file for this run is %s',DATA.LogFile),'',DATA.GUI.Segment);
-end;
-
-
-mybrowser('mailto:support@medviso.com');
-
-DATA.Pref.DoNotAsk = old_dna;
\ No newline at end of file
diff --git a/source/+transfer/getcredsfile.m b/source/+transfer/getcredsfile.m
deleted file mode 100644
index 7cdda00..0000000
--- a/source/+transfer/getcredsfile.m
+++ /dev/null
@@ -1,29 +0,0 @@
-function name = getcredsfile(inpath)
-%Returns the name of the credentials file. If not existing, then return
-%empty. Function looks in the default directory. If multiple files are
-%existing, the return them in a cell array.nn
-%
-%See also READCREDENTIALS
-
-%Einar Heiberg
-
-name = '';
-
-if nargin == 0
- f = dir('*.transfercreds');
-else
- f = dir([inpath filesep '*.transfercreds']);
-end;
-
-if isempty(f)
- return;
-end;
-
-if length(f)>1
- name = cell(1,length(f));
- for loop = 1:length(f)
- name{loop} = f(loop).name;
- end;
-else
- name = f(1).name;
-end;
\ No newline at end of file
diff --git a/source/+transfer/getcredsfile.p b/source/+transfer/getcredsfile.p
new file mode 100644
index 0000000..840afac
Binary files /dev/null and b/source/+transfer/getcredsfile.p differ
diff --git a/source/+transfer/gui.m b/source/+transfer/gui.m
deleted file mode 100644
index ee54c0b..0000000
--- a/source/+transfer/gui.m
+++ /dev/null
@@ -1,222 +0,0 @@
-classdef gui < maingui
-
- methods
-
- %-------------------------------
- function g = gui(programversion)
- %-------------------------------
- %Constructor
-
- %Call superclass constructor
- g = g@maingui(programversion);
-
- end
-
- %----------------------
- function initLogFile(g)
- %----------------------
- %This overloaded method sets the name of the log-file.
- pathname = g.getpreferencespath;
- g.LogFile = [pathname filesep sprintf('segmenttransferlog_%s.log',datestr(now,'yyyymmddHHMMSS'))];
- fid = fopen(g.LogFile,'w');
- if isequal(fid,-1)
- myfailed(dprintf('Could not create .log file %s.',g.LogFile));
- else
- fclose(fid); %Close the file, to make it empty
- g.startlog(g.LogFile); %Start diary.
- fprintf(1,'Segment Transfer Version %s\n',g.ProgramVersion);
- end;
- end
-
- %---------------------------
- function loadguipositions(g)
- %---------------------------
- %Load prestored positions of GUI's.
- %Overload this with empty function, do not need to load gui positions
- end;
-
- %----------------------
- function initmaingui(g)
- %----------------------
- %Initiates main GUI. Overloads mainGUI method to use Segment-transfer GUI instead
- g.GUI.Segment=mygui(['+transfer' filesep 'segmenttransfer.fig']);%Load custom GUI
- g.fig = g.GUI.Segment.fig;
- g.Handles = killhandles(g.fig,'segment.fig');
- g.ProgramName = 'Segment-Transfer';
-
- gui = g.GUI.Segment;
-
- %Create the progressbar
- gui.handles.overallpatch = patch(...
- [0 0 0 0],...
- [0 1 1 0],...
- [1 1 1 1],...
- 'parent',gui.handles.overallaxes);
- hold(gui.handles.overallaxes,'on'); hold(gui.handles.overallaxes,'on');
- gui.handles.overallline = plot(gui.handles.overallaxes,[0 0 1 1 0],[0 1 1 0 0],'k-');
- hold(gui.handles.overallaxes,'off');
- xlim(gui.handles.overallaxes,[0 1]);
- axis(gui.handles.overallaxes,'off');
- set(gui.handles.overalltext,'string','');
-
- set(gui.handles.overallline,'visible','off');
- set(gui.handles.overallpatch,'visible','off');
- set(gui.handles.overallaxes,'visible','off');
-
- %Create the detail waitbar
- gui.handles.detailpatch = patch(...
- [0 0 0 0],...
- [0 1 1 0],...
- [1 1 1 1],...
- 'parent',gui.handles.detailaxes);
- hold(gui.handles.detailaxes,'on');
- gui.handles.detailline = plot(gui.handles.detailaxes,[0 0 1 1 0],[0 1 1 0 0],'k-');
- hold(gui.handles.detailaxes,'off');
- xlim(gui.handles.detailaxes,[0 1]);
- axis(gui.handles.detailaxes,'off');
-
- set(gui.handles.detailtext,'string','');
- set(gui.handles.detailline,'visible','off');
- set(gui.handles.detailpatch,'visible','off');
- set(gui.handles.detailaxes,'visible','off');
-
- %Ensure that the credentials file exists
- if isempty(transfer.getcredsfile)
- mywarning(...
- ['The credentials file is not installed. This file contains necessary log-in '...
- 'information. You should have received this file in email. '...
- 'Please contact the study core-lab if you are missing the file, or support@medviso.com. ' ...
- 'You will now be prompted to locate the file.']);
-
- pause(0.1);
-
- %Ask for file
- g.askforfile();
- end;
-
- if isempty(transfer.getcredsfile)
- myfailed('Please fix problem with missing credentials and restart application.');
- end;
-
- end
-
- %----------------------
- function inittoolbar(g) %#ok
- %----------------------
- %Initiate toolbars. Overloads mainGUI method.
- end
-
- %---------------------------
- function updateicons(g,mode) %#ok
- %---------------------------
- %Overloads mainGUI method
-
- %Reset Tool structure
- g.Tools = [];
- end
-
- %------------------
- function askforfile(g) %#ok
- %------------------
- %Ask for creds file and copies it to pwd
-
- [filename,pathname] = myuigetfile('*.transfercreds','Select the file transfercreds file');
- if isequal(pathname,-1) || isequal(filename,-1)
- myfailed('Aborted.')
- return;
- end;
-
- if ~exist([pathname filesep filename],'file')
- myfailed('File does not exist. Aborted.');
- end;
- ok = copyfile([pathname filesep filename],[pwd filesep filename]);
- if ~ok
- myfailed(dprintf('Could not copy file. Folder %s write protected?',pwd));
- else
- mymsgbox('File copy successfull.');
- end;
- end
-
- %----------------------
- function updatetitle(g)
- %----------------------
- %Updates titleline of main GUI. Overloads method in SegmentGUI
-
- set(g.fig,'Name',['Segment Transfer v' changelog]);
- end
-
- end
-
- methods(Static)
-
- %-----------------------
- function dispwelcometext
- %-----------------------
- %Overloads method in mainGUI
- end
-
- %--------------------
- function versionhello
- %--------------------
- %Overloads method in mainGUI
- disp(['Segment Transfer v' changelog '.'])
- end
-
-
- %----------------------------------------------
- function h = mywaitbarstart(iter,stri,varargin)
- %----------------------------------------------
- global DATA
-
- %Just store it for future work
- gui = DATA.GUI.Segment;
- gui.numiter = iter;
- gui.iter = 0;
- gui.detailstri = stri;
-
- %Update text
- set(gui.handles.detailtext,'string',stri);
-
- %Make it visible
- set([...
- gui.handles.detailline...
- gui.handles.detailpatch ...
- gui.handles.detailtext],'visible','on');
- h = [];
- end;
-
- %--------------------------------
- function mywaitbarclose(varargin)
- %--------------------------------
- global DATA
-
- gui = DATA.GUI.Segment;
-
- %Make it invisible
- set([...
- gui.handles.detailline...
- gui.handles.detailpatch ...
- gui.handles.detailtext],'visible','off');
-
- end;
-
- %-------------------------------------
- function h = mywaitbarupdate(varargin)
- %-------------------------------------
- global DATA
-
- gui = DATA.GUI.Segment;
-
- gui.iter = gui.iter+1;
- f = gui.iter/gui.numiter;
-
- set(gui.handles.detailpatch,'xdata',[0 0 f f]);
- drawnow;
-
- h = [];
- end;
-
-
- end
-
-end
\ No newline at end of file
diff --git a/source/+transfer/hash.m b/source/+transfer/hash.m
deleted file mode 100644
index bfc4450..0000000
--- a/source/+transfer/hash.m
+++ /dev/null
@@ -1,79 +0,0 @@
-function h = hash(inp,meth)
-% HASH - Convert an input variable into a message digest using any of
-% several common hash algorithms
-%
-% USAGE: h = hash(inp,'meth')
-%
-% inp = input variable, of any of the following classes:
-% char, uint8, logical, double, single, int8, uint8,
-% int16, uint16, int32, uint32, int64, uint64
-% h = hash digest output, in hexadecimal notation
-% meth = hash algorithm, which is one of the following:
-% MD2, MD5, SHA-1, SHA-256, SHA-384, or SHA-512
-%
-% NOTES: (1) If the input is a string or uint8 variable, it is hashed
-% as usual for a byte stream. Other classes are converted into
-% their byte-stream values. In other words, the hash of the
-% following will be identical:
-% 'abc'
-% uint8('abc')
-% char([97 98 99])
-% The hash of the follwing will be different from the above,
-% because class "double" uses eight byte elements:
-% double('abc')
-% [97 98 99]
-% You can avoid this issue by making sure that your inputs
-% are strings or uint8 arrays.
-% (2) The name of the hash algorithm may be specified in lowercase
-% and/or without the hyphen, if desired. For example,
-% h=hash('my text to hash','sha256');
-% (3) Carefully tested, but no warranty. Use at your own risk.
-% (4) Michael Kleder, Nov 2005
-%
-% EXAMPLE:
-%
-% algs={'MD2','MD5','SHA-1','SHA-256','SHA-384','SHA-512'};
-% for n=1:6
-% h=hash('my sample text',algs{n});
-% disp([algs{n} ' (' num2str(length(h)*4) ' bits):'])
-% disp(h)
-% end
-
-inp=inp(:);
-% convert strings and logicals into uint8 format
-if ischar(inp) || islogical(inp)
- inp=uint8(inp);
-else % convert everything else into uint8 format without loss of data
- inp=typecast(inp,'uint8');
-end
-
-% verify hash method, with some syntactical forgiveness:
-meth=upper(meth);
-switch meth
- case 'SHA1'
- meth='SHA-1';
- case 'SHA256'
- meth='SHA-256';
- case 'SHA384'
- meth='SHA-384';
- case 'SHA512'
- meth='SHA-512';
- otherwise
-end
-algs={'MD2','MD5','SHA-1','SHA-256','SHA-384','SHA-512'};
-if isempty(strmatch(meth,algs,'exact'))
- error(['Hash algorithm must be ' ...
- 'MD2, MD5, SHA-1, SHA-256, SHA-384, or SHA-512']);
-end
-
-% create hash
-x=java.security.MessageDigest.getInstance(meth);
-x.update(inp);
-h=typecast(x.digest,'uint8');
-h=dec2hex(h)';
-if(size(h,1))==1 % remote possibility: all hash bytes < 128, so pad:
- h=[repmat('0',[1 size(h,2)]);h];
-end
-h=lower(h(:)');
-clear x
-return
\ No newline at end of file
diff --git a/source/+transfer/path2files.m b/source/+transfer/path2files.m
deleted file mode 100644
index 4e45c87..0000000
--- a/source/+transfer/path2files.m
+++ /dev/null
@@ -1,16 +0,0 @@
-function files = path2files(path)
-%Return the files in a path
-
- dd = dir(path);
- files = {};
-
- for i=1:numel(dd)
- if(dd(i).isdir)
- continue
- end
- if isequal(dd(i).name, 'dicom.cache')
- continue
- end
- files(end+1) = {[path dd(i).name]};
- end
-end
\ No newline at end of file
diff --git a/source/+transfer/path2study.m b/source/+transfer/path2study.m
deleted file mode 100644
index cef0734..0000000
--- a/source/+transfer/path2study.m
+++ /dev/null
@@ -1,20 +0,0 @@
-function r = path2study(path)
-%Returns a cell array with the paths to studies
- tt = dir(path);
- r = {};
- for i=1:numel(tt)
- if isequal(tt(i).name, '.')
- continue
- end
- if isequal(tt(i).name, '..')
- continue
- end
- if isequal(tt(i).name, '.svn')
- continue
- end
- if not(tt(i).isdir)
- continue
- end
- r{end+1} = transfer.path2files([path filesep tt(i).name filesep]);
- end
-end
\ No newline at end of file
diff --git a/source/+transfer/progressbar.m b/source/+transfer/progressbar.m
deleted file mode 100644
index d93ebc4..0000000
--- a/source/+transfer/progressbar.m
+++ /dev/null
@@ -1,11 +0,0 @@
-function progressbar(f,msg)
-global DATA
-
-try
- gui = DATA.GUI.Segment;
-
- set(gui.handles.overalltext,'string',msg);
- set(gui.handles.overallpatch,'xdata',[0 0 f f]);
- drawnow;
-catch %#ok
-end;
\ No newline at end of file
diff --git a/source/+transfer/readcredentials.m b/source/+transfer/readcredentials.m
deleted file mode 100644
index 75778db..0000000
--- a/source/+transfer/readcredentials.m
+++ /dev/null
@@ -1,70 +0,0 @@
-function [study, user, pw, url,pattern] = readcredentials()
-%Read the credentials file.
-
-%Jonatan Wulcan. Modified by Einar Heiberg
-name = transfer.getcredsfile;
-if isempty(name)
- error('SEGMENT:ERROR','Could not find any credentials file.');
-end;
-
-if iscell(name)
- %Found multiple
-
- %Loop over them to extract site name
- sitenames = cell(size(name));
- for loop = 1:length(sitenames)
- fid = fopen(name{loop},'rt');
- if isequal(fid,-1)
- error('SEGMENT:ERROR','Could not open credentials file.');
- end;
- stri = fgetl(fid);
- sitenames{loop} = stri;
- fclose(fid);
- end;
- m = mymenu('Select trial.',sitenames{:});
-
- if isequal(m,0)
- error('SEGMENT:ERROR','User aborted.');
- end;
-
- name = name{m};
-end;
-
-fid = fopen(name,'r');
-if fid == -1
- error('SEGMENT:ERROR', sprintf('Couldn''t open %s. Please contact core lab for support.',name)); %#ok
-end
-
-%Read study
-stri = fgetl(fid);
-if isempty(stri)
- error('SEGMENT:ERROR','Could not read study name.');
-end;
-study = stri;
-
-%Read username
-stri = fgetl(fid);
-if isempty(stri)
- error('SEGMENT:ERROR','Could not read user name.');
-end;
-user = stri;
-
-%Read password
-stri = fgetl(fid);
-if isempty(stri)
- error('SEGMENT:ERROR','Could not read password.');
-end;
-pw = stri;
-
-%Read url
-stri = fgetl(fid);
-if isempty(stri)
- error('SEGMENT:ERROR','Could not read URL.');
-end;
-url = stri;
-
-%Read pattern
-stri = fgetl(fid);
-pattern = stri;
-
-fclose(fid);
\ No newline at end of file
diff --git a/source/+transfer/readcredentials.p b/source/+transfer/readcredentials.p
new file mode 100644
index 0000000..58ee6f0
Binary files /dev/null and b/source/+transfer/readcredentials.p differ
diff --git a/source/+transfer/scaleim.m b/source/+transfer/scaleim.m
deleted file mode 100644
index 2b814c5..0000000
--- a/source/+transfer/scaleim.m
+++ /dev/null
@@ -1,20 +0,0 @@
-function outim = scaleim(im)
-%This function scales the image to get good contrast, see autocontrast
-%in segment_main for details.
-
-%Einar Heiberg, inspired by Janes autocontrast implementation
-
-%Set percentile values, see autocontast
-lowerpercentile=0.02;
-upperpercentile=0.99;
-
-sortim = sort(im(:));
-lowerthresh = sortim(round(lowerpercentile*length(sortim)));
-upperthresh = sortim(round(upperpercentile*length(sortim)));
-
-%Cut above/below
-outim = max(im,lowerthresh);
-outim = min(outim,upperthresh);
-
-%Normalize between 0..1
-outim = (outim-lowerthresh)/(upperthresh-lowerthresh);
diff --git a/source/+transfer/sendfile.m b/source/+transfer/sendfile.m
deleted file mode 100644
index 356d805..0000000
--- a/source/+transfer/sendfile.m
+++ /dev/null
@@ -1,71 +0,0 @@
-classdef sendfile < handle
- properties(SetAccess = private, GetAccess = private)
- data
- bytes_left
- chunksize
- sendfunc
- end
-
- methods(Access = public)
- function self = sendfile(sendfunc)
- self.data = struct('data', {}, 'pos', {}, 'fileid', {});
- self.chunksize = 2000000;
- self.bytes_left = self.chunksize;
- self.sendfunc = sendfunc;
- end
-
- function addfile(self, fileinfo)
- f = fopen(fileinfo.name, 'r');
- bytes = fread(f, inf, '*uint8');
- fclose(f);
-
- data_added = 0;
- while data_added ~= numel(bytes)
- data_added = data_added + ...
- self.add_data(bytes((1+data_added):end), data_added, fileinfo.id);
- end
- end
-
- function finalize(self)
- self.send();
- end
- end
-
- methods(Access = private)
- function send(self)
- if(numel(self.data) == 0)
- return
- end
- self.sendfunc(self.data);
- clear self.data;
- self.data = struct('data', {}, 'pos', {}, 'fileid', {});
- self.bytes_left = self.chunksize;
- end
-
- function data_added = add_data(self, raw_bytes, pos, id)
- % Find out how much data we want and b64encode it
- data_added = numel(raw_bytes);
- bytes = transfer.base64encode(raw_bytes(1:data_added));
- if(numel(bytes) > self.bytes_left)
- data_added = floor(self.bytes_left/1.3509)-100;
- bytes = transfer.base64encode(raw_bytes(1:data_added));
- end
- if(numel(bytes) > self.bytes_left)
- error('SEGMENT:PANIC', 'Couldn''t find good size');
- end
-
- self.data(end+1) = struct(...
- 'data', bytes, ...
- 'pos', pos, ...
- 'fileid', id);
- self.bytes_left = self.bytes_left - numel(bytes);
-
- if(self.bytes_left < 10000)
- self.send();
- end
- end
- end
-
- methods(Static, Access = public)
- end
-end
\ No newline at end of file
diff --git a/source/+transfer/sendmatfile.m b/source/+transfer/sendmatfile.m
deleted file mode 100644
index 09bbe11..0000000
--- a/source/+transfer/sendmatfile.m
+++ /dev/null
@@ -1,27 +0,0 @@
-function sendmatfile(server, study, matfile)
- % Get the hash and data
- f = fopen(matfile, 'r');
- data = fread(f, inf, '*uint8');
- fclose(f);
- h = transfer.hashfile(matfile);
-
- % Create the file
- file_id = server.new_matfile(study, h);
-
- % Send the acctual file
- pos = 1;
- chunksize = 524288;
- hw = waitbar(0,'Please wait uploading .mat file.');
- while(pos <= numel(data))
- server.update_matfile(file_id, pos-1, ...
- transfer.base64encode( ...
- data( ...
- pos:min([pos+chunksize-1 numel(data)]) ...
- ) ...
- ));
- pos = pos + chunksize;
- waitbar(pos/numel(data),hw);
- end
- close(hw);
- server.finalize_matfile(file_id);
-end
\ No newline at end of file
diff --git a/source/+transfer/sendmatfile.p b/source/+transfer/sendmatfile.p
new file mode 100644
index 0000000..81c2848
Binary files /dev/null and b/source/+transfer/sendmatfile.p differ
diff --git a/source/+transfer/sendserie.m b/source/+transfer/sendserie.m
deleted file mode 100644
index 7d405ea..0000000
--- a/source/+transfer/sendserie.m
+++ /dev/null
@@ -1,34 +0,0 @@
-function sendserie(server, study, desc, files, wbfac)
-
-serie_id = server.new_serie(desc, study);
-wb = wbfac(numel(files), 'Uploading files...');
-
-%First upload DICOMS
-senddicoms(server, files, wb, serie_id);
-
-%-----------------------------------------------
-function senddicoms(server, files, wb, serie_id)
-%-----------------------------------------------
-%Send DICOMs (stored in files) to server
-
-% Create fileinfos
-fileinfos = struct('name', {}, 'hash', {});
-for i=1:numel(files)
- fileinfos(i) = struct(...
- 'name', files{i}, ...
- 'hash', transfer.hashfile(files{i}));
-end
-
-% new dicomfiles
-fileinfos = server.new_dicomfiles(fileinfos, serie_id);
-
-% send files
-sendfile = transfer.sendfile(@(data) server.update_dicomfile(data));
-for i=1:numel(fileinfos)
- sendfile.addfile(fileinfos(i));
- wb.update();
-end
-sendfile.finalize();
-
-% finalize files
-server.finalize_dicomfile({fileinfos.id});
\ No newline at end of file
diff --git a/source/+transfer/sendstudy.m b/source/+transfer/sendstudy.m
deleted file mode 100644
index 111bb37..0000000
--- a/source/+transfer/sendstudy.m
+++ /dev/null
@@ -1,36 +0,0 @@
-function didfail = sendstudy(server, series, name, wbfac)
-%Send a study, series is a cell array struct of files
-
-if(numel(series) == 0)
- error('SEGMENT:ERROR', 'No series to send');
-end
-
-%Set up study object
-study = server.new_study('N/A', name);
-
-%Loop over series to send
-didfail = false;
-for i=1:numel(series)
-
- %Send serie
- try
- transfer.sendserie(...
- server, study, 'N/A', series{i}, wbfac);
- catch me
- disp(sprintf('Could not send serie %d',i)); %#ok
- mydispexception(me);
- didfail = true;
- end;
-
- %Update progress bar
- transfer.progressbar(0.3+0.7*i/numel(series),...
- sprintf('Sending serie %d/%d',i,numel(series)));
-end
-
-try
- server.finalize_study(study);
-catch me
- disp('Could not finalize study');
- mydispexception(me);
- didfail = true;
-end;
diff --git a/source/+transfer/server.m b/source/+transfer/server.m
deleted file mode 100644
index e4163c8..0000000
--- a/source/+transfer/server.m
+++ /dev/null
@@ -1,311 +0,0 @@
-classdef server < handle
- properties(SetAccess = private, GetAccess = private)
- user
- password
- url
- end
-
- methods(Access = public)
- function self = server(user, password, url)
- self.user = user;
- self.password = password;
- self.url = url;
- end
-
- function id = new_study(self, uid, name)
- r = self.send('new_study', {'uid', uid, 'name', name});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t create study: ' r{1}]);
- end
- id = r{2};
- end
-
- function id = new_serie(self, desc, study)
- r = self.send('new_serie', {'desc', desc, 'study', study});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t create serie: ' r{1}]);
- end
- id = r{2};
- end
-
- function fileinfos = new_dicomfiles(self, fileinfos, serie)
- r = self.send('new_dicomfile', {...
- 'hash', self.join( {fileinfos.hash} ), ...
- 'serie', serie});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t create file: ' r{1}]);
- end
- ids = self.split(r{2});
- for i=1:numel(ids)
- fileinfos(i).id = ids{i};
- end
- end
-
- function update_dicomfile(self, data)
- r = self.send('update_dicomfile', {...
- 'file', self.join( {data.fileid} ), ...
- 'pos', self.join( arrayfun(@(x) {sprintf('%d', x{1})}, {data.pos}) ), ...
- 'data', self.join( {data.data} ) ...
- } ) ;
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t upload part of file: ' r{1}]);
- end
- end
-
- function finalize_dicomfile(self, ids)
- r = self.send('finalize_dicomfile', {'file', self.join(ids)});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t finalize dicomfile: ' r{1}]);
- end
- end
-
- function id = new_thumbnail(self, thumb_big_hash, thumb_small_hash, thumb_anim_hash, serie, prio)
- r = self.send('new_thumbnail', { ...
- 'serie', serie, ...
- 'hash_big', self.join(thumb_big_hash), ...
- 'hash_small', self.join(thumb_small_hash), ...
- 'hash_anim', self.join(thumb_anim_hash), ...
- 'prio', self.join(prio)});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t create thumbnail: ' r{1}]);
- end
- id = self.split(r{2});
- end
-
- function update_thumbnail(self, data, type)
- r = self.send('update_thumbnail', {...
- 'thumb', self.join( {data.fileid} ), ...
- 'type', type, ...
- 'pos', self.join( arrayfun(@(x) {sprintf('%d', x{1})}, {data.pos}) )...
- 'data', self.join( {data.data} )});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t upload part of thumbnail: ' r{1}]);
- end
- end
-
- function finalize_thumbnail(self, id)
- r = self.send('finalize_thumbnail', {'thumb', self.join(id)});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t finalize thumbnail: ' r{1}]);
- end
- end
-
- function set_thumbnail(self, serie, thumb)
- r = self.send('set_thumbnail', ...
- {'serie', serie, 'thumb', thumb});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t set thumbnail: ' r{1}]);
- end
- end
-
- function finalize_study(self, study)
- r = self.send('finalize_study', ...
- {'study', study});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t finalize study: ' r{1}]);
- end
- end
-
- function study = get_waiting_for_mat(self)
- r = self.send('get_waiting_for_mat', {});
- if isequal(r{1}, 'ok') && length(r)>1
- study = r{2};
- elseif isequal(r{1}, 'nothing')
- study = [];
- elseif isequal(r{1},'noAccess')
- error('SEGMENT:ERROR','NoAccess returned. Probably incorrect credentials.');
- else
- error('SEGMENT:ERROR','An unknown error occurd while trying to fetch series waiting for mat.');
- end
- end
-
- function [pattern] = get_pattern_for_user(self)
- r = self.send('get_pattern_for_user', {});
- if isequal(r{1}, 'ok') && length(r)>1
- pattern = r(2); %return all studies
- return;
- end;
-
- if isequal(r{1},'patternNotSet')
- error('SEGMENT:ERROR','PatternNotSet returned. Pattern is not set for this user');
- end;
-
- if isequal(r{1},'noAccess')
- error('SEGMENT:ERROR','NoAccess returned. Probably incorrect credentials.');
- end;
-
- %Should not get here, should return above in ok clause. Throw error.
- error('SEGMENT:ERROR','An unknown error occurd while trying to get pattern.');
-
- end;
-
- function [study,names] = get_studies_by_status(self,status)
- r = self.send('get_studies_by_status', {'status', status});
- if isequal(r{1}, 'ok') && length(r)>1
- study = r(4:2:end); %return all studies
- names = r(3:2:end); %return all names
- elseif isequal(r{1}, 'nothing')
- study = [];
- names = {};
- elseif isequal(r{1},'noAccess')
- error('SEGMENT:ERROR','NoAccess returned. Probably incorrect credentials.');
- else
- error('SEGMENT:ERROR',sprintf('An unknown error occurd while trying to fetch series %s.',status)); %#ok
- end
- end;
-
- function [study,names] = get_studies_by_status_and_scantime(self, status, scantime)
- r = self.send('get_studies_by_status_and_scantime', {'status', status, 'scantime', scantime});
- if isequal(r{1}, 'ok') && length(r)>1
- study = r(4:2:end); %return all studies
- names = r(3:2:end); %return all names
- elseif isequal(r{1}, 'nothing')
- study = [];
- names = {};
- elseif isequal(r{1},'noAccess')
- error('SEGMENT:ERROR','NoAccess returned. Probably incorrect credentials.');
- else
- error('SEGMENT:ERROR',sprintf('An unknown error occurd while trying to fetch series %s.',status)); %#ok
- end
- end;
-
- function [study,names] = get_waiting_for_consensus(self)
- r = self.send('get_waiting_for_consensus', {});
- if isequal(r{1}, 'ok') && length(r)>1
- study = r(4:2:end); %return all studies
- names = r(3:2:end); %return all names
- elseif isequal(r{1}, 'nothing')
- study = [];
- names = {};
- elseif isequal(r{1},'noAccess')
- error('SEGMENT:ERROR','NoAccess returned. Probably incorrect credentials.');
- else
- error('SEGMENT:ERROR','An unknown error occurd while trying to fetch series waiting for consensus.');
- end
- end
-
- function r = get_intresting_series(self, study)
- r = self.send('get_intresting_series', {'study', study});
- if not(isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t get intresting series: ' r{1}]);
- end
- r(1:2) = [];
- end
-
- function r = get_dicom_files(self, series)
- %Probably obsoleted??? EH:
- r = self.send('get_dicom_files', {'series', series});
- if not(isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t get dicom files: ' r{1}]);
- end
- r(1:2) = [];
- end
-
- function r = get_mat_files(self, study, owner)
- r = self.send('get_mat_files', {'study', study, 'owner', owner});
- if not(isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t get mat files: ' r{1}]);
- end
- r(1:2) = [];
- end
-
- function r = get_dicom_data(self, dicom)
- r = self.rawsend('get_dicom_data', {'dicom', dicom});
- if isempty(r)
- error('SEGMENT:ERROR', 'Couldn''t get dicom data');
- end
- end
-
- function id = new_matfile(self, study, hash)
- r = self.send('new_matfile', {'study', study, 'hash', hash});
- if not(isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t create new matfile: ' r{1}]);
- end
- id = r{2};
- end
-
- function update_matfile(self, id, pos, data)
- r = self.send('update_matfile', {'matfile', id, 'pos', sprintf('%d', pos), 'data', data});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t upload part of matfile: ' r{1}]);
- end
- end
-
- function update_status(self,id,newstatus)
- r = self.send('update_status', ...
- {'study', id, 'newstatus', newstatus});
- if not(isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t update status: ' r{1}]);
- end
- end;
-
- function finalize_matfile(self, matfile)
- r = self.send('finalize_matfile', ...
- {'matfile', matfile});
- if(~isequal(r{1}, 'ok'))
- error('SEGMENT:ERROR', ['Couldn''t finalize matfile: ' r{1}]);
- end
- end
-
- end
-
- methods(Access = private)
- function r = send(self, action, args)
- r = self.unpack_result(self.rawsend(action, args));
- %r = self.unpack_result(urlread(self.url, 'post', ...
- % [{'user', self.user, 'password', self.password, 'action', action} args]));
- end
- end
-
- methods(Access = public)
- function r = rawsend(self, action, args)
- failed_attempts = 0;
- while true
- try
- r = urlread(self.url, 'post', ...
- [{'user', self.user, 'password', self.password, 'action', action} args]);
- catch e
- if strcmp(e.message, 'Error downloading URL.')
- if failed_attempts > 3
- error('SEGMENT:ERROR', 'Couldn''t connect to core lab server');
- else
- failed_attempts = failed_attempts + 1;
- continue;
- end
- else
- rethrow(e);
- end
- end
- break
- end
-
- end
- end
-
- methods(Static, Access = public)
- function r = unpack_result(res)
- r = {};
- while(numel(res) ~= 0)
- [A, ~, ~, nextindex] = sscanf(res, '%s', 1);
- A = A(uint8(A)~=255); %remove uint8(255) from string
- r{end+1} = A;
- res = res(nextindex:end);
- end
- end
-
- function r = join(str_list)
- r = '';
- for i=1:numel(str_list)
- if i == 1
- r = str_list{1};
- else
- r = [r '|' str_list{i}];
- end
- end
- end
-
- function r = split(data)
- r = regexp(data, '\|', 'split');
- end
- end
-end
\ No newline at end of file
diff --git a/source/+transfer/server.p b/source/+transfer/server.p
new file mode 100644
index 0000000..b8a2026
Binary files /dev/null and b/source/+transfer/server.p differ
diff --git a/source/+transfer/setproxy.m b/source/+transfer/setproxy.m
deleted file mode 100644
index 13dae22..0000000
--- a/source/+transfer/setproxy.m
+++ /dev/null
@@ -1,11 +0,0 @@
-function setproxy()
- [h, p] = transfer.findproxy();
- if not(isequal(h, ''))
- com.mathworks.mlwidgets.html.HTMLPrefs.setUseProxy(true);
- com.mathworks.mlwidgets.html.HTMLPrefs.setProxyHost(h);
- com.mathworks.mlwidgets.html.HTMLPrefs.setProxyPort(p);
- com.mathworks.mlwidgets.html.HTMLPrefs.setUseProxyAuthentication(false);
- else
- com.mathworks.mlwidgets.html.HTMLPrefs.setUseProxy(false);
- end
-end
\ No newline at end of file
diff --git a/source/+transfer/study.m b/source/+transfer/study.m
deleted file mode 100644
index 90fa42e..0000000
--- a/source/+transfer/study.m
+++ /dev/null
@@ -1,197 +0,0 @@
-classdef study < handle
- properties(SetAccess = private, GetAccess = private)
- temppath
- studypath
- waitbar
- pattern
- newname
- end
-
- methods(Access = public)
-
- function self = study(path, pattern, waitbar)
-
- global DATA
-
- gui = DATA.GUI.Segment;
-
- self.waitbar = waitbar;
- self.pattern = pattern;
-
- %--- Ask for new name for the study
- mymsgbox(dprintf([...
- 'You need to give the study a new. Please follow the pattern according to the CRF. '...
- 'In this trial the pattern is %s where the characters means: \n\n' ...
- 'n any numeric digit (0,1,2,3,4,5,6,7,8,9)\n' ...
- 'x any character, (A,B,C....,a,b,c...)\n' ...
- 'X (upper case letter). Must be exact this character\n' ...
- '0 numerical digit. Must be exactly this digit\n' ...
- '- dash\n' ...
- ': colon\n' ...
- '. point\n'],pattern));
-
- docheck = true;
- if isempty(pattern)
- docheck = false;
- pattern = 'Pnnnn';
- end;
-
- valid = false;
-
- %Keep asking until a valid name has been found.
- while ~valid
- s = inputdlg({['Enter new patient name according to the pattern ' pattern]},'Patient Name',1,{pattern});
- if isempty(s)
- error('SEGMENT:ERROR','User aborted on naming study.');
- else
- self.newname = s{1};
- end;
-
- %Ensure no uncessesary spaces
- self.newname = strtrim(self.newname);
-
- %--- Check validity of pattern
- if docheck
- [valid,msg] = transfer.checkpattern(pattern,self.newname); %Throws an error if not matching
- if ~valid
- mymsgbox(dprintf('Invalid name. Pattern is %s. %s',pattern,msg));
- end;
- else
- valid = true;
- end;
- end;
-
- %Enable the progress bar
- set(gui.handles.overallpatch,'visible','on');
- set(gui.handles.overallline,'visible','on');
- set(gui.handles.overalltext,'visible','on');
-
- self.temppath = tempname;
- mkdir(self.temppath);
-
- %--- Sort the files (1).
- transfer.progressbar(0.1,'Sort and copy files.');
- logargs.recurse = true;
- logargs.anonym = false;
- logargs.stable = false; % but slow
- logargs.keepname = false;
- logargs.makethumbs = false;
- logargs.usedesc = true; % sort by series description
- dicomsorter('sortit', path, 1, self.temppath, [], logargs);
- delete([self.temppath filesep 'log.txt']);
-
- % Check that we only have one study and get the patientpath name
- tt = dir(self.temppath);
- numfolders = sum(cat(1,tt(:).isdir));
-
- if isequal(numfolders,2)
- error('SEGMENT:ERROR', 'Didn''t find any valid DICOM files in choosen folder');
- end
-
- %Make a list of studies
- studies = [];
- studies.patient = [];
- studies.studydate = [];
- studies.folder = [];
- studies.series = [];
-
- numstudies = 0;
- for loop = 1:length(tt)
- if tt(loop).isdir && (~isequal(tt(loop).name,'.')) && (~isequal(tt(loop).name,'..'))
- %Folder => check for studies
-
- %get files & folders
- f = dir([self.temppath filesep tt(loop).name]);
-
- for sloop = 1:length(f)
- if f(sloop).isdir && (~isequal(f(sloop).name,'.')) && (~isequal(f(sloop).name,'..'))
- %Add to list of studies
- if isempty(strfind(f(sloop).name,'20XX-XX-XX'))
- %Ignored study without valid dates
- numstudies = numstudies+1;
- studies(numstudies).patient = tt(loop).name; %#ok
- studies(numstudies).studydate = f(sloop).name; %#ok
- studies(numstudies).folder = [self.temppath filesep tt(loop).name filesep f(sloop).name]; %#ok
-
- %Find number of series
- fs = dir(studies(numstudies).folder);
- studies(numstudies).series = sum(cat(1,fs(:).isdir))-2; %#ok
-
- if studies(numstudies).series<0
- studies(numstudies).series = 0; %#ok
- end;
-
- end;
- end;
-
- end; %Loop over studies
- end; %Valid patient
- end; %Loop over patients
-
- if numstudies == 0
- error('ERROR:SEGMENT', 'Found no studies.');
- end;
-
- if numstudies>1
- mywarning('Detected multiple studies. This should normally not occur.');
-
- %Create a menu structure
- studycell = cell(1,length(studies));
- for loop = 1:length(studycell)
- studycell{loop} = sprintf('Patient:%s Date:%s Series:%d',studies(loop).patient,studies(loop).studydate,studies(loop).series);
- end;
-
- selstudy = mymenu('Select which study to take',studycell{:});
- if isequal(selstudy,0)
- error('SEGMENT:ERROR', 'Aborted when chosing which study to take.');
- end;
-
- if ~yesno(dprintf('Selected study ''%s''. Are you sure?',studycell{selstudy}))
- error('SEGMENT:ERROR', 'Aborted when confirming which patient to upload.');
- end;
-
- else
- selstudy = 1; %There was only one...
- end;
-
- self.studypath = studies(selstudy).folder;
-
- %--- Anonymize (2)
- transfer.progressbar(0.2,'Anonymizing data.');
-
- anonsilent = true;
- anonwaitbar = true;
- dicomanonymize(self.studypath, self.newname, anonsilent, anonwaitbar); %Need only to sort the study path
- disp(sprintf('Sorted folder was:%s', self.studypath));
-
- %Rename the folder
- oldfolder = [self.temppath filesep studies(selstudy).patient];
- newfolder = [self.temppath filesep self.newname ];
-
- disp(sprintf('Renaming the folder to %s',newfolder));
-
- [ok,msg] = movefile(oldfolder, newfolder);
- if ~ok && ~strcmp(oldfolder,newfolder)
- disp(msg);
- error('SEGMENT:ERROR','Could not rename folder.');
- end;
-
- %Assign the newly renamed folder.
- self.studypath = [self.temppath filesep self.newname filesep studies(selstudy).studydate];
- end
-
- function p = getpath(self)
- p = self.studypath;
- end
-
- function n = getname(self)
- n = self.newname;
- end
-
- function delete(self)
- w = self.waitbar(1, 'Clearing up temporary files...'); %#ok
- transfer.deltree(self.temppath);
- clear w;
- end
- end
-end
\ No newline at end of file
diff --git a/source/+transfer/thumbnails.m b/source/+transfer/thumbnails.m
deleted file mode 100644
index 272b5dd..0000000
--- a/source/+transfer/thumbnails.m
+++ /dev/null
@@ -1,184 +0,0 @@
-classdef thumbnails < handle
- properties(SetAccess = private, GetAccess = private)
- temppath
- files
- studyuid
- description
- patname
- wbfac
- didfail
- time
- sequencename
- venc
- docleanup = true;
- end
-
- methods(Access = public)
- function self = thumbnails(files, wbf)
- self.wbfac = wbf;
- wb = self.wbfac(4, 'Generating thumbnails...');
- self.temppath = tempname;
- mkdir(self.temppath);
-
- % Load the data
- loader = segloader();
- loader.adddicomfiles(files);
-
- wb.update();
-
- self.didfail = false;
-
- % May throw exception
- [~, data] = loader.render('', []);
-
- wb.update();
-
- % Get the uid, the patient name and the description
- self.studyuid = data(1).preview.StudyUID;
- self.patname = data(1).preview.PatientInfo.Name;
- if (~isfield(data(1).preview,'SequenceName') || strcmp(strtrim(data(1).preview.SequenceName), '')) && (~isfield(data(1).preview,'SeriesDescription') || strcmp(strtrim(data(1).preview.SeriesDescription), ''))
- self.description = 'No description';
- self.sequencename = 'No sequence name';
- elseif ~isfield(data(1).preview,'SequenceName') || strcmp(strtrim(data(1).preview.SequenceName), '')
- self.description = strtrim(data(1).preview.SeriesDescription);
- self.sequencename = 'No sequence name';
- else
- t = data(1).preview.AcquisitionTime;
- hours = floor(t/3600);
- minutes = floor((t-hours*3600)/60);
- seconds = floor(t-hours*3600-minutes*60);
- self.time = sprintf(...
- '%02d:%02d:%02d', ...
- hours, minutes, seconds);
- self.description = strtrim(data(1).preview.SeriesDescription);
- self.sequencename = strtrim(data(1).preview.SequenceName);
- end
- if size(data(1).IM, 5) ~= 1
- self.description = [self.description ' VENC data is present'];
- end
-
- self.files = {};
- picnum = 0;
-
- %Loop over rendered stacks
- for no = 1:numel(data)
- imsz = size(data(no).IM);
- if numel(imsz) < 5
- imsz(5) = 1;
- if numel(imsz) < 4
- imsz(4) = 1;
- end
- end
-
- % Get the thumbnails
- frames = imsz(3);
- slices = imsz(4);
- if frames>30
- %If more than 30 frames, then take middle, else take first. This is
- %then a good guess to get enddiastole.
- timeslice = round((imsz(3)+1)/2);
- else
- timeslice = 1;
- end;
-
- %Assign to wholepic.
- %If few timeframes, treat as slices
- if frames < 4 && slices == 1
- imsz = [imsz(1:2) 1 imsz(3) imsz(5)];
- wholepic = reshape(data(no).IM,imsz);
- frames = 1;
- slices = imsz(4);
- else
- wholepic = data(no).IM;
- end
-
- %--- Automatically crop the data if timeresolved.
- roisizeslice = 300; %mm
- roisizestack = 250; %mm
- if (slices>1) && (frames>15)
- xsize = roisizestack/data(no).preview.ResolutionX;
- ysize = roisizestack/data(no).preview.ResolutionY;
- wholepic = autocrop(wholepic,xsize,ysize);
- elseif (frames>15)
- xsize = roisizeslice/data(no).preview.ResolutionX;
- ysize = roisizeslice/data(no).preview.ResolutionY;
- wholepic = autocrop(wholepic,xsize,ysize);
- end;
-
- %Loop over slices
- for i=1:size(wholepic, 4)
- picnum = picnum + 1;
-
- %Extract data
- pic = wholepic(:, :, timeslice, i);
-
- %Autocontrast of the image
- pic = transfer.scaleim(pic);
-
- %Generate stationary thumbnails
- imwrite(pic, sprintf('%s%sthumb-%d-big.jpg', self.temppath, filesep, picnum));
- pic_small = imresize(pic, [128 round(128*size(pic,2)/size(pic,1))]);
- imwrite(pic_small, sprintf('%s%sthumb-%d-small.jpg', self.temppath, filesep, picnum));
-
- %Generate animations
- pic = transfer.scaleim(wholepic(:,:,:,i));
- pic = uint8(floor(pic*255));
- createanimgif(pic,sprintf('%s%sthumb-%d-anim.gif', self.temppath, filesep, picnum));
-
- %Send the files
- self.files{end+1} = {...
- sprintf('%s%sthumb-%d-big.jpg',self.temppath, filesep, picnum), ...
- sprintf('%s%sthumb-%d-small.jpg',self.temppath, filesep, picnum), ...
- sprintf('%s%sthumb-%d-anim.gif',self.temppath, filesep, picnum)};
- end
- end
-
- wb.update();
- end
-
- function r = getthumbs(self)
- r = self.files;
- end
-
- function r = getstudyuid(self)
- r = self.studyuid;
- end
-
- function r = getstudyname(self)
- r = self.patname;
- end
-
- function r = getdescription(self)
- r = self.description;
- end
-
- function delete(self)
- if self.docleanup
- transfer.deltree(self.temppath);
- end
- end
-
- function r = ok(self)
- r = ~self.didfail;
- end;
-
- function r = getsequence(self)
- r = self.sequencename;
- end
-
- function r = gettime(self)
- r = self.time;
- end
-
- function r = getvenc(self)
- r = self.venc;
- end
-
- function donotcleanup(self)
- self.docleanup = false;
- end
-
-
- end
-
-end
\ No newline at end of file
diff --git a/source/+transfer/uploadcurrent_Callback.m b/source/+transfer/uploadcurrent_Callback.m
deleted file mode 100644
index 6ed92da..0000000
--- a/source/+transfer/uploadcurrent_Callback.m
+++ /dev/null
@@ -1,120 +0,0 @@
-function uploadcurrent_Callback
-%uploadcurrent_Callback Uploads the current study (i.e matfile) to core
-%lab features.
-
-%Jonatan Wulcan, modified by Einar Heiberg
-
-global DATA SET
-
-if isempty(SET)
- myfailed('No data to upload');
- return
-end
-
-% Get the study id
-if (not(isfield(SET(1), 'transferid'))) || isempty(SET(1).transferid)
- myfailed('Couldn''t find Transfer id. The current stack must originate from the Transfer system');
- return
-end
-
-idstr = SET(1).transferid;
-spaceloc = regexp(idstr,'[ ]');
-if length(spaceloc) ~= 1
- myfailed('Bad format in transferid');
- return
-end
-study_id = idstr(1:spaceloc-1);
-project_url = idstr(spaceloc+1:end);
-
-% Save matfile
-filename = 'transfer-temp.mat';
-matfile = [getpreferencespath filesep filename];
-topatientdatabase = false;
-h = msgbox('Storing file to disk. Please wait.');
-fail = filemenu('saveallas_helper',getpreferencespath,filename,topatientdatabase);
-try
- close(h);
-catch %#ok
-end;
-
-if fail
- myfailed('Couldn''t save. Aborting.');
- return;
-end;
-
-try
-
- try
- [~, user, pw, url] = transfer.readcredentials();
- catch me
- mydispexception(me);
- myfailed('Could not find any credential files.');
- return;
- end;
-
- match_url = url;
-
- %Remove http://
- if isequal(findstr(match_url,'http://'),1) %#ok<*FSTR>
- match_url = match_url(8:end);
- end;
-
- %Remove www.
- if isequal(findstr(match_url,'www.'),1)
- match_url = match_url(5:end);
- end;
-
- %Remove http://
- if isequal(findstr(project_url,'http://'),1)
- project_url = project_url(8:end);
- end;
-
- %Remove www.
- if isequal(findstr(project_url,'www.'),1)
- project_url = project_url(5:end);
- end;
-
- while ~strcmp(match_url,project_url)
- myfailed(dprintf(...
- 'Project URL does not match origin, You are trying to upload to wrong trial! \n\nUploading to %s and trial originated from %s.',...
- url,project_url));
-
- [~, user, pw, url, ~] = transfer.readcredentials();
-
- match_url = url;
-
- %Remove http://
- if isequal(findstr(match_url,'http://'),1)
- match_url = match_url(8:end);
- end;
-
- %Remove www.
- if isequal(findstr(match_url,'www.'),1)
- match_url = match_url(5:end);
- end;
-
- end
-catch %#ok
- return
-end
-
-try
- s = transfer.server(user, pw, url);
- transfer.sendmatfile(s, study_id, matfile);
-catch e
- if strcmp(e.identifier, 'SEGMENT:ERROR')
- myfailed(e.message);
- return
- else
- rethrow(e);
- end
-end
-
-% Delete matfile
-delete(matfile);
-
-% Display message
-old_dna = DATA.Pref.DoNotAsk;
-DATA.Pref.DoNotAsk = false;
-mymsgbox('Upload completed successfully!');
-DATA.Pref.DoNotAsk = old_dna;
diff --git a/source/+transfer/uploadcurrent_Callback.p b/source/+transfer/uploadcurrent_Callback.p
new file mode 100644
index 0000000..c6b57d2
Binary files /dev/null and b/source/+transfer/uploadcurrent_Callback.p differ
diff --git a/source/+transfer/uploaddicoms_Callback.m b/source/+transfer/uploaddicoms_Callback.m
deleted file mode 100644
index 2938998..0000000
--- a/source/+transfer/uploaddicoms_Callback.m
+++ /dev/null
@@ -1,103 +0,0 @@
-function uploaddicoms_Callback
-%This function upload DICOM files to central image repository.
-
-%Written by Jonatan Wulcan. Commented and modified by Einar Heiberg
-
-global DATA
-
-%In the previous version it asked from where to upload data. Now assume and
-%ask.
-
-%Find folder of CD-ROM
-pathname = myuigetdir('D:','Select the CD-ROM drive.');
-
-if isequal(pathname,0)
- myfailed('Aborted.');
- return;
-end;
-
-%Check if folder containing DICOMS
-f = dir(pathname);
-numdicomfolders = 0;
-dicomfolder = pathname;
-for loop = 1:length(f)
- if f(loop).isdir
- if ~isempty(strfind(lower(f(loop).name),'dicom'))
- numdicomfolders = numdicomfolders+1;
- dicomfolder = f(loop).name;
- end;
- end;
-end;
-
-%If found only one then
-if numdicomfolders == 1
- if yesno('Found one folder named ''dicom''. Do you want to restrict to this folder? (recommended)');
- pathname = [pathname filesep dicomfolder];
- else
- disp('Taking whole CD.');
- end;
-end;
-
-try
- wb = @(n, msg) transfer.waitbar(n, msg);
- [~, user, pw, url, pattern] = transfer.readcredentials();
-catch me
- disp('Could not read credential file.');
- mydispexception(me);
- transfer.failmessage;
- return; %Since fatal
-end;
-
-try
- %Create Server object
- s = transfer.server(user, pw, url);
-catch me
- disp('Could not create server object.');
- mydispexception(me);
- transfer.failmessage;
- return; %Since fatal
-end;
-
-try
- %Prepare the study (sort and anonymize)
- study = transfer.study(pathname, pattern, wb);
-catch me
- disp('Could not prepare the study (sort & anonymize)');
- mydispexception(me);
- transfer.failmessage;
- return; %Since fatal
-end;
-
-try
- %Send the study
- disp('Starting to send studies.');
- transfer.progressbar(0.3,'Transfering studies.');
- didfail = transfer.sendstudy(s, transfer.path2study(study.getpath), ...
- study.getname, wb);
-catch me
- mydispexception(me);
- transfer.failmessage;
- return;
-end;
-
-try
- clear study
-catch me
- disp('Could not clear study.');
- mydispexception(me);
- transfer.failmessage;
-end
-
-% Display message
-old_dna = DATA.Pref.DoNotAsk;
-DATA.Pref.DoNotAsk = false; %Ensure that message box is displayed.
-DATA.Buffer.KeyStroke = {}; %Ensure that message box is displayed.
-
-if ~didfail
- mymsgbox('Upload completed successfully!');
-else
- mymsgbox('Files uploaded. Errors were detected.!');
- transfer.failmessage;
-end;
-DATA.Pref.DoNotAsk = old_dna;
-
diff --git a/source/+transfer/viewcomments.m b/source/+transfer/viewcomments.m
deleted file mode 100644
index 56136da..0000000
--- a/source/+transfer/viewcomments.m
+++ /dev/null
@@ -1,44 +0,0 @@
-function viewcomments
-% View all comments on active image stacks
-
-%Nils Lundahl
-
-%Modified with fixcommentstri by Einar Heiberg
-
-global SET
-
-if ~isfield(SET,'Comment') || isempty([SET.Comment])
- myfailed('No comments available')
- return
-end
-
-stri = '';
-%Loop over all image stacks
-for no = 1:numel(SET)
- nostri = '';
- if ~isempty(SET(no).Comment)
- comments = SET(no).Comment;
- nostri = dprintf('Comments on image stack %d:\n\n',no);
- for cmt = comments
- txt = sprintf('%s @ %s\n%s\n\n',cmt.Username,cmt.Time,fixcommentstri(cmt.Text));
- nostri = [nostri txt];
- end
- end
- stri = [stri nostri];
-end
-
-msgbox(stri,'Comments')
-
-%------------------------------------------
-function commentstri = fixcommentstri(stri)
-%------------------------------------------
-%Ensures that commentstri is a vector of chars.
-
-if size(stri,1)>1
- commentstri = '';
- for loop = 1:size(stri,1)
- commentstri = [commentstri sprintf('\n') stri(loop,:)]; %#ok
- end;
-else
- commentstri = stri;
-end;
\ No newline at end of file
diff --git a/source/+transfer/viewcomments.p b/source/+transfer/viewcomments.p
new file mode 100644
index 0000000..965fb36
Binary files /dev/null and b/source/+transfer/viewcomments.p differ
diff --git a/source/+transfer/waitbar.m b/source/+transfer/waitbar.m
deleted file mode 100644
index adc8c4e..0000000
--- a/source/+transfer/waitbar.m
+++ /dev/null
@@ -1,25 +0,0 @@
-classdef waitbar < handle
- properties(SetAccess = private, GetAccess = private)
- h
- end
-
- methods(Access = public)
- function self = waitbar(n, msg)
- if n==1
- self.h = mywaitbarstart(2, msg);
- mywaitbarupdate(self.h);
- else
- self.h = mywaitbarstart(n, msg);
- end
- end
-
- function update(self)
- self.h = mywaitbarupdate(self.h);
- end
-
- function delete(self)
- mywaitbarclose(self.h);
- flushlog;
- end
- end
-end
\ No newline at end of file
diff --git a/source/+translation/dictionary.m b/source/+translation/dictionary.m
index e1165c9..991f566 100644
--- a/source/+translation/dictionary.m
+++ b/source/+translation/dictionary.m
@@ -4,14 +4,14 @@
% English string if no translation is available
global DATA
-persistent labels %#ok
+persistent labels
if nargin < 3
fromlanguage = 'English';
end
if nargin < 2
- if ~isempty(DATA) && isfield(DATA.Pref,'Language')
+ if ~isempty(DATA) && isprop(DATA,'Pref') && isfield(DATA.Pref,'Language')
language = DATA.Pref.Language;
else
language = 'English';
@@ -24,11 +24,34 @@
end
if isempty(labels)
- load(fullfile('+translation','dictionary.mat'),'labels')
+ if isdeployed
+ transpath = 'dictionary.mat';
+ else
+ transpath = fullfile([DATA.SegmentFolder filesep '+translation'],'dictionary.mat');
+ end
+ load(transpath,'labels')
+end
+
+dictind = find(strcmp(stri,{labels(:).(fromlanguage)}),1);
+% if ~isempty(dictind) && isfield(labels,language) && ...
+% ~isempty(labels(dictind).(language))
+% outstri = labels(dictind).(language);
+% end
+
+% new implementation that if the value does not exist in one language it is
+% searched in the english dictionary since it might be an enlish wording
+if isempty(dictind)
+ % try to find index in the english value
+ dictind = find(strcmp(stri,{labels(:).English}),1);
+end
+if ~isempty(dictind)
+ %translate if the value is found either in fromlanguage or in the english
+ if isfield(labels,language) && ~isempty(labels(dictind).(language))
+ % set value to the found value in the language
+ outstri = labels(dictind).(language);
+ else
+ % set value to the english one
+ outstri = labels(dictind).English;
+ end
end
-dictind = find(strcmp(stri,{labels.(fromlanguage)}),1);
-if ~isempty(dictind) && isfield(labels,language) && ...
- ~isempty(labels(dictind).(language))
- outstri = labels(dictind).(language);
-end
\ No newline at end of file
diff --git a/source/+translation/dictionary.mat b/source/+translation/dictionary.mat
index 6d52005..50a0016 100644
Binary files a/source/+translation/dictionary.mat and b/source/+translation/dictionary.mat differ
diff --git a/source/+translation/translatealllabels.m b/source/+translation/translatealllabels.m
index 53a8865..f887eca 100644
--- a/source/+translation/translatealllabels.m
+++ b/source/+translation/translatealllabels.m
@@ -5,34 +5,106 @@ function translatealllabels(handle,fromlanguage)
fromlanguage = 'English';
end
if isa(DATA,'maingui') && isfield(DATA.Pref,'Language') && ~strcmp(DATA.Pref.Language,fromlanguage)
- dotranslate(handle,DATA.Pref.Language,fromlanguage);
+ translateall(handle,DATA.Pref.Language,fromlanguage);
+end
+%-------------------------------------------------
+function translateall(handle,language,fromlanguage)
+%-------------------------------------------------
+
+switch handle.Type
+ case 'figure'
+ propertylist = {'Name'};
+ case 'uimenu'
+ propertylist = {'Label','Text'};
+ case 'uipanel'
+ propertylist = {'Title'};
+ case 'axes'
+ propertylist = {'Title','Xlabel','YLabel','Label'};
+ case 'uicontrol'
+ propertylist = {'String','Tooltip'};
+ case 'uibuttongroup'
+ propertylist = {'Title','Tooltip'};
+ otherwise
+ propertylist = {};
+end
+if ~isempty(propertylist)
+ alltext = get(handle,propertylist);
+ for ind = 1:numel(alltext)
+ % get and translate only the translatable properties
+ txt = alltext{ind};
+ if ~isempty(txt)
+ if ischar(txt)
+ set(handle,propertylist{ind},translation.dictionary(txt,language,fromlanguage));
+ elseif iscell(txt)
+ for j = 1:numel(txt)
+ if ischar(txt{j}) && ~isempty(txt{j})
+ txt{j} = translation.dictionary(txt{j},language,fromlanguage);
+ end
+ end
+ set(handle,propertylist{ind},txt);
+ end
+ end
+ end
+end
+kids = get(handle, 'Children');
+for i = 1:numel(kids)
+ translateall(kids(i),language,fromlanguage);
end
%-------------------------------------------------
function dotranslate(handle,language,fromlanguage)
%-------------------------------------------------
-hstruct = get(handle);
-fnames = fieldnames(hstruct);
-propertylist = {'Name','String','Label','Title','XLabel','YLabel','TooltipString'};
-plist = intersect(fnames,propertylist);
-for i = 1:numel(plist)
- p = plist{i};
- txt = hstruct.(p);
- if ~isempty(txt)
- if ischar(txt)
- set(handle,p,translation.dictionary(txt,language,fromlanguage));
- elseif iscell(txt)
- for j = 1:numel(txt)
- if ischar(txt{j}) && ~isempty(txt{j})
- txt{j} = translation.dictionary(txt{j},language,fromlanguage);
+propertylist = {'Name','String','Label','Title','XLabel','YLabel','TooltipString','Text'};
+for i = 1:numel(propertylist)
+ p = propertylist{i};
+ try
+
+ txt = get(handle,p);
+ if ~isempty(txt)
+ if ischar(txt)
+ set(handle,p,translation.dictionary(txt,language,fromlanguage));
+ elseif iscell(txt)
+ for j = 1:numel(txt)
+ if ischar(txt{j}) && ~isempty(txt{j})
+ txt{j} = translation.dictionary(txt{j},language,fromlanguage);
+ end
end
+ set(handle,p,txt);
end
- set(handle,p,txt);
end
+ catch
end
end
-kids = hstruct.Children;
+kids = handle.Children;
for i = 1:numel(kids)
dotranslate(kids(i),language,fromlanguage);
-end
\ No newline at end of file
+end
+
+
+% hstruct = get(handle);
+% fnames = fieldnames(hstruct);
+% propertylist = {'Name','String','Label','Title','XLabel','YLabel','TooltipString','Text'};
+% plist = intersect(fnames,propertylist);
+% for i = 1:numel(plist)
+% p = plist{i};
+% txt = hstruct.(p);
+% if ~isempty(txt)
+% if ischar(txt)
+% set(handle,p,translation.dictionary(txt,language,fromlanguage));
+% elseif iscell(txt)
+% for j = 1:numel(txt)
+% if ischar(txt{j}) && ~isempty(txt{j})
+% txt{j} = translation.dictionary(txt{j},language,fromlanguage);
+% end
+% end
+% set(handle,p,txt);
+% end
+% end
+% end
+%
+% kids = hstruct.Children;
+% for i = 1:numel(kids)
+% dotranslate(kids(i),language,fromlanguage);
+% end
+
diff --git a/source/+translation/uniquephrases.p b/source/+translation/uniquephrases.p
new file mode 100644
index 0000000..9e572cb
Binary files /dev/null and b/source/+translation/uniquephrases.p differ
diff --git a/source/+straintagging/CardiacMotion64.exe b/source/CardiacMotion64.exe
similarity index 100%
rename from source/+straintagging/CardiacMotion64.exe
rename to source/CardiacMotion64.exe
diff --git a/source/Docs/installationmanual.pdf b/source/Docs/installationmanual.pdf
deleted file mode 100644
index 1bd2b16..0000000
Binary files a/source/Docs/installationmanual.pdf and /dev/null differ
diff --git a/source/Docs/manual.pdf b/source/Docs/manual.pdf
deleted file mode 100644
index d30eed9..0000000
Binary files a/source/Docs/manual.pdf and /dev/null differ
diff --git a/source/Docs/techmanual.pdf b/source/Docs/techmanual.pdf
deleted file mode 100644
index 5ea8ef4..0000000
Binary files a/source/Docs/techmanual.pdf and /dev/null differ
diff --git a/source/LVrotation.m b/source/LVrotation.m
index fbe3c03..52d3221 100644
--- a/source/LVrotation.m
+++ b/source/LVrotation.m
@@ -11,7 +11,7 @@
%------------
-function init
+function init %#ok
%------------
%open the gui to define LV rotation
global DATA NO SET
@@ -23,7 +23,7 @@
%set rotation and slice
set(gui.handles.rotationslider,'value',SET(gui.no).SectorRotation);
-set(gui.handles.slicetext,'String',sprintf('Slice %d',gui.slice));
+set(gui.handles.slicetext,'String',dprintf('Slice %d',gui.slice));
if SET(NO).ZSize > 1
set(gui.handles.sliceslider,'Min',1,'Max',...
SET(NO).ZSize,'Value',SET(NO).ZSize-gui.slice+1,'SliderStep',...
@@ -32,7 +32,7 @@
set(gui.handles.sliceslider,'Visible','off');
set(gui.handles.slicetext,'Visible','off');
end
-
+segment('recursekeypressfcn',gui.fig,@(hObject,eventdata)LVrotation('keypressed',eventdata))
%plot image
plotimage;
@@ -43,6 +43,67 @@
ok_Callback;
end
+%--------------------------
+function requestfocus
+%--------------------------
+global DATA
+gui = DATA.GUI.LVrotation;
+warning off
+jFig = get(gui.fig,'JavaFrame');
+jFig.requestFocus;
+warning on;
+
+%-------------------------
+function keypressed(evt) %#ok
+%-------------------------
+%%Keypress function
+global DATA
+gui = DATA.GUI.LVrotation;
+% take away focus from sliders
+requestfocus;
+switch evt.Key
+ case {'downarrow','uparrow'}
+ %move slice
+ oldvalue = mygetslider(gui.handles.sliceslider);
+ h = gui.handles.sliceslider;
+ stepvalue = (h.Max - h.Min)*h.SliderStep(1);
+ if contains(evt.Key,'up')
+ newvalue = oldvalue + stepvalue;
+ else
+ newvalue = oldvalue - stepvalue;
+ end
+ if newvalue > h.Min && newvalue < h.Max
+ gui.handles.sliceslider.Value = newvalue;
+ elseif newvalue > h.Max
+ gui.handles.sliceslider.Value = h.Max;
+ elseif newvalue < h.Min
+ gui.handles.sliceslider.Value = h.Min;
+ end
+ sliceslider_Callback
+
+
+ case {'rightarrow','leftarrow'}
+ oldvalue = mygetslider(gui.handles.rotationslider);
+ h = gui.handles.rotationslider;
+ stepvalue = (h.Max - h.Min)*h.SliderStep(1);
+ if contains(evt.Key,'right')
+ newvalue = oldvalue + stepvalue;
+ else
+ newvalue = oldvalue - stepvalue;
+ end
+ if newvalue > h.Min && newvalue < h.Max
+ gui.handles.rotationslider.Value = newvalue;
+ elseif newvalue > h.Max
+ gui.handles.rotationslider.Value = h.Max;
+ elseif newvalue < h.Min
+ gui.handles.rotationslider.Value = h.Min;
+ end
+ rotationslider_Callback
+
+ otherwise
+ return
+
+end
%-----------------
function plotimage
@@ -70,19 +131,19 @@
[endox,endoy] = calcfunctions('resamplemodel',SET(gui.no).EndoX(:,tf,gui.slice),SET(gui.no).EndoY(:,tf,gui.slice),DATA.Pref.RadialProfiles);
if ~isempty(SET(gui.no).EpiX)
[epix,epiy] = calcfunctions('resamplemodel',SET(gui.no).EpiX(:,tf,gui.slice), SET(gui.no).EpiY(:,tf,gui.slice),DATA.Pref.RadialProfiles);
- end;
+ end
else
endox = SET(gui.no).EndoX(:,tf,gui.slice);
endoy = SET(gui.no).EndoY(:,tf,gui.slice);
if ~isempty(SET(gui.no).EpiX)
epix = SET(gui.no).EpiX(:,tf,gui.slice);
epiy = SET(gui.no).EpiY(:,tf,gui.slice);
- end;
-end;
+ end
+end
if isempty(SET(gui.no).EpiX)
epix = NaN;
epiy = NaN;
-end;
+end
%Plot contours
hold(gui.handles.imageaxes,'on');
@@ -135,15 +196,16 @@
%----------------------------
-function sliceslider_Callback %#ok
+function sliceslider_Callback
%----------------------------
%Callback for slider to toggle slice
global DATA SET
gui = DATA.GUI.LVrotation;
+requestfocus;
gui.slice = SET(gui.no).ZSize-round(mygetvalue(gui.handles.sliceslider))+1;
set(gui.handles.sliceslider,'Value',round(mygetvalue(gui.handles.sliceslider)));
-set(gui.handles.slicetext,'String',sprintf('Slice %d',gui.slice));
+set(gui.handles.slicetext,'String',dprintf('Slice %d',gui.slice));
plotimage;
@@ -154,6 +216,7 @@
global DATA SET
gui = DATA.GUI.LVrotation;
+requestfocus;
v = get(gui.handles.rotationfromannotationcheckbox,'value');
if v
@@ -180,13 +243,13 @@
for loop = 1:length(SET(no).Point.Z)
if isequal(SET(no).Point.Label{loop},'RV insertion') || isequal(SET(no).Point.Label{loop},'P1')|| isequal(SET(no).Point.Label{loop},'P2')
slices(SET(no).Point.Z(loop)) = true;
- end;
-end;
+ end
+end
%Find slices
pos = find(slices);
if isempty(pos)
- mywarning(sprintf('No RV points found. Current sector rotation is %0.5g',SET(no).SectorRotation));
+ mywarning(dprintf('No RV points found. Define two RV annotation points.'));
return
end
pos = reportbullseye('sectorrotationhelper',no);
@@ -210,7 +273,7 @@
reportbullseye('startbullseye');
%------------------------
-function cancel_Callback
+function cancel_Callback %#ok
%-----------------------
%cancel the analysis and close the LV rotation interface
close_Callback;
diff --git a/source/S.p b/source/S.p
index 5ec35d2..f8f3044 100644
Binary files a/source/S.p and b/source/S.p differ
diff --git a/source/SegmentMeasurements.txt b/source/SegmentMeasurements.txt
deleted file mode 100644
index 8b662fb..0000000
--- a/source/SegmentMeasurements.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-#;This is a comment line no semicolon in the line and end line with one;
-
-#;First argument is mode as used by the parser, i.e LV/RV/ROI/Scar;
-
-#;Second argument is type of specification;
-#; - mm is measurement;
-#; - roi is roi;
-#; - sp is special (more flexibility, see below);
-#; - ta is graphical description of how the table should look like;
-#; ta has a special syntax;
-
-#;Third argument is code in export;
-
-#;Fourth argument is short name (displayed);
-
-#;Fith argument is long name (displayed);
-
-#;Sixth argument is 1 if show in panel;
-
-#;Seventh argument is 1 if show in report (not implemented, but needs to be 1);
-
-#;Eight argument (sp only) is unit;
-
-#;Nineth argument (sp only) Matlab expression of what to output;
-
-#;Flow is outputed as CODE_NET,_FWD,_BKWD,_MF,_PEAK,_MEANVEL,_PEAKVEL,_SV,_DIS;
-
-#;For ta the arguments are in order;
-#;- Code;
-#;- Title;
-#;- Unused;
-#;- 1;
-#;- 1;
-#;- Number of columns;
-#;- Number of values;
-#;- Vector of column sizes;
-
-
-#;volumes tables;
-
-#;LV;
-LV;ta;LVTable;LV stack X;;1;1;2;1;[0.65 0.35];
-LV;sp;LVM; ED/ES LVM; 1;1;1;g;;
-LV;sp;LVEDV; LV-EDV; 1;1;1;ml;;
-LV;sp;LVESV; LV-ESV; 1;1;1;ml;;
-LV;sp;LVSV; LV-SV; 1;1;1;ml;;
-LV;sp;LVEF; LV-EF; 1;1;1;%;;
-LV;sp;LVHR; HR; 1;1;1;bpm;;
-
-#;RV;
-RV;ta;RVTable;RV stack X;;1;1;2;1;[0.65 0.35];
-RV;sp;RVM; ED/ES RVM; 1;1;1;g;;
-RV;sp;RVEDV; RV-EDV; 1;1;1;ml;;
-RV;sp;RVESV; RV-ESV; 1;1;1;ml;;
-RV;sp;RVSV; RV-SV; 1;1;1;ml;;
-RV;sp;RVEF; RV-EF; 1;1;1;%;;
-RV;sp;RVHR; HR; 1;1;1;bpm;;
-
-
-
-#;flow tables;
-
-#;Flow table;
-Flow;ta;FlowTable;Flow stack X;;1;1;2;1;[0.65 0.35];
-Flow;sp;ROI; ROI; ROI;1;1;;;
-Flow;sp;Netvol; Net; 1;1;1;ml;;
-Flow;sp;Forward; Forward; 1;1;1;ml;;
-Flow;sp;Backward; Backward; 1;1;1;ml;;
-Flow;sp;Regfrac; Regurg. frac;1;1;1;%;;
-Flow;sp;FlowHR; HR; 1;1;1;bpm;;
-
-
-#;measurement tables;
-
-#;Measurement table;
-Measurement;ta;MeasurementTable;Measurement stack X;;1;1;2;1;[0.6 0.4];
-Measurement;sp;m1; m1; 1;1;1;g;;
-Measurement;sp;m2; m2; 1;1;1;%;;
\ No newline at end of file
diff --git a/source/addcomment.fig b/source/addcomment.fig
index 0d848f7..f8a927d 100644
Binary files a/source/addcomment.fig and b/source/addcomment.fig differ
diff --git a/source/addextramenuitems.p b/source/addextramenuitems.p
new file mode 100644
index 0000000..9daab90
Binary files /dev/null and b/source/addextramenuitems.p differ
diff --git a/source/adminrequirement.m b/source/adminrequirement.m
index 61ac2a7..1705695 100644
--- a/source/adminrequirement.m
+++ b/source/adminrequirement.m
@@ -1,5 +1,12 @@
function adminrequirement
if isdeployed
- mymsgbox('This function may require that you are running the software as Administrator (not only be logged in with Administrator rights). To do so right click when starting software and select "Run as administrator".');
-end;
+ %check if can write file
+ fid = fopen('delete.me','wt');
+ if fid>0
+ fclose(fid);
+ delete('delete.me');
+ else
+ mymsgbox('This function may require that you are running the software as Administrator (not only be logged in with Administrator rights). To do so right click when starting software and select "Run as administrator".');
+ end
+end
diff --git a/source/alignSlides.m b/source/alignSlides.m
new file mode 100644
index 0000000..a3c74af
--- /dev/null
+++ b/source/alignSlides.m
@@ -0,0 +1,1268 @@
+function [setnew,r,myoT] = alignSlides(setold,t0, t1, slices, done)
+% Registers images from timeframe t0 to t1 in slices s,
+%inputs
+%int t0 initial timeframe.
+%int t1 final timeframe
+%index array slices, slices to register, set slices=[] to automaticly detect s where epi and endo is present
+%
+% done logical(number of timeframes x number of slices) to true to not
+% register an image, default is false
+
+%Written by Daniel
+%
+%Modified (slightly) for Segment coding standard and debugging by Einar Heiberg.
+
+global SETNEW OPT_PAR
+%parameters
+
+% faster and less robust parameter example
+OPT_PAR.nControl=10; %desired number of control points, range 2-80 increase it to improve results at the cost of running time
+OPT_PAR.weigthsRadius=10;% was 5; % raidius around epi and endo to register, in pixels.
+OPT_PAR.scale=1; %scales for gaussian low pass filter
+OPT_PAR.laplace=10; % smoothing parameter
+
+%Simulated anealing parameters
+OPT_PAR.META.boundTPS=0.1; %parameter bounds
+OPT_PAR.META.boundAffine=0.1;
+OPT_PAR.META.tMax=1; %maximum time per image in minutes, should not be reached
+OPT_PAR.META.TEMP_START=10; %initial temperaure, higher gives more random steps, zero for downhill simplex
+OPT_PAR.META.TEMP_END=0;
+OPT_PAR.META.MAX_ITER_TOTAL=10; %decrease for faster runtime at the cost of worse results (and increase to improve results)
+OPT_PAR.META.MAX_ITER_FIRST=20;
+OPT_PAR.META.COOL_RATE=0.95;
+OPT_PAR.META.RATIO=.99;
+calcResults=false; % get diagnostic results (dice) if true
+
+% % slower and more robust parameter example
+% %
+% %parameters
+% OPT_PAR.nControl=20; %desired number of control points, range 2-80 increase it to improve results at the cost of running time
+% OPT_PAR.weigthsRadius =5; % raidius around epi and endo to register, in pixels.
+% OPT_PAR.scale=[1]; %scales for gaussian low pass filter
+% OPT_PAR.laplace=10; % smoothing parameter
+%
+% %Simulated anealing parameters
+% OPT_PAR.META.boundTPS=0.1; %parameter bounds
+% OPT_PAR.META.boundAffine=0.1;
+% OPT_PAR.META.tMax=1; %maximum time per image in minutes, should not be reached
+% OPT_PAR.META.TEMP_START=100; %initial temperaure, higher gives more random steps, zero for downhill simplex
+% OPT_PAR.META.TEMP_END=0;
+% OPT_PAR.META.MAX_ITER_TOTAL=30; %decrease for faster runtime at the cost of worse results (and increase to improve results)
+% OPT_PAR.META.MAX_ITER_FIRST=20;
+% OPT_PAR.META.COOL_RATE=0.95;
+% OPT_PAR.META.RATIO=.99;
+% calcResults=false; % get diagnostic results (dice) if true
+
+SETNEW = setold;
+if nargin<5
+ done=logical(false(SETNEW.TSize,SETNEW.ZSize)); %default, register all images in range
+end
+
+if nargin<4
+ slices=[];
+end
+
+OPT_PAR.sz = size(SETNEW.IM);
+
+%Make sure it is a 4 element vector
+if length(OPT_PAR.sz)<4
+ OPT_PAR.sz = [OPT_PAR.sz 1 1];
+ OPT_PAR.sz = OPT_PAR.sz(1:4);
+end
+
+v = ~isnan(SETNEW.EpiX); %true in images where epi is present
+if isempty(slices)
+ slices=find(sum(sum(v,2),1)); %if slice not specified set where endo/epi is availible
+end
+ try
+ referenceFrame=SETNEW.referenceFrame; %reference frame already specified, ie, we are running again to refine results or add more timeframes
+ %[OPT_PAR.k,OPT_PAR.z,referenceFrame,slices]=init(referenceFrame,s); %% initilizes weigths and control points
+ catch
+
+ for i=1:size(slices)
+ referenceFrame(slices(i))=find(sum(v(:,:,slices(i)),1),1,'first');
+ end
+ %[OPT_PAR.k,OPT_PAR.z,referenceFrame,slices]=init([],s); %% initilizes weigths and control points, sets reference frame if its not specified
+ end
+
+r=zeros(OPT_PAR.sz(3),OPT_PAR.sz(4),4);
+SETNEW.referenceFrame=referenceFrame;
+wbstep = 1/(length(slices)*length(t0:t1));
+wbval = 0;
+h = mywaitbarstart(length(slices)*length(t0:t1),dprintf('Generating image stacks'));
+ for i=1:length(slices)
+ s=slices(i);
+ [OPT_PAR.k,OPT_PAR.z]=init(referenceFrame(s),s);
+ for t=t0:t1
+ a=[0 0;eye(2)];
+ c=zeros(size(OPT_PAR.z,1),2);
+ param=[a(:); c(:)]; %initial parameters
+
+
+ if ~(done(t,s) || (t==referenceFrame(s)))
+ tic;
+ [SETNEW.IM(:,:,t,s),param,r(t,s,1)]=register(SETNEW.IM(:,:,referenceFrame(s),s),SETNEW.IM(:,:,t,s), param,referenceFrame(s),s);
+
+ if calcResults && ~isnan(SETNEW.EpiY(1,t,s))
+
+ [r(t,s,2:3),myoT(t-t0+1,:,:)]=dice(param,OPT_PAR.z,referenceFrame(s),t,s);
+
+ end
+
+ r(t,s,4)=toc; % time per image
+ SETNEW.EpiY(:,t,s)=SETNEW.EpiY(:,referenceFrame(s),s);
+ SETNEW.EpiX(:,t,s)=SETNEW.EpiX(:,referenceFrame(s),s);
+ SETNEW.EndoY(:,t,s)=SETNEW.EndoY(:,referenceFrame(s),s);
+ SETNEW.EndoX(:,t,s)=SETNEW.EndoX(:,referenceFrame(s),s);
+ wbval = wbval + wbstep;
+% waitbar(wbval,h);
+ h = mywaitbarupdate(h);
+
+ end
+ end
+
+ end
+
+
+
+ setnew=SETNEW; %return
+ clear SETNEW
+ mywaitbarclose(h);
+% close(h);
+ clear OPT_PAR
+
+
+ function [dice,myoT,myoR]=dice(param,z,baseframe,t,s,sr)
+ % dice similarity measure, myocardium overlap coefficient for
+ % registred and unregistred images, requires endo/epi in t as well as baseframe.
+ % probably only useful to developer
+ % not used in registration
+ global SETNEW OPT_PAR
+ sz=OPT_PAR.sz;
+ A=reshape(param(1:6),3,2);
+ A=[[1 0 0]' A];
+ sr=2;%sampling rate
+ c=reshape(param(7:end),(length(param)-6)/2,2);
+ EpiR=[SETNEW.EpiY(:,baseframe,s) SETNEW.EpiX(:,baseframe,s)];
+ EndoR=[SETNEW.EndoY(:,baseframe,s) SETNEW.EndoX(:,baseframe,s)];
+ Epi=[SETNEW.EpiY(:,t,s) SETNEW.EpiX(:,t,s)];
+ Endo=[SETNEW.EndoY(:,t,s) SETNEW.EndoX(:,t,s)];
+ [X,Y]=meshgrid(1:1:sz(2)*sr,1:1:sz(1)*sr);
+ myoR=logical(false(sz(1)*sr,sz(2)*sr));
+ [IN] = inpolygon(X,Y,EpiR(:,1)*sr,EpiR(:,2)*sr);
+ myoR(IN)=true;
+ [IN] = inpolygon(X,Y,EndoR(:,1)*sr,EndoR(:,2)*sr);
+ myoR(IN)=false;
+
+ myo=logical(false(sz(1)*sr,sz(2)*sr));
+ [IN] = inpolygon(X,Y,Epi(:,1)*sr,Epi(:,2)*sr);
+ myo(IN)=true;
+
+ [IN] = inpolygon(X,Y,Endo(:,1)*sr,Endo(:,2)*sr);
+ myo(IN)=false;
+
+ myoT=transformIm(myo,A,c,[],z, 'final')>0.5;
+ dice(1)=2*(sum(myoT(:) .* myoR(:)))/(sum(myoT(:))+sum(myoR(:)));
+
+ dice(2)=2*(sum(myo(:) .* myoR(:)))/(sum(myo(:))+sum(myoR(:)));
+
+ %-----------------------------------------------
+function perf= perfusion(t,s)
+%-----------------------------------------------
+%not used for registration
+global SETNEW OPT_PAR
+imt=SETNEW.IM(:,:,t,s);
+
+endopct = (100-20)/100;
+epipct = 80/100;
+
+if endopct < 0 || endopct > 1 || epipct < 0 || epipct > 1 || (1-endopct) > epipct
+ myfailed('Invalid input of percentage')
+end
+
+
+
+
+ %Check if valid segmentation exists
+ if not(isnan(SETNEW.EndoX(1,t,s)))&¬(isnan(SETNEW.EpiX(1,t,s)))
+
+ %Make sure segmentation is correct
+ segment('checkconsistency',t,s);
+
+ endox = SETNEW.EndoX(:,t,s);
+ endoy = SETNEW.EndoY(:,t,s);
+ epix = SETNEW.EpiX(:,t,s);
+ epiy = SETNEW.EpiY(:,t,s);
+ xin = epix+(endox-epix)*(1-endopct);
+ yin = epiy+(endoy-epiy)*(1-endopct);
+ xout = epix+(endox-epix)*epipct;
+ yout = epiy+(endoy-epiy)*epipct;
+
+ end %valid segmentation exist
+ [X,Y]=meshgrid(1:1:OPT_PAR.sz(1)*1,1:1:OPT_PAR.sz(2)*1);
+ myoR=logical(false(OPT_PAR.sz(1),OPT_PAR.sz(2)));
+ [IN] = inpolygon(X,Y,yin,xin);
+ myoR(IN)=true;
+ [IN] = inpolygon(X,Y,yout,xout);
+ myoR(IN)=false;
+
+
+ perf(1)=mean(mean(imt(myoR)));
+ mx=mean(endox);
+ my=mean(endoy);
+ mrad=mean(sqrt((endox-mx).^2+(endoy-my).^2));
+ theta=1:pi/40:2*pi;
+ %halvLV=mrad/2*[sin(theta) cos(theta)];
+ LV=logical(false(size(myoR)));
+ LV(inpolygon(X,Y,mrad/2*sin(theta)+my,mrad/2*cos(theta)+mx))=true;
+ perf(2)=mean(mean(imt(LV)));
+
+
+
+
+
+
+
+
+
+
+
+function curve=transformC(X,A,c,z)
+ %transforms a curve,
+ % not used for registration
+ global OPT_PAR;
+
+ maX=max(max(OPT_PAR.sz(1:2)));
+ % scale coordinates
+ X=X./maX-0.5;
+ K=ctps_gen_K(X,z);
+ X=[ones(size(X,1),1) X];
+ U=X*A+K*[zeros(1,size(c,1))' c];
+ U=[U(:,2)./U(:,1) U(:,3)./U(:,1)];
+ %descale
+ curve=(U+0.5).*maX;
+
+function [k,z,ref,s]=init(ref,s)
+ %initializes constant parameters before optimization
+
+ global SETNEW OPT_PAR
+ OPT_PAR.sz=size(SETNEW.IM);
+ Epi=[SETNEW.EpiY(:,ref,s) SETNEW.EpiX(:,ref,s)];
+ Endo=[SETNEW.EndoY(:,ref,s) SETNEW.EndoX(:,ref,s)];
+ w = zeros(OPT_PAR.sz(1:2));
+ if isempty(SETNEW.EpiX)
+ %this should never happen, if it did anyway someone probably edited the
+ %main alignslides function
+ disp('Warning:No Epi/Endo in slice')
+ kant=round(0.2*sz(1:2));
+ w(kant(1):end-kant(1),kant(2):end-kant(2))=1;
+ else
+ %set weigths based on endo/epi
+ ind=[ [round(SETNEW.EpiX(:,ref,s)) ; round(SETNEW.EndoX(:,ref,s))] [round(SETNEW.EpiY(:,ref,s)); round(SETNEW.EndoY(:,ref,s))]];
+
+
+ OPT_PAR.weightsRadius=5;
+ for i =1:length(ind)
+ x=ind(i,1);
+ y=ind(i,2);
+ w(min(OPT_PAR.sz(1),max(1,x-OPT_PAR.weightsRadius)):min(OPT_PAR.sz(1),max(1,x+OPT_PAR.weightsRadius)),min(OPT_PAR.sz(2),max(1,y-OPT_PAR.weightsRadius)):min(OPT_PAR.sz(2),max(1,y+OPT_PAR.weightsRadius)))=1; % check if in bounds and set weigths
+ end
+ rectanguarGrid=false;
+ end
+
+ if rectanguarGrid
+ %rectangular control point grid, not currently used
+ [col,row] = find(w);
+ R2=10;
+ bounds=[min(row)-R2 max(row)+R2;min(col)-R2 max(col)+R2];
+ nControl=round(sqrt(OPT_PAR.nControl)); %total number of control points is nControl^2
+ gridsize=(bounds(:,2)-bounds(:,1))/nControl;
+ [X,Y] = meshgrid(gridsize(1)/2:gridsize(1):gridsize(1)*(nControl-0.5),gridsize(1)/2:gridsize(1):gridsize(1)*(nControl-0.5));
+
+ z=[X(:)+bounds(1,1) Y(:)+bounds(2,1)]; %control points
+
+ else %
+ % circular control point grid, replace with Helen's code
+ %%% Use code from Helen (centerline method).
+ z=Endo/2+Epi/2;
+ z=z(1:round(length(z)/OPT_PAR.nControl):length(z),:);
+ %z=[z; mean(z)];
+ end
+w=w(:);
+k=w>0;
+[x,y]=meshgrid(1:OPT_PAR.sz(2),1:OPT_PAR.sz(1));
+X=[x(:) y(:)];
+maX=max(max(OPT_PAR.sz(1:2)));
+OPT_PAR.X=X(k,:);
+OPT_PAR.x=x;
+OPT_PAR.y=y;
+OPT_PAR.X=(OPT_PAR.X)./maX-0.5; %scale image points
+z=z./maX-0.5;%scale control points
+
+
+
+function [Ir,param,r] = register(It, Ib, param,t0,s)
+
+ global OPT_PAR;
+
+ META=OPT_PAR.META;
+ a=[0 0;eye(2)];
+ c=zeros(size(OPT_PAR.z,1),2);
+ param0=[a(:); c(:)]; %initial parameters
+
+ A=eye(3,3);
+ [~,OPT_PAR.K]=transformIm(It,A,c,[],OPT_PAR.z, 'set_K'); %this will set K
+ for i =1:length(OPT_PAR.scale) %only one scale currently used
+ h = fspecial('gaussian',[21 21], OPT_PAR.scale(i));
+ IT = imfilter(It , h,'replicate');
+ IB = imfilter(Ib, h,'replicate');
+ OPT_PAR.IT=reshape(modNGF(IT),OPT_PAR.sz(1:2));
+ OPT_PAR.IT=single((OPT_PAR.IT(OPT_PAR.k)));
+ OPT_PAR.IB=single(reshape(modNGF(IB),OPT_PAR.sz(1:2)));
+ alfa=META.boundTPS*ones(size(param0));
+ alfa(1:6)=META.boundAffine;
+ ub=param0+alfa;
+ lb=param0-alfa;
+ f0=cost_SIMPSA(param0);
+ options = SIMPSASET('MAX_TIME',1,'TEMP_START',META.TEMP_START,'TEMP_END',0,'MAX_ITER_TOTAL', META.MAX_ITER_TOTAL,'MAX_ITER_TEMP_FIRST', META.MAX_ITER_FIRST,'COOL_RATE',META.COOL_RATE,'TOLFUN',0.001,'DISPLAY','none','TOLX', 10^-3,'INITIAL_ACCEPTANCE_RATIO',META.RATIO);
+ [param_final,FVAL,EXITFLAG]= SIMPSA('cost_SIMPSA',param0,lb,ub,options);%update parameters for each scale space/pyramid
+ f1=cost_SIMPSA(param_final);
+ r=f1/f0; %return for diagnostics
+ end
+ param=param_final; %parameters to return
+ A=reshape(param(1:6),3,2);
+ A=[[1 0 0]' A];
+ c=reshape(param(7:end),(length(param)-6)/2,2);
+ [Ir]=transformIm(Ib,A,c,[],OPT_PAR.z, 'final');
+
+
+
+function [K] = ctps_gen_K(x,z)
+
+% calulates TPS kernel matrix
+[n, M] = size (x);
+[m, N] = size (z);
+dim = M;
+
+% calc. the K matrix.
+% 2D: K = r^2 * log r
+% 3D: K = -r
+K= zeros (n,m);
+
+for it_dim=1:dim
+ tmp = x(:,it_dim) * ones(1,m) - ones(n,1) * z(:,it_dim)';
+ tmp = tmp .* tmp;
+ K = K + tmp;
+
+end
+if dim == 2
+ mask = K < 1e-10; % to avoid singularity.
+ K = 0.5*K .* log(K + mask) .* (K>1e-10);
+else
+ K = - sqrt(K);
+end
+
+
+function [I1,K,reg,motion_field]=transformIm(I0,A,c,K,z, method)
+ %image transformation I1=T(I0)
+
+ %inputs
+ %I0= image to be transformed
+ %A = affine transformation matrix 3 x 3
+ %c = TPS weigths 2 x (number of control points)
+ %K =TPS kernel (number of control points) x (number of pixels)
+ %K =[] sets K, do not re-set K if unless pixels or control points
+ %change
+ %z = TPS control points
+ % method = option string
+ %set_K do not transform, sets K
+
+ % "opt" faster using bilinear interpolation for optimization
+ % only transforms points w>0 K should already be set
+
+ % "final" whole image transformation
+ %outputs
+ % I1 =transformed image
+ % K =TPS kernel should only be set with "set_K" or "final"
+ % reg = laplacian regularization only set with "opt"
+ % motion_field only set by "final"
+
+
+ global OPT_PAR
+
+ I1=zeros(size(I0));
+
+ maX=max(max(OPT_PAR.sz(1:2)));
+ % scale coordinates
+
+ if isempty(K)
+
+ [K] = ctps_gen_K(OPT_PAR.X,z);
+
+ end
+ if strcmp('set_K', method) %do nothing, we only want to set K
+%
+
+
+ elseif strcmp('opt', method) %faster used for optimization
+
+ U= inverseFunc(OPT_PAR.X,A,c,K);
+
+ reg=sum(sum((OPT_PAR.X-U).^2));
+ %descale
+ U=(U+0.5).*maX;
+
+ I1 = interp2(OPT_PAR.x,OPT_PAR.y,I0,U(:,1), U(:,2));
+
+ elseif strcmp('final', method) % slower, used only for final transformation
+ [x,y]=meshgrid(1:size(I0,2),1:size(I0,1));
+ maX=max(size(I0));
+ X=[x(:) y(:)];
+ X=X./maX-0.5;
+ [K] = ctps_gen_K(X,z);
+ U= inverseFunc(X,A,c,K);
+ %descale
+ U=(U+0.5).*maX;
+ motion_field=(U-X);
+ I1 = interp2(x,y,I0,U(:,1), U(:,2));
+ I1(isnan(I1))=0;
+ I1=reshape(I1,size(I0));
+ end
+
+
+
+function U= inverseFunc(X,A,c,K)
+ %inverse TPS transformation
+
+ X=[ones(size(X,1),1) X];
+ U=(X-K*[zeros(1,size(c,1))' c])/(A);
+ %U=U(:,1:2);
+ U=[U(:,2)./U(:,1) U(:,3)./U(:,1)];
+ %diff=U-U1;
+
+
+function E= cost_SIMPSA(param)
+ %cost function
+global OPT_PAR
+ J=OPT_PAR.laplace;
+ A=reshape(param(1:6),3,2);
+ A=[[1 0 0]' A];
+ c=reshape(param(7:end),(length(param)-6)/2,2);
+ [Itrans,~,reg]= transformIm(OPT_PAR.IB,A,c,OPT_PAR.K,OPT_PAR.z, 'opt');
+ E=sum(sum((OPT_PAR.IT-Itrans).^2))+reg*J;
+
+
+
+
+
+
+
+function G=modNGF(I,noise)
+ % calculates amplitude of modified normalized gradient field
+ [FX,FY] = gradient((I));
+
+ n=numel(I);
+ gradnorm2=((FX.^2+FY.^2));
+ noise_diam=15;
+ if nargin<2
+ noise=noise_est((gradnorm2),ones(noise_diam)); %local noise estimation
+ %noise=std((gradnorm2(:))); %global noise estimation only for test
+ end
+ eps= noise+sum(sum(gradnorm2))/(noise_diam^2);
+ adjnorm=(gradnorm2+eps.^2).^(1/2);
+ x=FX./adjnorm;
+ y=FY./adjnorm;
+ G=x.^2+y.^2;
+
+function J = noise_est(varargin)
+% modified version of matlabs local noise estimation, classifies edges as
+% outliers
+%STDFILT Local standard deviation of image.
+
+% Copyright 1993-2005 The MathWorks, Inc.
+% $Revision.2 $ $Date: 2006/06/15 20:09:36 $
+
+[I, h] = ParseInputs(varargin{:});
+
+if (~isa(I,'double'))
+ I = double(I);
+end
+
+
+n = sum(h(:));
+
+% If n = 1 then return default J (all zeros) to avoid the divideByZero warning.
+% Otherwise, calculate standard deviation. The formula for standard deviation
+% can be rewritten in terms of the theoretical definition of
+% convolution. However, in practise, use correlation in IMFILTER to avoid a
+% flipped answer when NHOOD is asymmetric.
+% conv1 = imfilter(I.^2,h,'symmetric') / (n-1);
+% conv2 = imfilter(I,h,'symmetric').^2 / (n*(n-1));
+% std = sqrt(conv1-conv2).
+% These equations can be further optimized for speed.
+BW = edge(I,'canny');
+%BW=zeros(size(BW));
+n=imfilter(double(~BW), h , 'symmetric');
+n1 = n - 1;
+if n ~= 1
+ conv1 = imfilter(I.^2, h , 'symmetric')./(n.*n1);
+ conv2 = imfilter(I, h, 'symmetric').^2 ./ (n.*n1);
+ J = sqrt(max((conv1 - conv2),0));
+else
+ J = zeros(size(I));
+end
+
+%%%%%%%%%%%%%%%ParseInputs%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [I,H] = ParseInputs(varargin)
+
+narginchk(1,2);
+
+validateattributes(varargin{1},{'numeric','logical'},{'real','nonsparse'}, ...
+ mfilename, 'I',1);
+I = varargin{1};
+
+if nargin == 2
+ validateattributes(varargin{2},{'logical','numeric'},{'nonsparse'}, ...
+ mfilename,'NHOOD',2);
+ H = varargin{2};
+
+ eid = sprintf('Images:%s:invalidNeighborhood',mfilename);
+
+ % H must contain zeros and/or ones.
+ bad_elements = (H ~= 0) & (H ~= 1);
+ if any(bad_elements(:))
+ msg = 'NHOOD must be a matrix that contains zeros and/or ones.';
+ error(eid,'%s',msg);
+ end
+
+ % H's size must be a factor of 2n-1 (odd).
+ sizeH = size(H);
+ if any(floor(sizeH/2) == (sizeH/2) )
+ msg = 'NHOOD must have a size that is odd in each dimension.';
+ error(eid,'%s',msg);
+ end
+
+ if ~isa(H,'double')
+ H = double(H);
+ end
+
+else
+ H = ones(3);
+end
+
+
+
+function [X,FVAL,EXITFLAG,OUTPUT] = SIMPSA(FUN,X0,LB,UB,OPTIONS,varargin)
+%SIMPSA finds a minimum of a function of several variables using an algorithm
+% that is based on the combination of the non-linear smplex and the simulated
+% annealing algorithm (the SIMPSA algorithm, Cardoso et al., 1996).
+% In this paper, the algorithm is shown to be adequate for the global optimi-
+% zation of an example SETNEW of unconstrained and constrained NLP functions.
+%
+% SIMPSA attempts to solve problems of the form:
+% min F(X) subject to: LB <= X <= UB
+% X
+%
+% Algorithm partly based on section 10.4 and 10.9 in "Numerical Recipes in C",
+% ISBN 0-521-43108-5, and the paper of Cardoso et al, 1996.
+%
+% X=SIMPSA(FUN,X0) start at X0 and finds a minimum X to the function FUN.
+% FUN accepts input X and returns a scalar function value F evaluated at X.
+% X0 may be a scalar, vector, or matrix.
+%
+% X=SIMPSA(FUN,X0,LB,UB) defines a SETNEW of lower and upper bounds on the
+% design variables, X, so that a solution is found in the range
+% LB <= X <= UB. Use empty matrices for LB and UB if no bounds exist.
+% SETNEW LB(i) = -Inf if X(i) is unbounded below; SETNEW UB(i) = Inf if X(i) is
+% unbounded above.
+%
+% X=SIMPSA(FUN,X0,LB,UB,OPTIONS) minimizes with the default optimization
+% parameters replaced by values in the structure OPTIONS, an argument
+% created with the SIMPSASETNEW function. See SIMPSASETNEW for details.
+% Used options are TEMP_START, TEMP_END, COOL_RATE, INITIAL_ACCEPTANCE_RATIO,
+% MIN_COOLING_FACTOR, MAX_ITER_TEMP_FIRST, MAX_ITER_TEMP_LAST, MAX_ITER_TEMP,
+% MAX_ITER_TOTAL, MAX_TIME, MAX_FUN_EVALS, TOLX, TOLFUN, DISPLAY and OUTPUT_FCN.
+% Use OPTIONS = [] as a place holder if no options are SETNEW.
+%
+% X=SIMPSA(FUN,X0,LB,UB,OPTIONS,varargin) is used to supply a variable
+% number of input arguments to the objective function FUN.
+%
+% [X,FVAL]=SIMPSA(FUN,X0,...) returns the value of the objective
+% function FUN at the solution X.
+%
+% [X,FVAL,EXITFLAG]=SIMPSA(FUN,X0,...) returns an EXITFLAG that describes the
+% exit condition of SIMPSA. Possible values of EXITFLAG and the corresponding
+% exit conditions are:
+%
+% 1 Change in the objective function value less than the specified tolerance.
+% 2 Change in X less than the specified tolerance.
+% 0 Maximum number of function evaluations or iterations reached.
+% -1 Maximum time exceeded.
+%
+% [X,FVAL,EXITFLAG,OUTPUT]=SIMPSA(FUN,X0,...) returns a structure OUTPUT with
+% the number of iterations taken in OUTPUT.nITERATIONS, the number of function
+% evaluations in OUTPUT.nFUN_EVALS, the temperature profile in OUTPUT.TEMPERATURE,
+% the simplexes that were evaluated in OUTPUT.SIMPLEX and the best one in
+% OUTPUT.SIMPLEX_BEST, the costs associated with each simplex in OUTPUT.COSTS and
+% from the best simplex at that iteration in OUTPUT.COST_BEST, the amount of time
+% needed in OUTPUT.TIME and the options used in OUTPUT.OPTIONS.
+%
+% See also SIMPSASETNEW, SIMPSAGET
+
+
+
+% Copyright (C) 2006 Brecht Donckels, BIOMATH, brecht.donckels@ugent.be
+%
+% inspired by:
+% Systems Biology Toolbox for MATLAB
+% Copyright (C) 2005 Henning Schmidt, FCC, henning@fcc.chalmers.se
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+% USA.
+
+
+
+% handle variable input arguments
+
+if nargin < 5
+ OPTIONS = [];
+ if nargin < 4
+ UB = 1e5;
+ if nargin < 3
+ LB = -1e5;
+ end
+ end
+end
+
+% check input arguments
+
+if ~ischar(FUN)
+ error('''FUN'' incorrectly specified in ''SIMPSA''');
+end
+if ~isfloat(X0)
+ error('''X0'' incorrectly specified in ''SIMPSA''');
+end
+if ~isfloat(LB)
+ error('''LB'' incorrectly specified in ''SIMPSA''');
+end
+if ~isfloat(UB)
+ error('''UB'' incorrectly specified in ''SIMPSA''');
+end
+if length(X0) ~= length(LB)
+ error('''LB'' and ''X0'' have incompatible dimensions in ''SIMPSA''');
+end
+if length(X0) ~= length(UB)
+ error('''UB'' and ''X0'' have incompatible dimensions in ''SIMPSA''');
+end
+
+% declaration of global variables
+
+global NDIM nFUN_EVALS TEMP YBEST PBEST
+
+% SETNEW EXITFLAG to default value
+
+EXITFLAG = -2;
+
+% determine number of variables to be optimized
+
+NDIM = length(X0);
+
+% seed the random number generator
+
+rand('state',sum(100*clock));
+
+% SETNEW default options
+
+DEFAULT_OPTIONS = SIMPSASET('TEMP_START',[],... % starting temperature (if none provided, an optimal one will be estimated)
+ 'TEMP_END',1,... % end temperature
+ 'COOL_RATE',10,... % small values (<1) means slow convergence,large values (>1) means fast convergence
+ 'INITIAL_ACCEPTANCE_RATIO',0.95,... % when initial temperature is estimated, this will be the initial acceptance ratio in the first round
+ 'MIN_COOLING_FACTOR',0.9,... % minimum cooling factor (<1)
+ 'MAX_ITER_TEMP_FIRST',50,... % number of iterations in the preliminary temperature loop
+ 'MAX_ITER_TEMP_LAST',50,... % number of iterations in the last temperature loop (pure simplex)
+ 'MAX_ITER_TEMP',10,... % number of iterations in the remaining temperature loops
+ 'MAX_ITER_TOTAL',2500,... % maximum number of iterations tout court
+ 'MAX_TIME',2500,... % maximum duration of optimization
+ 'MAX_FUN_EVALS',2500,... % maximum number of function evaluations
+ 'TOLX',1e-6,... % maximum difference between best and worst function evaluation in simplex
+ 'TOLFUN',1e-3,... % maximum difference between the coordinates of the vertices
+ 'DISPLAY','none',... % 'iter' or 'none' indicating whether user wants feedback
+ 'OUTPUT_FCN',[]); % string with output function name
+
+% update default options with supplied options
+
+OPTIONS = SIMPSASET(DEFAULT_OPTIONS,OPTIONS);
+
+% store options in OUTPUT
+
+OUTPUT.OPTIONS = OPTIONS;
+
+% initialize simplex
+% ------------------
+
+% create empty simplex matrix p (location of vertex i in row i)
+P = zeros(NDIM+1,NDIM);
+% create empty cost vector (cost of vertex i in row i)
+Y = zeros(NDIM+1,1);
+% SETNEW best vertex of initial simplex equal to initial parameter guess
+PBEST = X0(:)';
+% calculate cost with best vertex of initial simplex
+YBEST = CALCULATE_COST(FUN,PBEST,LB,UB,varargin{:});
+
+% initialize temperature loop
+% ---------------------------
+
+% SETNEW temperature loop number to one
+TEMP_LOOP_NUMBER = 1;
+
+% if no TEMP_START is supplied, the initial temperature is estimated in the first
+% loop as described by Cardoso et al., 1996 (recommended)
+
+% therefore, the temperature is SETNEW to YBEST*1e5 in the first loop
+if isempty(OPTIONS.TEMP_START)
+ TEMP = abs(YBEST)*1e5;
+else
+ TEMP = OPTIONS.TEMP_START;
+end
+
+% initialize OUTPUT structure
+% ---------------------------
+
+OUTPUT.TEMPERATURE = zeros(OPTIONS.MAX_ITER_TOTAL,1);
+OUTPUT.SIMPLEX = zeros(NDIM+1,NDIM,OPTIONS.MAX_ITER_TOTAL);
+OUTPUT.SIMPLEX_BEST = zeros(OPTIONS.MAX_ITER_TOTAL,NDIM);
+OUTPUT.COSTS = zeros(OPTIONS.MAX_ITER_TOTAL,NDIM+1);
+OUTPUT.COST_BEST = zeros(OPTIONS.MAX_ITER_TOTAL,1);
+
+% initialize iteration data
+% -------------------------
+
+% start timer
+tic
+% SETNEW number of function evaluations to one
+nFUN_EVALS = 1;
+% SETNEW number of iterations to zero
+nITERATIONS = 0;
+
+% temperature loop: run SIMPSA till stopping criterion is met
+% -----------------------------------------------------------
+
+while 1
+
+ % detect if termination criterium was met
+ % ---------------------------------------
+
+ % if a termination criterium was met, the value of EXITFLAG should have changed
+ % from its default value of -2 to -1, 0, 1 or 2
+
+ if EXITFLAG ~= -2
+ break
+ end
+
+ % SETNEW MAXITERTEMP: maximum number of iterations at current temperature
+ % --------------------------------------------------------------------
+
+ if TEMP_LOOP_NUMBER == 1
+ MAXITERTEMP = OPTIONS.MAX_ITER_TEMP_FIRST*NDIM;
+ % The initial temperature is estimated (is requested) as described in
+ % Cardoso et al. (1996). Therefore, we need to store the number of
+ % successful and unsuccessful moves, as well as the increase in cost
+ % for the unsuccessful moves.
+ if isempty(OPTIONS.TEMP_START)
+ [SUCCESSFUL_MOVES,UNSUCCESSFUL_MOVES,UNSUCCESSFUL_COSTS] = deal(0);
+ end
+ elseif TEMP < OPTIONS.TEMP_END
+ TEMP = 0;
+ MAXITERTEMP = OPTIONS.MAX_ITER_TEMP_LAST*NDIM;
+ else
+ MAXITERTEMP = OPTIONS.MAX_ITER_TEMP*NDIM;
+ end
+
+ % construct initial simplex
+ % -------------------------
+
+ % 1st vertex of initial simplex
+ P(1,:) = PBEST;
+ Y(1) = CALCULATE_COST(FUN,P(1,:),LB,UB,varargin{:});
+
+ % if output function given then run output function to plot intermediate result
+ if ~isempty(OPTIONS.OUTPUT_FCN)
+ feval(OPTIONS.OUTPUT_FCN,P(1,:),Y(1));
+ end
+
+ % remaining vertices of simplex
+ for k = 1:NDIM
+ % copy first vertex in new vertex
+ P(k+1,:) = P(1,:);
+ % alter new vertex
+ P(k+1,k) = LB(k)+rand*(UB(k)-LB(k));
+ % calculate value of objective function at new vertex
+ Y(k+1) = CALCULATE_COST(FUN,P(k+1,:),LB,UB,varargin{:});
+ end
+
+ % store information on what step the algorithm just did
+ ALGOSTEP = 'initial simplex';
+
+ % add NDIM+1 to number of function evaluations
+ nFUN_EVALS = nFUN_EVALS + NDIM;
+
+ % note:
+ % dimensions of matrix P: (NDIM+1) x NDIM
+ % dimensions of vector Y: (NDIM+1) x 1
+
+ % give user feedback if requested
+ if strcmp(OPTIONS.DISPLAY,'iter')
+ if nITERATIONS == 0
+ disp(' Nr Iter Nr Fun Eval Min function Best function TEMP Algorithm Step');
+ else
+ disp(sprintf('%5.0f %5.0f %12.6g %15.6g %12.6g %s',nITERATIONS,nFUN_EVALS,Y(1),YBEST,TEMP,'best point'));
+ end
+ end
+
+ % run full metropolis cycle at current temperature
+ % ------------------------------------------------
+
+ % initialize vector COSTS, needed to calculate new temperature using cooling
+ % schedule as described by Cardoso et al. (1996)
+ COSTS = zeros((NDIM+1)*MAXITERTEMP,1);
+
+ % initialize ITERTEMP to zero
+
+ ITERTEMP = 0;
+
+ % start
+
+ for ITERTEMP = 1:MAXITERTEMP
+
+ % add one to number of iterations
+ nITERATIONS = nITERATIONS + 1;
+
+ % Press and Teukolsky (1991) add a positive logarithmic distributed variable,
+ % proportional to the control temperature T to the function value associated with
+ % every vertex of the simplex. Likewise,they subtract a similar random variable
+ % from the function value at every new replacement point.
+ % Thus, if the replacement point corresponds to a lower cost, this method always
+ % accepts a true down hill step. If, on the other hand, the replacement point
+ % corresponds to a higher cost, an uphill move may be accepted, depending on the
+ % relative COSTS of the perturbed values.
+ % (taken from Cardoso et al.,1996)
+
+ % add random fluctuations to function values of current vertices
+ YFLUCT = Y+TEMP*abs(log(rand(NDIM+1,1)));
+
+ % reorder YFLUCT, Y and P so that the first row corresponds to the lowest YFLUCT value
+ help = sortrows([YFLUCT,Y,P],1);
+ YFLUCT = help(:,1);
+ Y = help(:,2);
+ P = help(:,3:end);
+
+ % store temperature at current iteration
+ OUTPUT.TEMPERATURE(nITERATIONS) = TEMP;
+
+ % store information about simplex at the current iteration
+ OUTPUT.SIMPLEX(:,:,nITERATIONS) = P;
+ OUTPUT.SIMPLEX_BEST(nITERATIONS,:) = PBEST;
+
+ % store cost function value of best vertex in current iteration
+ OUTPUT.COSTS(nITERATIONS,:) = Y;
+ OUTPUT.COST_BEST(nITERATIONS) = YBEST;
+
+ if strcmp(OPTIONS.DISPLAY,'iter')
+ disp(sprintf('%5.0f %5.0f %12.6g %15.6g %12.6g %s',nITERATIONS,nFUN_EVALS,Y(1),YBEST,TEMP,ALGOSTEP));
+ end
+
+ % if output function given then run output function to plot intermediate result
+ if ~isempty(OPTIONS.OUTPUT_FCN)
+ feval(OPTIONS.OUTPUT_FCN,P(1,:),Y(1));
+ end
+
+ % end the optimization if one of the stopping criteria is met
+ %% 1. difference between best and worst function evaluation in simplex is smaller than TOLFUN
+ %% 2. maximum difference between the coordinates of the vertices in simplex is less than TOLX
+ %% 3. no convergence,but maximum number of iterations has been reached
+ %% 4. no convergence,but maximum time has been reached
+
+ if (abs(max(Y)-min(Y)) < OPTIONS.TOLFUN) && (TEMP_LOOP_NUMBER ~= 1)
+ if strcmp(OPTIONS.DISPLAY,'iter')
+ disp('Change in the objective function value less than the specified tolerance (TOLFUN).')
+ end
+ EXITFLAG = 1;
+ break;
+ end
+
+ if (max(max(abs(P(2:NDIM+1,:)-P(1:NDIM,:)))) < OPTIONS.TOLX) && (TEMP_LOOP_NUMBER ~= 1)
+ if strcmp(OPTIONS.DISPLAY,'iter')
+ disp('Change in X less than the specified tolerance (TOLX).')
+ end
+ EXITFLAG = 2;
+ break;
+ end
+
+ if (nITERATIONS >= OPTIONS.MAX_ITER_TOTAL*NDIM) || (nFUN_EVALS >= OPTIONS.MAX_FUN_EVALS*NDIM*(NDIM+1))
+ if strcmp(OPTIONS.DISPLAY,'iter')
+ disp('Maximum number of function evaluations or iterations reached.');
+ end
+ EXITFLAG = 0;
+ break;
+ end
+
+ if toc/60 > OPTIONS.MAX_TIME
+ if strcmp(OPTIONS.DISPLAY,'iter')
+ disp('Exceeded maximum time.');
+ end
+ EXITFLAG = -1;
+ break;
+ end
+
+ % begin a new iteration
+
+ %% first extrapolate by a factor -1 through the face of the simplex
+ %% across from the high point,i.e.,reflect the simplex from the high point
+ [YFTRY,YTRY,PTRY] = AMOTRY(FUN,P,-1,LB,UB,varargin{:});
+
+ %% check the result
+ if YFTRY <= YFLUCT(1)
+ %% gives a result better than the best point,so try an additional
+ %% extrapolation by a factor 2
+ [YFTRYEXP,YTRYEXP,PTRYEXP] = AMOTRY(FUN,P,-2,LB,UB,varargin{:});
+ if YFTRYEXP < YFTRY
+ P(end,:) = PTRYEXP;
+ Y(end) = YTRYEXP;
+ ALGOSTEP = 'reflection and expansion';
+ else
+ P(end,:) = PTRY;
+ Y(end) = YTRY;
+ ALGOSTEP = 'reflection';
+ end
+ elseif YFTRY >= YFLUCT(NDIM)
+ %% the reflected point is worse than the second-highest, so look
+ %% for an intermediate lower point, i.e., do a one-dimensional
+ %% contraction
+ [YFTRYCONTR,YTRYCONTR,PTRYCONTR] = AMOTRY(FUN,P,-0.5,LB,UB,varargin{:});
+ if YFTRYCONTR < YFLUCT(end)
+ P(end,:) = PTRYCONTR;
+ Y(end) = YTRYCONTR;
+ ALGOSTEP = 'one dimensional contraction';
+ else
+ %% can't seem to get rid of that high point, so better contract
+ %% around the lowest (best) point
+ X = ones(NDIM,NDIM)*diag(P(1,:));
+ P(2:end,:) = 0.5*(P(2:end,:)+X);
+ for k=2:NDIM
+ Y(k) = CALCULATE_COST(FUN,P(k,:),LB,UB,varargin{:});
+ end
+ ALGOSTEP = 'multiple contraction';
+ end
+ else
+ %% if YTRY better than second-highest point, use this point
+ P(end,:) = PTRY;
+ Y(end) = YTRY;
+ ALGOSTEP = 'reflection';
+ end
+
+ % the initial temperature is estimated in the first loop from
+ % the number of successfull and unsuccesfull moves, and the average
+ % increase in cost associated with the unsuccessful moves
+
+ if TEMP_LOOP_NUMBER == 1 && isempty(OPTIONS.TEMP_START)
+ if Y(1) > Y(end)
+ SUCCESSFUL_MOVES = SUCCESSFUL_MOVES+1;
+ elseif Y(1) <= Y(end)
+ UNSUCCESSFUL_MOVES = UNSUCCESSFUL_MOVES+1;
+ UNSUCCESSFUL_COSTS = UNSUCCESSFUL_COSTS+(Y(end)-Y(1));
+ end
+ end
+
+ end
+
+ % stop if previous for loop was broken due to some stop criterion
+ if ITERTEMP < MAXITERTEMP
+ break;
+ end
+
+ % store cost function values in COSTS vector
+ COSTS((ITERTEMP-1)*NDIM+1:ITERTEMP*NDIM+1) = Y;
+
+ % calculated initial temperature or recalculate temperature
+ % using cooling schedule as proposed by Cardoso et al. (1996)
+ % -----------------------------------------------------------
+
+ if TEMP_LOOP_NUMBER == 1 && isempty(OPTIONS.TEMP_START)
+ TEMP = -(UNSUCCESSFUL_COSTS/(SUCCESSFUL_MOVES+UNSUCCESSFUL_MOVES))/log(((SUCCESSFUL_MOVES+UNSUCCESSFUL_MOVES)*OPTIONS.INITIAL_ACCEPTANCE_RATIO-SUCCESSFUL_MOVES)/UNSUCCESSFUL_MOVES);
+ elseif TEMP_LOOP_NUMBER ~= 0
+ STDEV_Y = std(COSTS);
+ COOLING_FACTOR = 1/(1+TEMP*log(1+OPTIONS.COOL_RATE)/(3*STDEV_Y));
+ TEMP = TEMP*min(OPTIONS.MIN_COOLING_FACTOR,COOLING_FACTOR);
+ end
+
+ % add one to temperature loop number
+ TEMP_LOOP_NUMBER = TEMP_LOOP_NUMBER+1;
+
+end
+
+% return solution
+X = PBEST;
+FVAL = YBEST;
+
+% store number of function evaluations
+OUTPUT.nFUN_EVALS = nFUN_EVALS;
+
+% store number of iterations
+OUTPUT.nITERATIONS = nITERATIONS;
+
+% trim OUTPUT data structure
+OUTPUT.TEMPERATURE(nITERATIONS+1:end) = [];
+OUTPUT.SIMPLEX(:,:,nITERATIONS+1:end) = [];
+OUTPUT.SIMPLEX_BEST(nITERATIONS+1:end,:) = [];
+OUTPUT.COSTS(nITERATIONS+1:end,:) = [];
+OUTPUT.COST_BEST(nITERATIONS+1:end) = [];
+
+% store the amount of time needed in OUTPUT data structure
+OUTPUT.TIME = toc;
+
+return
+
+% ==============================================================================
+
+% AMOTRY FUNCTION
+% ---------------
+
+function [YFTRY,YTRY,PTRY] = AMOTRY(FUN,P,fac,LB,UB,varargin)
+% Extrapolates by a factor fac through the face of the simplex across from
+% the high point, tries it, and replaces the high point if the new point is
+% better.
+
+global NDIM TEMP
+
+% calculate coordinates of new vertex
+psum = sum(P(1:NDIM,:))/NDIM;
+PTRY = psum*(1-fac)+P(end,:)*fac;
+
+% evaluate the function at the trial point.
+YTRY = CALCULATE_COST(FUN,PTRY,LB,UB,varargin{:});
+% substract random fluctuations to function values of current vertices
+YFTRY = YTRY-TEMP*abs(log(rand(1)));
+
+return
+
+% ==============================================================================
+
+% COST FUNCTION EVALUATION
+% ------------------------
+
+function [YTRY] = CALCULATE_COST(FUN,PTRY,LB,UB,varargin)
+
+global YBEST PBEST NDIM nFUN_EVALS
+
+for i = 1:NDIM
+ % check lower bounds
+ if PTRY(i) < LB(i)
+ YTRY = 1e12+(LB(i)-PTRY(i))*1e6;
+ return
+ end
+ % check upper bounds
+ if PTRY(i) > UB(i)
+ YTRY = 1e12+(PTRY(i)-UB(i))*1e6;
+ return
+ end
+end
+
+% calculate cost associated with PTRY
+YTRY = feval(FUN,PTRY,varargin{:});
+
+% add one to number of function evaluations
+nFUN_EVALS = nFUN_EVALS + 1;
+
+% save the best point ever
+if YTRY < YBEST
+ YBEST = YTRY;
+ PBEST = PTRY;
+end
+
+return
+
+function options = SIMPSASET(varargin)
+%SIMPSASETNEW Create/alter simpsa optimization OPTIONS structure.
+% OPTIONS = SIMPSASETNEW('PARAM1',VALUE1,'PARAM2',VALUE2,...) creates an
+% optimization options structure OPTIONS in which the named parameters have
+% the specified values. Any unspecified parameters are SETNEW to [] (parameters
+% with value [] indicate to use the default value for that parameter when
+% OPTIONS is passed to the optimization function). It is sufficient to type
+% only the leading characters that uniquely identify the parameter. Case is
+% ignored for parameter names.
+% NOTE: For values that are strings, the complete string is required.
+%
+% OPTIONS = SIMPSASETNEW(OLDOPTS,'PARAM1',VALUE1,...) creates a copy of OLDOPTS
+% with the named parameters altered with the specified values.
+%
+% OPTIONS = SIMPSASETNEW(OLDOPTS,NEWOPTS) combines an existing options structure
+% OLDOPTS with a new options structure NEWOPTS. Any parameters in NEWOPTS
+% with non-empty values overwrite the corresponding old parameters in
+% OLDOPTS.
+%
+% SIMPSASETNEW with no input arguments and no output arguments displays all
+% parameter names and their possible values, with defaults shown in {}
+% when the default is the same for all functions that use that option -- use
+% SIMPSASETNEW(OPTIMFUNCTION) to see options for a specific function.
+%
+% OPTIONS = SIMPSASETNEW (with no input arguments) creates an options structure
+% OPTIONS where all the fields are SETNEW to [].
+
+% See also SIMPSAGET, SIMPSA
+%
+% Copyright (C) 2006 Brecht Donckels, BIOMATH, brecht.donckels@ugent.be
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+% USA.
+
+
+
+% Print out possible values of properties.
+if (nargin == 0) && (nargout == 0)
+ fprintf(' TEMP_START: [ positive scalar ]\n');
+ fprintf(' TEMP_END: [ positive scalar ]\n');
+ fprintf(' COOL_RATE: [ positive scalar ]\n');
+ fprintf(' INITIAL_ACCEPTANCE_RATIO: [ positive scalar < 1 {0.95} ]\n');
+ fprintf(' MIN_COOLING_FACTOR: [ positive scalar < 1 {0.9}]\n');
+ fprintf(' MAX_ITER_TEMP_FIRST: [ positive scalar {100} ]\n');
+ fprintf(' MAX_ITER_TEMP_LAST: [ positive scalar {20} ]\n');
+ fprintf(' MAX_ITER_TOTAL: [ positive scalar {2500} ]\n');
+ fprintf(' MAX_TIME: [ positive scalar {2500} ]\n');
+ fprintf(' MAX_FUN_EVALS: [ positive scalar {2500} ]\n');
+ fprintf(' TOLX: [ positive scalar {1e-6} ]\n');
+ fprintf(' TOLFUN: [ positive scalar {1e-6} ]\n');
+ fprintf(' DISPLAY: [ ''iter'' or ''none'' {''iter''} ]\n');
+ fprintf(' OUTPUT_FCN: [ function_handle ]\n');
+ fprintf('\n');
+return;
+end
+
+Names = [
+ 'TEMP_START '
+ 'TEMP_END '
+ 'COOL_RATE '
+ 'INITIAL_ACCEPTANCE_RATIO '
+ 'MIN_COOLING_FACTOR '
+ 'MAX_ITER_TEMP_FIRST '
+ 'MAX_ITER_TEMP_LAST '
+ 'MAX_ITER_TEMP '
+ 'MAX_ITER_TOTAL '
+ 'MAX_TIME '
+ 'MAX_FUN_EVALS '
+ 'TOLX '
+ 'TOLFUN '
+ 'DISPLAY '
+ 'OUTPUT_FCN '
+ ];
+
+m = size(Names,1);
+names = lower(Names);
+
+% Combine all leading options structures o1, o2, ... in odeSETNEW(o1,o2,...).
+options = [];
+for j = 1:m
+ options.(deblank(Names(j,:))) = [];
+end
+i = 1;
+while i <= nargin
+ arg = varargin{i};
+ if ischar(arg) % arg is an option name
+ break;
+ end
+ if ~isempty(arg) % [] is a valid options argument
+ if ~isa(arg,'struct')
+ error('MATLAB:odeSETNEW:NoPropNameOrStruct',...
+ ['Expected argument %d to be a string property name ' ...
+ 'or an options structure\ncreated with SIMANSETNEW.'], i);
+ end
+ for j = 1:m
+ if any(strcmp(fieldnames(arg),deblank(Names(j,:))))
+ val = arg.(deblank(Names(j,:)));
+ else
+ val = [];
+ end
+ if ~isempty(val)
+ options.(deblank(Names(j,:))) = val;
+ end
+ end
+ end
+ i = i + 1;
+end
+
+% A finite state machine to parse name-value pairs.
+if rem(nargin-i+1,2) ~= 0
+ error('MATLAB:odeSETNEW:ArgNameValueMismatch',...
+ 'Arguments must occur in name-value pairs.');
+end
+expectval = 0; % start expecting a name, not a value
+while i <= nargin
+ arg = varargin{i};
+
+ if ~expectval
+ if ~ischar(arg)
+ error('MATLAB:odeSETNEW:NoPropName',...
+ 'Expected argument %d to be a string property name.', i);
+ end
+
+ lowArg = lower(arg);
+ j = strmatch(lowArg,names);
+ if isempty(j) % if no matches
+ error('MATLAB:odeSETNEW:InvalidPropName',...
+ 'Unrecognized property name ''%s''.', arg);
+ elseif length(j) > 1 % if more than one match
+ % Check for any exact matches (in case any names are subSETNEWs of others)
+ k = strmatch(lowArg,names,'exact');
+ if length(k) == 1
+ j = k;
+ else
+ msg = sprintf('Ambiguous property name ''%s'' ', arg);
+ msg = [msg '(' deblank(Names(j(1),:))];
+ for k = j(2:length(j))'
+ msg = [msg ', ' deblank(Names(k,:))];
+ end
+ msg = sprintf('%s).', msg);
+ error('MATLAB:odeSETNEW:AmbiguousPropName', msg);
+ end
+ end
+ expectval = 1; % we expect a value next
+
+ else
+ options.(deblank(Names(j,:))) = arg;
+ expectval = 0;
+
+ end
+ i = i + 1;
+end
+
+if expectval
+ error('MATLAB:odeSETNEW:NoValueForProp',...
+ 'Expected value for property ''%s''.', arg);
+end
+
+
+
+
\ No newline at end of file
diff --git a/source/annotationpoint.m b/source/annotationpoint.m
index 1257b6a..7b47b9d 100644
--- a/source/annotationpoint.m
+++ b/source/annotationpoint.m
@@ -12,98 +12,6 @@
feval(varargin{:}); % FEVAL switchyard
end
-%---------------------------------
-function pointmove_Callback(dx,dy) %#ok
-%---------------------------------
-%Helper function to move points.
-global SET NO
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-
-pos = pointfind(true); %Call it in silent mode
-
-if isnan(pos)
- return;
-end;
-
-tools('enableundo',no);
-
-SET(no).Point.X(pos) = SET(no).Point.X(pos)+dx;
-SET(no).Point.Y(pos) = SET(no).Point.Y(pos)+dy;
-
-drawfunctions('drawsliceno');
-
-%-----------------------------
-function pointforward_Callback %#ok
-%-----------------------------
-%Track point forward in time.
-global DATA SET NO
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-
-pos = pointfind;
-
-if isnan(SET(no).Point.T(pos))
- myfailed('Not a time-resolved point.',DATA.GUI.Segment);
- return;
-end;
-
-x = SET(no).Point.X(pos);
-y = SET(no).Point.Y(pos);
-z = SET(no).Point.Z(pos);
-label = SET(no).Point.Label{pos};
-
-%Find corresponding point
-t = SET(no).CurrentTimeFrame;
-t = t+1;
-if t>SET(no).TSize
- t = 1;
-end;
-
-%Possible matches
-ind = find((round(SET(no).Point.Z)==z)&(SET(no).Point.T==t));
-score = 1e10; %Smaller the better
-foundind = NaN;
-for loop=1:length(ind)
- if isequal(SET(no).Point.Label{ind(loop)},label)
- temp = sqrt(...
- (SET(no).Point.X(ind(loop))-x).^2+...
- (SET(no).Point.Y(ind(loop))-y).^2);
- if temp0
@@ -186,7 +107,7 @@ function pointclearall_helper(no)
outdata{4+offset,1} = 'Time[ms]';
for tloop=1:SET(no).TSize
outdata{4+offset+tloop,1} = (tloop-1)*SET(no).TIncr*1000;
- end;
+ end
%extract data
ind = not(isnan(SET(no).Point.T));
@@ -200,55 +121,25 @@ function pointclearall_helper(no)
outdata{4+offset,3+(loop-1)*4} = 'X';
outdata{4+offset,4+(loop-1)*4} = 'Y';
outdata{4+offset,5+(loop-1)*4} = 'Z';
- end;
+ end
for lloop=1:length(labelstodo)
for loop=1:length(SET(no).Point.X)
if not(isnan(SET(no).Point.T(loop)))&&isequal(labelstodo{lloop},SET(no).Point.Label{loop})
if not(isempty(outdata{4+offset+SET(no).Point.T(loop),2+(lloop-1)*4}))
- mywarning(dprintf(...
- 'Multiple points with same label, ambigous result. Timeframe %d, slice %d ',...
+ mywarning(dprintf('Multiple points with same label, ambigous result. Timeframe %d, slice %d ',...
SET(no).Point.T(loop),SET(no).Point.Z(loop)),DATA.GUI.Segment);
- end;
+ end
outdata{4+offset+SET(no).Point.T(loop),2+(lloop-1)*4} = SET(no).Point.Label{loop};
outdata{4+offset+SET(no).Point.T(loop),3+(lloop-1)*4} = SET(no).Point.X(loop)*SET(no).ResolutionX;
outdata{4+offset+SET(no).Point.T(loop),4+(lloop-1)*4} = SET(no).Point.Y(loop)*SET(no).ResolutionY;
outdata{4+offset+SET(no).Point.T(loop),5+(lloop-1)*4} = SET(no).Point.Z(loop)*(SET(no).SliceThickness+SET(no).SliceGap);
- end;
- end;
- end;
-end;
-
-segment('cell2clipboard',outdata);
-
-%-------------------------------
-function pointdeletethis_Callback %#ok
-%-------------------------------
-%Delete point
-
-global SET NO
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-tools('enableundo',no);
-
-pos = pointfind;
-if isnan(pos)
- myfailed('No point found.');
- return;
+ end
+ end
+ end
end
-ind = true(1,length(SET(no).Point.X));
-ind(pos) = false;
-SET(no).Point.X = SET(no).Point.X(ind);
-SET(no).Point.Y = SET(no).Point.Y(ind);
-SET(no).Point.T = SET(no).Point.T(ind);
-SET(no).Point.Z = SET(no).Point.Z(ind);
-SET(no).Point.Label = SET(no).Point.Label(ind);
-drawfunctions('drawimageno');
+segment('cell2clipboard',outdata);
%------------------------------------
function pointcleartemplate_Callback %#ok
@@ -260,20 +151,20 @@ function pointclearall_helper(no)
no = NO;
if ~isempty(SET(NO).Parent)
no = SET(NO).Parent;
-end;
+end
if isempty(SET(no).Point)||isempty(SET(no).Point.X)
myfailed('No points to delete.',DATA.GUI.Segment)
return;
-end;
+end
-s = inputdlg({'Delete points labeled as:'},'Template',1,{''});
+s = myinputdlg({'Delete points labeled as:'},'Template',1,{''});
if isempty(s)
myfailed('Invalid template.',DATA.GUI.Segment);
return;
else
s = s{1};
-end;
+end
tools('enableundo',no);
@@ -281,72 +172,19 @@ function pointclearall_helper(no)
for loop=1:length(SET(no).Point.Z)
if isequal(SET(no).Point.Label{loop},s)
ind(loop) = false;
- end;
-end;
+ end
+end
-if ~yesno(dprintf('Deleting %d points are you sure?',sum(not(ind))),[],DATA.GUI.Segment);
+if ~yesno(dprintf('Deleting %d points are you sure?',sum(not(ind))),[],DATA.GUI.Segment)
return;
-end;
-
-SET(no).Point.X = SET(no).Point.X(ind);
-SET(no).Point.Y = SET(no).Point.Y(ind);
-SET(no).Point.T = SET(no).Point.T(ind);
-SET(no).Point.Z = SET(no).Point.Z(ind);
-SET(no).Point.Label = SET(no).Point.Label(ind);
-drawfunctions('drawimageno');
-
-%------------------------------------------
-function pointmaketimeresolvedthis_Callback %#ok
-%------------------------------------------
-%Converts a none time resolved point to a time resolved point.
-global DATA SET NO
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-tools('enableundo',no);
-
-pos = pointfind;
-
-if isnan(pos)
- myfailed('No point found');
- return;
end
-ind = true(1,length(SET(no).Point.X));
-ind(pos) = false;
-
-%Backup
-x = SET(no).Point.X(pos);
-y = SET(no).Point.Y(pos);
-z = SET(no).Point.Z(pos);
-label = SET(no).Point.Label(pos);
-
-%Remove old
SET(no).Point.X = SET(no).Point.X(ind);
SET(no).Point.Y = SET(no).Point.Y(ind);
SET(no).Point.T = SET(no).Point.T(ind);
SET(no).Point.Z = SET(no).Point.Z(ind);
SET(no).Point.Label = SET(no).Point.Label(ind);
-
-%Add new
-x = repmat(x,[1 SET(no).TSize]);
-y = repmat(y,[1 SET(no).TSize]);
-z = repmat(z,[1 SET(no).TSize]);
-t = 1:SET(no).TSize;
-label = repmat(label,[1 SET(no).TSize]);
-SET(no).Point.X = cat(2,SET(no).Point.X,x);
-SET(no).Point.Y = cat(2,SET(no).Point.Y,y);
-SET(no).Point.Z = cat(2,SET(no).Point.Z,z);
-SET(no).Point.T = cat(2,SET(no).Point.T,t);
-SET(no).Point.Label = cat(2,SET(no).Point.Label,label);
-
-mymsgbox('Point now timeresolved.','Done!',DATA.GUI.Segment);
-
-%Update image
-drawfunctions('drawimageno');
+viewfunctions('setview'); %drawfunctions('drawimageno');
%------------------------------------
function pointrenametemplate_Callback %#ok
@@ -358,237 +196,39 @@ function pointclearall_helper(no)
no = NO;
if ~isempty(SET(NO).Parent)
no = SET(NO).Parent;
-end;
+end
if isempty(SET(no).Point)||isempty(SET(no).Point.X)
pointclearall;
myfailed('No points exist.',DATA.GUI.Segment);
return;
-end;
+end
-s = inputdlg({'Rename points labeled as:'},'Template',1,{''});
+s = myinputdlg({'Rename points labeled as:'},'Template',1,{''});
if isempty(s)
myfailed('Invalid template.',DATA.GUI.Segment);
return;
else
s = s{1};
-end;
+end
-stri = inputdlg({'New name:'},'Newname',1,{''});
+stri = myinputdlg({'New name:'},'Newname',1,{''});
if isempty(stri)
myfailed('Invalid new name.',DATA.GUI.Segment);
return;
else
stri = stri{1};
-end;
+end
tools('enableundo',no);
for loop=1:length(SET(no).Point.Z)
if isequal(SET(no).Point.Label{loop},s)
SET(no).Point.Label{loop} = stri;
- end;
-end;
-
-drawfunctions('drawimageno');
-
-%--------------------------------
-function pointrenamethis_Callback %#ok
-%--------------------------------
-%Rename point
-global DATA SET NO
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-tools('enableundo',no);
-
-ind = pointfind;
-
-if isnan(ind)
- myfailed('No point found.');
- return;
-end
-
-s = inputdlg({'Enter name'},'Name',1,{sprintf('%s',SET(no).Point.Label{ind})});
-if isempty(s)
- myfailed('Invalid name.',DATA.GUI.Segment);
- return;
-end;
-SET(no).Point.Label(ind) = s;
-
-drawfunctions('drawimageno');
-
-%------------------------------
-function pointclearall_Callback %#ok
-%------------------------------
-%Clear all points.
-global SET NO DATA
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-tools('enableundo',no);
-
-pointclearall_helper(no);
-
-if strcmp(DATA.CurrentTheme,'3dp')
- segment3dp.tools('update3DP')
-else
- drawfunctions('drawimageno');
-end
-%----------------------
-function point_Buttonup %#ok
-%----------------------
-%Button up function for points.
-global DATA SET NO
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-tools('enableundo',no);
-
-%Restore so no motion is called
-set(DATA.imagefig,'WindowButtonMotionFcn','');
-
-%Restore main buttonup function
-set(DATA.imagefig,'WindowButtonUpFcn',...
- sprintf('%s(''buttonup_Callback'')','segment'));
-
-SET(no).Point.X(DATA.MeasureN) = DATA.MeasureX;
-SET(no).Point.Y(DATA.MeasureN) = DATA.MeasureY;
-
-drawfunctions('drawimageno');
-
-
-
-%--------------------
-function point_Motion %#ok
-%--------------------
-%Motion function for points.
-global DATA SET NO
-
-%If straintagging initiated adjust LVupdated
-if ~isempty(SET(NO).StrainTagging) && isfield(SET(NO).StrainTagging, 'LVupdated')
- SET(NO).StrainTagging.LVupdated = 1;
-end
-
-[x,y,slice] = segment('getclickedcoords');
-
-% first line is for montage
-% second line is for one-view.
-if (slice==SET(NO).CurrentSlice) && ...
- (x>0.5) && (y>0.5) && (x
-%-------------------------------
-%Find neareast point.
-global DATA SET NO
-
-%Get clicked coordinate
-[x,y,slice] = segment('getclickedcoords');
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-
-%Find correct point
-ind = NaN;
-mindist = 1e10;
-for loop=1:length(SET(no).Point.X)
- if slice==round(SET(no).Point.Z(loop))
- if (isnan(SET(no).Point.T(loop))) || (SET(no).Point.T(loop)==SET(no).CurrentTimeFrame)
- dist = min(sqrt(...
- (SET(no).Point.X(loop)-y).^2+...
- (SET(no).Point.Y(loop)-x).^2));
- if dist
-%--------------------------------------
-%Buttondown function when clicked at a point.
-global DATA SET NO
-
-if nargin==1
- type = get(DATA.imagefig,'SelectionType');
-end;
-
-segment('switchtopanel',panel);
-
-[~,~,slice] = segment('getclickedcoords');
-if (slice>SET(NO).ZSize)
- return;
+ end
end
-segment('switchtoslice',slice);
-
-%Use to point to mag data set
-no = NO;
-if ~isempty(SET(NO).Parent)
- no = SET(NO).Parent;
-end;
-
-ind = pointfind;
-
-%Prepare DATA.Measure info
-DATA.MeasureN = ind;
-DATA.MeasureX = SET(no).Point.X(ind);
-DATA.MeasureY = SET(no).Point.Y(ind);
-switch DATA.ViewPanelsType{panel}
- case {'one','mmodespatial','ortho'}
- DATA.MeasureOffsetX = 0;
- DATA.MeasureOffsetY = 0;
- case {'montage','montagerow','montagefit','sax3'}
- DATA.MeasureOffsetY = SET(no).XSize*floor((slice-1)/DATA.ViewPanelsMatrix{panel}(2));
- DATA.MeasureOffsetX = SET(no).YSize*mod(slice-1,DATA.ViewPanelsMatrix{panel}(2));
- otherwise
- return;
-end;
-
-switch type
- case 'alt'
- DATA.contextmenu;
- otherwise
- %Call point motion
- set(DATA.imagefig,'WindowButtonMotionFcn',sprintf('%s(''point_Motion'');',mfilename));
- set(DATA.imagefig,'WindowButtonUpFcn',...
- sprintf('%s(''point_Buttonup'')',mfilename));
-end;
+viewfunctions('setview'); %drawfunctions('drawimageno');
%----------------------------
function filterpoints_Callback %#ok
@@ -602,15 +242,14 @@ function pointat_Buttondown(panel,type) %#ok
no = NO;
%Find points to filter
-z = SET(no).Point.Z;
labels = SET(no).Point.Label;
labels = union(labels,{}); %Remove duplicates.
c = mymenu('Select point to filter',labels{:});
if isequal(c,0)
- myfailed('Aborted.');
+% myfailed('Aborted.');
return;
-end;
+end
name = labels{c}; %This is the name to be found.
@@ -621,8 +260,8 @@ function pointat_Buttondown(panel,type) %#ok
for loop = 1:length(SET(no).Point.X)
if isequal(SET(no).Point.Label{loop},name)
ind(loop) = true;
- end;
-end;
+ end
+end
%Extract
x = SET(no).Point.X;
@@ -634,7 +273,7 @@ function pointat_Buttondown(panel,type) %#ok
if ~isequal(length(x),SET(no).TSize)
myfailed('Number of points is not equal to number of timeframes. Duplicated point names?');
return;
-end;
+end
%Ask for standard deviation
s.Noise = 0.3;
@@ -642,7 +281,7 @@ function pointat_Buttondown(panel,type) %#ok
if ~ok
myfailed('Aborted or illegal value.');
return;
-end;
+end
%Extract it
objectnoise = s.Noise;
@@ -662,9 +301,9 @@ function pointat_Buttondown(panel,type) %#ok
hold on;
plot(t,xnew,'b-');
hold off;
-title('X-coordinate.');
-xlabel('Time [s]');
-ylabel('Position (pixel)');
+title(dprintf('X-coordinate.'));
+xlabel(dprintf('Time [s]'));
+ylabel(dprintf('Position (pixel)'));
%X coordinate
subplot(2,1,2);
@@ -672,17 +311,17 @@ function pointat_Buttondown(panel,type) %#ok
hold on;
plot(t,ynew,'b-');
hold off;
-title('Y-coordinate.');
-xlabel('Time [s]');
-ylabel('Position (pixel)');
+title(dprintf('Y-coordinate.'));
+xlabel(dprintf('Time [s]'));
+ylabel(dprintf('Position (pixel)'));
-set(99,'numbertitle','off','name','Position over time');
+set(99,'numbertitle','off','name',dprintf('Position over time'));
%Crop it back from triplicate
xnew = xnew((length(x)+1):2*length(x));
ynew = ynew((length(y)+1):2*length(y));
-if yesno('Do you want to apply filter?');
+if yesno('Do you want to apply filter?')
%Prepare to store by backup...
tools('enableundo',no);
@@ -691,11 +330,10 @@ function pointat_Buttondown(panel,type) %#ok
SET(no).Point.Y(ind) = ynew;
mymsgbox('Filter applied.');
-end;
+end
close(99);
-
%----------------------------------------------
function importpoint_Callback(no) %#ok
%----------------------------------------------
@@ -710,7 +348,7 @@ function importpoint_Callback(no) %#ok
if length(SET)<2
myfailed('Only one image stack in memory, import from file instead (under File menu).',DATA.GUI.Segment);
return;
-end;
+end
if nargin==0
%Find what imagestack
@@ -726,17 +364,17 @@ function importpoint_Callback(no) %#ok
return;
else
no = impstacks(s);
- end;
-end;
+ end
+end
if no==NO
myfailed('Cannot import from same image stack.',DATA.GUI.Segment);
return;
-end;
+end
if (no>length(SET))||(no<1)
myfailed('Invalid image stack selected.',DATA.GUI.Segment);
return;
-end;
+end
%Check what to do - later optionally take from input arguments.
if ~isempty(SET(no).Point)
@@ -745,11 +383,8 @@ function importpoint_Callback(no) %#ok
return;
end
-
-segment('updatemodeldisplay');
segment('updatevolume');
-segment_main('viewrefreshall_Callback');
-drawfunctions('drawallslices');
+viewfunctions('setview');
%----------------------------------------------------------------------------------
function importpointhelper(tono,fromno)
@@ -757,59 +392,32 @@ function importpointhelper(tono,fromno)
%Helper function to segmentimportsegmention Callback.
%- tono is destination of segmentation.
%- fromno is source.
-%
-%The function is capable of handeling slice offsets and different
-%pixelssizes as well as situations when number of timeframes differ. When
-%destination is not timeresolved and source is timeresolved then user is
-%asked from what timeframe to take the segmentation from.
-%
-%Work horse in importing. This function would benefit from anti-cut
-%and paste treatment.
global SET
-[sourceslices,destslices,sourcetime,desttime,zdirsource,zdirdest] = ...
- segmentation('findmatchingslices',tono,fromno,0,0,0,0);
-
-%Loop over the number of slices in destination images
-if ~isempty(SET(tono).Point)
- currentind = length(SET(tono).Point.X);
-else
- currentind = 0;
-end
-for zloop = 1:length(destslices)
-
- %Match slices, see above.
- sourceslice = sourceslices(zloop);
- destslice = destslices(zloop);
-
- %Match positions
- cornerpossource = SET(fromno).ImagePosition-zdirsource*(zloop-1)*(SET(fromno).SliceThickness+SET(fromno).SliceGap);
- cornerposdest = SET(tono).ImagePosition-zdirdest*(destslice-1)*(SET(tono).SliceThickness+SET(tono).SliceGap);
-
- xofs = (cornerpossource-cornerposdest)*(SET(tono).ImageOrientation(4:6)'); %Project on one axis in mm
- yofs = (cornerpossource-cornerposdest)*(SET(tono).ImageOrientation(1:3)'); %Project on the other axis in mm
-
- xofs = xofs / SET(tono).ResolutionX; %Now in pixels in destination coordinates
- yofs = yofs / SET(tono).ResolutionY; %Now in pixels in destination coordinates
+x = SET(fromno).Point.X;
+y = SET(fromno).Point.Y;
+z = SET(fromno).Point.Z;
- %factor between
- fx = SET(fromno).ResolutionX/SET(tono).ResolutionX;
- fy = SET(fromno).ResolutionY/SET(tono).ResolutionY;
-
- ind = find(SET(fromno).Point.Z == sourceslice);
- if ~isempty(ind)
- %Equal time resolution
- if isequal(desttime,sourcetime)
- SET(tono).Point.X(currentind+1:currentind+length(ind)) = min(SET(tono).XSize,max(1,SET(fromno).Point.X(ind)*fx+xofs));
- SET(tono).Point.Y(currentind+1:currentind+length(ind)) = min(SET(tono).YSize,max(1,SET(fromno).Point.Y(ind)*fy+yofs));
- SET(tono).Point.T(currentind+1:currentind+length(ind)) = SET(fromno).Point.T(ind);
- SET(tono).Point.Z(currentind+1:currentind+length(ind)) = ones(1,length(ind))*destslice;
- for indloop = 1:length(ind)
- SET(tono).Point.Label{currentind+indloop} = SET(fromno).Point.Label{ind(indloop)};
- end
- currentind = currentind+length(ind);
- end
+%Convert coordinates
+pos = calcfunctions('xyz2rlapfh',fromno,x,y,z);
+pos = calcfunctions('rlapfh2xyz',tono,pos(:,1),pos(:,2),pos(:,3));
+
+%Copy the points
+for loop = 1:size(pos,2)
+ x = pos(1,loop);
+ y = pos(2,loop);
+ z = pos(3,loop);
+ if ...
+ (x>0) && (x<=SET(tono).XSize) && ...
+ (y>0) && (y<=SET(tono).YSize) && ...
+ (z>0) && (z<=SET(tono).ZSize)
+ SET(tono).Point.X(end+1) = x;
+ SET(tono).Point.Y(end+1) = y;
+ SET(tono).Point.Z(end+1) = z;
+ SET(tono).Point.T(end+1) = SET(fromno).Point.T(loop);
+ SET(tono).Point.Label{end+1} = SET(fromno).Point.Label{loop};
end
-
-end;
+
+end
+
diff --git a/source/anonymization.m b/source/anonymization.m
new file mode 100644
index 0000000..470327b
--- /dev/null
+++ b/source/anonymization.m
@@ -0,0 +1,704 @@
+ function varargout = anonymization(varargin)
+%---------------------------------------------
+% ANONYMIZATION GUI for pseudonymization of dicom-files or mat-files as
+%extensive, partial or corrective pseudonymization, for a single file/folder or for
+%a whole working list.
+
+% Written by Jane Tufvesson
+
+%Todo
+% :code to make partial/normal anonymization of dicom files
+%
+% : code to make full anonymization of dicom files
+%
+% : code to make corrective anonymization of dicom files by removing
+% the added tags
+%
+% :rewrite find patient details to be compatible with import to work
+% list
+
+macro_helper(varargin{:});
+[varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
+
+%-----------------------------
+function initgui(filetype)
+%-----------------------------
+global SET DATA WL
+
+if ~isempty(SET)
+ myfailed('Please save and close your current analysis in order to pseudonymize multiple files.');
+ return
+end
+
+%open figure
+if isequal(filetype,'mat')
+ DATA.GUI.Anonymization = mygui('anonymizationmat.fig');
+ WL=[];
+elseif isequal(filetype,'dcm')
+ DATA.GUI.Anonymization = mygui('anonymizationdicom.fig');
+ WL=[];
+end
+fig = DATA.GUI.Anonymization.fig;
+
+set(fig,'DeleteFcn','anonymization(''deletegui_Callback'')');
+
+updatelist;
+
+%--------------------------
+function deletegui_Callback
+%--------------------------
+global DATA WL
+
+try
+ DATA.GUI.Anonymization = close(DATA.GUI.Anonymization);
+catch %#ok
+ delete(gcf);
+ if isa(DATA,'maingui')
+ DATA.GUI.Anonymization = [];
+ end
+end
+
+WL=[];
+
+%--------------------------
+function updategui_Callback
+%--------------------------
+updatelist;
+
+%-----------------------------
+function addsinglemat_Callback
+%-----------------------------
+global DATA
+
+%select file
+[filename{1},filepath{1}] = myuigetfile('*.mat','Select .mat-file.');
+if isequal(filepath{1},0)||isequal(filename,0)
+ myfailed('Function aborted. No file selected.',DATA.GUI.Segment);
+ return;
+end
+
+[~,filename{1}] = fileparts(filename{1});
+
+%add to worklist
+addtolistmat(filepath,filename);
+
+%-----------------------------
+function addmatfolder_Callback
+%-----------------------------
+global DATA
+
+%select folder
+pathname = DATA.Pref.datapath;
+pathname = myuigetdir(pathname,'Select a folder (including subfolders) with .mat files');
+
+if isequal(pathname,0)
+ myfailed('Aborted.');
+ return;
+end
+
+ext = '.mat';
+
+%find files in folder
+filelist = createtree(pathname,ext);
+numfiles = length(filelist);
+
+for loop = 1:numfiles
+ [filepath{loop},filename{loop}] = fileparts(filelist{loop});
+end
+
+%add to work list
+addtolistmat(filepath,filename);
+
+
+%-------------------------------------
+function importlist_Callback(filetype)
+%-------------------------------------
+global DATA WL
+
+temp = pwd;
+cd(DATA.Pref.datapath);
+[filename,pathname] = myuigetfile(...
+ '*.*','Select Excel file to load worklist from');
+cd(temp);
+
+fullfilename=[pathname filesep filename];
+
+%Load Excel file
+[~, ~,textfromfile] = xlsread(fullfilename);
+%remove header and extract correct amount of columns
+WLfromfile=textfromfile(2:end,1:4);
+
+%format variable anonymize in WL from file
+
+if isempty(WL)
+ WL=WLfromfile;
+else
+ WL=[WL; WLfromfile]; %add to current WL
+end
+
+updatelist;
+
+%-------------------------------------
+function clearlist_Callback(filetype)
+%-------------------------------------
+global WL
+
+WL=[];
+updatelist;
+
+%-----------------------------------
+function savelist_Callback
+%-----------------------------------
+global WL DATA
+
+getlistfromgui;
+
+gui=DATA.GUI.Anonymization;
+titles=get(gui.handles.worklisttable,'ColumnName');
+WLtofile=[titles';WL];%add header row to file
+
+segment('cell2clipboard',WLtofile,true);%true in order to writetofile
+
+%-------------------------------
+function adddicomfolder_Callback
+%-------------------------------
+global DATA
+
+if isempty(DATA)
+ pathname = myuigetdir(pwd,'Select directory to pseudonymize DICOM files in. Note: recursive behaviour.');
+else
+ pathname = myuigetdir(DATA.Pref.datapath,'Select directory to pseudonymize DICOM files in. Note: recursive behaviour.');
+end
+if isequal(pathname,0)
+ myfailed('Aborted.',DATA.GUI.Segment);
+ return;
+end
+
+filesepindex=strfind(pathname,filesep);
+lastfilesep=find(filesepindex
+ h = mywaitbarstart(numfiles,'Pseudonymizing files. Please wait.',1);
+ corruptedfiles='';
+ segment('filecloseall_Callback',true);
+ for fileloop=1:numfiles
+ %--- Load file
+ DATA.Silent = true; %Turn on "silent" mode to avoid to much update on screen when loading etc.
+ listindex=indextoanonymize(fileloop);
+ newname=WL{listindex,2};
+ filename=WL{listindex,3};
+ pathname=WL{listindex,4};
+ ext='.mat';
+
+ disp(dprintf('Loading %s.',filename));
+ %Make sure a fresh start
+
+ %---- try
+ %Load
+ SET=[];
+ load([pathname filesep filename ext],'-mat','setstruct','info');
+
+ %Assign
+ if not(isempty(setstruct))
+ SET = setstruct;
+ clear setstruct;
+
+ %Call to intialize all variables correcly after loaded data.
+ openfile('setupstacksfrommat',1);
+ segment('renderstacksfrommat');
+
+ if savekeyfile
+ output{fileloop+1,1}=newname;
+ if saveasnewname
+ output{fileloop+1,2}=newname;
+ else
+ output{fileloop+1,2}=filename;
+ end
+ output{fileloop+1,3}=filename;
+ output{fileloop+1,4}=pathname;
+ output{fileloop+1,5}=SET(1).PatientInfo.Name;
+ output{fileloop+1,6}=SET(1).PatientInfo.ID;
+ output{fileloop+1,7}=SET(1).PatientInfo.BirthDate;
+ if isequal(anontype,'full')
+ output{fileloop+1,8}=SET(1).PatientInfo.Sex;
+ output{fileloop+1,9}=SET(1).PatientInfo.Age;
+ output{fileloop+1,10}=SET(1).PatientInfo.AcquisitionDate;
+ output{fileloop+1,11}=SET(1).PatientInfo.Length;
+ output{fileloop+1,12}=SET(1).PatientInfo.Weight;
+ output{fileloop+1,13}=SET(1).PatientInfo.BSA;
+ output{fileloop+1,14}=SET(1).PatientInfo.Institution;
+ end
+ end
+
+ %anonymize dataset
+ if isequal(anontype,'full')
+ tools('anonymoustotal_Callback',true,newname);
+ elseif isequal (anontype, 'partial')
+ tools('anonymous_Callback',true,newname);
+ else
+ tools('anonymouscorrective_Callback',true,newname);
+ end
+
+ %Create thumbnails before storing.
+ calcfunctions('calcdatasetpreview');
+
+ % Set view settings
+ DATA.ViewPanels = 1;
+ DATA.ViewPanelsType = {'one'};
+ DATA.ViewMatrix = [1 1];
+ DATA.ThisFrameOnly = 0;
+ DATA.CurrentPanel = 1;
+ DATA.CurrentTheme = 'lv';
+ DATA.CurrentTool = 'select';
+
+ %Save the file.
+ disp('Saving...');
+ %segment('filesaveall_Callback');
+ corrupted=segment('checkcorrupteddataforautomaticsave');
+ if corrupted
+ corruptedfiles=sprintf('%s, %s',corruptedfiles,filename);
+ mywarning(dprintf('Image file %s seems to be corrupted from last save. Please load and pseudonymize manually to ensure that the image is not corrupted before saving.',filename));
+ else
+ if saveasnewname && not(isequal(filename,newname))
+ [sucess,m] = mymovefile([pathname filesep filename ext],[pathname filesep newname ext],'f'); %rename file
+ if not(sucess)
+ myfailed(dprintf('Failed to rename file %s',filename));
+ else
+ filemenu('saveallas_helper',pathname,newname);
+ end
+ else
+ filemenu('saveallas_helper',pathname,filename);
+ end
+ end
+ segment('filecloseall_Callback',true);
+ end
+ setstruct=[];
+ info=[]; %#ok
+ h = mywaitbarupdate(h);
+ end
+ mywaitbarclose(h);
+
+ if isempty(corruptedfiles)
+ if isequal(anontype,'full')
+ donestri = 'Patient identity and info removed in the selected .mat files.';
+ elseif isequal(anontype,'partial')
+ donestri = 'Patient identity removed in the selected .mat files.';
+ else
+ donestri = 'Filename and pathname removed in the selected .mat files.';
+ end
+ mymsgbox(donestri,'Done!',DATA.GUI.Segment);
+ else
+ myfailed(dprintf('The following files have not been pseudonymized: %s',corruptedfiles),DATA.GUI.Segment);
+ end
+
+ segment('filecloseall_Callback',true);
+catch me
+ mydispexception(me);
+ myfailed('Error in pseudonymization process. The files are not correclty pseudonymized. Please review that all filepaths are correct.');
+end
+
+if savekeyfile
+ segment('cell2clipboard',output,true);%true in order to writetofile
+end
+
+DATA.Silent=0;
+
+%-------------------------------
+function anonymizedicom_Callback
+%-------------------------------
+%Anonymize dicom-files according to anonymization type selcted by
+%radiobuttons
+
+global DATA WL
+
+if isempty(WL)
+ myfailed('Worklist is empty. Please add files to pseudonymize.');
+ return;
+end
+
+%get type of anonymization from radiobutton
+gui=DATA.GUI.Anonymization;
+if get(gui.handles.fullradiobutton,'value')
+ anontype='full';
+elseif get(gui.handles.partialradiobutton,'value')
+ anontype='partial';
+elseif get(gui.handles.correctiveradiobutton,'value')
+ anontype='corrective';
+else
+ myfailed('Select which type of pseudonymization to perform.');
+ return;
+end
+if isequal(anontype,'full')||isequal(anontype,'corrective')
+ myfailed('Only partial pseudonymization is implemented');
+ return;
+end
+
+if isequal(anontype,'full')
+ stri = 'This feature will remove all subject identity and info on the selected DICOM files. Are you sure?';
+elseif isequal(anontype,'partial')
+ stri = 'This feature will remove subject identity (patient ID, name and birth date) on the selected DICOM files. Are you sure?';
+else
+ stri = 'This feature will only remove obscure tags which might contain patient name/ID/birthdate without editing the original patient ID/name/birthdate on the selected DICOM files. Are you sure?';
+end
+
+if ~yesno(stri)
+ mymsgbox('Aborted.','');
+ return;
+end
+
+savekeyfile=get(gui.handles.savelistcheckbox,'value');
+
+%update list from gui
+getlistfromgui;
+
+%find which files to anonymize from worklist
+anonymize=zeros(size(WL,1),1);
+[anonymize(:)]=[WL{:,1}];
+indextoanonymize=find(anonymize);
+numfiles=length(indextoanonymize);
+
+%doublecheck with the user if worklist shall be saved
+if not(savekeyfile)
+ if ~yesno('You have chosen to not save the work list. This will be your only key to identify the subjects. Are you sure that you want to continue without saving the work list?')
+ return;
+ end
+end
+try
+ silent=true;
+ showwaitbar=true;
+ h = mywaitbarstart(numfiles,'Pseudonymizing files. Please wait.',1);
+ corruptedfiles='';
+ for fileloop=1:numfiles
+ %--- Load file
+ DATA.Silent = true; %Turn on "silent" mode to avoid to much update on screen when loading etc.
+ listindex=indextoanonymize(fileloop);
+ newname=WL{listindex,2};
+ foldername=WL{listindex,3};
+ pathname=WL{listindex,4};
+
+ disp(dprintf('Loading %s.',foldername));
+
+ %recursive anonymisation for current path to the current new name
+ dicomanonymize(pathname,newname,silent,showwaitbar);
+ h = mywaitbarupdate(h);
+ end
+ mywaitbarclose(h);
+
+ if isempty(corruptedfiles)
+ if isequal(anontype,'full')
+ donestri = 'Patient identity and info removed in the selected DICOM files.';
+ elseif isequal(anontype,'partial')
+ donestri = 'Patient identity removed in the selected DICOM files.';
+ else
+ donestri = 'Filename and pathname removed in the selected DICOM files.';
+ end
+ mymsgbox(donestri,'Done!',DATA.GUI.Segment);
+ else
+ myfailed(dprintf('The following files have not been pseudonymized: %s',corruptedfiles),DATA.GUI.Segment);
+ end
+
+ segment('filecloseall_Callback',true);
+
+catch me
+ mydispexception(me);
+ mydisp('Error in pseudonymization process. The files are not correclty pseudonymized.');
+end
+
+if savekeyfile
+ savelist_Callback;
+end
+
+DATA.Silent=0;
+
+
+%---------------------------------------------
+function addtolistmat(filepath,filename,newname)
+%--------------------------------------------
+global WL
+
+if nargin<3
+ newname=filename;
+end
+
+%initialize WL
+if isempty(WL)
+ numlines=0;
+ WL=cell(1,4);
+else
+ numlines=size(WL,1);
+ getlistfromgui;
+end
+
+%add data in WL
+numnewlines=length(filepath);
+for loop=1:numnewlines
+ WL{numlines+loop,1}=true;%anonymize
+ WL{numlines+loop,2}=newname{loop};%default:new name same as filename
+ WL{numlines+loop,3}=filename{loop};
+ WL{numlines+loop,4}=filepath{loop};%filepath in last column
+end
+
+updatelist;
+
+%---------------------------------------------
+function subdirbatch_Callback %#ok
+%---------------------------------------------
+
+global DATA
+
+%select folder
+pathname = DATA.Pref.datapath;
+pathname = myuigetdir(pathname,'Select a folder (including subfolders) with DICOM files');
+
+if isequal(pathname,0)
+ myfailed('Aborted.');
+ return
+end
+
+subdirbatch(pathname)
+
+
+%---------------------------------------------
+function subdirbatch(basefolder)
+%--------------------------------------------
+
+global WL
+
+%initialize WL
+if isempty(WL)
+ numlines=0;
+ WL = cell(1,4);
+else
+ numlines = size(WL,1);
+ getlistfromgui;
+end
+
+flist = dir(basefolder);
+
+addtoline = numlines;
+
+for floop = 1:length(flist)
+ f = flist(floop);
+
+ if strcmp(f.name, '.') || strcmp(f.name, '..')
+ continue
+ end
+
+ if ~f.isdir
+ continue
+ end
+
+ % OK, we have a subdir, add it to the list
+ addtoline = addtoline + 1;
+
+ WL{addtoline,1} = true;
+ WL{addtoline,2} = f.name;
+ WL{addtoline,3} = f.name;
+ WL{addtoline,4} = fullfile(f.folder, f.name);
+end
+
+updatelist;
+
+
+%---------------------------------------------
+function addtolistdicom(filepath,foldername, newname)
+%--------------------------------------------
+global WL
+
+if nargin<3
+ newname=cell(size(filepath));
+ newname{:}='Hidden';
+end
+
+%initialize WL
+if isempty(WL)
+ numlines=0;
+ WL=cell(1,4);
+else
+ numlines=size(WL,1);
+ getlistfromgui;
+end
+
+%add data in WL
+numnewlines=length(filepath);
+for loop=1:numnewlines
+ WL{numlines+loop,1}=true;%anonymize
+ WL{numlines+loop,2}=newname{loop};%default:new name same as filename
+ WL{numlines+loop,3}=foldername{loop};
+ WL{numlines+loop,4}=filepath{loop};%filepath in last column
+end
+
+updatelist;
+
+%------------------
+function updatelist
+%------------------
+global DATA WL
+
+gui=DATA.GUI.Anonymization;
+set(gui.handles.worklisttable,'Data',WL);
+DATA.GUI.Anonymization=gui;
+
+%-----------------------
+function getlistfromgui
+%----------------------
+global DATA WL
+
+gui=DATA.GUI.Anonymization;
+WL=get(gui.handles.worklisttable,'Data');
+
+
+%-----------------------------
+function initguisubject
+%-----------------------------
+%initiate the GUI for pseydonymization for current .mat-file
+global DATA SET
+
+if isempty(SET)
+ myfailed('This feature applies to open files. Please open the file to pseudonymize, or use the batch pseudonymization features.');
+ return
+end
+
+%open figure
+DATA.GUI.Anonymization = mygui('anonymizationsubject.fig');
+
+fig = DATA.GUI.Anonymization.fig;
+
+set(fig,'DeleteFcn','anonymization(''deleteguisubject_Callback'')');
+
+
+%--------------------------
+function deleteguisubject_Callback
+%--------------------------
+%close the GUI for pseydonymization for current .mat-file
+global DATA
+
+try
+ DATA.GUI.Anonymization = close(DATA.GUI.Anonymization);
+catch %#ok
+ delete(gcf);
+ if isa(DATA,'maingui')
+ DATA.GUI.Anonymization = [];
+ end
+end
+
+%-----------------------------
+function anonymizesubject_Callback
+%-----------------------------
+%Anonymize current .mat-file according to anonymization type selcted by
+%radiobuttons
+
+global DATA
+
+handles = DATA.GUI.Anonymization.handles;
+
+if get(handles.partialradiobutton,'value')
+ tools('anonymous_Callback'); %partial
+elseif get(handles.extensiveradiobutton,'value')
+ tools('anonymoustotal_Callback'); %extensive
+end
+
+deleteguisubject_Callback;
+
diff --git a/source/anonymizationdicom.fig b/source/anonymizationdicom.fig
new file mode 100644
index 0000000..265c8e7
Binary files /dev/null and b/source/anonymizationdicom.fig differ
diff --git a/source/anonymizationmat.fig b/source/anonymizationmat.fig
new file mode 100644
index 0000000..1189672
Binary files /dev/null and b/source/anonymizationmat.fig differ
diff --git a/source/anonymizationsubject.fig b/source/anonymizationsubject.fig
new file mode 100644
index 0000000..e400490
Binary files /dev/null and b/source/anonymizationsubject.fig differ
diff --git a/source/atrialscar.m b/source/atrialscar.m
index 3daedbf..22c9393 100644
--- a/source/atrialscar.m
+++ b/source/atrialscar.m
@@ -25,7 +25,7 @@
global SET NO DATA
SET(NO).AtrialScar = [];
-drawfunctions('drawimagepanel',DATA.CurrentPanel);
+drawfunctions('drawpanel',DATA.CurrentPanel);
segment_main('updatevolume');
%--------------------
@@ -71,111 +71,26 @@ function update(no)
dist = sqrt((xr-circshift(xr,[1 0])).^2+(yr-circshift(yr,[1 0])).^2)/10; %10 to convert to cm
totarea = totarea+sum(dist(:))*slicethickness;
totscararea = totscararea+sum(dist(:))*slicethickness*(sum(rr))/length(rr);
- end;
-end;
+ end
+end
SET(no).AtrialScar.TotArea = totarea;
SET(no).AtrialScar.Percentage = (totscararea/totarea)*100;
-drawfunctions('drawimagepanel',DATA.CurrentPanel);
+%drawfunctions('drawimagepanel',DATA.CurrentPanel);
+drawfunctions('drawpanel',DATA.CurrentPanel);
segment_main('updatevolume');
-%---------------------------
-function drawimageone(no,panel) %#ok
-%---------------------------
-global DATA SET
-
-if isequal(get(DATA.Handles.hidescaricon,'state'),'on')
- hide = true;
-else
- hide = false;
-end;
-
-if ~hide
- x = SET(no).RVEndoX(:,SET(no).CurrentTimeFrame,SET(no).CurrentSlice);
- y = SET(no).RVEndoY(:,SET(no).CurrentTimeFrame,SET(no).CurrentSlice);
-
- logind = SET(no).AtrialScar.Result(:,SET(no).CurrentTimeFrame,SET(no).CurrentSlice);
- x1 = x(logind);
- y1 = y(logind);
-else
- x1 = NaN;
- y1 = NaN;
-end;
-
-if isempty(x1)
- x1 = NaN;
- y1 = NaN;
-end;
-
-DATA.Handles.atrialscarcontour(panel) = plot(DATA.Handles.imageaxes(panel),y1,x1,'y.');
-
-%----------------------------------
-function drawimagemontage(no,panel) %#ok
-%----------------------------------
-global DATA SET
-
-if isequal(get(DATA.Handles.hidescaricon,'state'),'on')
- hide = true;
-else
- hide = false;
-end;
-
-if ~hide
- x = SET(no).RVEndoXView(:,SET(no).CurrentTimeFrame);
- y = SET(no).RVEndoYView(:,SET(no).CurrentTimeFrame);
-
- logind = vertcat( ...
- SET(no).AtrialScar.Result,true(1,SET(no).TSize,SET(no).ZSize));
- x1 = x(logind(:));
- y1 = y(logind(:));
-else
- x1 = NaN;
- y1 = NaN;
-end;
-
-if isempty(x1)
- x1 = NaN;
- y1 = NaN;
-end;
-
-DATA.Handles.atrialscarcontour(panel) = plot(DATA.Handles.imageaxes(panel),y1,x1,'y.');
-
-%-----------------------------
-function drawsliceone(no,panel) %#ok
-%-----------------------------
-global DATA SET
-
-if isequal(get(DATA.Handles.hidescaricon,'state'),'on')
- hide = true;
-else
- hide = false;
-end;
-
-if ~hide
- x = SET(no).RVEndoX(:,SET(no).CurrentTimeFrame,SET(no).CurrentSlice);
- y = SET(no).RVEndoY(:,SET(no).CurrentTimeFrame,SET(no).CurrentSlice);
-
- logind = SET(no).AtrialScar.Result(:,SET(no).CurrentTimeFrame,SET(no).CurrentSlice);
- x1 = x(logind);
- y1 = y(logind);
-else
- x1 = NaN;
- y1 = NaN;
-end;
-
-set(DATA.Handles.atrialscarcontour(panel),'ydata',x1,'xdata',y1,'color',[1 1 0]);
-
%-----------------------------------------
function manualdraw_Buttonup(no,type,xr,yr) %#ok
%-----------------------------------------
-%Callback called from manualdraw_Buttonup in segment_main
+%Callback called from buttonupfunctions.m
global SET
if isempty(SET(no).AtrialScar)
initscar(no); %Initalize data structure
-end;
+end
%Create a mask
mask = segment('createmask',[SET(no).XSize SET(no).YSize],xr,yr);
@@ -188,12 +103,12 @@ function manualdraw_Buttonup(no,type,xr,yr) %#ok
ind = find(z>0.5); %logical index
%Assign
-switch type
+switch lower(type)
case 'scar'
SET(no).AtrialScar.Manual(ind,SET(no).CurrentTimeFrame,SET(no).CurrentSlice) = int8(1);
case 'rubberpen'
SET(no).AtrialScar.Manual(ind,SET(no).CurrentTimeFrame,SET(no).CurrentSlice) = int8(-1);
-end;
+end
update(no);
@@ -227,12 +142,12 @@ function manualdraw_Buttonup(no,type,xr,yr) %#ok
if contcheck>0
myfailed('Slices are not contigous. Missing segmentation in some slice.');
return;
-end;
+end
if length(slices)<2
myfailed('Expected at least two slices for atrial scar visualization.');
return;
-end;
+end
%Extract tf,slices
x = squeeze(x(:,tf,slices));
@@ -244,7 +159,7 @@ function manualdraw_Buttonup(no,type,xr,yr) %#ok
for loop = 1:length(slices)
tempmask = segment('createmask',[SET(NO).XSize SET(NO).YSize],x(:,loop),y(:,loop));
mask(:,:,loop) = tempmask;
-end;
+end
%--- Create smoothing filter
n = 7;
@@ -286,7 +201,7 @@ function manualdraw_Buttonup(no,type,xr,yr) %#ok
ind = sub2ind([SET(NO).XSize SET(NO).YSize length(slices)],round(xr2),round(yr2),repmat(loop,size(xr2)));
mask(ind) = 1;
end
-end;
+end
%--- Smooth scar mask
% originalmask = mask;
@@ -303,7 +218,7 @@ function manualdraw_Buttonup(no,type,xr,yr) %#ok
% cdata(cdata<(maxv/2)) = 0;
if maxv==0
maxv = 1;
-end;
+end
cdata = 0.2+0.8*cdata/maxv;
%--- Scale vertices before visualization
@@ -312,7 +227,7 @@ function manualdraw_Buttonup(no,type,xr,yr) %#ok
fv.vertices(:,3) = fv.vertices(:,3)*(SET(NO).SliceThickness+SET(NO).SliceGap);
%--- Display it
-figure(12);
+fig = figure(12);
clf;
h = patch(fv);
set(h,'cdata',cdata,'facecolor','interp','facealpha',0.7,'edgealpha',0);
@@ -321,6 +236,6 @@ function manualdraw_Buttonup(no,type,xr,yr) %#ok
%set(h,'edgealpha',0);
axis off image;
colormap(hot);
-cameratoolbar(12);
+cameratoolbar(fig);
set(gca,'clim',[0 1]);
diff --git a/source/autocrop.p b/source/autocrop.p
index 01a72f3..505fc55 100644
Binary files a/source/autocrop.p and b/source/autocrop.p differ
diff --git a/source/autocropall.p b/source/autocropall.p
index 6bd3bb3..7777e84 100644
Binary files a/source/autocropall.p and b/source/autocropall.p differ
diff --git a/source/autocropallgui.fig b/source/autocropallgui.fig
new file mode 100644
index 0000000..33f7edc
Binary files /dev/null and b/source/autocropallgui.fig differ
diff --git a/source/autocropallgui.p b/source/autocropallgui.p
new file mode 100644
index 0000000..a9097b7
Binary files /dev/null and b/source/autocropallgui.p differ
diff --git a/source/autosave.m b/source/autosave.m
new file mode 100644
index 0000000..82c9e68
--- /dev/null
+++ b/source/autosave.m
@@ -0,0 +1,192 @@
+function [varargout] = autosave(varargin)
+%Tools for autosaving
+
+%Einar Heiberg
+
+%Autosave was included many years ago in Segment but is now re-introduced
+%in 2020-10-17. Previous implementation was problematic due to overwriting,
+%and also wrote to working folder that could have been a slow network disc.
+%New implementation writes series of files to getpreferencespath.
+%
+%Autosave clears files such as:
+% 1) there no more than 500 MB in old files (=> max space 1 GB)
+% 2) older files than 24 hours.
+% 3) no more than 10 files stored.
+%
+%Potential problems with new implementation
+%1) Potential to get non anonymized data in getpreferencespath
+%2) If the files are very big then a lot of data will be in the getpreferencespath (max 1GB)
+%3) There is no guarantee that the files are save in a bad state du to
+%ongoing computations, some precautions are performed.
+
+%macro_helper(varargin{:}); %No need for macro recorder
+[varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
+
+%------------
+function init %#ok
+%------------
+%Init function check if should start timer
+
+global DATA
+
+if DATA.Pref.AutoSave
+ startit;
+else
+ DATA.AutoSaveTimer = [];
+end
+
+%---------------
+function startit
+%---------------
+%Starts the timer
+
+global DATA
+
+if ~isfield(DATA,'AutoSaveTimer')
+ DATA.AutoSaveTimer = [];
+end
+
+%This code is inspired from sectra.m
+if ~isempty(DATA.AutoSaveTimer) && isa(DATA.AutoSaveTimer,'timer')
+ %it is a timer, ensure it is stopped properly
+ stop(DATA.AutoSaveTimer);
+ delete(DATA.AutoSaveTimer);
+end
+
+t = 15*60; %15 minutes in seconds
+DATA.AutoSaveTimer = timer('StartDelay',t,'Period',t,'ExecutionMode','fixedSpacing');
+DATA.AutoSaveTimer.TimerFcn = 'autosave(''doautosave'')';
+start(DATA.AutoSaveTimer);
+disp('Autosave timer started.');
+
+%--------------
+function stopit
+%--------------
+%Stop autosave timer
+
+global DATA
+
+%Try to cleanup
+try
+ cleanup;
+catch me
+ disp('Could not perform cleanup before stopping autosave');
+ mydispexception(me);
+end
+
+%Try to stop
+try
+ stop(DATA.AutoSaveTimer);
+ delete(DATA.AutoSaveTimer);
+ DATA.AutoSaveTimer = [];
+ disp('Autosave time deleted.');
+catch me
+ disp('Something went wrong stopping autosave timer.');
+ mydispexception(me);
+end
+
+%------------------
+function doautosave %#ok
+%------------------
+%Performs the autosave, first performs cleanup
+
+global DATA
+
+%Do not save if no data loaded.
+if ~DATA.DataLoaded
+ return;
+end
+
+%Try to cleanup prior to save
+try
+ cleanup;
+catch me
+ disp('Could not perform cleanup.');
+ mydispexception(me);
+end
+
+%check if there is 'myworkon' running
+pointer = get(DATA.imagefig,'pointer');
+
+while isequal(pointer,'watch')
+ pause(5); %pause 5 seconds to wait for ongoing computations to finish, user interface is not locked while we perform pause
+ pointer = get(DATA.imagefig,'pointer');
+end
+
+%Now the current pointer is no longer a waitbar, this indicates to use that
+%it is relatively safe to do autosave
+
+%Save it
+topatientdatabase = false;
+silent = true;
+pathname = getpreferencespath;
+filename = sprintf('autosave-%s.mat',datestr(now,'yyyymmddTHHMMSS',now));
+h = msgbox(dprintf('Autosaving %s%s%s',pathname,filesep,filename)); %Reason for msgbox instead of mymsgbox is that msgbox is non modular (i.e code does not stop and wait for ok).
+disp(sprintf('Autosaving %s%s%s',pathname,filesep,filename)); %#ok
+filemenu('saveallas_helper',pathname,filename,topatientdatabase,silent)
+disp('Autosave done.');
+
+try
+ delete(h); %Try to delete the message box
+catch
+end
+
+%---------------
+function cleanup
+%---------------
+%Removes old autosaves
+
+%Removes:
+%1) autosaves older than 24 hours
+%2) only keeps 4 files (in practise there will be 5 files as cleanup is
+%called prior to doautosave.
+
+pathname = getpreferencespath;
+
+%Get potential autosave files to delete
+f = dir([pathname filesep 'autosave*.mat']);
+
+if isempty(f)
+ disp('No autosave files to delete.');
+ return;
+end
+
+disp('Checking for autosave files to clean.');
+
+%Files are returned alphanumerically, we should delete "the first ones"
+numfiles = length(f);
+
+%find cumulative size of files, counting backwards
+cumbytes = zeros(numfiles,1);
+totbytes = 0;
+for loop = numfiles:-1:1
+ totbytes = totbytes + f(loop).bytes;
+ cumbytes(loop) = totbytes;
+end
+
+%Delete so that there is no more than 500 MB stored
+bytelimit = 500*1024*1024;
+dodelete = cumbytes>bytelimit;
+
+%Also delete old files
+fileage = now-cat(1,f(:).datenum); %unit is days
+dodelete = dodelete | (fileage>1) ; %files older than 24 hours
+
+if sum(~dodelete)>10
+ ind = find(~dodelete);
+ dodelete(ind(1)) = true; %delete the first one
+end
+
+%loop over to delete
+if sum(dodelete)>0
+ for loop = 1:length(dodelete)
+ if dodelete(loop)
+ disp(sprintf('Deleting autosave file %s',f(loop).name)); %#ok
+ delete([pathname filesep f(loop).name]);
+ end
+ end
+else
+ disp('No files to delete.');
+end
+
+
diff --git a/source/avplane.fig b/source/avplane.fig
index f133058..9996d1e 100644
Binary files a/source/avplane.fig and b/source/avplane.fig differ
diff --git a/source/avplane.p b/source/avplane.p
index 9e36fb0..385c085 100644
Binary files a/source/avplane.p and b/source/avplane.p differ
diff --git a/source/axestable.m b/source/axestable.m
index 17b774f..3b9aed8 100644
--- a/source/axestable.m
+++ b/source/axestable.m
@@ -121,11 +121,11 @@ function clearAllValues(obj,clearStr,draw)
end
%set all values to clearStr in table.
for loop=1:length(obj.Key) %Update all values.
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
obj.Key{loop}.values{vloop}=clearStr;
end
if draw&¬(obj.createHandles)
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
set(obj.Key{loop}.valuesHandle{vloop},'String',clearStr);
end
end
@@ -148,11 +148,11 @@ function clearByUnit(obj,unit,clearStr,draw)
for loop=1:length(obj.Key) %Update all values.
if strcmp(obj.Key{loop}.Unit,unit)
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
obj.Key{loop}.values{vloop}=clearStr;
end
if draw&¬(obj.createHandles)
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
set(obj.Key{loop}.valuesHandle{vloop},'String',clearStr);
end
end
@@ -186,12 +186,12 @@ function hide(obj)
%-----------------
function draw(obj)
%-----------------
- if obj.NbrTables==0,
+ if obj.NbrTables==0
disp('No tables to draw');
return
end
- if obj.hidden && not(obj.createHandles),
+ if obj.hidden && not(obj.createHandles)
return %dont do anything when object is invisible.
end
@@ -215,7 +215,7 @@ function draw(obj)
set(obj.Table{loop}.Handle,'String',stri,'color',obj.fontcolor)
end
for loop=1:length(obj.Key) %Update all values.
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
stri=obj.parseValue(obj.Key{loop}.values{vloop});
set(obj.Key{loop}.valuesHandle{vloop},...
'String',stri,...
@@ -260,7 +260,7 @@ function addTable(obj,title,col,nbrValues,colsize)
if nargin<5
obj.Table{obj.NbrTables}.xstep=ones(1,col)*obj.FigWith/col;
elseif sum(colsize)<1+1e-5&&sum(colsize)>1-1e-5 &&...
- length(colsize)==col,
+ length(colsize)==col
obj.Table{obj.NbrTables}.xstep=colsize*(obj.FigWith-obj.xstart);
else
obj.Table{obj.NbrTables}.xstep=ones(1,col)*obj.FigWith/col;
@@ -292,12 +292,12 @@ function addTableHead(obj,column_names)
return
end
- if obj.Table{obj.NbrTables}.nbrValues+1~=length(column_names),
+ if obj.Table{obj.NbrTables}.nbrValues+1~=length(column_names)
disp('addTableHeader: Wrong number or fields.');
return;
end
- if obj.Table{obj.NbrTables}.CurCols~=1,
+ if obj.Table{obj.NbrTables}.CurCols~=1
disp('addTableHeader: Call this method directly after addTable');
return;
end
@@ -325,7 +325,7 @@ function addKey(obj,key,name,unit,values)
error('Forbidden to add Keys once table is drawn')
end
- if obj.NbrTables==0,
+ if obj.NbrTables==0
error('No table, call newtable');
end
@@ -333,7 +333,7 @@ function addKey(obj,key,name,unit,values)
values={values};
end
- if length(values)~=obj.Table{obj.NbrTables}.nbrValues,
+ if length(values)~=obj.Table{obj.NbrTables}.nbrValues
error('Wrong number of values for current table');
end
@@ -356,7 +356,7 @@ function addKey(obj,key,name,unit,values)
obj.Key{nbr_keys}.valuesXpos=[];
obj.Key{nbr_keys}.valuesYpos=[];
- for loop=1:length(values),%figure out postition
+ for loop=1:length(values) %figure out postition
obj.Key{nbr_keys}.valuesXpos(loop)=obj.xpos;
obj.Key{nbr_keys}.valuesYpos(loop)=obj.ypos;
obj.xpos=obj.xpos+obj.Table{obj.NbrTables}.xstep(obj.Table{obj.NbrTables}.CurCols);
@@ -364,7 +364,7 @@ function addKey(obj,key,name,unit,values)
end
if obj.Table{obj.NbrTables}.CurCols>...
- obj.Table{obj.NbrTables}.Cols,
+ obj.Table{obj.NbrTables}.Cols
obj.ypos=obj.ypos+obj.Table{obj.NbrTables}.ystep;
obj.Table{obj.NbrTables}.CurCols=1;
obj.xpos=obj.xstart;
@@ -374,7 +374,7 @@ function addKey(obj,key,name,unit,values)
%---------------------
function addSpace(obj)
%---------------------
- if obj.NbrTables==0,
+ if obj.NbrTables==0
obj.ypos=obj.ypos+obj.ystep;
else
obj.xpos=obj.xstart;
@@ -397,14 +397,14 @@ function updateKey(obj,key,values,draw)
end
for loop=1:length(obj.Key)
- if strcmp(obj.Key{loop}.Key,key),
- if length(values)~=length(obj.Key{loop}.values),
+ if strcmp(obj.Key{loop}.Key,key)
+ if length(values)~=length(obj.Key{loop}.values)
error('Nbr of values does not match');
end
obj.Key{loop}.values=values;
if draw&&~obj.createHandles
- for vloop=1:length(values),
+ for vloop=1:length(values)
stri=obj.parseValue(obj.Key{loop}.values{vloop});
set(obj.Key{loop}.valuesHandle{vloop},'String',stri);
end
@@ -436,7 +436,7 @@ function updateName(obj,key,names,draw)
end
for loop=1:length(obj.Key)
- if strcmp(obj.Key{loop}.Key,key),
+ if strcmp(obj.Key{loop}.Key,key)
% if length(names)~=length(obj.Key{loop}.Name),
% error('Nbr of names does not match');
% end
@@ -459,7 +459,7 @@ function updateUnit(obj,key,unit,draw)
end
for loop=1:length(obj.Key)
- if strcmp(obj.Key{loop}.Key,key),
+ if strcmp(obj.Key{loop}.Key,key)
% if length(names)~=length(obj.Key{loop}.Name),
% error('Nbr of names does not match');
% end
@@ -493,7 +493,7 @@ function keyVisible(obj,key,visible,draw)
draw=false;
end
for loop=1:length(obj.Key)
- if strcmp(obj.Key{loop}.Key,key),
+ if strcmp(obj.Key{loop}.Key,key)
obj.Key{loop}.showKey=visible;
if visible
@@ -503,7 +503,7 @@ function keyVisible(obj,key,visible,draw)
end
if draw&¬(obj.createHandles)
set(obj.Key{loop}.keyHandle,'Visible',vis);
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
set(obj.Key{loop}.valuesHandle{vloop},'Visible',vis);
end
end
@@ -553,12 +553,12 @@ function firstdraw(obj)
obj.Table{loop}.Title,obj.Table{loop}.xpos,obj.Table{loop}.ypos);
obj.Table{loop}.LineHandle = putline(obj,obj.Table{loop}.ypos);
- if isfield(obj.Table{loop},'Head'),
+ if isfield(obj.Table{loop},'Head')
obj.Table{loop}.Head.LineHandle=...
putline(obj,obj.Table{loop}.Head.lineypos);
col_lenth=length(obj.Table{loop}.Head.Title);
x_pos=[obj.xstart obj.xstart+cumsum(obj.Table{obj.NbrTables}.xstep(1:end-1))];
- for vloop=1:col_lenth*obj.Table{loop}.Head.Repeat;
+ for vloop=1:col_lenth*obj.Table{loop}.Head.Repeat
ind=mod(vloop-1,col_lenth)+1;
obj.Table{loop}.Head.TitleHandle{vloop}=putstring(obj,...
obj.Table{loop}.Head.Title{ind}, x_pos(vloop) ,...
@@ -637,12 +637,12 @@ function setVisible(obj,value)
for loop=1:length(obj.Key) %Update all values.
if obj.Key{loop}.showKey
set(obj.Key{loop}.keyHandle,'Visible',value);
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
set(obj.Key{loop}.valuesHandle{vloop},'Visible',value);
end
else
set(obj.Key{loop}.keyHandle,'Visible','off');
- for vloop=1:length(obj.Key{loop}.values),
+ for vloop=1:length(obj.Key{loop}.values)
set(obj.Key{loop}.valuesHandle{vloop},'Visible','off');
end
end
diff --git a/source/balloonimage.mexw32 b/source/balloonimage.mexw32
deleted file mode 100644
index 9517906..0000000
Binary files a/source/balloonimage.mexw32 and /dev/null differ
diff --git a/source/bullseye.fig b/source/bullseye.fig
index dc9eb64..e0bd920 100644
Binary files a/source/bullseye.fig and b/source/bullseye.fig differ
diff --git a/source/buttondownfunctions.m b/source/buttondownfunctions.m
new file mode 100644
index 0000000..ffbb9a9
--- /dev/null
+++ b/source/buttondownfunctions.m
@@ -0,0 +1,1891 @@
+function buttondownfunctions(varargin)
+% Functions for buttondowns
+
+% Broken out by Klas
+
+%Invoke subfunction
+macro_helper(varargin{:}); %future macro recording use
+feval(varargin{:}); % FEVAL switchyard
+
+%-------------------------------------
+function buttondown(panel,currenttool) %#ok
+%-------------------------------------
+global DATA SET
+persistent ismaxnumrois
+
+scale = viewfunctions('getscale',panel);
+no = DATA.ViewPanels(panel);
+clicktype = get(DATA.fig,'SelectionType');
+
+%store the current panel after graphical update and return. The
+%procedure is that first the panel is selected then you can start selecting
+%slices and rois.
+if DATA.CurrentPanel ~= panel
+ viewfunctions('switchpanel',panel)
+ DATA.updatevolumeaxes;
+ return
+end
+
+%if montage select slice
+if any(strcmp(DATA.ViewPanelsType{panel},{'montagesegmented','montagerow','montage'}))
+ [x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+ slice = viewfunctions('clickedslice',panel,x,y);
+ if ~isempty(slice)
+ if slice ~= SET(no).CurrentSlice && ismember(currenttool,{'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp','GeneralPenInterp'})
+ SET(no).StartSlice = slice;
+ SET(no).EndSlice = slice;
+ SET(no).CurrentSlice = slice;
+ drawfunctions('drawno',no);
+ return;
+ else
+ SET(no).StartSlice = slice;
+ SET(no).EndSlice = slice;
+ SET(no).CurrentSlice = slice;
+ drawfunctions('drawno',no);
+ end
+ else
+ return
+ end
+end
+
+%Only measures available for these panels
+if any(strcmp(DATA.ViewPanelsType{panel},{'hla','gla','vla'}))
+ if ~strcmp(currenttool,'Measure')
+ if ~strcmp(currenttool,'select')
+ return
+ end
+ end
+end
+
+%This enables undo.
+if any(ismember(DATA.ViewPanelsType{panel},{'trans3DP','sag3DP','cor3DP','speedim'}))
+ %segment3dp.tools('enableundo')
+else
+ tools('enableundo',no);
+end
+
+switch clicktype
+ case 'normal'
+ %these are used to store information about rightclick. Type tells us
+ %which context menu to use objectind tells us which index we right
+ %clicked next to.
+ DATA.LastObjectType = [];
+ DATA.LastObject = [];
+ case 'open'
+ %this is the double click
+ % check the current tool, since double click option is only valid for
+ % select tool
+ if ~strcmp(currenttool,'select')|| strcmp(DATA.CurrentTheme,'3dp') %|| isdeployed
+ return
+ end
+ if isempty(DATA.LastView)
+ % save the last view
+ DATA.LastView.ViewPanels = DATA.ViewPanels;
+ DATA.LastView.ViewPanelsType = DATA.ViewPanelsType;
+ DATA.LastView.ViewMatrix = DATA.ViewMatrix;
+ DATA.LastView.CurrentPanel = DATA.CurrentPanel;
+ DATA.LastView.NormalZoomState = {SET.NormalZoomState};
+ if numel(DATA.ViewPanels) == 1
+ % check whether to switch to one panel view
+ switch DATA.ViewPanelsType{1}
+ case 'one'
+ newview = 'montage';
+ case {'montage', 'montagerow'}
+ newview = 'one';
+ otherwise
+ return
+ end
+ viewfunctions('setviewtype',newview);
+ else
+ % go to one view
+ DATA.ViewMatrix = [1,1];
+ viewfunctions('setview',DATA.ViewMatrix(1),DATA.ViewMatrix(2),[]);
+ end
+ return
+ else
+ %reset to previous view
+ try
+ DATA.ViewPanels = DATA.LastView.ViewPanels;
+ DATA.ViewPanelsType = DATA.LastView.ViewPanelsType;
+ DATA.ViewMatrix = DATA.LastView.ViewMatrix;
+ DATA.CurrentPanel = DATA.LastView.CurrentPanel;
+ panelstodo = find(DATA.LastView.ViewPanels);
+ for actpanel = panelstodo
+ no = DATA.ViewPanels(actpanel);
+ SET(no).NormalZoomState = DATA.LastView.NormalZoomState{no};
+ end
+ viewfunctions('setview',DATA.ViewMatrix(1),DATA.ViewMatrix(2),DATA.ViewPanels);
+ catch me
+ mydispexception(me);
+ end
+ DATA.LastView = [];
+ end
+
+ case 'alt'
+ if ~strcmp(DATA.CurrentTheme,'3dp')
+ if SET(no).EndoInterpOngoing || SET(no).EpiInterpOngoing ||...
+ SET(no).RVEndoInterpOngoing || SET(no).RVEpiInterpOngoing
+ tools('connectinterpolation',no);
+ return
+ end
+ [y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));%this needs to transformed to the stored coordinate system
+ slice = viewfunctions('clickedslice',panel,y,x);
+ slices = viewfunctions('slicesinpanel',panel);
+
+ %normalize clicked position to contour domain
+ [yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices == slice,1));
+ x = x/scale - (xl-1)*SET(no).XSize;
+ y = y/scale - (yl-1)*SET(no).YSize;
+ stateandicon = viewfunctions('iconson','point');
+ pointstate = stateandicon{1};
+ modifier = get(gcbf, 'Currentmodifier');
+ if pointstate && not(isempty(modifier)) && strcmp(modifier,'control')
+ % if place annotation point is on then place point where the right
+ % click was done
+ [~,pointind] = findfunctions('closestpoint',panel,x,y);
+
+ %This way if you click close to a measure you drag that point of the
+ %measure.
+ DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''point_buttonup'',%d,%d,%d)',panel,pointind,slice);
+ return
+ else
+ DATA.LastClickType = clicktype;% helper in findfunctions(closestmeasure)
+ [type,objectind] = findfunctions('closestobject',panel,x,y);
+ %place context menu. which one is triggered depends on the
+ %closestobject
+ DATA.LastObjectType = type;
+ DATA.LastObject = [objectind,slice,SET(no).CurrentTimeFrame];
+ viewfunctions('placecontextmenu',panel,type,objectind);
+ DATA.LastClickType = [];
+ return
+ end
+ else
+ %3DP and right click
+ p = get(DATA.fig,'CurrentPoint');
+ [r,g,b] = segment3dp.tools('getclickedposition3DP');
+ %SET(no).LevelSet.View.RSlice = r; %Store
+ %SET(no).LevelSet.View.GSlice = g;
+ %SET(no).LevelSet.View.BSlice = b;
+
+ [x,y,z] = segment3dp.tools('rgb2xyz',r,g,b);
+ %[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel))%this needs to transformed to the stored coordinate system
+ [type,objectind] = findfunctions('closestobject',panel,x,y,z);
+ switch type
+ case 'Image'
+ set(DATA.Handles.view2dcontextmenu,'Position',p,'Visible','on');
+ case 'Point'
+ DATA.LastObject = [objectind z 1]; %1=timeframe
+ set(DATA.Handles.point3dpcontextmenu,'Position',p,'Visible','on');
+ end
+ return
+ end
+ case 'extend'
+ if ~strcmp(DATA.CurrentTheme,'3dp')
+ if SET(no).EndoInterpOngoing || SET(no).EpiInterpOngoing ||...
+ SET(no).RVEndoInterpOngoing || SET(no).RVEpiInterpOngoing
+ tools('connectinterpolation',no)
+ return
+ end
+ end
+ if ~strcmp(DATA.CurrentTool,'Measure')% && ~strcmp(DATA.CurrentTool,'spliteraser')
+ %Do panning of current image
+ pan_buttondown(panel);
+ return
+ end
+end
+
+%check if number of points, rois or measurements in current slice is larger than 20 then give
+%message that this is not supported.
+
+%Rois
+if (not(isempty(regexpi('roi',currenttool))) || not(isempty(regexpi('roiput',currenttool)))...
+ || not(isempty(regexpi('roiballoon',currenttool)))) && strcmp(DATA.ViewPanelsType{panel},'one')
+ %check number of rois in current slice
+ numrois = sum(cellfun(@(x) any(~isempty(x)) && x==SET(no).CurrentSlice,{SET(no).Roi.Z}));
+ if numrois >=10 %isfield(DATA.Handles,'roitext') && numrois>=length(DATA.Handles.roitext)
+ if isempty (ismaxnumrois)
+ ismaxnumrois = true;
+ mymsgbox('Cannot have more than 10 ROIs desriptions.','Maximum description reached', DATA.GUI.Segment);
+ if (isempty(regexpi('roiput',currenttool)))
+ return
+ end
+ end
+ set(DATA.Handles.roitext(panel,:),'Position',[nan nan]);
+ end
+end
+
+%Points
+if ~isempty(regexpi('point',currenttool)) && strcmp(DATA.ViewPanelsType{panel},'one')
+ %check number of points in slice current timeframe if in single frame
+ %mode.
+ %check maximum number of points in slice all timeframes.
+ pinslices= SET(no).Point.Z==SET(no).CurrentSlice;
+
+ if not(DATA.ThisFrameOnly) %findindented(DATA.Handles.hideiconholder,'allframesmode')
+ %all frames mode
+ uniquetf = unique(SET(no).Point.T(pinslices));
+ numpoints = 0;
+ for t = uniquetf(~isnan(uniquetf))
+ tmp = sum(ismember(SET(no).Point.T(pinslices),[t,nan]));
+ if numpoints=length(DATA.Handles.pointtext)
+ myfailed('Cannot have more than twenty points in a slice and timeframe')
+ return
+ end
+end
+
+%Measurements
+if ~isempty(SET(no).Measure)
+ [measure,slice] = viewfunctions('getmeasurecoords',panel);
+ nummeasures = 0;
+ if not(DATA.ThisFrameOnly) %findindented(DATA.Handles.hideiconholder,'allframesmode')
+ %all frames mode
+ for tloop = 1:SET(no).TSize
+ nummeasuresintf = 0;
+ for loop=1:length(SET(no).Measure)
+ ziv = round(measure(loop).Z);
+ ziv = min(ziv):max(ziv);
+
+ if ismember(slice,ziv) && ...
+ (SET(no).Measure(loop).T==tloop)||(isnan(SET(no).Measure(loop).T))
+ nummeasuresintf = nummeasuresintf + 1;
+ end
+ end
+
+ if nummeasuresintf>nummeasures
+ nummeasures = nummeasuresintf;
+ end
+ end
+ else
+ for loop=1:length(SET(no).Measure)
+ ziv = round(measure(loop).Z);
+ ziv = min(ziv):max(ziv);
+ if ismember(slice,ziv) && ...
+ (SET(no).Measure(loop).T==SET(no).CurrentTimeFrame)||(isnan(SET(no).Measure(loop).T))
+ nummeasures = nummeasures + 1;
+ end
+ end
+ end
+
+ if nummeasures>=length(DATA.Handles.measurementtext)
+ myfailed('Cannot have more than twenty measurements in a slice and timeframe')
+ return
+ end
+end
+
+%Here we toggle to different buttondowns.
+switch currenttool
+ case 'scale'
+ buttondownfunctions('scale_buttondown',panel)
+ case 'move'
+ buttondownfunctions('translate_buttondown',panel)
+ case 'select'
+ buttondownfunctions('select_buttondown',panel)
+ case {'Endo','Epi','RVEndo','RVEpi','Roi','Scar','MO','MaR','ScarRubber','MORubber','MaRRubber','GeneralPen', 'CalciumPen', 'CalciumPenRemove', 'CalciumPenBlue', 'CalciumPenRed', 'CalciumPenLilac' }
+ buttondownfunctions('pen_buttondown',panel,currenttool)
+ case {'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp','GeneralPenInterp'}
+ buttondownfunctions('interp_buttondown',panel,currenttool)
+ case 'Measure'
+ buttondownfunctions('measure_buttondown',panel)
+ case 'Contrast'
+ buttondownfunctions('contrast_buttondown',panel)
+ case 'RoiPut'
+ buttondownfunctions('putroi_buttondown',panel,'Roi')
+ case 'RoiBalloon'
+ buttondownfunctions('balloon_buttondown',panel,'Roi')
+ case 'EndoBalloon'
+ buttondownfunctions('balloon_buttondown',panel,'Endo')
+ case 'RVEndoBalloon'
+ buttondownfunctions('balloon_buttondown',panel,'RVEndo')
+ case 'EpiBalloon'
+ buttondownfunctions('scale_buttondown',panel)
+% buttondownfunctions('balloon_buttondown',panel,'Epi')
+ case 'crop'
+ %can only crop in one and montage viewmodes
+ if ~any(strcmp(DATA.ViewPanelsType{panel},{'one','montage','montagesegmented','montagerow'}))
+ return
+ end
+ buttondownfunctions('crop_buttondown',panel)
+ case 'Point'
+ buttondownfunctions('point_buttondown',panel)
+ case 'cutvessel'
+ segment3dp.tools('enableundo');
+ segment3dp.buttondownfunctions('cutvessel_buttondown',panel)
+ case 'moveall'
+ buttondownfunctions('translateall_buttondown',panel)
+ case 'fastmarching'
+ segment3dp.tools('enableundo');
+ segment3dp.buttondownfunctions('fastmarching_buttondown')
+ case 'wand'
+ segment3dp.buttondownfunctions('wand_buttondown')
+ case 'localwand'
+ segment3dp.tools('enableundo');
+ segment3dp.tools('storeclickedposition');
+ segment3dp.tools('wandexpand_Callback');
+ case 'localsmooth'
+ segment3dp.tools('enableundo');
+ segment3dp.buttondownfunctions('localsmooth_buttondown')
+ case 'localclose'
+ segment3dp.tools('enableundo');
+ segment3dp.buttondownfunctions('localclose_buttondown')
+ case 'localpatch'
+ segment3dp.tools('enableundo');
+ segment3dp.buttondownfunctions('localpatch_buttondown')
+ case 'localseparate'
+ segment3dp.tools('enableundo');
+ segment3dp.buttondownfunctions('localseparate_buttondown')
+ case 'localfill'
+ segment3dp.tools('enableundo');
+ segment3dp.buttondownfunctions('localfill_buttondown')
+ case 'keep'
+ segment3dp.tools('keepclick_Callback')
+ case {'localthreshold','draw','rubber'}
+ segment3dp.tools('enableundo');
+ if ~strcmp(clicktype, 'alt')
+ segment3dp.buttondownfunctions('pen3dp_buttondown',currenttool)
+ else
+ if segment3dp.tools('is2d')
+ segment3dp.tools('split2d_Callback');
+ else
+ segment3dp.tools('split3d_Callback');
+ end
+ end
+ case 'crop3dp'
+ crop3dp_buttondown(panel)
+ case 'box3dp'
+ segment3dp.tools('enableundo');
+ box3dp_buttondown(panel)
+ case 'click3d'
+ drawfunctions('drawpoint3D',panel)
+ case 'addcalcium'
+ addcalcium_buttondown;
+ case 'addaortacalcium'
+ addaortacalcium_buttondown;
+ case 'addmitralcalcium'
+ addmitralcalcium_buttondown;
+ case 'addcoronarycalcium'
+ addcoronarycalcium_buttondown;
+end
+
+%----------------------------------
+function updatebuttondowns(currenttool,panels) %#ok
+%----------------------------------
+%The buttondown is always used within a panel. A buttondown should
+%therefore always have the panel as the first argument.
+global DATA
+
+if nargin == 0 || isempty(currenttool)
+ currenttool = DATA.CurrentTool;
+end
+
+%if still is empty then it hasnt been set yet then assume select.
+if isempty(currenttool)
+ currenttool = 'select';
+end
+
+if nargin<2
+ panels = 1:length(DATA.ViewPanels);
+end
+
+%Set the correct cursor type
+switch currenttool
+ case {'scale','move','Contrast'}
+ load('pointers.mat','pointer');
+ set(DATA.imagefig,...
+ 'pointer','custom',...
+ 'pointershapecdata',1+pointer.(lower(currenttool)),...
+ 'pointershapehotspot',[7 7]);
+
+ case 'select'
+ set(DATA.imagefig,'pointer','arrow');
+ case {'RoiPut','Point'}
+ load('pointers.mat','pointer');
+ set(DATA.imagefig,...
+ 'pointer','custom',...
+ 'pointershapecdata',1+pointer.point,...
+ 'pointershapehotspot',[7 7]);
+
+ case {'Endo','Epi','RVEndo','RVEpi','Roi','Scar',...
+ 'MO','MaR','ScarRubber','MORubber','MaRRubber',...
+ 'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp','GeneralPenInterp',...
+ 'Measure','RoiBalloon','EndoBalloon', 'EpiBalloon','crop','GeneralPen','addcalcium', 'CalciumPen' , 'CalciumPenBlue', 'CalciumPenRed', 'CalciumPenLilac', 'CalciumPenRemove', 'addaortacalcium', 'addmitralcalcium', 'addcoronarycalcium'}
+ if isa(DATA.GUISettings.DrawPointer,'string')||isa(DATA.GUISettings.DrawPointer,'char')
+ set(DATA.imagefig,'pointer',DATA.GUISettings.DrawPointer);
+ else
+ set(DATA.imagefig,'pointer','custom',...
+ 'pointershapecdata',DATA.GUISettings.DrawPointer.cdata,...
+ 'pointershapehotspot',DATA.GUISettings.DrawPointer.hotspot);
+ end
+end
+
+viewfunctions('updatetoolhidestate',currenttool);
+%Set the buttondowns on each panel
+for p = panels
+ set(DATA.Handles.imageaxes(p).Children,'ButtonDownFcn',sprintf('buttondownfunctions(''buttondown'',%d, ''%s'')',p,currenttool))
+ set(DATA.Handles.imageaxes(p),'ButtonDownFcn',sprintf('buttondownfunctions(''buttondown'',%d,''%s'')',p,currenttool))
+end
+
+%Reset previous motion and buttonup functions just for sure
+%set(DATA.fig,'WindowButtonMotionFcn','');
+set(DATA.fig,'WindowButtonMotionFcn','segment(''toggleplaceholdermotion'')');
+set(DATA.fig,'WindowButtonUpFcn','');
+
+%Set the CurrentTool field
+DATA.CurrentTool = currenttool;
+
+%-----------------------------------
+function contrast_buttondown(panel) %#ok
+%-----------------------------------
+%Activated by contrast tool, different from resetlight_Callback (above).
+
+global DATA
+
+%first we get the clicked position
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,x,y);
+
+%get x and y size of panel to normalize distance with
+xsize = get(DATA.Handles.imageaxes(panel),'xlim');
+xsize = xsize(end)-xsize(1);
+ysize = get(DATA.Handles.imageaxes(panel),'ylim');
+ysize = ysize(end)-ysize(1);
+
+%we set the motion function and the buttonupfunction with input start
+%position
+set(DATA.fig,'WindowButtonMotionFcn',sprintf('motionfunctions(''contrast_motion'',%d,%d,%f,%f,%f,%f)',panel,slice,x,y,xsize,ysize));
+set(DATA.fig,'WindowButtonUpFcn',sprintf('buttonupfunctions(''contrast_buttonup'',%d,%d,%f,%f,%f,%f)',panel,slice,x,y,xsize,ysize));
+
+%-----------------------------------------------------------------------------------
+function [interpx,interpy] = interpdrawhelper(interpx,interpy,contourx,contoury,x,y,slice)
+%-----------------------------------------------------------------------------------
+%Helper fcn to interpdrawbuttondown
+%Side effects is update of DATA.Pin.
+global DATA SET NO
+
+% new=true;
+tf = SET(NO).CurrentTimeFrame;
+if nargin < 7
+ slice = SET(NO).CurrentSlice;
+end
+
+%New interpolation point. User has not clicked close to old point.
+%Prepare to store point
+if isempty(interpx)||...
+ size(interpx,1)=add many points.
+ %Interpolate points
+ newcontourx = contourx(:,tf,slice);
+ newcontoury = contoury(:,tf,slice);
+ n = size(contourx,1);
+ nstep = n/DATA.Pref.NumInterpPoints; %Later take from preferences.
+ newcontourx = newcontourx(round(1:nstep:n));
+ newcontoury = newcontoury(round(1:nstep:n));
+ newcontourx = newcontourx(:);
+ newcontoury = newcontoury(:);
+ y = []; %Do not add the point
+ x = []; %Do not add the point
+ else
+ %Contour and previous points exist => find closest gap
+ pinx = [interpx{tf,slice}; y];
+ piny = [interpy{tf,slice}; x];
+ contx = contourx(:,tf,slice);
+ conty = contoury(:,tf,slice);
+
+ pinxrep=repmat(pinx',[length(contx) 1]);
+ contxrep=repmat(contx,[1 length(pinx)]);
+ pinyrep=repmat(piny',[length(conty) 1]);
+ contyrep=repmat(conty,[1 length(piny)]);
+ pindist2cont = (pinxrep-contxrep).^2+(pinyrep-contyrep).^2;
+ [~,mindistindex] =min(pindist2cont);
+ [~,sortindex] =sort(mindistindex);
+ pinx=pinx(sortindex);
+ piny=piny(sortindex);
+
+ interpx{tf,slice}=pinx;
+ interpy{tf,slice}=piny;
+
+ y = []; %Do not add the point
+ x = []; %Do not add the point
+ end
+end
+
+%Add points
+interpx{tf,slice} = [...
+ interpx{tf,slice} ; ...
+ newcontourx;y];
+interpy{tf,slice} = [...
+ interpy{tf,slice} ; ...
+ newcontoury;x];
+
+%----------------------------------------------
+function crop_buttondown(panel)
+%----------------------------------------------
+%New buttondown function for cropping. You cannot crop in montage viewmodes only in one.
+global DATA
+
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,x,y);
+%5 coords make a box
+X = [x,x,x,x,x];
+Y = [y,y,y,y,y];
+
+DATA.CursorX = X;
+DATA.CursorY = Y;
+
+DATA.Handles.cursor.Color = 'y';
+DATA.Handles.cursor.LineStyle = '--';
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+DATA.Handles.cursor.XData = DATA.CursorX;
+DATA.Handles.cursor.YData = DATA.CursorY;
+
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''crop_motion'',%d,%f,%f)',panel,x,y);
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''crop_buttonup'',%d, %f, %f, %d)',panel,x,y,slice);
+
+%----------------------------------------------
+function box3dp_buttondown(panel)
+%----------------------------------------------
+%New buttondown function for cropping. You cannot crop in montage viewmodes only in one.
+global DATA
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+segment3dp.tools('boxmotion',x,y);
+set(DATA.fig,'WindowButtonMotionFcn','segment3dp.tools(''boxmotion'')');
+set(DATA.fig,'WindowButtonUpFcn','segment3dp.tools(''levelsetboxbuttonup'')');
+
+%----------------------------------------------
+function crop3dp_buttondown(panel)
+%----------------------------------------------
+%New buttondown function for cropping. You cannot crop in montage viewmodes only in one.
+global DATA
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+segment3dp.tools('boxmotion',x,y);
+set(DATA.fig,'WindowButtonMotionFcn','segment3dp.tools(''boxmotion'')');
+set(DATA.fig,'WindowButtonUpFcn','segment3dp.tools(''cropboxbuttonup'')');
+
+%----------------------------------------------
+function interp_buttondown(panel,type) %#ok
+%----------------------------------------------
+%New buttondown function input is panel and type. The types handled here
+%are {EndoInterp,EpiInterp,RVendoInterp,RVepiInterp}.
+
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+scale = viewfunctions('getscale',panel);
+%get closest interpolation point
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));%this needs to transformed to the stored coordinate system
+slice = viewfunctions('clickedslice',panel,y,x);
+slices = viewfunctions('slicesinpanel',panel);
+
+%normalize clicked position to contour domain
+[yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices == slice,1));
+x = x/scale - (xl-1)*SET(no).XSize;
+y = y/scale - (yl-1)*SET(no).YSize;
+
+%then we need to create a nan matrix with size [numpoints,TSize,ZSize]
+if isempty(SET(no).([type(1:end-6),'X']))
+ SET(no).([type(1:end-6),'X']) = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+ SET(no).([type(1:end-6),'Y']) = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+end
+
+%then we need to create a cell with size [TSize,ZSize]
+if isempty(SET(no).([type,'X']))
+ SET(no).([type,'X']) = cell(SET(no).TSize,SET(no).ZSize);
+ SET(no).([type,'Y']) = cell(SET(no).TSize,SET(no).ZSize);
+end
+
+%Double check so that there is a cell with the correct size for the used
+%type
+if ~all([size(SET(no).([type,'X']),1)==SET(no).TSize,size(SET(no).([type,'X']),2)==SET(no).ZSize])
+ tmpX = cell(SET(no).TSize,SET(no).ZSize);
+ tmpY = cell(SET(no).TSize,SET(no).ZSize);
+ sz = size(SET(no).([type,'X']));
+ tmpX(1:sz(1),1:sz(2)) = SET(no).([type,'X'])(1:sz(1),1:sz(2));
+ tmpY(1:sz(1),1:sz(2)) = SET(no).([type,'Y'])(1:sz(1),1:sz(2));
+ SET(no).([type,'X']) = tmpX;
+ SET(no).([type,'Y']) = tmpY;
+end
+
+
+%Old files may have nan vectors in them remove them if so
+if all(isnan(SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}))
+ SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice} = [];
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice} = [];
+end
+
+[mindist,ind] = findfunctions('closestinterp',panel,type,x,y,slice);
+if ~isempty(mindist) && mindist=add many points.
+ %Interpolate points
+ newcontourx = SET(no).([type(1:end-6),'X'])(:,SET(no).CurrentTimeFrame,slice);
+ newcontoury = SET(no).([type(1:end-6),'Y'])(:,SET(no).CurrentTimeFrame,slice);
+ n = size(SET(no).([type(1:end-6),'X']),1);
+ nstep = n/DATA.Pref.NumInterpPoints; %Later take from preferences.
+ SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}= newcontourx(round(1:nstep:n));
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice} = newcontoury(round(1:nstep:n));
+
+ %do graphical update and return
+ viewfunctions('updatedrawlist',panel);
+ drawfunctions('drawinterp',panel)
+ return
+else
+ %closest point on the contour then use this to find the two closest
+ %interpolation points in different directions along the contour this
+ %should remove the case where you have close turns on the contour i.e the
+ %horseshoe
+
+ [val,~] = min(sqrt((x-SET(no).([type(1:end-6),'X'])(:,SET(no).CurrentTimeFrame,slice)).^2+(y-SET(no).([type(1:end-6),'Y'])(:,SET(no).CurrentTimeFrame,slice)).^2));
+ if ~isnan(val) && ~SET(no).([type(1:end-6),'InterpOngoing'])%val< DATA.Pref.ContourAdjustDistance
+ %First we find the closest point on the contour then we consider
+ %the distance to each point from the closest points. Since contour
+ %is equidistantly sampled we can use indexes as our metric. To
+ %ensure that there is a point close when clicking next to the
+ %contour we upsample the contour to a thousand points with linear interpolation.
+ datax = SET(no).([type(1:end-6),'X'])(:,SET(no).CurrentTimeFrame,slice);
+ datay = SET(no).([type(1:end-6),'Y'])(:,SET(no).CurrentTimeFrame,slice);
+
+ valueind = ~isnan(datax);
+ datax = datax(valueind);
+ datay = datay(valueind);
+ [contourx,contoury] = calcfunctions('resamplecurve',datax,datay,1000);
+ [~,ind] = min(sqrt((x-contourx).^2+(y-contoury).^2));
+ p2pcontour = zeros(1,length(contourx));
+ p2pcontour(1:ind) = ind - 1:-1:0;
+ p2pcontour(ind+1:end) = 1:length(p2pcontour)-ind;
+ p2pcontour(end-(floor(length(p2pcontour)/2)-ind)+1:end) = floor(length(p2pcontour)/2):-1:ind + 1;
+ %then we map each interpolation point to a distance on p2pcontour
+ %by finding there equivalent on the contour
+ interpdistalongcontourmap = zeros(1,length(SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}));
+ values = interpdistalongcontourmap;
+ for i = 1:length(SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice})
+ [val,ind] = min((SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}(i)...
+ -contourx).^2+...
+ (SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}(i)...
+ -contoury).^2);
+ interpdistalongcontourmap(i) = ind;
+ values(i) = val;
+ end
+ %find the two minimal distance points
+ [~,inds] = sort(p2pcontour(interpdistalongcontourmap));
+ %JB-2020-08-06 attempt to solve #2107
+ % use the closest point ind(1) -> determine index of the
+ indstart = inds(1);
+ pstart = [SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}(indstart),...
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}(indstart)];
+ if indstart == 1
+ indbefore = length(inds);
+ else
+ indbefore = indstart-1;
+ end
+ pbefore = [SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}(indbefore),...
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}(indbefore)];
+ if indstart == length(inds)
+ indafter = 1;
+ else
+ indafter = indstart+1;
+ end
+ pafter = [SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}(indafter),...
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}(indafter)];
+ pnew = [x,y];
+ % calculate angle between closest point-newpoint-left neighbor
+% angleft = atan2d((det([pnew-pstart;pleft-pnew])),dot(pnew-pstart,pleft-pnew))
+ P0 = [pnew 0];
+ P1 = [pbefore 0];
+ P2 = [pstart 0];
+ n1 = (P2 - P0) / norm(P2 - P0); % Normalized vectors
+ n2 = (P1 - P0) / norm(P1 - P0);
+ angleft = atan2d(norm(cross(n1, n2)), dot(n1, n2));
+
+ P1 = [pafter 0];
+ n1 = (P2 - P0) / norm(P2 - P0); % Normalized vectors
+ n2 = (P1 - P0) / norm(P1 - P0);
+ angright = atan2d(norm(cross(n1, n2)), dot(n1, n2));
+
+ anglelimit = 60;
+ if (indbefore == inds(2) && angleft < anglelimit)
+ % switch the order of the points
+ inds(2) = indafter;
+ elseif(indafter == inds(2) && angright < anglelimit)
+ inds(2) = indbefore;
+ end
+ % end of attempt to solve #2107
+ %this should capture the case between the last and first endpoint
+ if abs(inds(1)-inds(2))>1
+ indl = 0;
+ SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice} = [x;SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}];
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice} = [y;SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}];
+ else
+ indl = min(inds(1:2));
+ SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice} = [SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}(1:indl);x;SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}(indl+1:end)];
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice} = [SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}(1:indl);y;SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}(indl+1:end)];
+ end
+ minind = indl+1;
+ else
+ minind = length(SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice})+1;
+ SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice}(minind,1)=x;
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice}(minind,1)=y;
+ end
+end
+if SET(no).([type(1:end-6),'InterpOngoing'])
+ numinterppoints = length(SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice});
+ numpoints = floor(DATA.NumPoints/15)*(numinterppoints-1);
+ if numpoints > DATA.NumPoints
+ numpoints = DATA.NumPoints;
+ end
+else
+ numpoints = DATA.NumPoints;
+end
+%here we need to interpolate and store curve into contours.
+%The below function removes duplicate points and resamples the contour.
+[x,y] = calcfunctions('resamplecurve',SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice},...
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice},numpoints-1);
+
+%write the results back to the contour field in the SET struct if we've
+%placed more than one point
+if length(x)>1
+ switch type
+ case 'Roi'
+ %would be nice to introduce RoiInterpX...
+ otherwise
+ if SET(no).([type(1:end-6),'InterpOngoing'])
+ expectedlength = length(SET(no).([type(1:end-6),'X'])(:,SET(no).CurrentTimeFrame,slice));
+ if numpoints < expectedlength
+ % fill up with NaNs
+ x = cat(2,x,nan(1,expectedlength-numpoints));
+ y = cat(2,y,nan(1,expectedlength-numpoints));
+ end
+ end
+ SET(no).([type(1:end-6),'X'])(:,SET(no).CurrentTimeFrame,slice)= [x,x(1)];
+ SET(no).([type(1:end-6),'Y'])(:,SET(no).CurrentTimeFrame,slice)= [y,y(1)];
+ drawfunctions('drawcontours',panel)
+ end
+elseif length(x) == 1
+ SET(no).([type(1:end-6),'InterpOngoing']) = true;
+ drawfunctions('updateinterpolationsettings',panel,type);
+end
+
+drawfunctions('drawinterp',panel);
+
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''interp_motion'',%d,''%s'',%d,%d)',panel,type,slice,minind);
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''interp_buttonup'',%d,''%s'',%d)',panel,type,slice);
+
+%-------------------------------------
+function orthoview_buttondown(panel,x,y)
+%-------------------------------------
+%Rotate GLA view using handle on intersection line
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+scale = viewfunctions('getscale',panel);
+
+switch DATA.ViewPanelsType{panel}
+ case 'orth'
+ %get the angle handle position
+ xhan = DATA.Handles.orthoanglehandle.XData;
+ yhan = DATA.Handles.orthoanglehandle.YData;
+
+ %If sufficiently close to rotation handle trigger rotation else update center position
+ if norm([xhan yhan]-[x,y])<3
+ set(DATA.Handles.cursor,'markersize',20,'marker', '.', 'color', 'w','parent',DATA.Handles.imageaxes(panel))
+ set(DATA.fig,'WindowButtonMotionFcn',sprintf('motionfunctions(''glarotatehandle_Motion'',%d)',panel));
+ set(DATA.fig,'WindowButtonUpFcn',sprintf('buttonupfunctions(''glarotatehandle_Buttonup'',%d)',panel));
+ return
+ end
+
+ SET(no).HLA.slice = round(y/scale);
+ SET(no).VLA.slice = round(x/scale);
+ viewfunctions('setglacenter',no);
+ case 'hla'
+ SET(no).VLA.slice = round(x/scale);
+ SET(no).CurrentSlice = round(y/scale);
+ viewfunctions('setglacenter',no);
+ case 'gla'
+ [vslice,hslice] = calcfunctions('gla2sax',y/scale,x/scale,no);
+ SET(no).HLA.slice = round(vslice);
+ SET(no).VLA.slice = round(hslice);
+ SET(no).CurrentSlice = round(y/scale);
+ viewfunctions('setglacenter',no);
+ case 'vla'
+ SET(no).HLA.slice = round(x/scale);
+ SET(no).CurrentSlice = round(y/scale);
+ viewfunctions('setglacenter',no);
+end
+
+%updates the plane intersections
+drawfunctions('drawplaneintersections');
+
+%update the angle handle for orthoview
+DATA.Handles.orthoanglehandle.XData = nan;
+DATA.Handles.orthoanglehandle.YData = nan; % this forces the orthoangle handle to refresh after translation
+drawfunctions('draworthoanglehandle',find(strcmp('orth',DATA.ViewPanelsType)))
+
+%empty the DATA.viewim to force creation of new images in all panels but
+%the current as it is unnecessary.
+for p = 1:length(DATA.ViewPanels)
+ if p~=panel
+ calcfunctions('segmentationintersection_helper',p,SET(no).CurrentTimeFrame) %this updates segmentation intersections for the selected panel and current timeframe so it is necessary that intersections are updated for all files at buttonup at buttonup.
+ DATA.ViewIM{p} = [];
+ drawfunctions('drawpanel',p)
+ end
+end
+
+%force graphics update
+drawnow
+
+%after doing the current timeframe update we do it for all timeframes
+for p = 1:length(DATA.ViewPanels)
+ if p~=panel
+ for t = 1:SET(no).TSize
+ calcfunctions('segmentationintersection_helper',p,t) %this updates stored segmentation intersections for remaining timeframes no graphical update needed.
+ end
+ end
+end
+
+%------------------------------
+function scale_buttondown(panel) %#ok
+%-----------------------
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+if not(isempty(SET(no).Flow)) && isfield(SET(no).Flow,'MagnitudeNo') && not(isempty(SET(no).Flow.MagnitudeNo))
+ magno = SET(no).Flow.MagnitudeNo;
+else
+ magno = no;
+end
+scale = viewfunctions('getscale',panel);
+
+%this makes the clicked roi current roi
+select_buttondown(panel)
+[ystart,xstart] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));%this needs to transformed to the stored coordinate system
+slice = viewfunctions('clickedslice',panel,ystart,xstart);
+
+xl = floor(xstart/scale/SET(no).XSize)*SET(no).XSize;
+yl = floor(ystart/scale/SET(no).YSize)*SET(no).YSize;
+x = xstart/scale - xl;
+y = ystart/scale - yl;
+
+[type,objectind] = findfunctions('closestobject',panel,x,y,slice);
+
+%below follows the scalables
+switch type
+ case {'Endo','Epi','RVEndo','RVEpi','EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp'}
+ %objectind is not used for contours
+ if contains(type,'Interp')
+ tools('connectinterpolation',no,{type});
+ %delete Interp at the end
+ type = type(1:end-6);
+ else
+ tools('connectinterpolation',no,{[type,'Interp']});
+ end
+ DATA.CursorX = xl +...
+ scale*SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice);
+ DATA.CursorY = yl + ...
+ scale*SET(no).([type,'Y'])(:,SET(no).CurrentTimeFrame,slice);
+
+ case 'Roi'
+ DATA.CursorX = xl + ...
+ scale*SET(magno).Roi(objectind).X(:,SET(no).CurrentTimeFrame);
+ DATA.CursorY = yl + ...
+ scale*SET(magno).Roi(objectind).Y(:,SET(no).CurrentTimeFrame);
+
+ otherwise
+ return
+end
+xc = mean(DATA.CursorX);
+yc = mean(DATA.CursorY);
+startrad = norm([xstart,ystart]-[xc,yc]);
+
+%Set marker color
+DATA.Handles.cursor.Color = 'w';
+DATA.Handles.cursor.Marker = 'none';
+
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+DATA.Handles.cursor.YData = DATA.CursorX;
+DATA.Handles.cursor.XData = DATA.CursorY;
+
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''scale_motion'',%d,%f)',panel,startrad);
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''scale_buttonup'',%d,''%s'',%d,%d,%f)',panel,type,objectind,slice,startrad);
+
+%---------------------
+function translate_buttondown(panel) %#ok
+%-----------------------
+global DATA SET
+
+scale = viewfunctions('getscale',panel);
+no = DATA.ViewPanels(panel);
+
+%fix so possible to translate roi in phase image stack
+if not(isempty(SET(no).Flow)) && isfield(SET(no).Flow,'MagnitudeNo') && not(isempty(SET(no).Flow.MagnitudeNo))
+ magno = SET(no).Flow.MagnitudeNo;
+else
+ magno = no;
+end
+
+[ystart,xstart] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));%this needs to transformed to the stored coordinate system
+slice = viewfunctions('clickedslice',panel,ystart,xstart);
+xl = floor(xstart/scale/SET(no).XSize)*SET(no).XSize;
+yl = floor(ystart/scale/SET(no).YSize)*SET(no).YSize;
+x = xstart/scale - xl;
+y = ystart/scale - yl;
+
+[type,objectind] = findfunctions('closestobject',panel,x,y,slice);
+
+%below follows the translateables
+switch type
+ case {'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp'} %does the same as the later but need to handle dynamic calling differently
+ tools('connectinterpolation',no,{type});
+ %objectind is not used for contours
+ DATA.CursorX = xl +...
+ scale*SET(no).([type(1:end-6),'X'])(:,SET(no).CurrentTimeFrame,slice);
+ DATA.CursorY = yl + ...
+ scale*SET(no).([type(1:end-6),'Y'])(:,SET(no).CurrentTimeFrame,slice);
+
+ %When translating we remove the interpolation points
+ if ~isempty(SET(no).([type,'X']))
+ SET(no).([type,'X']){SET(no).CurrentTimeFrame,slice} = [];
+ SET(no).([type,'Y']){SET(no).CurrentTimeFrame,slice} = [];
+ drawfunctions('drawinterp',panel)
+ end
+
+ %Set marker color
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.Marker = 'none';
+
+ case {'Endo','Epi','RVEndo','RVEpi'}
+ tools('connectinterpolation',no,{[type,'Interp']});
+ %objectind is not used for contours
+ DATA.CursorX = xl +...
+ scale*SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice);
+ DATA.CursorY = yl + ...
+ scale*SET(no).([type,'Y'])(:,SET(no).CurrentTimeFrame,slice);
+
+ %When translating we remove the interpolation points
+ if ~isempty(SET(no).([type,'InterpX']))
+ SET(no).([type,'InterpX']){SET(no).CurrentTimeFrame,slice} = [];
+ SET(no).([type,'InterpY']){SET(no).CurrentTimeFrame,slice} = [];
+ drawfunctions('drawinterp',panel)
+ end
+
+ %Set marker color
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.Marker = 'none';
+
+ case 'Roi'
+ DATA.CursorX = xl + ...
+ scale*SET(magno).Roi(objectind).X(:,SET(no).CurrentTimeFrame);
+ DATA.CursorY = yl + ...
+ scale*SET(magno).Roi(objectind).Y(:,SET(no).CurrentTimeFrame);
+ %Set marker color
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'Measure'
+ %measures
+ %Set marker color
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.Marker = '+';
+ [measure,~] = viewfunctions('getmeasurecoords',panel);
+ DATA.CursorX = xl + scale * measure(objectind).X;
+ DATA.CursorY = yl + scale * measure(objectind).Y;
+ case 'Point'
+ %Set marker color
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.Marker = '+';
+ DATA.CursorX = xl + scale * SET(no).Point.X(objectind);
+ DATA.CursorY = yl + scale * SET(no).Point.Y(objectind);
+ case 'Center'
+ %Set marker color
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.Marker = '+';
+ DATA.CursorX = xl + scale * SET(no).CenterX;
+ DATA.CursorY = yl + scale * SET(no).CenterY;
+ %When translating we remove the center point
+ if ~isempty(SET(no).([type,'X']))
+ % set to a very high number so that the original center cross is not
+ % seen during motion
+ SET(no).([type,'X']) = 10^6;
+ SET(no).([type,'Y']) = 10^6;
+ drawfunctions('drawcentercross',panel)
+ end
+ otherwise
+ pan_buttondown(panel);
+ return;
+end
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+DATA.Handles.cursor.YData = DATA.CursorX;DATA.Handles.cursor.XData = DATA.CursorY;
+
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''translate_motion'',%d,%f,%f)',panel,xstart,ystart);
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''translate_buttonup'',%d,''%s'',%d,%f,%f,%d)',panel,type,objectind,xstart,ystart,slice);
+
+
+%----------------------------------------------
+function balloon_buttondown(panel,type) %#ok
+%----------------------------------------------
+%New buttondown function input is type. The types handled here
+%are {Endo,Epi,RVendo,RVepi,Roi}. All temporary drawing is made using the
+%cursor object.
+
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,y,x);
+slices = viewfunctions('slicesinpanel',panel);
+scale = viewfunctions('getscale',panel);
+%Set the color of the cursor object which draws the temporary line according to the selected type
+switch type
+ case 'Endo'
+ DATA.Handles.cursor.Color = 'r';
+ DATA.Handles.cursor.LineStyle = '--';
+ DATA.Handles.cursor.Marker = 'none';
+ useconvhull = 1;
+ thetasz = 200;
+ tools('connectinterpolation',no,{'EndoInterp'})
+ case 'Epi'
+ DATA.Handles.cursor.Color = 'g';
+ DATA.Handles.cursor.LineStyle = '--';
+ DATA.Handles.cursor.Marker = 'none';
+ useconvhull = 1;
+ tools('connectinterpolation',no,{'EpiInterp'})
+ case 'RVEndo'
+ %check if Epi segmentation exists
+ if isempty(SET(no).EpiX)|| any(isnan(SET(no).EpiX(:,SET(no).CurrentTimeFrame,SET(no).CurrentSlice)))
+ myfailed('LV Epi segmentation must exist in order to use this tool');
+ DATA.Handles.configiconholder.undent('balloonrvendo',0);
+ DATA.Handles.configiconholder.indent('rvendopen',1);
+ return
+ end
+ tools('connectinterpolation',no,{'RVEndoInterp'})
+ DATA.Handles.cursor.Color = 'm';
+ DATA.Handles.cursor.LineStyle = '--';
+ DATA.Handles.cursor.Marker = 'none';
+ useconvhull = 1;
+ thetasz = 200;
+ case 'RVEpi'
+ DATA.Handles.cursor.Color = 'c';
+ DATA.Handles.cursor.LineStyle = '--';
+ DATA.Handles.cursor.Marker = 'none';
+ useconvhull = 1;
+ tools('connectinterpolation',no,{'RVEpiInterp'})
+ case 'Roi'
+ if ~DATA.ThisFrameOnly && strcmpi(type,'roi')
+ clr = 'm';
+ else
+ clr = 'b';
+ end
+ DATA.Handles.cursor.Color = clr;
+ DATA.Handles.cursor.LineStyle = '--';
+ DATA.Handles.cursor.Marker = 'none';
+ useconvhull = 1;
+ thetasz = 200;
+end
+
+%clear interpolation points
+%When drawing we remove the interpolation points
+if ~any(strcmp(type,{'Roi'})) && ~isempty(SET(no).([type,'InterpX']))
+ SET(no).([type,'InterpX']){SET(no).CurrentTimeFrame,slice} = [];
+ SET(no).([type,'InterpY']){SET(no).CurrentTimeFrame,slice} = [];
+ drawfunctions('drawinterp',panel)
+end
+
+%normalize clicked position to contour domain
+[yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice,1));
+x = x/scale - (xl-1)*SET(no).XSize;
+y = y/scale - (yl-1)*SET(no).YSize;
+
+%create polar image that can be used in motion and
+r = round(min([abs(x-SET(no).XSize),x-1,abs(y-SET(no).YSize),y-1]));
+im = SET(no).IM(:,:,SET(no).CurrentTimeFrame,slice);
+
+%Get polar matrix
+DATA.ImP = calcfunctions('imtopolar',im(round(x)-r:round(x)+r,round(y)-r:round(y)+r),0,1,r,thetasz);
+
+%Draw initial circle with radius 5 using Cursor before the algorithm has found anything
+d = 1;
+theta = linspace(0,2*pi,DATA.NumPoints);
+DATA.CursorX = (d*cos(theta)+y+(yl-1)*SET(no).YSize)*scale;
+DATA.CursorY = (d*sin(theta)+x+(xl-1)*SET(no).XSize)*scale;
+DATA.Handles.cursor.XData = DATA.CursorX;
+DATA.Handles.cursor.YData = DATA.CursorY;
+
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+DATA.fig.WindowButtonMotionFcn = sprintf('lvsegmentation(''balloon_motion'',%d,%d,%f,%f,%d)',panel,slice,x,y,useconvhull);
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''balloon_buttonup'',%d,''%s'',%d,%d)',panel,type,slice,SET(no).CurrentTimeFrame);
+
+
+%----------------------------------------------
+function putroi_buttondown(panel,type) %#ok
+%----------------------------------------------
+%New buttondown function input is type. The types handled here
+%are {Endo,Epi,RVendo,RVepi,Roi}. All temporary drawing is made using the
+%cursor object.
+
+global DATA SET
+no = DATA.ViewPanels(panel);
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,y,x);
+slices = viewfunctions('slicesinpanel',panel);
+scale = viewfunctions('getscale',panel);
+
+%Set the color of the cursor object which draws the temporary line according to the selected type
+if ~DATA.ThisFrameOnly && strcmpi(type,'roi')
+ clr = 'm';
+else
+ clr = 'b';
+end
+DATA.Handles.cursor.Color = clr;
+DATA.Handles.cursor.LineStyle = '--';
+
+%normalize clicked position to contour domain
+[yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice,1));
+x = x/scale - (xl-1)*SET(no).XSize;
+y = y/scale - (yl-1)*SET(no).YSize;
+
+%Draw initial circle with radius 5 using Cursor before the algorithm has found anything
+d = 10;
+theta = linspace(0,2*pi,DATA.NumPoints);
+DATA.CursorX = (d*cos(theta)'/SET(no).ResolutionY+y + (yl-1)*SET(no).YSize)*scale;
+DATA.CursorY = (d*sin(theta)'/SET(no).ResolutionX+x + (xl-1)*SET(no).XSize)*scale;
+DATA.Handles.cursor.XData = DATA.CursorX;
+DATA.Handles.cursor.YData = DATA.CursorY;
+
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''putroi_motion'',%d)',panel);
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''pen_buttonup'',%d,''%s'',%d,%d)',panel,type,slice,SET(no).CurrentTimeFrame);
+
+
+%----------------------------------------------
+function pen_buttondown(panel,type) %#ok
+%----------------------------------------------
+%New buttondown function input is type. The types handled here
+%are {Endo,Epi,RVendo,RVepi}. All temporary drawing is made using the
+%cursor object.
+
+global DATA SET
+no = DATA.ViewPanels(panel);
+switch type
+ case {'Endo','Epi','RVEndo','RVEpi'}
+ tools('connectinterpolation',no,{'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp'})
+end
+viewfunctions('updatetoolhidestate',type);
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,y,x);
+%Set the color of the cursor object which draws the temporary line according to the selected type
+switch type
+ case 'Endo'
+ DATA.Handles.cursor.Color = 'r';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'Epi'
+ DATA.Handles.cursor.Color = 'g';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'RVEndo'
+ DATA.Handles.cursor.Color = 'm';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'RVEpi'
+ DATA.Handles.cursor.Color = 'c';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'Roi'
+ if DATA.ThisFrameOnly
+ clr = 'b';
+ else
+ clr = 'm';
+ end
+ DATA.Handles.cursor.Color = clr;
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'Scar'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'MO'
+ DATA.Handles.cursor.Color = 'r';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'MaR'
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'ScarRubber'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = ':';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'MaRRubber'
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.LineStyle = ':';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'GeneralPen'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = '-';
+ DATA.Handles.cursor.Marker = 'none';
+ case 'CalciumPen'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = ':';
+ DATA.Handles.cursor.LineWidth = 2;
+ DATA.Handles.cursor.Marker = 'none';
+ case 'CalciumPenBlue'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = ':';
+ DATA.Handles.cursor.LineWidth = 2;
+ DATA.Handles.cursor.Marker = 'none';
+ case 'CalciumPenRed'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = ':';
+ DATA.Handles.cursor.LineWidth = 2;
+ DATA.Handles.cursor.Marker = 'none';
+ case 'CalciumPenLilac'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = ':';
+ DATA.Handles.cursor.LineWidth = 2;
+ DATA.Handles.cursor.Marker = 'none';
+ case 'CalciumPenRemove'
+ DATA.Handles.cursor.Color = 'y';
+ DATA.Handles.cursor.LineStyle = ':';
+ DATA.Handles.cursor.LineWidth = 2;
+ DATA.Handles.cursor.Marker = 'none';
+end
+
+%Clear the cursorX and cursorY field
+DATA.CursorX = [];
+DATA.CursorY = [];
+
+%If scar then the stack must not be timeresolved
+if any(strcmp(type,{'Scar','MO','ScarRubber'}))&& SET(no).TSize>1
+ myfailed('Tool not enabled for time-resolved data. Perhaps delete time frames?')
+ indent(DATA.Handles.configiconholder,'select',1);
+ return;
+end
+
+%If scar then endocardium should exist
+if any(strcmp(type,'Scar')) && isempty(SET(no).EndoX)
+ myfailed('Endocardium segmentation must exist to draw scar.')
+ return;
+end
+
+%clear interpolation points
+%When drawing we remove the interpolation points
+if ~any(strcmp(type,{'Scar','MaR','MO','ScarRubber','MaRRubber', 'Roi','CalciumPen','CalciumPenBlue', 'CalciumPenRed', 'CalciumPenLilac', 'CalciumPenRemove'})) && ~isempty(SET(no).([type,'InterpX']))
+ SET(no).([type,'InterpX']){SET(no).CurrentTimeFrame,slice} = [];
+ SET(no).([type,'InterpY']){SET(no).CurrentTimeFrame,slice} = [];
+ drawfunctions('drawinterp',panel)
+end
+
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''pen_motion'',%d)',panel);
+if strcmp(type,'MaR')
+ DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''pen_buttonup'',%d,''%s'')',panel,type);
+else
+ DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''pen_buttonup'',%d,''%s'',%d,%d)',panel,type,slice,SET(no).CurrentTimeFrame);%last input is doall timeframes
+end
+%----------------------------------------------
+function measureadd_buttondown(panel,measureind,slice) %#ok
+%----------------------------------------------
+%New buttondown function input is type. The types handled here
+%are {Endo,Epi,RVendo,RVepi}. All temporary drawing is made using the
+%cursor object.
+
+global DATA
+
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,x,y);
+DATA.CursorX = [DATA.CursorX,x];
+DATA.CursorY = [DATA.CursorY,y];
+DATA.CursorZ = [DATA.CursorZ,slice];
+
+if strcmp(DATA.fig.SelectionType, 'normal')
+ buttonupfunctions('measure_buttonup',panel,measureind,slice);
+ return
+end
+
+pointind = length(DATA.CursorY);
+DATA.Handles.cursor.XData = DATA.CursorX;
+DATA.Handles.cursor.YData = DATA.CursorY;
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''measure_motion'',%d,%d)',panel,pointind);
+
+
+%----------------------------------------------
+function translateall_buttondown(panel) %#ok
+%----------------------------------------------
+%button down for translating all existing contours
+
+global DATA SET
+
+%retrieve clicked point no in panel, clicked slice, slices in panel and scale
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+no = DATA.ViewPanels(panel);
+slice = viewfunctions('clickedslice',panel,y,x);
+scale = viewfunctions('getscale',panel);
+slices = viewfunctions('slicesinpanel',panel);
+
+%get parameters for transferring into panel coordinates
+[yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice,1));
+
+%set cursor color
+DATA.Handles.cursor.Color = 'w';
+DATA.Handles.cursor.LineStyle = '--';
+DATA.Handles.cursor.Marker = 'none';
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+%Empty out any scrap in CursorX and CursorY container.
+DATA.CursorX = [];
+DATA.CursorY = [];
+
+%Retrieve all the existing contours transfer there coordinates to the panel
+%coordinates and store into DATA.CursorX/Y
+types = {'Endo','Epi','RVEndo','RVEpi'};
+
+for i = 1:length(types)
+ if ~isempty(SET(no).([types{i},'X'])) && ~all(isnan(SET(no).([types{i},'X'])(:,SET(no).CurrentTimeFrame,slice)))
+ DATA.CursorX =[DATA.CursorX;nan; (SET(no).([types{i},'X'])(:,SET(no).CurrentTimeFrame,slice) + (xl-1)*SET(no).XSize)*scale];
+ DATA.CursorY =[DATA.CursorY;nan; (SET(no).([types{i},'Y'])(:,SET(no).CurrentTimeFrame,slice) + (yl-1)*SET(no).YSize)*scale];
+ end
+end
+types = {'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp'};
+for type = 1:length(types)
+%When translating we remove the interpolation points
+ if ~isempty(SET(no).([types{type},'X']))
+ SET(no).([types{type},'X']){SET(no).CurrentTimeFrame,slice} = [];
+ SET(no).([types{type},'Y']){SET(no).CurrentTimeFrame,slice} = [];
+ drawfunctions('drawinterp',panel)
+ end
+end
+
+DATA.Handles.cursor.XData = DATA.CursorY;
+DATA.Handles.cursor.YData = DATA.CursorX;
+
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''translateall_buttonup'',%d,%f,%f,%d)',panel,x,y,slice);
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''translate_motion'',%d,%f,%f)',panel,x,y);
+
+%----------------------------------------------
+function pan_buttondown(panel)
+%----------------------------------------------
+%button down for panning
+global DATA
+
+%get starting position relative to window this is so that we can obtain the
+%movement undependent of the xlim ylim
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+
+xw = x-DATA.Handles.imageaxes(panel).XLim(1);
+yw = y-DATA.Handles.imageaxes(panel).YLim(1);
+
+%Place the original boundaries in Cursor information fields
+DATA.CursorX = DATA.Handles.imageaxes(panel).XLim;%-mean(DATA.Handles.imageaxes(panel).XLim);
+DATA.CursorY = DATA.Handles.imageaxes(panel).YLim;%-mean(DATA.Handles.imageaxes(panel).YLim);
+
+%hide all texts
+DATA.Handles.text(panel).Position = [nan,nan];
+% % % for c = 'cygmkwrb'
+% % % set(DATA.Handles.([c,'roitext'])(panel,:),'Position',[nan,nan])
+% % % end
+set(DATA.Handles.roitext(panel,:),'Position',[nan,nan])
+set(DATA.Handles.measurementtext(panel,:),'Position',[nan,nan])
+set(DATA.Handles.pointtext(panel,:),'Position',[nan,nan])
+
+%set motion and buttonup function
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''pan_motion'',%d,%f,%f)',panel,xw,yw);
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''pan_buttonup'',%d)',panel);
+
+%----------------------------------------------
+function point_buttondown(panel)%#ok %,measureind)
+%----------------------------------------------
+%button down for points
+
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,y,x);
+
+%Set the color of the cursor object which draws the temporary line according to the selected type
+DATA.Handles.cursor.Color = 'w';
+DATA.Handles.cursor.Marker = '+';
+DATA.Handles.cursor.MarkerSize = 8;
+
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+%For 3dp the slices is empty
+if ~any(strcmp(DATA.ViewPanelsType{panel},{'trans3DP','sag3DP','speedim','cor3DP'}))
+
+ slices = viewfunctions('slicesinpanel',panel);
+ scale = viewfunctions('getscale',panel);
+ %get montage coordinates of clicked position
+ [yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice,1));
+
+ %Find closest point in current timeframe and slice
+ try
+ [pointdist,pointind] = findfunctions('closestpoint',panel,x/scale - (xl-1)*SET(no).XSize,...
+ y/scale - (yl-1)*SET(no).YSize,slice);
+ catch
+ pointdist = Inf;
+ pointind = [];
+ end
+else
+ %Find closest 3dp point
+ [pointdist,pointind] = findfunctions('closestpoint3dp',panel,x,y,slice);
+end
+%If it after the above still is empty create new measure
+if isempty(pointind) || pointdist>DATA.Pref.ContourAdjustDistance
+ pointind = length(SET(no).Point.X)+1;
+end
+
+%plot clicked position
+DATA.Handles.cursor.XData = y;
+DATA.Handles.cursor.YData = x;
+
+%This way if you click close to a measure you drag that point of the
+%measure.
+DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''point_buttonup'',%d,%d,%d)',panel,pointind,slice);
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''point_motion'',%d)',panel);
+
+%-------------------------------
+function cutvessel_buttondown(~) %#ok
+%-------------------------------
+%Buttondown function for cutting vessels
+
+myfailed('3D Vessel Cut not yet implemented in 2D view.');
+
+%----------------------------------------------
+function centercross_buttondown(panel)%#ok %,measureind)
+%----------------------------------------------
+%New buttondown function input is type. All temporary drawing is made using the
+%cursor object.
+
+global DATA
+
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+
+DATA.Handles.cursor.Color = 'w';
+DATA.Handles.cursor.Marker = '+';
+DATA.Handles.cursor.MarkerSize = 8;
+
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+DATA.CursorX = [x,x];
+DATA.CursorY = [y,y];
+
+%----------------------------------------------
+function measure_buttondown(panel)%#ok %,measureind)
+%----------------------------------------------
+%New buttondown function input is type. The types handled here
+%are {Endo,Epi,RVendo,RVepi}. All temporary drawing is made using the
+%cursor object.
+
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+slice = viewfunctions('clickedslice',panel,x,y);
+slices = viewfunctions('slicesinpanel',panel);
+scale = viewfunctions('getscale',panel);
+
+%get montage coordinates of clicked position
+[xl,yl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice,1));
+
+%Set the color of the cursor object which draws the temporary line according to the selected type
+DATA.Handles.cursor.Color = 'w';
+DATA.Handles.cursor.Marker = 'o';
+DATA.Handles.cursor.MarkerSize = 5;
+
+%set parent of the cursor
+DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+
+%get measure number if new measurenN = nummeasures+1;
+[measureind,pointind,measureX,measureY, measureZ] = findfunctions('closestmeasure',panel,x/scale - (xl-1)*SET(no).XSize...
+ ,y/scale - (yl-1)*SET(no).YSize);
+
+%If it after the above still is empty create new measure
+if isempty(pointind)
+ measureind = length(SET(no).Measure)+1;
+ DATA.CursorX = [x,x];
+ DATA.CursorY = [y,y];
+ DATA.CursorZ = [slice,slice];%clicked slice
+ pointind = 2;
+else %this case handles grabbing of measure point aswell as extend clicking since pointind = number of coordinates + 1
+ measureX(pointind) = x/scale;
+ measureY(pointind) = y/scale;
+ DATA.CursorY = measureX*scale; %the usual switch for correct rendering
+ DATA.CursorX = measureY*scale;
+ DATA.CursorZ = measureZ;
+end
+
+%This way if you click close to a measure you drag that point of the
+%measure.
+if strcmp(DATA.fig.SelectionType, 'normal')
+ DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''measure_buttonup'',%d,%d,%d)',panel,measureind,slice);
+else
+ set(DATA.Handles.imageaxes(panel).Children,'ButtonDownFcn',sprintf('buttondownfunctions(''measureadd_buttondown'',%d,%d,%d)',panel,measureind,slice))
+ set(DATA.Handles.imageaxes(panel),'ButtonDownFcn',sprintf('buttondownfunctions(''measureadd_buttondown'',%d,%d,%d)',panel,measureind,slice))
+end
+
+DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''measure_motion'',%d,%d)',panel,pointind);
+
+%--------------------------------
+function select_buttondown(panel)
+%--------------------------------
+%Function that highlights the selected panel if montage also highlight the frame
+global DATA SET
+% %store the current panel after graphical update and return. The
+% %procedure is that first the panel is selected then you can start selecting
+% %slices and rois.
+
+%no = DATA.ViewPanels(panel);
+
+%orthoview, montage and montage segmented procedure
+switch DATA.ViewPanelsType{panel}
+ case 'one'
+ %select and update roi
+ viewfunctions('selectroi',panel);
+ case {'montage','montagesegmented','montagerow'}
+ %select and update roi
+ viewfunctions('selectroi',panel);
+ [x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+ slice = viewfunctions('clickedslice',panel,x,y);
+
+ DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''select_motion'',%d)',panel);
+ DATA.fig.WindowButtonUpFcn = 'buttonupfunctions(''select_buttonup'')';
+
+ case {'orth','hla','gla','vla'}
+ %select and update roi
+ viewfunctions('selectroi',panel);
+ [x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+ orthoview_buttondown(panel,x,y);
+
+ case {'trans3DP','speedim','sag3DP','cor3DP'}
+ clicktype = get(DATA.fig,'SelectionType');
+
+ switch clicktype
+ case 'normal'
+ %Normal click
+ segment3dp.tools('storeclickedposition')
+ segment3dp.tools('update3DP')
+ for loop = 1:length(DATA.ViewPanels)
+ if ~isequal(DATA.ViewPanelsType{loop},'speedim')
+ drawfunctions('drawtext',loop);
+ end
+ end
+ %set(DATA.fig,'WindowButtonMotionFcn','motionfunctions(''select3dp_motion'')')
+ %set(DATA.fig,'WindowButtonUpFcn','buttonupfunctions(''buttonup_Callback'')');
+ case 'alt'
+ %Right click => was cut
+ %Now done by context menu
+ %if segment3dp.tools('is2d')
+ % segment3dp.tools('split2d_Callback');
+ %else
+ % segment3dp.tools('split3d_Callback');
+ %end
+ end
+end
+
+if strcmp(DATA.ProgramName, 'Segment') % only executed for segment research version
+ scale = viewfunctions('getscale',panel);
+ no = DATA.ViewPanels(panel);
+ [ystart,xstart] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));%this needs to transformed to the stored coordinate system
+ slice = viewfunctions('clickedslice',panel,ystart,xstart);
+ xl = floor(xstart/scale/SET(no).XSize)*SET(no).XSize;
+ yl = floor(ystart/scale/SET(no).YSize)*SET(no).YSize;
+ x = xstart/scale - xl;
+ y = ystart/scale - yl;
+
+ [type,objectind] = findfunctions('closestobject',panel,x,y,slice);
+ if strcmp(type, 'Center')
+ state = viewfunctions('iconson','hideplus');
+ if not(state{1}) %not indented
+ %Set marker color
+ DATA.Handles.cursor.Color = 'w';
+ DATA.Handles.cursor.Marker = '+';
+ DATA.CursorX = xl + scale * SET(no).CenterX;
+ DATA.CursorY = yl + scale * SET(no).CenterY;
+ %When translating we remove the center point
+ if ~isempty(SET(no).([type,'X']))
+ % set to a very high number so that the original center cross is not
+ % seen during motion
+ SET(no).([type,'X']) = 10^6;
+ SET(no).([type,'Y']) = 10^6;
+ drawfunctions('drawcentercross',panel)
+ end
+ %set parent of the cursor
+ DATA.Handles.cursor.Parent = DATA.Handles.imageaxes(panel);
+ DATA.Handles.cursor.YData = DATA.CursorX;
+ DATA.Handles.cursor.XData = DATA.CursorY;
+
+ DATA.fig.WindowButtonMotionFcn = sprintf('motionfunctions(''translate_motion'',%d,%f,%f)',panel,xstart,ystart);
+ DATA.fig.WindowButtonUpFcn = sprintf('buttonupfunctions(''translate_buttonup'',%d,''%s'',%d,%f,%f,%d)',panel,type,objectind,xstart,ystart,slice);
+ end
+ end
+end
+
+%-----------------------------
+function addcalcium_buttondown
+%-----------------------------
+%buttondown when user clicks at object
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if isempty(SET(no).CT)
+ return;
+end
+
+if ~isfield(SET(no).CT,'CalciumMask')
+ return;
+end
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(DATA.CurrentPanel));%this needs to transformed to the stored coordinate system
+slice = viewfunctions('clickedslice',DATA.CurrentPanel,y,x);
+
+x = max(min(round(x),SET(no).XSize),1);
+y = max(min(round(y),SET(no).YSize),1);
+slice = round(slice);
+
+%
+[sx, sy, st, sslice]=size(SET(no).CT.CalciumMask);
+calculatedpixelid=[];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y,slice)];
+
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y-1,slice)];
+
+binim=SET(no).CT.CalciumMask>0;
+binim = squeeze(binim);
+bw = bwconncomp(binim);
+
+for i=1:length(bw.PixelIdxList)
+ for j=1:length(calculatedpixelid)
+ if ismember(calculatedpixelid(j),bw.PixelIdxList{1,i})%==1
+ rightlist=bw.PixelIdxList{1,i};
+ for k=1:length(rightlist)
+ SET(no).CT.CalciumMask(rightlist(k))=uint8(3);
+ end
+ end
+ end
+end
+%
+%SET(no).CT.CalciumMask(x,y,slice) = uint8(3);
+
+DATA.ViewIM{DATA.CurrentPanel} = [];
+drawfunctions('drawimages',DATA.CurrentPanel);
+%Maybe later the bwconn should be precalculated and stored
+%im = calcfunctions('calctruedata',SET(no).IM,no); %g?r om till Hounsfieldunits
+%outputmask = uint8((im>=130));
+%imbin = (im>=130); %allt ?ver 130 Hu r?knas som kalk
+%imbin = squeeze(imbin);
+%bw = bwconncomp(imbin);
+
+%-----------------------------
+function addmitralcalcium_buttondown
+%-----------------------------
+%buttondown when user clicks at object
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if isempty(SET(no).CT)
+ return;
+end
+
+if ~isfield(SET(no).CT,'CalciumMask')
+ return;
+end
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(DATA.CurrentPanel));%this needs to transformed to the stored coordinate system
+slice = viewfunctions('clickedslice',DATA.CurrentPanel,y,x);
+
+x = max(min(round(x),SET(no).XSize),1);
+y = max(min(round(y),SET(no).YSize),1);
+slice = round(slice);
+
+%
+[sx, sy, st, sslice]=size(SET(no).CT.CalciumMask);
+calculatedpixelid=[];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y,slice)];
+
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y-1,slice)];
+
+
+binim=SET(no).CT.CalciumMask>0;
+binim = squeeze(binim);
+bw = bwconncomp(binim);
+
+for i=1:length(bw.PixelIdxList)
+ for j=1:length(calculatedpixelid)
+ if ismember(calculatedpixelid(j),bw.PixelIdxList{1,i})%==1
+ rightlist=bw.PixelIdxList{1,i};
+ for k=1:length(rightlist)
+ SET(no).CT.CalciumMask(rightlist(k))=uint8(7);
+ end
+ end
+ end
+end
+%
+
+DATA.ViewIM{DATA.CurrentPanel} = [];
+drawfunctions('drawimages',DATA.CurrentPanel);
+
+%-----------------------------
+function addaortacalcium_buttondown
+%-----------------------------
+%buttondown when user clicks at object
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if isempty(SET(no).CT)
+ return;
+end
+
+if ~isfield(SET(no).CT,'CalciumMask')
+ return;
+end
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(DATA.CurrentPanel));%this needs to transformed to the stored coordinate system
+slice = viewfunctions('clickedslice',DATA.CurrentPanel,y,x);
+
+x = max(min(round(x),SET(no).XSize),1);
+y = max(min(round(y),SET(no).YSize),1);
+slice = round(slice);
+
+%
+[sx, sy, st, sslice]=size(SET(no).CT.CalciumMask);
+calculatedpixelid=[];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y,slice)];
+
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y-1,slice)];
+
+binim=SET(no).CT.CalciumMask>0;
+binim = squeeze(binim);
+bw = bwconncomp(binim);
+
+for i=1:length(bw.PixelIdxList)
+ for j=1:length(calculatedpixelid)
+ if ismember(calculatedpixelid(j),bw.PixelIdxList{1,i})%==1
+ rightlist=bw.PixelIdxList{1,i};
+ for k=1:length(rightlist)
+ SET(no).CT.CalciumMask(rightlist(k))=uint8(6);
+ end
+ end
+ end
+end
+%
+
+DATA.ViewIM{DATA.CurrentPanel} = [];
+drawfunctions('drawimages',DATA.CurrentPanel);
+
+%-----------------------------
+function addcoronarycalcium_buttondown
+%-----------------------------
+%buttondown when user clicks at object
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if isempty(SET(no).CT)
+ return;
+end
+
+if ~isfield(SET(no).CT,'CalciumMask')
+ return;
+end
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(DATA.CurrentPanel));%this needs to transformed to the stored coordinate system
+slice = viewfunctions('clickedslice',DATA.CurrentPanel,y,x);
+
+x = max(min(round(x),SET(no).XSize),1);
+y = max(min(round(y),SET(no).YSize),1);
+slice = round(slice);
+
+%
+[sx, sy, st, sslice]=size(SET(no).CT.CalciumMask);
+calculatedpixelid=[];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y,slice)];
+
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x+1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x-1,y-1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y+1,slice)];
+calculatedpixelid= [calculatedpixelid sub2ind(size(squeeze(SET(no).CT.CalciumMask)),x,y-1,slice)];
+binim=SET(no).CT.CalciumMask>0;
+binim = squeeze(binim);
+bw = bwconncomp(binim);
+
+for i=1:length(bw.PixelIdxList)
+ for j=1:length(calculatedpixelid)
+ if ismember(calculatedpixelid(j),bw.PixelIdxList{1,i})%==1
+ rightlist=bw.PixelIdxList{1,i};
+ for k=1:length(rightlist)
+ SET(no).CT.CalciumMask(rightlist(k))=uint8(8);
+ end
+ end
+ end
+end
+%
+
+DATA.ViewIM{DATA.CurrentPanel} = [];
+drawfunctions('drawimages',DATA.CurrentPanel);
+
diff --git a/source/buttonupfunctions.m b/source/buttonupfunctions.m
new file mode 100644
index 0000000..bff41eb
--- /dev/null
+++ b/source/buttonupfunctions.m
@@ -0,0 +1,1836 @@
+function varargout = buttonupfunctions(varargin)
+% Functions for buttonups
+
+% Broken out by Klas
+
+%Invoke subfunction
+
+macro_helper(varargin{:}); %future macro recording use
+if (nargout)
+ [varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
+else
+ feval(varargin{:}); % FEVAL switchyard
+end
+
+%-----------------------------------
+function glarotatehandle_Buttonup(panel) %#ok
+%-----------------------------------
+%Update view according to new rotation
+global SET DATA
+
+no = DATA.ViewPanels(panel);
+scale = viewfunctions('getscale',panel);
+[x,y] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+
+x = x/scale;
+y = y/scale;
+
+glaangle = mod(atan2(SET(no).ResolutionX*(y-SET(no).HLA.slice), ...
+ SET(no).ResolutionY*(x-SET(no).VLA.slice))+pi/2,pi)-pi/2;
+SET(no).GLA.angle = glaangle;
+
+%also do gla center update this updates the x0 y0 coordinates. Which is
+%needed for calculating the plane intersection.
+viewfunctions('setglacenter',no);
+
+set(DATA.fig,'WindowButtonMotionFcn',[], ...
+ 'WindowButtonUpFcn',[]);
+
+DATA.Handles.orthoanglehandle.XData = DATA.Handles.cursor.XData(2);
+DATA.Handles.orthoanglehandle.YData = DATA.Handles.cursor.YData(2);
+
+%clear cursor
+DATA.Handles.cursor.XData = nan;
+DATA.Handles.cursor.YData = nan;
+DATA.Handles.cursor.Marker = 'none';
+
+%update the ortho panel and the gla panel intersection
+drawfunctions('drawplaneintersections');
+
+%and gla panel
+glapanel = find(strcmp(DATA.ViewPanelsType,'gla'));
+
+%update gla segmentation intersections
+for t = 1:SET(no).TSize
+ calcfunctions('segmentationintersection_helper',glapanel,t) %this updates stored segmentation intersections for remaining timeframes no graphical update needed.
+end
+
+DATA.ViewIM{glapanel} = []; %forces viewim update of the glapanel
+drawfunctions('drawpanel',glapanel);
+
+%------------------------------
+function crop_buttonup(panel,xstart,ystart,slice) %#ok
+%-----------------------
+%This function adds the interpolated contour to all timeframes if all
+%timeframes mode is selected it also removes motion and buttonupfunction
+%settings in DATA.fig
+
+global DATA SET
+no = DATA.ViewPanels(panel);
+scale = viewfunctions('getscale',panel);
+
+[Xout, Yout] = motionfunctions('crop_motion',panel,xstart,ystart);
+
+%get translation from montage case
+slices = viewfunctions('slicesinpanel',panel);
+[xl,yl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice));
+xt = (xl-1)*SET(no).YSize*scale;
+yt = (yl-1)*SET(no).XSize*scale;
+
+%this removes any translation from montage and scaling so the format is the
+%same as we store coordinates in.
+xstart = (xstart-xt)/scale;
+ystart = (ystart-yt)/scale;
+xlast = (Xout(3)-xt)/scale;
+ylast = (Yout(3)-yt)/scale;
+
+%Get min max points in box and provide to crophelper
+yind = max(round([1,min([xlast,xstart])])):min(round([SET(no).YSize,max([xlast,xstart])]));
+xind = max(round([1,min([ylast,ystart])])):min(round([SET(no).XSize,max([ylast,ystart])]));
+
+%remove buttonup and motionfunctions
+buttonup_Callback
+
+if ~yesno('Apply crop?',[],DATA.GUI.Segment)
+ %reset cursor
+ DATA.Handles.cursor.XData = nan;
+ DATA.Handles.cursor.YData = nan;
+ return;
+end
+
+%reset cursor
+DATA.Handles.cursor.XData = nan;
+DATA.Handles.cursor.YData = nan;
+
+tools('crophelper',no,xind,yind); %after this we are done
+
+tools('disableundo')
+DATA.ViewIM{DATA.CurrentPanel}=[];
+drawfunctions('drawno',no)
+drawfunctions('drawselectedframe',panel)
+
+%also update thumbnail!
+drawfunctions('drawthumbnails',1,0)
+
+%------------------------------
+function interp_buttonup(panel,type,slice) %#ok
+%-----------------------
+%This function adds the interpolated contour to all timeframes if all
+%timeframes mode is selected it also removes motion and buttonupfunction
+%settings in DATA.fig
+
+global DATA SET
+no = DATA.ViewPanels(panel);
+ctf = SET(no).CurrentTimeFrame;
+
+%If straintagging initiated adjust LVupdated
+if ~isempty(SET(no).StrainTagging) && isfield(SET(no).StrainTagging, 'LVupdated')
+ SET(no).StrainTagging.LVupdated = 1;
+end
+
+%This applies the contours and interpolation points to all timeframes
+if not(DATA.ThisFrameOnly) %findindented(DATA.Handles.hideiconholder,'allframesmode')
+ %all frames mode
+ for tf = 1:SET(no).TSize
+ SET(no).([type(1:end-6),'X'])(:,tf,slice)=SET(no).([type(1:end-6),'X'])(:,ctf,slice);
+ SET(no).([type(1:end-6),'Y'])(:,tf,slice)=SET(no).([type(1:end-6),'Y'])(:,ctf,slice);
+ SET(no).([type,'X']){tf,slice} = SET(no).([type,'X']){ctf,slice};
+ SET(no).([type,'Y']){tf,slice} = SET(no).([type,'Y']){ctf,slice};
+ end
+end
+
+buttonup_Callback
+if SET(no).([type(1:end-6),'InterpOngoing'])
+ drawfunctions('drawinterp',panel,type);
+else
+ drawfunctions('drawno',no);
+end
+
+calcfunctions('updatemarandscar',no);
+
+%update result panel
+switch type
+ case {'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp'}
+ if ~SET(no).([type(1:end-6),'InterpOngoing'])
+ segment('updatevolume')
+ end
+end
+
+%------------------------------
+function scale_buttonup(panel,type,objectind,slice,startrad) %#ok
+%-----------------------
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+if not(isempty(SET(no).Flow)) && isfield(SET(no).Flow,'MagnitudeNo') && not(isempty(SET(no).Flow.MagnitudeNo))
+ magno = SET(no).Flow.MagnitudeNo;
+else
+ magno = no;
+end
+scale = viewfunctions('getscale',panel);
+
+xc = mean(DATA.CursorX);
+yc = mean(DATA.CursorY);
+
+xl = floor(xc/scale/SET(no).XSize)*SET(no).XSize;
+yl = floor(yc/scale/SET(no).YSize)*SET(no).YSize;
+
+%Update cursor coordinates then right back into SET struct
+[DATA.CursorX,DATA.CursorY, scalevalue] = motionfunctions('scale_motion',panel,startrad);
+switch type
+ case {'Endo','Epi'}
+% %objectind is not used for contours
+% if DATA.ThisFrameOnly %findindented(DATA.Handles.hideiconholder,'allframesmode')
+% %all frames mode
+% % SET(no).([type,'X'])(:,:,slice) = ...
+% % repmat(DATA.CursorX/scale - xl,[1,SET(no).TSize]);
+% % SET(no).([type,'Y'])(:,:,slice) = ...
+% % repmat(DATA.CursorY/scale - yl,[1,SET(no).TSize]);
+% tf = SET(no).CurrentTimeFrame;
+% else
+% % SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice) = ...
+% % DATA.CursorX/scale - xl;
+% % SET(no).([type,'Y'])(:,SET(no).CurrentTimeFrame,slice) = ...
+% % DATA.CursorY/scale - yl;
+% tf = 1:SET(magno).TSize;
+% end
+ stepsize = (scalevalue-1)/0.02;
+ lv('segmentexpandcontract_Callback',stepsize,lower(type),slice);
+
+ %If straintagging initiated adjust LVupdated
+ if ~isempty(SET(no).StrainTagging) && isfield(SET(no).StrainTagging, 'LVupdated')
+ SET(no).StrainTagging.LVupdated = 1;
+ end
+ calcfunctions('updatemarandscar',no);
+ case {'RVEndo','RVEpi'}
+ stepsize = (scalevalue-1)/0.02;
+ rv('expandcontract_Callback',stepsize,lower(type),slice);
+
+ case 'Roi'
+ if DATA.ThisFrameOnly %not(findindented(DATA.Handles.hideiconholder,'allframesmode'))
+ %single frame mode
+ DATA.DoThisFrameOnly = true; %flag for calc functions
+ SET(magno).Roi(objectind).X(:,SET(no).CurrentTimeFrame) = DATA.CursorX/scale - xl;
+ SET(magno).Roi(objectind).Y(:,SET(no).CurrentTimeFrame) = DATA.CursorY/scale - yl;
+ else
+ tf = 1:SET(magno).TSize;
+ mx = repmat(mean(SET(magno).Roi(SET(magno).RoiCurrent).X(:,tf)),size(SET(magno).Roi(SET(magno).RoiCurrent),1),1);
+ my = repmat(mean(SET(magno).Roi(SET(magno).RoiCurrent).Y(:,tf)),size(SET(magno).Roi(SET(magno).RoiCurrent),1),1);
+ SET(magno).Roi(objectind).X(:,tf) = bsxfun(@plus,mx,scalevalue*bsxfun(@minus,SET(magno).Roi(SET(magno).RoiCurrent).X(:,tf),mx));
+ SET(magno).Roi(objectind).Y(:,tf) = bsxfun(@plus,my,scalevalue*bsxfun(@minus,SET(magno).Roi(SET(magno).RoiCurrent).Y(:,tf),my));
+% SET(magno).Roi(objectind).X = repmat(DATA.CursorX/scale - xl,[1,SET(no).TSize]);
+% SET(magno).Roi(objectind).Y = repmat(DATA.CursorY/scale - yl,[1,SET(no).TSize]);
+ end
+ %KG: update Area and Mean of the ROI
+ [~,SET(magno).Roi(objectind).Area] = ...
+ calcfunctions('calcroiarea',magno,objectind);
+ [m,sd]=calcfunctions('calcroiintensity',magno,objectind);
+ SET(magno).Roi(objectind).Mean = m;
+ SET(magno).Roi(objectind).StD = sd;
+ %KG: update flowpanel, and flowresult, for FLOW ROI
+ if isfield(SET(magno).Roi(objectind), 'FlowSnake')
+ segment('updateflow');
+ end
+ DATA.DoThisFrameOnly = false; %flag for calc functions
+end
+
+drawfunctions('drawno',no)
+
+DATA.Handles.cursor.YData = nan;
+DATA.Handles.cursor.XData = nan;
+DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+DATA.fig.WindowButtonUpFcn = '';
+
+%----------------------------------------------
+function contrast_buttonup(panel,slice,xstart,ystart,xsize,ysize)
+%----------------------------------------------
+global DATA SET
+no = DATA.ViewPanels(panel);
+[contrast,brightness] = motionfunctions('contrast_motion',panel,slice,xstart,ystart,xsize,ysize);
+SET(no).IntensityMapping.Contrast = contrast;
+SET(no).IntensityMapping.Brightness = brightness;
+DATA.ViewIM{panel} = [];
+drawfunctions('drawimages',panel);
+
+DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+DATA.fig.WindowButtonUpFcn = '';
+
+%------------------------------
+function translate_buttonup(panel,type,objectind,xstart,ystart,slice) %#ok
+%-----------------------
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+if not(isempty(SET(no).Flow)) && isfield(SET(no).Flow,'MagnitudeNo') && not(isempty(SET(no).Flow.MagnitudeNo))
+ magno = SET(no).Flow.MagnitudeNo;
+else
+ magno = no;
+end
+scale = viewfunctions('getscale',panel);
+xl = floor(xstart/scale/SET(no).XSize)*SET(no).XSize;
+yl = floor(ystart/scale/SET(no).YSize)*SET(no).YSize;
+
+%Update cursor coordinates then right back into SET struct
+[DATA.CursorX,DATA.CursorY] = motionfunctions('translate_motion',panel,xstart,ystart);
+
+x = DATA.CursorX/scale - xl;
+y = DATA.CursorY/scale - yl;
+
+%check if any part of the contour is out of bounds then place it along the
+%edge of the image.
+x = min(x,SET(no).XSize-2);
+x = max(x,2);
+
+y = min(y,SET(no).YSize-2);
+y = max(y,2);
+
+switch type
+ case {'Endo','Epi','RVEndo','RVEpi'}
+ %objectind is not used for contours
+ if not(DATA.ThisFrameOnly) %findindented(DATA.Handles.hideiconholder,'allframesmode')
+ %all frames mode
+ diffx = SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice) - DATA.CursorX/scale + xl;
+ diffy = SET(no).([type,'Y'])(:,SET(no).CurrentTimeFrame,slice) - DATA.CursorY/scale + yl;
+
+ newx = SET(no).([type,'X'])(:,:,slice) - diffx;
+ newx = min(newx,SET(no).XSize-2);
+ newx = max(newx,2);
+ newy = SET(no).([type,'Y'])(:,:,slice) - diffy;
+
+ newy = min(newy,SET(no).YSize-2);
+ newy = max(newy,2);
+ SET(no).([type,'X'])(:,:,slice) = newx;% repmat(x,[1,SET(no).TSize]);
+ SET(no).([type,'Y'])(:,:,slice) = newy;% repmat(y,[1,SET(no).TSize]);
+ else
+ SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice) = x;
+ SET(no).([type,'Y'])(:,SET(no).CurrentTimeFrame,slice) = y;
+ end
+
+ %If straintagging initiated adjust LVupdated
+ if ~isempty(SET(no).StrainTagging) && isfield(SET(no).StrainTagging, 'LVupdated')
+ SET(no).StrainTagging.LVupdated = 1;
+ end
+ calcfunctions('updatemarandscar',no);
+ %update volumes in case of cropped by border
+ segment('updatevolume')
+
+ case 'Roi'
+ if DATA.ThisFrameOnly %~findindented(DATA.Handles.hideiconholder,'allframesmode')
+ %single frame mode
+ DATA.DoThisFrameOnly = true; %flag for calc functions
+ SET(magno).Roi(objectind).X(:,SET(no).CurrentTimeFrame) = x;
+ SET(magno).Roi(objectind).Y(:,SET(no).CurrentTimeFrame) = y;
+ else
+ diffx = SET(magno).Roi(objectind).X(:,SET(no).CurrentTimeFrame) - DATA.CursorX/scale + xl;
+ diffy = SET(magno).Roi(objectind).Y(:,SET(no).CurrentTimeFrame) - DATA.CursorY/scale + yl;
+ newx = SET(magno).Roi(objectind).X - diffx;
+ newx = min(newx,SET(no).XSize-2);
+ newx = max(newx,2);
+ newy = SET(magno).Roi(objectind).Y - diffy;
+
+ newy = min(newy,SET(no).YSize-2);
+ newy = max(newy,2);
+ SET(magno).Roi(objectind).X = newx;%repmat(x,[1,SET(no).TSize]);
+ SET(magno).Roi(objectind).Y = newy;%repmat(y,[1,SET(no).TSize]);
+ end
+
+ %update mean area std in case of cropped by border
+ [~,SET(magno).Roi(objectind).Area] = ...
+ calcfunctions('calcroiarea',magno,objectind);
+ [m,sd]=calcfunctions('calcroiintensity',magno,objectind);
+ SET(magno).Roi(objectind).Mean = m;
+ SET(magno).Roi(objectind).StD = sd;
+
+ case 'Measure'
+ measurex = x;
+ measurey = y;
+ switch DATA.ViewPanelsType{panel}
+ case 'hla'
+ SET(no).Measure(objectind).X = ones(size(measurey))*SET(no).HLA.slice;
+ SET(no).Measure(objectind).Y = measurey;
+ SET(no).Measure(objectind).Z = measurex;
+ case 'vla'
+ SET(no).Measure(objectind).X = measurey;
+ SET(no).Measure(objectind).Y = ones(size(measurey))*SET(no).VLA.slice;
+ SET(no).Measure(objectind).Z = measurex;
+ case 'gla'
+ [SET(no).Measure(objectind).X,SET(no).Measure(measureN).Y,...
+ SET(no).Measure(objectind).Z] = calcfunctions('gla2sax',measurex,measurey,no);
+ otherwise
+ SET(no).Measure(objectind).X = measurex;
+ SET(no).Measure(objectind).Y = measurey;
+ SET(no).Measure(objectind).Z = ones(size(measurey))*SET(no).CurrentSlice;
+ end
+ %Calc length in case of cropped by border
+ L = sum(sqrt(...
+ (SET(no).ResolutionX*diff(measurex)).^2+...
+ (SET(no).ResolutionY*diff(measurey)).^2+...
+ ((SET(no).SliceThickness+SET(no).SliceGap)*diff(SET(no).Measure(objectind).Z)).^2));
+
+ SET(no).Measure(objectind).Length = L;
+
+ case 'Point'
+ SET(no).Point.X(objectind) = x;
+ SET(no).Point.Y(objectind) = y;
+ case 'Center'
+ SET(no).CenterX = x;
+ SET(no).CenterY = y;
+end
+
+%draw changes
+drawfunctions('drawno',no)
+
+%update result panel
+switch type
+ case {'Endo','Epi','RVEndo','RVEpi'}
+ segment('updatevolume');
+ case 'Roi'
+ segment('updateflow');
+ DATA.DoThisFrameOnly = false; %flag for calc functions
+ otherwise
+ segment('updatemeasurement');
+end
+
+DATA.Handles.cursor.YData = nan;
+DATA.Handles.cursor.XData = nan;
+
+DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+DATA.fig.WindowButtonUpFcn = '';
+
+
+%------------------------------
+function translateall_buttonup(panel,xstart,ystart,slice) %#ok
+%-----------------------
+global DATA SET
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+no = DATA.ViewPanels(panel);
+scale = viewfunctions('getscale',panel);
+
+%translate the contours by xstart-x transferred to SET contour domain.
+tx = (xstart-x)/scale;
+ty = (ystart-y)/scale;
+
+
+
+types = {'Endo','Epi','RVEndo','RVEpi'};
+
+for i = 1:length(types)
+ type = types{i};
+ if ~isempty(SET(no).([type,'X'])) && ~all(isnan(SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice)))
+ contourx = SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice)-tx;
+ contoury = SET(no).([type,'Y'])(:,SET(no).CurrentTimeFrame,slice)-ty;
+
+ %check if any part of the contour is out of bounds then place it along the
+ %edge of the image.
+ contourx = min(contourx,SET(no).XSize-2);
+ contourx = max(contourx,2);
+ contoury = min(contoury,SET(no).YSize-2);
+ contoury = max(contoury,2);
+
+ SET(no).([type,'X'])(:,SET(no).CurrentTimeFrame,slice) = contourx;
+ SET(no).([type,'Y'])(:,SET(no).CurrentTimeFrame,slice) = contoury;
+ end
+end
+
+%If straintagging initiated adjust LVupdated
+if ~isempty(SET(no).StrainTagging) && isfield(SET(no).StrainTagging, 'LVupdated')
+ SET(no).StrainTagging.LVupdated = 1;
+end
+calcfunctions('updatemarandscar',no);
+drawfunctions('drawno',no)
+
+DATA.CursorX = [];
+DATA.CursorY = [];
+DATA.Handles.cursor.YData = nan;
+DATA.Handles.cursor.XData = nan;
+
+DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+DATA.fig.WindowButtonUpFcn = '';
+
+%----------------------------------------------
+function point_buttonup(panel,pointind,slice) %#ok
+%----------------------------------------------
+%Point button up function. Has the current panel and index of the
+%dragged point we are updating as input.
+
+global DATA SET
+
+if nargin == 2
+ slice = [];
+end
+
+no = DATA.ViewPanels(panel);
+%Restore/Kill all action functions
+DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+DATA.fig.WindowButtonUpFcn = '';
+
+[y,x] = mygetcurrentpoint(DATA.Handles.imageaxes(panel));
+
+%check if placed in 3dp view then we need to store it in a different way
+if any(strcmp(DATA.ViewPanelsType{panel},{'trans3DP','sag3DP','speedim','cor3DP'}))
+
+ [xsz,ysz,~,~] = segment3dp.tools('viewsizeandres',SET(no).LevelSet.Pen.Color,no);
+
+ px = min(x,xsz-2);
+ px = max(px,2);
+ py = min(y,ysz-2);
+ py = max(py,2);
+
+ [r,g,b] = segment3dp.tools('xy2rgb',SET(no).LevelSet.Pen.Color,px,py);
+ [x,y,z] = segment3dp.tools('rgb2xyz',r,g,b);
+
+ segment3dp.tools('addpoint_helper',x,y,z,no)
+
+ if segment3dp.isviewportalive
+ segment3dp.tools('addpointstoviewport'); %updates all points
+ end
+
+ %Indent show icon
+ DATA.Handles.configiconholder.indent('showpoint',1);
+
+ for p = 1:length(DATA.ViewPanels)
+ if ~isequal(DATA.ViewPanelsType{p},'viewport')
+ viewfunctions('updatedrawlist',p)
+ drawfunctions('drawpanel',p)
+ end
+ end
+
+else
+ %Not 3DP
+ slices = viewfunctions('slicesinpanel',panel);
+ scale = viewfunctions('getscale',panel);
+ %get montage coordinates of clicked position
+ [yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice));
+ xt = (xl-1)*SET(no).XSize*scale;
+ yt = (yl-1)*SET(no).YSize*scale;
+
+ %this removes any translation from montage and scaling so the format is the
+ %same as we store coordinates in.
+ px = (x-xt)/scale;
+ py = (y-yt)/scale;
+
+ %check if any part of the contour is out of bounds then place it along the
+ %edge of the image.
+ px = min(px,SET(no).XSize-2);
+ px = max(px,2);
+
+ py = min(py,SET(no).YSize-2);
+ py = max(py,2);
+
+ SET(no).Point.X(pointind) = px;
+ SET(no).Point.Y(pointind) = py;
+ SET(no).Point.Z(pointind) = slice;
+ if length(SET(no).Point.Label)
+%----------------------------------------------
+%Measure button up function. Has the current panel index of the currently
+%dragged point and finally the index of the measure we are updating as
+%input.
+
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+%Restore/Kill all action functions
+DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+DATA.fig.WindowButtonUpFcn = '';
+
+%get the slice and normalize the coordinates
+scale = viewfunctions('getscale',panel);
+
+slices = viewfunctions('slicesinpanel',panel);
+
+%get montage coordinates of clicked position
+[xl,yl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice,1));
+if isempty(xl)
+ xl = 1;
+ yl = 1;
+end
+measurey = DATA.CursorX/scale-(xl-1)*SET(no).YSize;
+measurex = DATA.CursorY/scale-(yl-1)*SET(no).XSize;
+
+%check if any part of the contour is out of bounds then place it along the
+%edge of the image.
+measurex = min(measurex,SET(no).XSize-2);
+measurex = max(measurex,2);
+
+measurey = min(measurey,SET(no).YSize-2);
+measurey = max(measurey,2);
+
+switch DATA.ViewPanelsType{panel}
+ case 'hla'
+ SET(no).Measure(measureN).X = ones(size(measurey))*SET(no).HLA.slice;
+ SET(no).Measure(measureN).Y = measurey;
+ SET(no).Measure(measureN).Z = measurex;
+ case 'vla'
+ SET(no).Measure(measureN).X = measurey;
+ SET(no).Measure(measureN).Y = ones(size(measurey))*SET(no).VLA.slice;
+ SET(no).Measure(measureN).Z = measurex;
+ case 'gla'
+ [SET(no).Measure(measureN).X,SET(no).Measure(measureN).Y,...
+ SET(no).Measure(measureN).Z] = calcfunctions('gla2sax',measurex,measurey,no);
+ otherwise
+ SET(no).Measure(measureN).X = measurex;
+ SET(no).Measure(measureN).Y = measurey;
+ SET(no).Measure(measureN).Z = DATA.CursorZ;%ones(size(measurey))*SET(no).CurrentSlice;
+end
+
+%Calc length
+L = sum(sqrt(...
+ (SET(no).ResolutionX*diff(measurex)).^2+...
+ (SET(no).ResolutionY*diff(measurey)).^2+...
+ ((SET(no).SliceThickness+SET(no).SliceGap)*diff(SET(no).Measure(measureN).Z)).^2));
+
+SET(no).Measure(measureN).Length = L;
+SET(no).Measure(measureN).Name = [];
+SET(no).Measure(measureN).T = SET(no).CurrentTimeFrame;
+SET(no).Measure(measureN).LongName = [];
+
+DATA.Handles.cursor.XData = nan;
+DATA.Handles.cursor.YData = nan;
+DATA.CursorX = [];
+DATA.CursorY = [];
+DATA.CursorZ = [];
+
+%Remove markers from cursor object
+DATA.Handles.cursor.Marker = 'none';
+
+if any(strcmp(DATA.ViewPanelsType{panel},{'orth','hla','gla','vla'}))
+ for p = 1:length(DATA.ViewPanels)
+ drawfunctions('drawmeasures',p)
+ end
+else
+ drawfunctions('drawmeasures',panel)
+end
+
+buttondownfunctions('updatebuttondowns','Measure');
+viewfunctions('updatedrawlist',panel);
+drawfunctions('drawpanel',panel);
+segment('updatemeasurement');
+
+
+%------------------------------------------------------------------------
+function select_buttonup
+%------------------------------------------------------------------------
+%Function that highlights the selected panel if montage also highlight the frame
+global DATA
+
+DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+DATA.fig.WindowButtonUpFcn = '';
+drawfunctions('drawplaneintersections')
+
+
+%----------------------------------------------
+function balloon_buttonup(panel,type,slice,tf) %#ok
+%----------------------------------------------
+%Generic buttonup that only clears motion and buttonup function in fig.
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+
+if not(isempty(SET(no).Flow)) && isfield(SET(no).Flow,'MagnitudeNo') && not(isempty(SET(no).Flow.MagnitudeNo))
+ no = SET(no).Flow.MagnitudeNo;
+end
+
+y = DATA.CursorX;
+x = DATA.CursorY;
+
+if isempty(x)
+ DATA.Handles.cursor.XData = nan;
+ DATA.Handles.cursor.YData = nan;
+ DATA.CursorX = [];
+ DATA.CursorY = [];
+
+ DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+ DATA.fig.WindowButtonUpFcn = '';
+ return
+end
+
+%Determine which slice we are drawing in and interpolation mode to translate the cursor contour .
+scale = viewfunctions('getscale',panel);
+slices = viewfunctions('slicesinpanel',panel);
+[yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice));
+xt = (xl-1)*SET(no).XSize*scale;
+yt = (yl-1)*SET(no).YSize*scale;
+%this removes any translation from montage and scaling so the format is the
+%same as we store coordinates in.
+x = (x-xt)/scale;
+y = (y-yt)/scale;
+
+%Adjust curve direction.
+[x,y]=mypoly2cw(x,y);
+
+switch type
+ case 'Roi'
+ %we do not merge rois
+ x_comp = [];
+ y_comp = [];
+ otherwise
+ if ~isempty(SET(no).([type,'X']))
+ x_comp = SET(no).([type,'X'])(:,tf,slice);
+ y_comp = SET(no).([type,'Y'])(:,tf,slice);
+ else
+ x_comp = [];
+ y_comp = [];
+ end
+end
+
+
+%this will trigger if exists segmentation in slice and timeframe
+if ~isempty(x_comp) && ~all(isnan(x_comp))
+ %determine if polygon is inside other polygon. If all is inside we keep the
+ % new contour.
+ mnew = poly2mask(x,y,SET(no).XSize,SET(no).YSize);
+ mold = poly2mask(x_comp,y_comp,SET(no).XSize,SET(no).YSize);
+
+ %this means that there is overlap between the old balloon and the new and an addition in the new blob that we need to
+ %incorporate
+ if any(mnew(:).*mold(:)>0) && any(mnew(:)-mold(:)>0)
+ m = mold+mnew>0;
+ [mi,mj] = ind2sub(size(m),find(m,1));
+ X = bwtraceboundary(m,[mi,mj],'W');
+
+ xm = zeros(length(X),1);
+ ym = zeros(length(X),1);
+
+ %idea is to find the closest point of all points which are not
+ %inside a polygon
+ [in1,~] = inpolygon(x,y,x_comp,y_comp);
+ [in2,~] = inpolygon(x_comp,y_comp,x,y);
+ x_cat = cat(1,x(~in1),x_comp(~in2));
+ y_cat = cat(1,y(~in1),y_comp(~in2));
+
+ %find the closest points on the combined polygon of the contour and
+ %the drawn. Then let resamplecurve work removing any duplicates.
+ for i = 1:length(X)
+ [~,ind] = min((X(i,2)-x_cat).^2+(X(i,1)-y_cat).^2);
+ xm(i) = x_cat(ind);
+ ym(i) = y_cat(ind);
+ end
+ x = xm;
+ y = ym;
+ end
+end
+
+%This might fail for fast clicks where xy contains duplicates or is empty.
+%if so clear the cursor object and motion buttonupfunctions and return before writing anything back to SET.
+try
+ %removes duplicate points and resamples the contour
+ [x,y] = calcfunctions('resamplecurve',x,y,DATA.NumPoints-1);
+
+ %Close the contour
+ x = [x,x(1)];
+ y = [y,y(1)];
+
+catch
+ DATA.Handles.cursor.XData = nan;
+ DATA.Handles.cursor.YData = nan;
+ DATA.CursorX = [];
+ DATA.CursorY = [];
+ DATA.Handles.cursor.LineStyle = '-';
+
+ DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+ DATA.fig.WindowButtonUpFcn = '';
+ return
+end
+
+switch type
+ case 'Roi'
+ %For the balloon case the we always create a new Roi
+ emptyroiinds = find(cellfun(@isempty,{SET(no).Roi.X}));
+ if ~isempty(emptyroiinds)
+ roiind = emptyroiinds(1);
+ else
+ roiind =length(SET(no).Roi)+1;
+ end
+
+ if not(DATA.ThisFrameOnly) %findindented(DATA.Handles.hideiconholder,'allframesmode')
+ %all frames mode
+ SET(no).Roi(roiind).X = repmat(x',[1,SET(no).TSize]);
+ SET(no).Roi(roiind).Y = repmat(y',[1,SET(no).TSize]);
+ else
+ DATA.DoThisFrameOnly = true; %flag for calc functions
+ tmpx = nan(length(x),SET(no).TSize);
+ tmpy = nan(length(x),SET(no).TSize);
+ tmpx(:,tf) = x;
+ tmpy(:,tf) = y;
+ SET(no).Roi(roiind).X = tmpx;
+ SET(no).Roi(roiind).Y = tmpy;
+ end
+
+ SET(no).Roi(roiind).T = 1:SET(no).TSize;
+ SET(no).Roi(roiind).Z = slice;
+
+ %Set roicurrent
+ SET(no).RoiCurrent = roiind;
+
+ %Increase number of rois
+ SET(no).RoiN = SET(no).RoiN + 1;
+
+ %Update roi name
+
+ SET(no).Roi(roiind).Sign = 1;
+ SET(no).Roi(roiind).Name = sprintf('ROI-%d',SET(no).RoiN);
+ newlinecolor = roi('roisetcolorbasedonposition',no);
+ SET(no).Roi(roiind).LineSpec = [newlinecolor,'-'];
+
+ %Calculate area and intensity of ROI
+ [~,SET(no).Roi(roiind).Area] = ...
+ calcfunctions('calcroiarea',no,roiind);
+ [m,sd]=calcfunctions('calcroiintensity',no,roiind);
+ SET(no).Roi(roiind).Mean = m;
+ SET(no).Roi(roiind).StD = sd;
+
+ %Update result panel
+ segment('updateflow');
+ DATA.DoThisFrameOnly = false; %flag for calc functions
+
+ otherwise
+
+ if strcmp(type, 'RVEndo')
+ [x,y] = calcfunctions('calcpointsoutsideLV',x,y,no);
+ end
+
+ if isempty(SET(no).([type,'X']))
+ SET(no).([type,'Y']) = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+ SET(no).([type,'X']) = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+ end
+
+ if not(DATA.ThisFrameOnly) %findindented(DATA.Handles.hideiconholder,'allframesmode')
+ %all frames mode
+ SET(no).([type,'Y'])(:,:,slice)=repmat(y',[1,SET(no).TSize]);
+ SET(no).([type,'X'])(:,:,slice)=repmat(x',[1,SET(no).TSize]);
+ else
+ SET(no).([type,'Y'])(:,tf,slice)=y;
+ SET(no).([type,'X'])(:,tf,slice)=x;
+ end
+ %If straintagging initiated adjust LVupdated
+ if ~isempty(SET(no).StrainTagging) && isfield(SET(no).StrainTagging, 'LVupdated')
+ SET(no).StrainTagging.LVupdated = 1;
+ end
+ calcfunctions('updatemarandscar',no);
+ segment('updatevolume')
+end
+
+% %generate image from normals of the endo contour
+% x = SET(no).([type,'Y'])(:,tf,slice);
+% y = SET(no).([type,'X'])(:,tf,slice);
+%
+% %use 100 points
+% [x,y] = calcfunctions('resamplecurve',x,y,150);%round(DATA.NumPoints/2));
+% x = x';
+% y = y';
+%
+% dy = conv([x(end-1);x],[1 0 -1]/2,'valid');%diff(SET(no).([type,'Y'])(:,tf,slice),);
+% dx = conv([y(end-1);y],[1 0 -1]/2,'valid');%diff(SET(no).([type,'X'])(:,tf,slice));
+%
+% %get normals
+% normals = -[0 -1 ; 1 0]*[dx,dy]'./sqrt(dx.*dx+dy.*dy)';
+% X = [y(1:end-1),x(1:end-1)]';
+% %extract lines from along normals in image
+% A = linspace(0,40,200);
+% lines =X + normals.*reshape(repmat(A,2,1),2,1,200);
+%
+% imA = zeros(size(lines,2),size(lines,3));
+%
+% %image we retrieve values from
+% imq = histeq(SET(no).IM(:,:,tf,slice),100);
+%
+% for i =1:size(lines,2)
+% xinds = round(squeeze(lines(1,i,:)));
+% yinds = round(squeeze(lines(2,i,:)));
+% inds = xinds>0 & xinds<=SET(no).YSize & yinds>0 & yinds<=SET(no).XSize;
+% xinds = xinds(inds);
+% yinds = yinds(inds);
+% indq = sub2ind(size(imq),xinds,yinds);
+% imA(i,inds) = imq(indq);
+% end
+%
+% %we can bin the bloodpool content and fit a gaussian to this which we draw
+% %the content of imA from.
+% padim = padarray(imA,[2,2],'replicate');
+% A = conv2(padim,ones(5)/25,'valid');
+%
+% %alternative idea
+% %[~,medmed] = max(abs(diff(mean(A))));
+% %medianres = ones(1,size(lines,2))*medmed;
+%
+% sample = A(:,1:6);
+% mu = mean2(sample);
+% sigma = std(sample(:));
+% y = normpdf(A(:),mu,sigma);
+% draw_imA = reshape(y,size(imA));
+% level = graythresh(draw_imA);
+%
+% %multithresh
+% %levels = multithresh(draw_imA,2);
+% %a = single(draw_imA>levels(1) & draw_imAlevel);
+% a(a==0) = -inf;
+% t = cumsum(a,2);
+%
+% %take the local median or less around a row intervall
+% medianres = max(t,[],2);
+%
+% medianres(isinf(medianres)) = nan;
+% %medianres = medfilt1(maxvals,5);
+% medmed = round(nanmedian(medianres));
+%
+% %just apply median for all
+% medianres(:) = medmed;
+%
+% if isempty(SET(no).EpiX)
+% SET(no).EpiY = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% SET(no).EpiX = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% end
+%
+% %apply this median index as the number of steps along the normal of the endo contour
+% tmpy = zeros(1,size(lines,2));
+% tmpx = zeros(1,size(lines,2));
+%
+% for i = 1:size(lines,2)
+% tmpy(i)=lines(2,i,medianres(i));
+% tmpx(i)=lines(1,i,medianres(i));
+% end
+%
+% %apply this median index as the number of steps along the normal of the endo contour
+% [x,y] = calcfunctions('resamplecurve',tmpx',tmpy',DATA.NumPoints-1);
+%
+% %Close the contour
+% x = [x,x(1)];
+% y = [y,y(1)];
+%
+% SET(no).EpiY(:,tf,slice)=y;
+% SET(no).EpiX(:,tf,slice)=x;
+%
+% %do refine then smooth twice
+% %epismoothsegmentation_helper(no,tf,slice)
+% %lvpeter('segmentrefineepi_Callback')
+% %epismoothsegmentation_helper(no,tf,slice)
+%
+
+% figure; plot(SET(no).EpiY(:,tf,slice),SET(no).EpiX(:,tf,slice),'g')
+% hold on
+% plot(SET(no).EndoY(:,tf,slice),SET(no).EndoX(:,tf,slice),'r')
+% find
+% figure; imagesc(draw_imA
+%----------------------------------------------
+global DATA SET
+panelslinked = find(ismember(DATA.ViewPanels,SET(DATA.ViewPanels(panel)).Linked));
+for actpanel = panelslinked
+ no = DATA.ViewPanels(actpanel);
+
+ %Update text position and show text again
+ viewfunctions('updatetextposition',actpanel)
+ scale = viewfunctions('getscale',actpanel);
+
+ switch DATA.ViewPanelsType{actpanel}
+ case 'trans3DP'
+ SET(no).LevelSet.View.RZoomState(1:2) = DATA.Handles.imageaxes(actpanel).XLim/scale;
+ SET(no).LevelSet.View.RZoomState(3:4) = DATA.Handles.imageaxes(actpanel).YLim/scale;
+ case 'sag3DP'
+ SET(no).LevelSet.View.GZoomState(1:2) = DATA.Handles.imageaxes(actpanel).XLim/scale;
+ SET(no).LevelSet.View.GZoomState(3:4) = DATA.Handles.imageaxes(actpanel).YLim/scale;
+ case 'cor3DP'
+ SET(no).LevelSet.View.BZoomState(1:2) = DATA.Handles.imageaxes(actpanel).XLim/scale;
+ SET(no).LevelSet.View.BZoomState(3:4) = DATA.Handles.imageaxes(actpanel).YLim/scale;
+ otherwise
+ %update the normalzoomstate field
+ SET(no).NormalZoomState(1:2) = DATA.Handles.imageaxes(panel).XLim/scale;
+ SET(no).NormalZoomState(3:4) = DATA.Handles.imageaxes(panel).YLim/scale;
+ end
+
+ %Draw all existing texts by calling drawpanel
+ drawfunctions('drawpanel',actpanel)
+end
+
+buttonup_Callback
+
+%----------------------------------------------
+function pen_buttonup(panel,type,slice,tf,doall) %#ok
+%----------------------------------------------
+%New button up function input is type and panel. The types handled here
+%are {Endo,Epi,RVendo,RVepi,Roi}.
+global DATA SET
+
+no = DATA.ViewPanels(panel);
+
+if not(isempty(SET(no).Flow)) && isfield(SET(no).Flow,'MagnitudeNo') && not(isempty(SET(no).Flow.MagnitudeNo))
+ no = SET(no).Flow.MagnitudeNo;
+end
+
+if nargin<4
+ tf = SET(no).CurrentTimeFrame;
+end
+
+if nargin<5
+ doall = 0;
+end
+
+if nargin < 3
+ slice = SET(no).CurrentSlice;
+end
+
+y = DATA.CursorX;
+x = DATA.CursorY;
+
+if isempty(x) || ismember(DATA.ViewPanelsType(panel),{'hla','vla','gla'})
+ DATA.Handles.cursor.XData = nan;
+ DATA.Handles.cursor.YData = nan;
+ DATA.CursorX = [];
+ DATA.CursorY = [];
+
+ DATA.fig.WindowButtonMotionFcn = 'segment(''toggleplaceholdermotion'')';
+ DATA.fig.WindowButtonUpFcn = '';
+ return
+end
+
+%Adjust curve direction.
+[x,y]=mypoly2cw(x,y);
+
+%Determine which slice we are drawing in and interpolation mode to translate the cursor contour .
+scale = viewfunctions('getscale',panel);
+slices = viewfunctions('slicesinpanel',panel);
+[yl,xl] = ind2sub(DATA.ViewPanelsMatrix{panel},find(slices==slice));
+xt = (xl-1)*SET(no).XSize*scale;
+yt = (yl-1)*SET(no).YSize*scale;
+
+%this removes any translation from montage and scaling so the format is the
+%same as we store coordinates in.
+x = (x-xt)/scale;
+y = (y-yt)/scale;
+
+%check if any part of the contour is out of bounds then place it along the
+%edge of the image.
+x = min(x,SET(no).XSize-2);
+x = max(x,2);
+
+y = min(y,SET(no).YSize-2);
+y = max(y,2);
+
+
+%two possibilities, either the segmentation overwrites the entire contour
+%field in the SET struct or it is appended to it. this is determined by
+%checking if it is closer to the startpoint of the drawing or the closest
+%point on the contour. As the orientation of the contour is adjusted so
+%both have a counterclockwise orientation we only need to handle two cases if we are going to append.
+%These cases are if the start index of the prior is removed in the append
+%or not. We set up both these cases and evaluate the two potential closed
+%curves and then choose the one which constitutes the largest area.
+switch type
+ case {'Scar','MaR','MO','ScarRubber','MaRRubber','CalciumPen', 'CalciumPenRemove', 'CalciumPenBlue', 'CalciumPenRed', 'CalciumPenLilac'}
+ %This will trigger new contour case
+ x_close = [];
+ y_close = [];
+ startdist = inf;
+ enddist = inf;
+ drawdist = 0;
+
+ case 'Roi'
+ if not(isempty(SET(no).Flow)) && isfield(SET(no).Flow,'MagnitudeNo') && not(isempty(SET(no).Flow.MagnitudeNo))
+ [startdist,roiind1,ind1] = findfunctions('closestroi',panel,x(1),y(1),[],[],no);
+ [enddist,roiind2,ind2] = findfunctions('closestroi',panel,x(end),y(end),[],[],no);
+ else
+ [startdist,roiind1,ind1] = findfunctions('closestroi',panel,x(1),y(1));
+ [enddist,roiind2,ind2] = findfunctions('closestroi',panel,x(end),y(end));
+ end
+ drawdist = sqrt((x(1)-x(end)).^2+(y(1)-y(end)).^2);
+
+ [~,closest] = min([startdist,enddist,drawdist]);
+ switch closest
+ case 1 %the starting point has a roi that is very close
+ x_close = SET(no).Roi(roiind1).X(:,tf);
+ y_close = SET(no).Roi(roiind1).Y(:,tf);
+ newroi = false;
+ roiind = roiind1;
+ case 2 %the end point has a roi that is very close
+ x_close = SET(no).Roi(roiind2).X(:,tf);
+ y_close = SET(no).Roi(roiind2).Y(:,tf);
+ newroi = false;
+ roiind = roiind2;
+ case 3 %the starting point is closest to the endpoint of the roi.
+ x_close = [];
+ y_close = [];
+ newroi = true;
+ emptyroiinds = find(cellfun(@isempty,{SET(no).Roi.X}));
+ if ~isempty(emptyroiinds)
+ roiind = emptyroiinds(1);
+ else
+ roiind =length(SET(no).Roi)+1;
+ end
+ end
+ otherwise
+ if ~isempty(SET(no).([type,'X'])) && ...
+ ~all(isnan(SET(no).([type,'X'])(:,tf,slice)))
+
+ x_close = SET(no).([type,'X'])(:,tf,slice);
+ y_close = SET(no).([type,'Y'])(:,tf,slice);
+
+ %distance to and index of closestcontour point from drawing startpoint
+ [startdist,ind1] = min((y_close-y(1)).^2+...
+ (x_close-x(1)).^2);
+
+ %distance to and index of closestcontour point from drawing endpoint
+ [enddist,ind2] = min((y_close-y(end)).^2+...
+ (x_close-x(end)).^2);
+
+ %distance between drawing start and endpoint
+ drawdist = (y(1)-y(end)).^2+...
+ (x(1)-x(end)).^2;
+ else
+ %This will trigger new contour case
+ x_close = [];
+ y_close = [];
+ startdist = inf;
+ enddist = inf;
+ drawdist = 0;
+ end
+end
+
+if isrow(x_close)
+ x_close = x_close';
+ y_close = y_close';
+end
+
+%this is the new contour decision
+if drawdist
+%-----------------------------
+%Button up function for fastmarch tool.
+
+global DATA SET NO
+
+set(DATA.fig,'WindowButtonMotionFcn',@DATA.toggleplaceholdermotion);
+set(DATA.fig,'WindowButtonUpFcn','');
+
+%If we are still calculating arrivaltimes then we return after clearing the
+%motion and buttonupfunctions.
+if DATA.Run
+ return
+end
+
+segment3dp.tools('storeclickedposition');
+
+[x,y,z] = segment3dp.tools('rgb2xyz',SET(NO).LevelSet.View.RSlice,SET(NO).LevelSet.View.GSlice, SET(NO).LevelSet.View.BSlice);
+arrivaltime = DATA.LevelSet.ArrivalTime(x,y,z);
+
+if isnan(arrivaltime)
+ arrivaltime = max(DATA.LevelSet.ArrivalTime(:));
+end
+
+%normal code
+SET(NO).LevelSet.BW(DATA.LevelSet.ArrivalTime < arrivaltime) = uint8(255);
+
+%--- code to make the outer nicer
+
+%Extract subvolume
+box = segment3dp.tools('findboundingbox',DATA.LevelSet.ArrivalTime < arrivaltime,2); %0=margin
+bw = SET(NO).LevelSet.BW(box.xmin:box.xmax,box.ymin:box.ymax,box.zmin:box.zmax);
+A = DATA.LevelSet.ArrivalTime(box.xmin:box.xmax,box.ymin:box.ymax,box.zmin:box.zmax);
+S = SET(NO).LevelSet.SpeedIM(box.xmin:box.xmax,box.ymin:box.ymax,box.zmin:box.zmax);
+logim = ( A < arrivaltime);
+
+%dilate subvolume
+se = segment3dp.tools('getse_helper',1);
+largerlogim = imdilate(logim,se);
+largerlogim = imdilate(largerlogim,se);
+corelogim = imerode(logim,se);
+
+%Store to bw
+bw(largerlogim) = uint8(255);
+
+%Get the added region
+%logim = logical(largerlogim-logim);
+bw(largerlogim) = min(bw(largerlogim),segment3dp.tools('calcthreshold3DP',S(largerlogim)));
+%bw(logim) = segment3dp.tools('calcthreshold3DP',A(logim));
+bw(corelogim) = uint8(255);
+
+%Assign
+SET(NO).LevelSet.BW(box.xmin:box.xmax,box.ymin:box.ymax,box.zmin:box.zmax) = bw;
+
+segment3dp.tools('storetoobject');
+segment3dp.tools('bwupdated');
+segment3dp.tools('update3DP');
+
+%----------------------
+function pen3dp_buttonup(tool) %#ok
+%----------------------
+global DATA
+
+%Manual draw
+motionfunctions('pen3dp_motion',tool,1)
+%This fixes icons tooltip
+set(DATA.fig,'WindowButtonMotionFcn','segment(''toggleplaceholdermotion'')');
+set(DATA.fig,'WindowButtonUpFcn','');
+DATA.LevelSet.motionon = false;
+
+%Reset .Man
+DATA.LevelSet.Man = int8(0)*DATA.LevelSet.Man;
+segment3dp.tools('storetoobject');
+segment3dp.tools('bwupdated');
+segment3dp.tools('update3DP');
+
+%------------------------------------
+function viewportpoints_buttonup(ind) %#ok
+%------------------------------------
+%button up of moving points in viewport
+
+global DATA SET NO
+
+coord = getclickedcoord(DATA.LevelSet.ViewPort);
+
+set(DATA.fig,'WindowButtonMotionFcn',''); %'segment(''toggleplaceholdermotion'')');
+set(DATA.fig,'WindowButtonUpFcn','');
+
+if ~isnan(coord(1))
+ x = coord(1)+DATA.LevelSet.Box.xmin-1; %This adds if the the volume is cropped
+ y = coord(2)+DATA.LevelSet.Box.ymin-1;
+ z = coord(3)+DATA.LevelSet.Box.zmin-1;
+
+ SET(NO).Point.X(ind) = x;
+ SET(NO).Point.Y(ind) = y;
+ SET(NO).Point.Z(ind) = z;
+
+end
+
+segment3dp.tools('addpointstoviewport');
+
+for p = 1:length(DATA.ViewPanels)
+ if ~isequal(DATA.ViewPanelsType{p},'viewport')
+ viewfunctions('updatedrawlist',p)
+ drawfunctions('drawpanel',p)
+ end
+end
+
+%See if we should update the line
+if ~isempty(SET(NO).Line3D.Points)
+ if ismember(ind,SET(NO).Line3D.Points{1})
+ segment3dp.linetools('createline','',SET(NO).Line3D.Points{1}); %Later possibility to have more lines
+ end
+end
diff --git a/source/calcfunctions.m b/source/calcfunctions.m
index 4400a8c..f43ee70 100644
--- a/source/calcfunctions.m
+++ b/source/calcfunctions.m
@@ -12,139 +12,229 @@
feval(varargin{:}); % FEVAL switchyard
end
+%---------------------
+function segmentationintersection_helper(panel,t)
+%-----------------------
+%This is updates segmentation intersections for selected panel and timeframe.
+global DATA
+
+[DATA.endointersectionx{panel}{t},DATA.endointersectiony{panel}{t}] = ...
+ calcfunctions('calcsegmentationintersections',panel,'epi',t,DATA.ViewPanelsType{panel});
+
+[DATA.epiintersectionx{panel}{t},DATA.epiintersectiony{panel}{t}] = ...
+ calcfunctions('calcsegmentationintersections',panel,'epi',t,DATA.ViewPanelsType{panel});
+
+%----------------------------------------------
+function [x,y] = resamplecurve(x,y,numpoints) %#ok
+%----------------------------------------------
+%Calculate total length and remove duplicate points
+global DATA
+
+if nargin==2
+ numpoints = DATA.NumPoints;
+end
+
+if length(x)>1
+ len = sqrt(...
+ conv2(x',[1 -1],'valid').^2+...
+ conv2(y',[1 -1],'valid').^2);
+ len = [0;len(:)]; %Add zero first
+ len = cumsum(len);
+ tempind = find(conv2(len,[1;-1],'valid')~=0); %Remove doublets
+ len = [len(1);len(tempind+1)]; %used in interpolation later
+ x = [x(1); x(tempind+1)];
+ y = [y(1); y(tempind+1)];
+ totallength = len(end);%used in interpolation later
+ %Resample
+ x = interp1(len,x,linspace(0,totallength,numpoints),'pchip');
+ y = interp1(len,y,linspace(0,totallength,numpoints),'pchip');
+
+ %assert correct clockwise order
+ [x,y] = mypoly2cw(x,y);
+
+ xr = y;
+ yr = x;
+ mx = mean(xr);
+ my = mean(yr);
+
+ [~,inda] = min(angle(complex(mx-xr,my-yr)));
+ x(1:(numpoints-inda)) = yr(inda+1:end);
+ y(1:(numpoints-inda)) = xr(inda+1:end);
+ x((numpoints+1-inda):end) = yr(1:inda);
+ y((numpoints+1-inda):end) = xr(1:inda);
+
+end
+
+%---------------------
+function preallocatesegmentationintersections(panels) %#ok
+%-----------------------
+%This is the preallocation of segmentation intersections Not doing the
+%calculation within image rendering should be a large speed up.
+global DATA SET
+
+%If no panels supplied these are the panels that needs calculation. A panel can be empty thats
+%why this is needed.
+if nargin == 0
+ panels = find(DATA.ViewPanels(DATA.ViewPanels>0));
+end
+
+if length(DATA.endointersectionx)~=length(DATA.ViewPanels)
+ DATA.endointersectionx = cell(1,length(DATA.ViewPanels));
+ DATA.endointersectiony = cell(1,length(DATA.ViewPanels));
+ DATA.epiintersectionx = cell(1,length(DATA.ViewPanels));
+ DATA.epiintersectiony = cell(1,length(DATA.ViewPanels));
+
+ %if the number of panels has changed we need to update all panel
+ %intersections. This overrides the input panels
+ panels = find(DATA.ViewPanels(DATA.ViewPanels>0));
+end
+
+for i = panels
+ DATA.endointersectionx{i} = cell(1,SET(DATA.ViewPanels(i)).TSize);
+ DATA.endointersectiony{i} = cell(1,SET(DATA.ViewPanels(i)).TSize);
+ DATA.epiintersectionx{i} = cell(1,SET(DATA.ViewPanels(i)).TSize);
+ DATA.epiintersectiony{i} = cell(1,SET(DATA.ViewPanels(i)).TSize);
+end
+
+for i = panels
+ %Contour intersection
+ for t = 1:SET(DATA.ViewPanels(i)).TSize
+ segmentationintersection_helper(i,t)
+ end
+end
+
%------------------------------------------
-function [edmax, MaxdiameterPoint, Zslice_no] = maxsaxdiameter(no,tf,type)
+function [edmax, MaxdiameterPoint, Zslice_no] = maxsaxdiameter(no,tf,type) %#ok
%------------------------------------------
%Get maximum endocardial diameter in short-axis cine stack
-% Input: no - no of stack,
-% tf - time frame,
+% Input: no - no of stack,
+% tf - time frame,
% type - 'RV', 'LV'
% Output: edmax - max LV/RV diameter
% MaxdiameterPoint - points with the largest distance in form [x,y]
% Zslice_no - slice number with largest LV/RV diameter
-%
+%
global SET
xres = SET(no).ResolutionX;
yres = SET(no).ResolutionY;
switch type
- case 'LV'
- edxall = squeeze(SET(no).EndoX(:,tf,:));
- edyall = squeeze(SET(no).EndoY(:,tf,:));
-
- edmax = 0;
- edmax_temp = 0;
- MaxdiameterPoint = [];
- Zslice_no=[];
+ case 'LV'
+ edxall = squeeze(SET(no).EndoX(:,tf,:));
+ edyall = squeeze(SET(no).EndoY(:,tf,:));
+
+ edmax = 0;
+ edmax_temp = 0;
+ MaxdiameterPoint = [];
+ Zslice_no=[];
+
+ for z = 1:SET(no).ZSize
+ edx = edxall(:,z);
+ if ~isnan(edx(1))
+ edy = edyall(:,z);
+ edxmat = repmat(edx,1,length(edx));
+ edymat = repmat(edy,1,length(edy));
+ eddist = sqrt((xres*(edxmat'-edxmat)).^2+ ...
+ (yres*(edymat'-edymat)).^2);
- for z = 1:SET(no).ZSize
- edx = edxall(:,z);
- if ~isnan(edx(1))
- edy = edyall(:,z);
- edxmat = repmat(edx,1,length(edx));
- edymat = repmat(edy,1,length(edy));
- eddist = sqrt((xres*(edxmat'-edxmat)).^2+ ...
- (yres*(edymat'-edymat)).^2);
-
- % edmax = max(edmax,max(eddist(:)));
- edmax_temp=max(eddist(:));
- if edmax_temp>edmax
- edmax=edmax_temp;
- [row, col] = find(ismember(eddist, edmax));
- MaxdiameterPoint(1,:)=[edx(row(1)),edy(row(1))];
- MaxdiameterPoint(2,:)=[edx(col(1)),edy(col(1))];
- Zslice_no=z; % #slice number
- end
- end
+ % edmax = max(edmax,max(eddist(:)));
+ edmax_temp=max(eddist(:));
+ if edmax_temp>edmax
+ edmax=edmax_temp;
+ [row, col] = find(ismember(eddist, edmax));
+ MaxdiameterPoint(1,:)=[edx(row(1)),edy(row(1))];
+ MaxdiameterPoint(2,:)=[edx(col(1)),edy(col(1))];
+ Zslice_no=z; % #slice number
end
- %% In case of RV max diameter, first we find center point of LV based on EPI contour
- % Then we finiding septum, and calculate the middle point of septum
- % The last part is to find the intersection between line (center LV and center septum) with RV endo contur.
- % This intersecton defines our maximal RV dimater.
- case 'RV'
- edmax = 0;
- edmax_temp = 0;
- MaxdiameterPoint=[];
- Zslice_no=[];
+ end
+ end
+ % In case of RV max diameter, first we find center point of LV based on EPI contour
+ % Then we finiding septum, and calculate the middle point of septum
+ % The last part is to find the intersection between line (center LV and center septum) with RV endo contur.
+ % This intersecton defines our maximal RV dimater.
+ case 'RV'
+ edmax = 0;
+ edmax_temp = 0;
+ MaxdiameterPoint=[];
+ Zslice_no=[];
+
+ edxall = squeeze(SET(no).RVEndoX(:,tf,:));
+ edyall = squeeze(SET(no).RVEndoY(:,tf,:));
+ epxLVall = squeeze(SET(no).EpiX(:,tf,:));
+ epyLVall = squeeze(SET(no).EpiY(:,tf,:));
+
+
+ %Center of Epi LV ROI for each slice
+ xLVcen=mean(epxLVall);
+ yLVcen=mean(epyLVall);
+
+ % Convhull RV roi
+ for z = 1:SET(no).ZSize
+ edx = edxall(:,z);
+ edxLV=epxLVall(:,z);
+ if isnan(edxLV(1))
+ continue
+ end
+ if ~isnan(edx(1))
+ edy = edyall(:,z);
+ k=convhull(edx,edy);
- edxall = squeeze(SET(no).RVEndoX(:,tf,:));
- edyall = squeeze(SET(no).RVEndoY(:,tf,:));
- epxLVall = squeeze(SET(no).EpiX(:,tf,:));
- epyLVall = squeeze(SET(no).EpiY(:,tf,:));
+ xhull=edx(k);
+ yhull=edy(k);
-
- %Center of Epi LV ROI for each slice
- xLVcen=mean(epxLVall);
- yLVcen=mean(epyLVall);
+ len=diff(xhull).^2+diff(yhull).^2;
- % Convhull RV roi
- for z = 1:SET(no).ZSize
- edx = edxall(:,z);
- edxLV=epxLVall(:,z);
- if isnan(edxLV(1))
- continue
- end
- if ~isnan(edx(1))
- edy = edyall(:,z);
- k=convhull(edx,edy);
-
- xhull=edx(k);
- yhull=edy(k);
-
- len=diff(xhull).^2+diff(yhull).^2;
-
- %%maximum length line segment is made out of the septum points. An addition
- %to make this more robust is to pick out the n largest line segments and check the area of the concavity the maximum area concavity should be the LV.
- [~,ind]=max(len);
- a=[xhull(ind),yhull(ind)];
- b=[xhull(ind+1),yhull(ind+1)];
-
- %find closest points on RV contour
- [~,ind_a]=min((edx-a(1)).^2+(edy-a(2)).^2);
- [~,ind_b]=min((edx-b(1)).^2+(edy-b(2)).^2);
-
- %%number of poinst between A and B
- if (edx(ind_a) < edx(ind_a+1))&&(edx(ind_b) < edx(ind_b+1))
- noABx=[edx(1:ind_a-1); edx(ind_b+1:end)];
- else
- noABx=edx(ind_a+1:ind_b-1);
- end
-
- %% point which is in the middle between A and B
- ind_midAB=ceil(length(noABx)/2);
- % middle point
- if ind_a <= ind_midAB
- midRVab=[edx(end-(ind_midAB-ind_a)), edy(end-(ind_midAB-ind_a))];
- else
- midRVab=[edx(ind_a-ind_midAB), edy(ind_a-ind_midAB)];
-
- end
-
- %%line between center LV and centre of septal RV
- x=[xLVcen(z), midRVab(1)];
- y=[yLVcen(z), midRVab(2)];
- p = polyfit(x,y,1);
+ %maximum length line segment is made out of the septum points. An addition
+ %to make this more robust is to pick out the n largest line segments and check the area of the concavity the maximum area concavity should be the LV.
+ [~,ind]=max(len);
+ a=[xhull(ind),yhull(ind)];
+ b=[xhull(ind+1),yhull(ind+1)];
+
+ %find closest points on RV contour
+ [~,ind_a]=min((edx-a(1)).^2+(edy-a(2)).^2);
+ [~,ind_b]=min((edx-b(1)).^2+(edy-b(2)).^2);
+
+ %number of poinst between A and B
+ if (edx(ind_a) < edx(ind_a+1))&&(edx(ind_b) < edx(ind_b+1))
+ noABx=[edx(1:ind_a-1); edx(ind_b+1:end)];
+ else
+ noABx=edx(ind_a+1:ind_b-1);
+ end
+
+ % point which is in the middle between A and B
+ ind_midAB=ceil(length(noABx)/2);
+ % middle point
+ if ind_a <= ind_midAB
+ midRVab=[edx(end-(ind_midAB-ind_a)), edy(end-(ind_midAB-ind_a))];
+ else
+ midRVab=[edx(ind_a-ind_midAB), edy(ind_a-ind_midAB)];
- %%calculate line
- x_space=linspace(min(edx), max(edx),100);
- y_space=p(1)*x_space+p(2);
-
- %% Intersection between the line LV - septal centre and RV segmentation
- [xi,yi] = polyxpoly(edx,edy,x_space,y_space);
-
- %% Max RV diameter
- edmax_temp=sqrt((xres*diff(xi)).^2+(yres*diff(yi)).^2);
- if edmax_temp>edmax
- edmax=edmax_temp;
- MaxdiameterPoint(1,:)=[xi(1),yi(1)];
- MaxdiameterPoint(2,:)=[xi(2),yi(2)];
- Zslice_no=z; % #slice number
- end
- end
end
+
+ % line between center LV and centre of septal RV
+ x=[xLVcen(z), midRVab(1)];
+ y=[yLVcen(z), midRVab(2)];
+ p = polyfit(x,y,1);
+
+ % calculate line
+ x_space=linspace(min(edx), max(edx),100);
+ y_space=p(1)*x_space+p(2);
+
+ % Intersection between the line LV - septal centre and RV segmentation
+ [xi,yi] = polyxpoly(edx,edy,x_space,y_space);
+
+ % Max RV diameter
+ edmax_temp=sqrt((xres*diff(xi)).^2+(yres*diff(yi)).^2);
+ if edmax_temp>edmax
+ edmax=edmax_temp;
+ MaxdiameterPoint(1,:)=[xi(1),yi(1)];
+ MaxdiameterPoint(2,:)=[xi(2),yi(2)];
+ Zslice_no=z; % #slice number
+ end
+ end
+ end
end
-
%----------------------------------------
function [N,xc,yc,zc] = lsplanefit(x,y,z) %#ok, used by makecut
%---------------------------------------
@@ -169,39 +259,39 @@
% Syy = y*y';
% Sxz = x*z';
% Syz = y*z';
-%
+%
% %using that there is no problem with fixating one param in the equation and
% %that the point cloud is zero centered i.e sum(x)=0 etc we get that it is
% %sufficient to solve the below system
% A = [Sxx,Sxy;Sxy,Syy];
% B = -[Sxz;Syz];
-%
+%
% params = A\B;
% N = [params;1];
%using svd
A=[x;y;z];
-[U,~,~] = svd(A);
+[U,~,~] = svd(A,'econ');
N = cross(U(:,1),U(:,2));
% point = [0,0,0];
% normal = N';
-%# a plane is a*x+b*y+c*z+d=0
-%# [a,b,c] is the normal. Thus, we have to calculate
-%# d and we're set
+% a plane is a*x+b*y+c*z+d=0
+% [a,b,c] is the normal. Thus, we have to calculate
+% d and we're set
% d = -point*normal'; %'# dot product for less typing
-% %# create x,y
+% % create x,y
% [xx,yy]=ndgrid(linspace(-1,1,10),linspace(-1,1,10));
-%
-% %# calculate corresponding z
+%
+% % calculate corresponding z
% zz = (-normal(1)*xx - normal(2)*yy - d)/normal(3);
-%# plot the surface
+% plot the surface
% figure
% surf(xx,yy,zz)
-% hold on
+% hold on
% plot3(x',y',z','k*')
%----------------------
@@ -228,15 +318,22 @@ function calcvolume(no) %#ok
docomp=true;
elseif SET(no).Longaxis > 1%SET(NO).Longaxis > 1
docomp = true;
-end;
+end
if SET(no).Rotated
calclvvolumepolar(no);
return;
-end;
+end
-ind = (findfunctions('findslicewithendo',no))|(findfunctions('findslicewithepi',no)); %Accepts empty endo and epi if exist
+% needtodo = false;
+% if ~isempty(SET(no).EndoX)
+% needtodo = true;
+% end
+% if ~isempty(SET(no).EpiX)
+% needtodo = true;
+% end
+ind = (findfunctions('findslicewithendo',no))|(findfunctions('findslicewithepi',no)); %Accepts empty endo and epi if exist
if ~any(ind)
SET(no).LVV = nan(1,SET(no).TSize);
SET(no).EPV = SET(no).LVV;
@@ -253,74 +350,96 @@ function calcvolume(no) %#ok
if nargout>0
varargout = cell(1,1);
varargout{1} = [];
- end;
+ end
if nargout>1
varargout{2} = [];
- end;
+ end
return;
-end;
+end
+
%Find what slices to do
if SET(no).ZSize>1
pos = find(ind);
else
pos = 1;
-end;
-LVVall = zeros(length(pos),SET(no).TSize);
-EPVall = zeros(length(pos),SET(no).TSize);
+end
+% LVVall = zeros(length(pos),SET(no).TSize);
+% EPVall = zeros(length(pos),SET(no).TSize);
% if isempty(SET(no).EndoX)
% %This far then create
% SET(no).EndoX = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
-% SET(no).EndoY = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
-% end;
-%
+% SET(no).EndoY = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% end
+%
% if isempty(SET(no).EpiX)
% %This far then create
% SET(no).EpiX = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
-% SET(no).EpiY = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
-% end;
+% SET(no).EpiY = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% end
%Loop over all segmented slices
-for sloop=1:length(pos)
- for tloop=1:SET(no).TSize
- if ~isempty(SET(no).EndoX)&&~isnan(SET(no).EndoX(1,tloop,pos(sloop)))
- A = stablepolyarea(...
- SET(no).ResolutionY*SET(no).EndoY(1:end-1,tloop,pos(sloop)),...
- SET(no).ResolutionX*SET(no).EndoX(1:end-1,tloop,pos(sloop)));
- LVVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000; %to cm3
- end;
- if ~isempty(SET(no).EpiX)&&~isnan(SET(no).EpiX(1,tloop,pos(sloop)))
- A = stablepolyarea(...
- SET(no).ResolutionY*SET(no).EpiY(1:end-1,tloop,pos(sloop)),...
- SET(no).ResolutionX*SET(no).EpiX(1:end-1,tloop,pos(sloop)));
- EPVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000; %to cm3
- end;
- end;
-end;
+if ~isempty(SET(no).EndoX)
+ LVVall = squeeze(polyarea(SET(no).ResolutionY*SET(no).EndoY(1:end-1,:,pos),...
+ SET(no).ResolutionX*SET(no).EndoX(1:end-1,:,pos))*(SET(no).SliceThickness+SET(no).SliceGap)/1000);
+ if length(pos)>1
+ LVVall = nansum(LVVall');
+ end
+else
+ LVVall = zeros(1,SET(no).TSize);
+end
-%Sum to get total volume
-if length(pos)>1
- SET(no).LVV = sum(LVVall);
- SET(no).EPV = sum(EPVall);
+if ~isempty(SET(no).EpiX)
+ EPVall = squeeze(polyarea(SET(no).ResolutionY*SET(no).EpiY(1:end-1,:,pos),...
+ SET(no).ResolutionX*SET(no).EpiX(1:end-1,:,pos))*(SET(no).SliceThickness+SET(no).SliceGap)/1000);
+ if length(pos)>1
+ EPVall = nansum(EPVall');
+ end
else
- SET(no).LVV = LVVall;
- SET(no).EPV = EPVall;
-end;
+ EPVall = zeros(1,SET(no).TSize);
+end
+
+
+% for sloop=1:length(pos)
+% for tloop=1:SET(no).TSize
+% if ~isempty(SET(no).EndoX)&&~isnan(SET(no).EndoX(1,tloop,pos(sloop)))
+% A = stablepolyarea(...
+% SET(no).ResolutionY*SET(no).EndoY(1:end-1,tloop,pos(sloop)),...
+% SET(no).ResolutionX*SET(no).EndoX(1:end-1,tloop,pos(sloop)));
+% LVVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000; %to cm3
+% end
+% if ~isempty(SET(no).EpiX)&&~isnan(SET(no).EpiX(1,tloop,pos(sloop)))
+% A = stablepolyarea(...
+% SET(no).ResolutionY*SET(no).EpiY(1:end-1,tloop,pos(sloop)),...
+% SET(no).ResolutionX*SET(no).EpiX(1:end-1,tloop,pos(sloop)));
+% EPVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000; %to cm3
+% end
+% end
+% end
+
+%Sum to get total volume
+% if length(pos)>1
+% SET(no).LVV = sum(LVVall');
+% SET(no).EPV = sum(EPVall');
+% else
+SET(no).LVV = LVVall;
+SET(no).EPV = EPVall;
+% end
SET(no).LVM = SET(no).EPV-SET(no).LVV+SET(no).PV;
-
+
if nargout>0
varargout = cell(1,1);
varargout{1} = LVVall;
-end;
+end
if nargout>1
varargout{2} = EPVall;
-end;
+end
if nargout>2
varargout{3} = 1.05*(EPVall-LVVall); %LVM in g, NOTE not include Papillary volume (PV)
-end;
+end
%Update EDV,ESV
SET(no).EDV = SET(no).LVV(SET(no).EDT);
@@ -333,9 +452,9 @@ function calcvolume(no) %#ok
if (SET(no).ZSize>2)&&docomp
LVVnocomp = SET(no).LVV;
EPVnocomp = SET(no).EPV;
-
+
for rloop=1:1 %Converges very quickly
-
+
%Calculate compensation mechanism
if (SET(no).LVV(SET(no).EDT)-SET(no).LVV(SET(no).EST)~=0)
pp = SET(no).LVV;
@@ -345,20 +464,20 @@ function calcvolume(no) %#ok
pp = min(max(pp,0),1);
else
pp = ones(size(SET(no).LVV));
- end;
+ end
err = zeros(1,20);
-
+
%Compensate
%pp = pp.*pp;
-
+
%Check if autodetect
if SET(no).AutoLongaxis
for loop=1:20
-
+
%Calculate slices
slices = (loop-1); %Convert to mm
slices = slices/(SET(no).SliceThickness+SET(no).SliceGap); %Convert to slices
-
+
sloop=1;
SET(no).LVV = LVVnocomp; %Restore
SET(no).EPV = EPVnocomp;
@@ -368,27 +487,27 @@ function calcvolume(no) %#ok
SET(no).EPV = SET(no).EPV-min(slices,1)*EPVall(sloop,:).*pp;
slices = slices-1;
sloop = sloop+1;
- end;
-
+ end
+
%Calculate error
err(loop) = max(SET(no).EPV-SET(no).LVV+SET(no).PV)-min(SET(no).EPV-SET(no).LVV+SET(no).PV);
- end; %loop
+ end %loop
[~,inde] = min(err);
SET(no).Longaxis = inde;
- end; %autodetect
-
+ end %autodetect
+
%Convert to slices => 1mm between, first is zero
slices = (SET(no).Longaxis-1);
if isempty(slices)
slices = 0;
end
slices = slices/(SET(no).SliceThickness+SET(no).SliceGap);
-
+
%Compensate the last time, now store it!
sloop=1;
SET(no).LVV = LVVnocomp; %Restore
SET(no).EPV = EPVnocomp;
-
+
%Check if need to fix with outline
if ~isempty(SET(no).EndoX)
zloop = find(not(isnan(SET(no).EndoX(1,SET(no).CurrentTimeFrame,:))));
@@ -402,76 +521,22 @@ function calcvolume(no) %#ok
zloop = SET(no).CurrentSlice;
else
zloop = zloop(1);
- end;
-
- %Make sure that it is updated
- %if docomp
- % updatemodeldisplay;
- %end;
+ end
while (slices>0)&&(sloop<=size(LVVall,1))
%Remove whole slice or fraction of it.
SET(no).LVV = SET(no).LVV-min(slices,1)*LVVall(sloop,:).*pp;
SET(no).EPV = SET(no).EPV-min(slices,1)*EPVall(sloop,:).*pp;
-
- [xofs,yofs] = calcoffset(zloop,'montage');
-
- %Need to fix with outline?
- if 0%get(DATA.Handles.volumeoutlinecheckbox,'value')
- for tloop=1:SET(no).TSize
- if ~isempty(SET(no).EndoX)
- SET(no).EndoXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- (SET(no).EndoX(:,tloop,zloop)-SET(no).CenterX)*(1-pp(tloop)*min(1,slices))+SET(no).CenterX+xofs;
- SET(no).EndoYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- (SET(no).EndoY(:,tloop,zloop)-SET(no).CenterY)*(1-pp(tloop)*min(1,slices))+SET(no).CenterY+yofs;
- end
- if ~isempty(SET(no).EpiX)
- SET(no).EpiXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- (SET(no).EpiX(:,tloop,zloop)-SET(no).CenterX)*(1-pp(tloop)*min(1,slices))+SET(no).CenterX+xofs;
- SET(no).EpiYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- (SET(no).EpiY(:,tloop,zloop)-SET(no).CenterY)*(1-pp(tloop)*min(1,slices))+SET(no).CenterY+yofs;
- end
- end;
- else
- for tloop=1:SET(no).TSize
- if ~isempty(SET(no).EndoX)
- SET(no).EndoXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- SET(no).EndoX(:,tloop,zloop)+xofs;
- SET(no).EndoYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- SET(no).EndoY(:,tloop,zloop)+yofs;
- end
- if ~isempty(SET(no).EpiX)
- SET(no).EpiXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- SET(no).EpiX(:,tloop,zloop)+xofs;
- SET(no).EpiYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
- SET(no).EpiY(:,tloop,zloop)+yofs;
- end
- end;
- end;
zloop = zloop+1;
slices = slices-1;
sloop = sloop+1;
- end;
- end; %rloop
+ end
+ end %rloop
if DATA.Silent
return;
- end;
-
- for loop=1:length(DATA.ViewPanels)
- if isequal(no,DATA.ViewPanels(loop))
- if 0%isequal(get(DATA.Handles.volumeoutlinecheckbox,'value'),1) &&...
- ismember(DATA.ViewPanelsType{DATA.CurrentPanel},{'montage','montagerow','montagefit','sax3'})
- set(DATA.Handles.endocontour(loop),'LineStyle',':');
- set(DATA.Handles.epicontour(loop),'LineStyle',':');
- else
- set(DATA.Handles.endocontour(loop),'LineStyle','-');
- set(DATA.Handles.epicontour(loop),'LineStyle','-');
- end;
- end;
- end;
-
-end; %If docompensation
+ end
+end %If docompensation
%-----------------------------
@@ -500,7 +565,7 @@ function calclvvolumepolar(no)
SET(no).EF = 0;
SET(no).SV = 0;
return;
-end;
+end
%Find rotation axis, rotation around x-axis
my = SET(no).RotationCenter;
@@ -518,14 +583,14 @@ function calclvvolumepolar(no)
else
dxds = econv3(temp,[-1;1]);
dxds = dxds(2:end,:,:); %Different convolves have different "outside"
- end;
+ end
y = double(SET(no).ResolutionY)*double((SET(no).EndoY(:,:,ind)-my))/10; %cm
vol = pi*alphapart*y.^2.*sign(y).*dxds;
vol = nansum(nansum(vol,1),3);
SET(no).LVV = vol; %Store
else
SET(no).LVV = zeros(1,SET(no).TSize);
-end;
+end
%--- Calc epi volume
if ~isempty(SET(no).EpiX) && ~all(isnan(SET(no).EpiX(:)))
@@ -536,20 +601,20 @@ function calclvvolumepolar(no)
else
dxds = econv3(temp,[-1;1]);
dxds = dxds(2:end,:,:); %Different convolves have different "outside"
- end;
+ end
y = double(SET(no).ResolutionY)*double(SET(no).EpiY(:,:,ind)-my)/10; %cm
vol = pi*alphapart*y.^2.*sign(y).*dxds;
vol = nansum(nansum(vol,1),3);
SET(no).EPV = vol; %Store
else
- SET(no).EPV = zeros(1,SET(no).TSize);
-end;
+ SET(no).EPV = zeros(1,SET(no).TSize);
+end
%------------------------------------
function [varargout] = calcrvvolume(no)
%------------------------------------
%Calculate RV volume. no is the image stack.
-%The RV volume calculation does not involve any longaxis
+%The RV volume calculation does not involve any longaxis
%compensation.
global SET
@@ -557,26 +622,26 @@ function calclvvolumepolar(no)
needtodo = false;
if ~isempty(SET(no).RVEndoX)
needtodo = true;
-end;
+end
if ~isempty(SET(no).RVEpiX)
needtodo = true;
-end;
+end
if SET(no).Rotated
calcrvvolumepolar(no);
return;
-end;
-
+end
+
if ~needtodo
SET(no).RVV = zeros(1,SET(no).TSize);
SET(no).RVEPV = zeros(1,SET(no).TSize);
SET(no).RVEDV = 0;
- SET(no).RVESV = 0;
+ SET(no).RVESV = 0;
SET(no).RVSV = 0;
SET(no).RVEF = 0;
SET(no).RVM = 0;
varargout = cell(1,nargout);
return;
-end;
+end
ind = (findfunctions('findslicewithrvendo',no))|(findfunctions('findslicewithrvepi',no)); %Accepts empty endo and epi if exist
@@ -585,7 +650,7 @@ function calclvvolumepolar(no)
pos = find(ind);
else
pos = 1;
-end;
+end
RVVall = zeros(length(pos),SET(no).TSize);
EPVall = zeros(length(pos),SET(no).TSize);
@@ -599,37 +664,37 @@ function calclvvolumepolar(no)
SET(no).ResolutionY*SET(no).RVEndoY(1:end-1,tloop,pos(sloop)),...
SET(no).ResolutionX*SET(no).RVEndoX(1:end-1,tloop,pos(sloop)));
RVVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000;
- end;
- end;
- end;
-end;
-SET(no).RVV=sum(RVVall,1); %Buggfix for RV calculation. Addded ,1 EH:
+ end
+ end
+ end
+end
+SET(no).RVV=nansum(RVVall,1); %Buggfix for RV calculation. Addded ,1 EH:
SET(no).RVEDV = SET(no).RVV(SET(no).EDT);
SET(no).RVESV = SET(no).RVV(SET(no).EST);
SET(no).RVEPV = zeros(1,SET(no).TSize);
if ~isempty(SET(no).RVEpiX)
- for sloop=1:length(pos)
+ for sloop=1:length(pos)
for tloop=1:SET(no).TSize
if ~isnan(SET(no).RVEpiX(1,tloop,pos(sloop)))
A = stablepolyarea(...
SET(no).ResolutionY*SET(no).RVEpiY(1:end-1,tloop,pos(sloop)),...
SET(no).ResolutionX*SET(no).RVEpiX(1:end-1,tloop,pos(sloop)));
EPVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000;
- end;
- end;
- end;
-end;
-SET(no).RVEPV=sum(EPVall,1); %Buggfix for RV calculation. Addded ,1 EH:
+ end
+ end
+ end
+end
+SET(no).RVEPV=nansum(EPVall,1); %Buggfix for RV calculation. Addded ,1 EH:
if nargout>0
varargout = cell(1,1);
varargout{1} = RVVall;
-end;
+end
if nargout>1
varargout{2} = EPVall;
-end;
+end
%-----------------------------
function calcrvvolumepolar(no)
@@ -649,7 +714,7 @@ function calcrvvolumepolar(no)
SET(no).RVEF = 0;
SET(no).RVSV = 0;
return;
-end;
+end
%Find rotation axis, rotation around x-axis
my = SET(no).RotationCenter;
@@ -661,20 +726,20 @@ function calcrvvolumepolar(no)
if ~isempty(SET(no).RVEndoX)
%Calc dx/ds
temp = SET(no).ResolutionX*cat(1,SET(no).RVEndoX(:,:,ind),SET(no).RVEndoX(1,:,ind))/10; %cm
- if ndims(temp)==2
+ if ismatrix(temp)
dxds = conv2(temp,[1;-1],'same');
dxds = dxds(1:(end-1),:,:); %Remove "outside" data
else
dxds = econv3(temp,[-1;1]);
dxds = dxds(2:end,:,:); %Different convolves have different "outside"
- end;
+ end
y = SET(no).ResolutionY*(SET(no).RVEndoY(:,:,ind)-my)/10; %cm
vol = pi*alphapart*y.^2.*sign(y).*dxds;
vol = nansum(nansum(vol,1),3);
SET(no).RVV = vol; %Store
else
SET(no).RVV = zeros(1,SET(no).TSize);
-end;
+end
%--- Calc epi volume
if ~isempty(SET(no).RVEpiX)
@@ -685,14 +750,14 @@ function calcrvvolumepolar(no)
else
dxds = econv3(temp,[-1;1]);
dxds = dxds(2:end,:,:); %Different convolves have different "outside"
- end;
+ end
y = SET(no).ResolutionY*(SET(no).RVEpiY(:,:,ind)-my)/10; %cm
vol = pi*alphapart*y.^2.*sign(y).*dxds;
vol = nansum(nansum(vol,1),3);
SET(no).RVEPV = vol; %Store
else
- SET(no).RVEPV = zeros(1,SET(no).TSize);
-end;
+ SET(no).RVEPV = zeros(1,SET(no).TSize);
+end
%-------------------------
function volume_helper(no)
@@ -701,7 +766,7 @@ function volume_helper(no)
%Lots of checks to prevent NaN or Inf to be presented
%when some of the data are missing.
-global SET
+global SET
%Find zeros in volume
SET(no).LVV(SET(no).LVV==0) = NaN;
@@ -714,7 +779,7 @@ function volume_helper(no)
%Prevent that when endo is empty that epi may be viewed
if not(isnan(SET(no).EPV(1)))&&(isnan(SET(no).LVV(1)))
SET(no).LVV = zeros(size(SET(no).LVV));
-end;
+end
%Find peak ejection rate, peak filling rate
if SET(no).TSize>2
@@ -736,7 +801,7 @@ function volume_helper(no)
SET(no).RVPER = 0;
SET(no).RVPFRT = 1;
SET(no).RVPERT = 1;
-end;
+end
%Store LV-EDV,ESV,SV
SET(no).EDV = SET(no).LVV(SET(no).EDT)-SET(no).PV(SET(no).EDT);
@@ -753,7 +818,7 @@ function volume_helper(no)
SET(no).EF = SET(no).SV/SET(no).EDV; %Ejection fraction
else
SET(no).EF = NaN;
-end;
+end
if ~isempty(SET(no).RVEndoX)
%Store RV-EDV,ESV,SV
@@ -766,32 +831,130 @@ function volume_helper(no)
SET(no).RVEF = 0;
else
SET(no).RVEF = SET(no).RVSV/SET(no).RVEDV; %Ejection fraction
- end;
-end;
+ end
+end
if isnan(SET(no).RVEDV)
SET(no).RVEDV = 0;
-end;
+end
if isnan(SET(no).RVESV)
SET(no).RVESV = 0;
-end;
+end
if isnan(SET(no).RVSV)
SET(no).RVSV = 0;
-end;
+end
if isnan(SET(no).RVEF)
SET(no).RVEF = 0;
-end;
+end
if isequal(SET(no).EDT,SET(no).EST)
SET(no).RVESV=NaN;
SET(no).RVSV=NaN;
SET(no).RVEF=NaN;
end
+%-------------------------------------
+function age = calcageyearfraction(age,ageunit) %#ok
+%-------------------------------------
+%Calculates age as fraction of the year
+denominator = 372; %corresponds to the 12month*31days for easier calculations
+switch lower(ageunit)
+ case 'm' %months
+ numerator = 31;
+ case 'd' %days
+ numerator = 1;
+ case 'w' %weeks
+ numerator = 7; % to calculate into corresponding number of days
+ case 'y' % years
+ return; % no calculation necessary
+end
+age = age*numerator/denominator;
+
+%-------------------------------------
+function [age,ageunit] = calcagewithunits(age) %#ok
+%-------------------------------------
+%Calculates age that is given as fraction of the year into "normal"
+denominator = 372; %corresponds to the 12month*31days for easier calculations
+numdaysinmonth = 31;
+if not(isempty(age))
+ if age >= 1 % corresponds to years
+ if age < 2
+ ageunit = dprintf('year');
+ else
+ ageunit = dprintf('years');
+ end
+ else
+ newage = age*denominator;
+ if newage < numdaysinmonth % corresponds to days
+ age = newage;
+ if age < 2
+ ageunit = dprintf('day');
+ else
+ ageunit = dprintf('days');
+ end
+ else %corresponds to months
+ age = newage/numdaysinmonth;
+ if age < 2
+ ageunit = dprintf('month');
+ else
+ ageunit = dprintf('months');
+ end
+ end
+ end
+else
+ ageunit = '';
+end
+
+%-------------------------------------
+function [agedigits,ageunit] = calcagefrombirthdate(birthdate, acqusitiondate) %#ok
+%-------------------------------------
+%Calculates age as difference between birthdate and acquisition date
+
+switch length(birthdate)
+ case 4
+ birthinputformat = 'yyyy';
+ case 8
+ birthinputformat = 'yyyyMMdd';
+ otherwise
+ agedigits = [];
+ ageunit = '';
+ return;
+end
+
+try
+ datedifference = between(datetime(birthdate,'InputFormat',birthinputformat),...
+ datetime(acqusitiondate,'InputFormat','yyyyMMdd'),...
+ {'years','months','days'});
+catch me
+ mydispexception(me)
+ agedigits = [];
+ ageunit = '';
+ return
+end
+
+% split into number of years/moths/days
+[numyears,nummonths,numdays] = split(datedifference,{'years','months','days'});
+% set up digits and units
+if numyears > 0 % years digit
+ agedigits = numyears;
+ ageunit = 'y';
+else
+ if nummonths > 0
+ agedigits = nummonths;
+ ageunit = 'm';
+ else
+ agedigits = numdays;
+ ageunit = 'd';
+ end
+end
+
%-------------------------------------
function bsa = calcbsa(weight,height) %#ok
%-------------------------------------
%Calculates BSA. Formula based on Mosteller
%weight in kilo and height in cm.
+
+%This code is duplicated in segdicomtags to avoid compiler leak of
+%segmentserversorter
bsa = sqrt(weight*height/3600);
%-----------------------------------
@@ -812,7 +975,7 @@ function volume_helper(no)
if nargin<2
no = NO;
-end;
+end
if not(isa(z,'int16')) && ~isempty(SET(no).IntensityOffset)
%z = im*SET(no).IntensityScaling+SET(no).IntensityOffset;
im = (z-SET(no).IntensityOffset)/SET(no).IntensityScaling;
@@ -821,18 +984,23 @@ function volume_helper(no)
end
%-------------------------------
-function z = calctruedata(im,no)
+function z = calctruedata(im,no)
%-------------------------------
%Calculate true image intensities (as before Segment internal
%normalization). Uses IntensityScaling and IntensityOffset stored
-%in SET structure. im is input image, and no is image stack,
+%in SET structure. im is input image, and no is image stack,
%where to take the scaling from.
global SET NO
if nargin<2
no = NO;
-end;
+end
+
+if isequal(SET(no).IntensityScaling,1) && isequal(SET(no).IntensityOffset,0)
+ z = im;
+ return;
+end
if ~isempty(SET(no).IntensityScaling)
if not(isa(im,'int16'))
@@ -844,19 +1012,19 @@ function volume_helper(no)
z = (im-0.5)*2*SET(no).VENC;
else
z = im;
-end;
+end
%----------------------------------------
function radvel = calcradialvelocity(no) %#ok
%----------------------------------------
-%Calculate radial velocity of the endocardium.
+%Calculate radial velocity of the endocardium.
%Forward difference is used.
global SET NO
if nargin<1
no = NO;
-end;
+end
%Calc radius
rad = calcendoradius(no);
@@ -870,71 +1038,70 @@ function volume_helper(no)
temp = cat(2,temp,temp(:,end,:));
else
temp = zeros(size(rad));
- end;
-end;
+ end
+end
temp = temp(:,2:end,:); %Remove first timeframe, wrong derivate
radvel = temp/10; %=> cm/s
%--------------------------
-function [meanarea,area]=calcroiarea(no,roino,thisframeonly) %#ok
+function [meanarea,area] = calcroiarea(no,roino) %#ok
%--------------------------
%Calculates roi area (helper fcn)
+%no: current image stack
+%roino: selected ROI in current image stack
+global DATA SET
-global SET
-
-if nargin < 3
- thisframeonly = false;
-end
-if thisframeonly
+if DATA.DoThisFrameOnly
tvec = SET(no).CurrentTimeFrame;
else
tvec = SET(no).Roi(roino).T;
end
-area=nan(1,SET(no).TSize);
-for tloop=tvec
- if not(isnan(SET(no).Roi(roino).Y(1,tloop)))
- area(tloop)= (1/100)*stablepolyarea(...
- SET(no).ResolutionY*SET(no).Roi(roino).Y(:,tloop),...
- SET(no).ResolutionX*SET(no).Roi(roino).X(:,tloop));
- end
+if ~isfield(SET(no).Roi(roino),'Area') || isempty(SET(no).Roi(roino).Area)
+ area = nan(1,SET(no).TSize);
+else
+ area = SET(no).Roi(roino).Area;
end
-if thisframeonly
- area = area(tvec);
+
+for tloop = tvec
+ if not(isnan(SET(no).Roi(roino).Y(1,tloop)))
+ area(tloop) = (1/100)*stablepolyarea(...
+ SET(no).ResolutionY*SET(no).Roi(roino).Y(:,tloop),...
+ SET(no).ResolutionX*SET(no).Roi(roino).X(:,tloop));
+ end
end
-meanarea=mynanmean(area);
+
+meanarea = mynanmean(area);
%-----------------------------------------------------------------------------
-function [m,sd,rmin,rmax] = calcroiintensity(no,roino,normalize,thisframeonly) %#ok
+function [m,sd,rmin,rmax] = calcroiintensity(no,roino) %#ok
%-----------------------------------------------------------------------------
%Calculates intensity within a ROI (helper fcn)
-global SET
-if nargin < 3
- normalize = false;
-end
-if nargin < 4
- thisframeonly = false;
-end
+%no: current image stack
+%roino: selected ROI in current image stack
+global DATA SET
-if thisframeonly
+if DATA.DoThisFrameOnly
tvec = SET(no).CurrentTimeFrame;
else
tvec = SET(no).Roi(roino).T;
end
-m = nan(1,SET(no).TSize);
-sd = m;
-rmin = m;
-rmax = m;
+if ~isfield(SET(no).Roi(roino),'Mean') || isempty(SET(no).Roi(roino).Mean)
+ m = nan(1,SET(no).TSize);
+ sd = m;
+else
+ m = SET(no).Roi(roino).Mean;
+ sd = SET(no).Roi(roino).StD;
+end
+rmin = nan(1,SET(no).TSize);
+rmax = rmin;
+
z = SET(no).Roi(roino).Z;
-for tloop=tvec
+for tloop = tvec
if not(isnan(SET(no).Roi(roino).Y(1,tloop)))
- if normalize
- temp = SET(no).IM(:,:,tloop,z);
- else
- temp = calctruedata(SET(no).IM(:,:,tloop,z),no);
- end;
+ temp = calctruedata(SET(no).IM(:,:,tloop,z),no);
roimask = segment('createmask',...
[SET(no).XSize SET(no).YSize],...
SET(no).Roi(roino).Y(:,tloop),...
@@ -945,18 +1112,10 @@ function volume_helper(no)
sd(tloop) = std(temp(ind));
rmin(tloop) = min(temp(ind));
rmax(tloop) = max(temp(ind));
- end;
+ end
end
end
-if thisframeonly
- m = m(tvec);
- sd = sd(tvec);
- rmin = rmin(tvec);
- rmax = rmax(tvec);
-end
-
-
%-----------------------------------------------
function res = calcmyocardvolume(numsectors,no,tf) %#ok
%-----------------------------------------------
@@ -968,22 +1127,22 @@ function volume_helper(no)
if nargin<2
no = NO;
-end;
+end
if nargin < 3
tf = SET(no).CurrentTimeFrame;
end
-
+
res = nan([numsectors SET(no).ZSize]);
if isempty(SET(no).EndoX)
myfailed('No LV endocardium available.',DATA.GUI.Segment);
return;
-end;
+end
if isempty(SET(no).EpiX)
myfailed('No LV endocardium available.',DATA.GUI.Segment);
return;
-end;
+end
numpoints = DATA.Pref.RadialProfiles;
@@ -996,9 +1155,9 @@ function volume_helper(no)
endoy = SET(no).EndoY(:,tf,:);
epix = SET(no).EpiX(:,tf,:);
epiy = SET(no).EpiY(:,tf,:);
-end;
+end
-for slice=1:SET(no).ZSize
+for slice=1:SET(no).ZSize
if not(isnan(epix(1,slice)))
if numsectors == 1
res(1,slice) = 1e-3*(SET(no).SliceThickness+SET(no).SliceGap)*...
@@ -1017,7 +1176,7 @@ function volume_helper(no)
meanyendo = meanyepi;
else
[meanxendo,meanyendo,endosectors] = findmeaninsectorslice('endo',numpoints,tf,slice,numsectors,no);
- end;
+ end
for loop=1:numsectors
if episectors(loop)<=episectors(loop+1)
@@ -1030,7 +1189,7 @@ function volume_helper(no)
tempepiy = [...
epiy(episectors(loop):numpoints,slice) ; ...
epiy(1:episectors(loop+1),slice)];
- end;
+ end
if isnan(endox(1,slice))
tempendox = repmat(meanxendo,size(tempepix));
@@ -1046,8 +1205,8 @@ function volume_helper(no)
tempendoy = [...
endoy(endosectors(loop):numpoints,slice) ; ...
endoy(1:endosectors(loop+1),slice)];
- end;
- end;
+ end
+ end
%Calc volume in [ml]
res(loop,slice) = 1e-3*(SET(no).SliceThickness+SET(no).SliceGap)*...
@@ -1055,7 +1214,7 @@ function volume_helper(no)
SET(no).ResolutionY*[tempendoy;flipud(tempepiy);tempendoy(1)],...
SET(no).ResolutionX*[tempendox;flipud(tempepix);tempendox(1)]);
- end;
+ end
%correct the volume so the total volume in the current slice is correct
if ~isnan(endox(1,slice))
slicevolume = 1e-3*(SET(no).SliceThickness+SET(no).SliceGap)*...
@@ -1068,11 +1227,11 @@ function volume_helper(no)
SET(no).ResolutionY*[tempendoy;flipud(epiy(:,slice));tempendoy],...
SET(no).ResolutionX*[tempendox;flipud(epix(:,slice));tempendox]);
end
- correction = slicevolume/sum(res(:,slice));
+ correction = slicevolume/nansum(res(:,slice));
res(:,slice) = res(:,slice)*correction;
end
- end;
-end;
+ end
+end
%---------------------------------
function rad = calcendoradius(no)
@@ -1085,13 +1244,13 @@ function volume_helper(no)
if nargin<1
no = NO;
-end;
+end
if isempty(SET(no).EndoX)
rad = zeros(DATA.Pref.RadialProfiles,SET(no).TSize,SET(no).ZSize);
myfailed('No LV endocardium available.',DATA.GUI.Segment);
return;
-end;
+end
%Upsample model
if not(DATA.Pref.RadialProfiles==DATA.NumPoints)
@@ -1099,11 +1258,11 @@ function volume_helper(no)
else
endox = SET(no).EndoX;
endoy = SET(no).EndoY;
-end;
+end
rad = zeros(DATA.Pref.RadialProfiles,SET(no).TSize,SET(no).ZSize);
for zloop=1:SET(no).ZSize
- for tloop=1:SET(no).TSize
+ for tloop=1:SET(no).TSize
if SET(no).EndoCenter
%Calc mean
meanx = mean(SET(no).EndoX(:,tloop,zloop));
@@ -1111,14 +1270,14 @@ function volume_helper(no)
else
meanx = mean(SET(no).EpiX(:,tloop,zloop));
meany = mean(SET(no).EpiY(:,tloop,zloop));
- end;
+ end
%Calc radius
rad(:,tloop,zloop) = sqrt(...
((endox(:,tloop,zloop)-meanx)*SET(no).ResolutionX).^2+...
((endoy(:,tloop,zloop)-meany)*SET(no).ResolutionY).^2);
- end;
-end;
+ end
+end
%--------------------------------
function rad = calcepiradius(no)
@@ -1131,13 +1290,13 @@ function volume_helper(no)
if nargin<1
no = NO;
-end;
+end
if isempty(SET(no).EpiX)
rad = zeros(DATA.Pref.RadialProfiles,SET(no).TSize,SET(no).ZSize);
myfailed('No LV epicardium available.',DATA.GUI.Segment);
return;
-end;
+end
%Upsample model
if not(DATA.Pref.RadialProfiles == DATA.NumPoints)
@@ -1145,7 +1304,7 @@ function volume_helper(no)
else
epix = SET(no).EpiX;
epiy = SET(no).EpiY;
-end;
+end
rad = zeros(DATA.Pref.RadialProfiles,SET(no).TSize,SET(no).ZSize);
for zloop=1:SET(no).ZSize
@@ -1154,18 +1313,18 @@ function volume_helper(no)
if SET(no).EndoCenter && ~isnan(SET(no).EndoX(1,tloop,zloop))
%Calc mean
meanx = mean(SET(no).EndoX(:,tloop,zloop));
- meany = mean(SET(no).EndoY(:,tloop,zloop));
+ meany = mean(SET(no).EndoY(:,tloop,zloop));
else
meanx = mean(SET(no).EpiX(:,tloop,zloop));
meany = mean(SET(no).EpiY(:,tloop,zloop));
- end;
-
+ end
+
%Calc radius
rad(:,tloop,zloop) = sqrt(...
(SET(no).ResolutionX*(epix(:,tloop,zloop)-meanx)).^2+...
(SET(no).ResolutionY*(epiy(:,tloop,zloop)-meany)).^2);
- end;
-end;
+ end
+end
%------------------------------------------------------
function [wallthickness,endox,endoy,epix,epiy] = calcwallthickness(sectors,no) %#ok
@@ -1182,12 +1341,12 @@ function volume_helper(no)
if isempty(SET(no).EndoX)
myfailed('No LV endocardium available.',DATA.GUI.Segment);
return;
-end;
+end
if isempty(SET(no).EpiX)
myfailed('No LV epicardium available.',DATA.GUI.Segment);
return;
-end;
+end
pos = find(findfunctions('findslicewithendo',no)&findfunctions('findslicewithepi',no));
nslices = length(pos);
@@ -1195,7 +1354,7 @@ function volume_helper(no)
if length(nslices)<1
myfailed('Need more than one segmented slice.',DATA.GUI.Segment);
return;
-end;
+end
%Calc radius
endorad = calcendoradius(no);
@@ -1247,28 +1406,187 @@ function volume_helper(no)
end
%---------------------------------------------------------------------
-function [xout,yout] = calcsegmentationintersections(no,type,viewtype) %#ok
+function [xout,yout] = calcsegmentationintersections(panel,type,t,viewtype) %#ok
%---------------------------------------------------------------------
%Calculates intersections between segmentation in image stacks.
-%no is image stack and type is endo or epi, can also be rvendo etc.
-%the type is a string that dynamically calls a field of the SET struct.
+%Input is panel and type is endo or epi, can also be rvendo etc.
+%the type is a string that dynamically calls a field of the SET struct. t
+%is the current timeframe in the panel. This should be used to calculate
+%the matching phase in the other image stacks.
global DATA SET
-if nargin < 3
- viewtype = 'one';
-end
+no = DATA.ViewPanels(panel);
%Always return something
xout = nan;
yout = nan;
+
+%We dont display intersections in montage views
+if strcmp(DATA.ViewPanelsType{panel},{'montage','montagesegmented','montagerow'})
+ return
+end
+
+%this is the strings for the contour we are calculating intersections for
espot = regexp(type,'[e]');
xfield = [upper(type(1:espot)) type(espot+1:end) 'X'];
yfield = [upper(type(1:espot)) type(espot+1:end) 'Y'];
-if DATA.Silent
- return;
-end;
+%Find active panels in type
+panels = find(DATA.ViewPanels>0);
+
+%Remove the current panel from panels as we dont want to plot intersections with
+%oneself
+panels = panels(panels ~= panel);
+
+%no panels then return
+if isempty(panels)
+ return
+end
+
+%find nos with segmentation in the current timeframe t if no segmentation
+%return from function
+
+%first we find the nophase
+nophase = SET(no).TimeVector(t)/SET(no).TimeVector(end);
+
+
+%find panels with nos that have segmentation
+% ind = cellfun(@(x,y)~isempty(x) ,{SET(DATA.ViewPanels(panels)).(xfield)});
+ind = (~cellfun('isempty' ,{SET(DATA.ViewPanels(panels)).(xfield)}));
+
+if isempty(ind) || all(ind==0)
+ return
+end
+
+%get the nos from the panels
+noswithseg = DATA.ViewPanels(panels(ind));
+
+if ~isnan(nophase) && t~=1
+ TV_tmp = nan(length(noswithseg),max([SET(noswithseg).TSize]));
+ for i = 1:length(noswithseg)
+ TV_tmp(i,1:SET(noswithseg(i)).TSize) = SET(noswithseg(i)).TimeVector;
+ end
+ denomntr = [SET(noswithseg).TSize]-1;
+ if any(denomntr == 0)
+ % if denominator can be 0, then set time frames to 1
+ tfs = ones(1,length(noswithseg));
+ else
+ %Then we find the matching phases in the other nos
+ [~,tfs] = min((TV_tmp./([SET(noswithseg).TIncr].*(denomntr))'-nophase)'.^2);
+ %min((vertcat(SET(noswithseg).TimeVector)./([SET(noswithseg).TIncr].*([SET(noswithseg).TSize]-1))'-nophase)'.^2);
+ end
+ %check which slices there exists segmentation in the matching timeframes
+ nosz = cell(1,length(tfs));
+
+ for i = 1:length(noswithseg)
+ nosz{i} = find(~any(isnan(squeeze(SET(noswithseg(i)).(xfield)(:,tfs(i),:)))));
+ end
+else
+ nosz = cell(1,length(t));
+ for i = 1:length(noswithseg)
+ nosz{i} = find(~any(isnan(squeeze(SET(noswithseg(i)).(xfield)(:,t,:)))));
+ end
+end
+
+%If there where no slices with segmentation in that timeframe remove
+%them from noswithseg
+ind = cellfun(@isempty,nosz);
+noswithseg(ind) = [];
+nosz(ind) = [];
+
+if ~isnan(nophase) && t~=1
+ tfs(ind) = [];
+end
+%if no noswithseg return
+if isempty(noswithseg)
+ return
+end
+
+%Find equation for no plane using the position we find if image planes
+%intersect
+if ~ismember(viewtype,{'hla','vla','gla'})
+ [pos,~,~,zdir] = calcfunctions('getimageposandorientation',no,SET(no).CurrentSlice,viewtype);
+else
+ [pos,~,~,zdir] = calcfunctions('getimageposandorientation',no,SET(no).(upper(viewtype)).slice,viewtype);
+ if strcmp(viewtype,'gla')
+ ang = SET(no).GLA.angle;
+ res = SET(no).ResolutionY*cos(ang)+SET(no).ResolutionX*abs(sin(ang));
+ end
+end
+
+d = sum(pos.*zdir);
+
+%For each no with seg calculate intersection with the current plane
+xbuild = [];
+ybuild = [];
+for loop = 1:length(noswithseg)
+ if ~isnan(nophase) && t~=1
+ x = squeeze(SET(noswithseg(loop)).(xfield)(:,tfs(loop),nosz{loop}));
+ y = squeeze(SET(noswithseg(loop)).(yfield)(:,tfs(loop),nosz{loop}));
+ else
+ x = squeeze(SET(noswithseg(loop)).(xfield)(:,1,nosz{loop}));
+ y = squeeze(SET(noswithseg(loop)).(yfield)(:,1,nosz{loop}));
+ end
+ z = repmat(nosz{loop},size(x,1),1);
+
+ pos = calcfunctions('xyz2rlapfh',...
+ noswithseg(loop),...
+ x(:),...
+ y(:),...
+ z(:));
+
+ if ~isempty(pos) %pos may be empty from rotated stacks.
+ %Find crossings
+ disttoplane = pos*(zdir')-d;
+ calcdist = (disttoplane(1:(end-1)).*disttoplane(2:end));
+ ind = find(and(calcdist<0,abs(round(calcdist,4))>0.0000));
+
+ if ~isempty(ind)
+ crosspos = 0.5*(pos(ind,:)+pos(ind+1,:));
+
+ xyzno = calcfunctions('rlapfh2xyz',no,crosspos(:,1),crosspos(:,2),crosspos(:,3));
+
+ switch viewtype
+ case 'hla'
+ xbuild = [xbuild xyzno(3,:)]; %#ok
+ ybuild = [ybuild xyzno(2,:)]; %#ok
+ case 'vla'
+ xbuild = [xbuild xyzno(3,:)]; %#ok
+ ybuild = [ybuild xyzno(1,:)]; %#ok
+ case 'gla'
+ xbuild = [xbuild xyzno(3,:)]; %#ok
+ [~,glay] = sax2gla(xyzno(1,:),xyzno(2,:),0,noswithseg(loop));
+ ybuild = [ybuild glay]; %#ok
+ otherwise
+ xbuild = [xbuild xyzno(1,:)]; %#ok
+ ybuild = [ybuild xyzno(2,:)]; %#ok
+ end
+ end
+ end
+
+end
+
+if ~isempty(xbuild)
+ xout = xbuild;
+ yout = ybuild;
+end
+
+%---------------------------------------------------------------------
+function [xout,yout] = calcsegmentationintersections2(no,type,t,viewtype) %#ok
+%---------------------------------------------------------------------
+%Calculates intersections between segmentation in image stacks.
+%no is image stack and type is endo or epi, can also be rvendo etc.
+%the type is a string that dynamically calls a field of the SET struct.
+
+global DATA SET
+
+%Always return something
+xout = nan;
+yout = nan;
+espot = regexp(type,'[e]');
+xfield = [upper(type(1:espot)) type(espot+1:end) 'X'];
+yfield = [upper(type(1:espot)) type(espot+1:end) 'Y'];
%Find existing segmentation
panelix = find(DATA.ViewPanels>0);
@@ -1279,22 +1597,22 @@ function volume_helper(no)
noloop = DATA.ViewPanels(loop);
if ~isempty(SET(noloop).(xfield))
noseg(loop) = noloop;
- typeseg{loop} = DATA.ViewPanelsType{loop};
+ typeseg{loop} = 'one';%DATA.ViewPanelsType{loop};
%break %This causes segmentation from only one stack to be displayed
- end;
-end;
+ end
+end
typeseg = typeseg(noseg>0);
noseg = noseg(noseg>0);
if length(noseg)<1
return;
-end;
-
+end
+
%Find equation for no plane
if ~ismember(viewtype,{'hla','vla','gla'})
- [pos,~,~,zdir] = getimageposandorientation(no,SET(no).CurrentSlice,viewtype);
+ [pos,~,~,zdir] = calcfunctions('getimageposandorientation',no,SET(no).CurrentSlice,viewtype);
else
- [pos,~,~,zdir] = getimageposandorientation(no,SET(no).(upper(viewtype)).slice,viewtype);
+ [pos,~,~,zdir] = calcfunctions('getimageposandorientation',no,SET(no).(upper(viewtype)).slice,viewtype);
if strcmp(viewtype,'gla')
ang = SET(no).GLA.angle;
res = SET(no).ResolutionY*cos(ang)+SET(no).ResolutionX*abs(sin(ang));
@@ -1308,30 +1626,26 @@ function volume_helper(no)
if ~isequal(noseg(loop),no) || ~isequal(typeseg{loop},viewtype)
x = SET(noseg(loop)).(xfield);
y = SET(noseg(loop)).(yfield);
-
+
if ~isempty(x)% || any(findfunctions(['findslicewith',type,'all'],noseg(loop)))
%calculate corresponding timeframe
if SET(no).TSize == 2
- if SET(no).CurrentTimeFrame == SET(noseg(loop)).CurrentTimeFrame
- tfs = SET(no).CurrentTimeFrame;
+ if t == SET(noseg(loop)).CurrentTimeFrame
+ tfs = t;
else
tfs = [];
tfdiff = [];
end
- elseif any(findfunctions(['findslicewith',type,'all'],noseg(loop)))
+ elseif any(findfunctions(['findslicewith',type,'all'],noseg(loop)))
alltf = (1+((1:40)-1)/(SET(noseg(loop)).TSize-1)*(SET(no).TSize-1));
- [~,closestsegind] = min(abs(SET(no).CurrentTimeFrame-round(alltf)));
+ [~,closestsegind] = min(abs(t-round(alltf)));
tfs = max(1,min(SET(noseg(loop)).TSize,closestsegind));
- tfdiff = abs(alltf(tfs)-SET(no).CurrentTimeFrame);
+ tfdiff = abs(alltf(tfs)-t);
elseif SET(no).TSize>2
%find a corresponding (closest) tf in no, for each tf in noseg
alltf = (1+((1:40)-1)/(SET(noseg(loop)).TSize-1)*(SET(no).TSize-1));
- tfs = max(1,min(SET(noseg(loop)).TSize,find(SET(no).CurrentTimeFrame==round(alltf))));
- tfdiff = abs(alltf(tfs)-SET(no).CurrentTimeFrame);
-% tf = round(1+(SET(no).CurrentTimeFrame-1)/(SET(no).TSize-1)*(SET(noseg(loop)).TSize-1));
- %[~,tf] = min(abs(SET(noseg(loop)).TimeVector-SET(no).TimeVector(SET(no).CurrentTimeFrame)));
-
- %
+ tfs = max(1,min(SET(noseg(loop)).TSize,find(t==round(alltf))));
+ tfdiff = abs(alltf(tfs)-t);
else
tfs = 1;
end
@@ -1361,16 +1675,16 @@ function volume_helper(no)
end
end
end
-
+
if ~isempty(pos) %pos may be empty from rotated stacks.
%Find crossings
disttoplane = pos*(zdir')-d;
ind = find((disttoplane(1:(end-1)).*disttoplane(2:end))<0);
-
+
if ~isempty(ind)
crosspos = 0.5*(pos(ind,:)+pos(ind+1,:));
-
- xyzno = rlapfh2xyz(no,crosspos(:,1),crosspos(:,2),crosspos(:,3));
+
+ xyzno = calcfunctions('rlapfh2xyz',no,crosspos(:,1),crosspos(:,2),crosspos(:,3));
switch viewtype
case 'hla'
@@ -1387,18 +1701,18 @@ function volume_helper(no)
xbuild = [xbuild xyzno(1,:)]; %#ok
ybuild = [ybuild xyzno(2,:)]; %#ok
end
- end;
- end;
+ end
+ end
- end; %empty slice
- end; %zloop
+ end %empty slice
+ end %zloop
if ~isempty(xbuild)
xout = xbuild;
yout = ybuild;
end
- end; %empty segmentation
- end; %equal segmation
-end;
+ end %empty segmentation
+ end %equal segmation
+end
%--------------------------------------------------------------------
function [x,y] = calcplaneintersections(NO,no,TYPE,type,slice,hslice) %#ok
@@ -1418,10 +1732,10 @@ function volume_helper(no)
if isequal(no,0)
return;
-end;
+end
if isequal(NO,0)
return;
-end;
+end
if nargin < 5
slice = SET(no).CurrentSlice;
@@ -1430,6 +1744,20 @@ function volume_helper(no)
TYPE = 'one';
type = 'one';
end
+if isempty(type)
+ if not(isempty(TYPE))
+ type = TYPE;
+ else
+ type = 'one';
+ end
+end
+if isempty(TYPE)
+ if not(isempty(type))
+ TYPE = type;
+ else
+ TYPE = 'one';
+ end
+end
xszNO = SET(NO).XSize;
xresNO = SET(NO).ResolutionX;
@@ -1460,14 +1788,14 @@ function volume_helper(no)
glaangle = SET(NO).GLA.angle;
res = SET(NO).ResolutionY*cos(glaangle)+SET(NO).ResolutionX*abs(sin(glaangle));
yszNO = floor(SET(NO).YSize*abs(cos(glaangle))+SET(NO).XSize*abs(sin(glaangle)));
- yresNO = res;
+ yresNO = res;
end
-% if strcmp(type,'vla')
-% xszNO = SET(NO).YSize;
-% xresNO = SET(NO).ResolutionY;
-% yszNO = SET(NO).ZSize;
-% yresNO = SET(NO).SliceThickness + SET(NO).SliceGap;
-% end
+ % if strcmp(type,'vla')
+ % xszNO = SET(NO).YSize;
+ % xresNO = SET(NO).ResolutionY;
+ % yszNO = SET(NO).ZSize;
+ % yresNO = SET(NO).SliceThickness + SET(NO).SliceGap;
+ % end
[posNO,xdirNO,ydirNO] = getimageposandorientation(NO,hslice,TYPE(1:3));
end
@@ -1483,15 +1811,15 @@ function volume_helper(no)
% +--- lc ---+
ladir = ydirNO;
-lapos = posNO;
+lapos = posNO;
maxka = (yszNO-1)*yresNO; %in mm
lbdir = xdirNO;
-lbpos = posNO;
+lbpos = posNO;
maxkb = (xszNO-1)*xresNO;
lcdir = ydirNO;
-lcpos = posNO+xdirNO*(xszNO-1)*xresNO;
+lcpos = posNO+xdirNO*(xszNO-1)*xresNO;
maxkc = (yszNO-1)*yresNO;
lddir = xdirNO;
@@ -1516,13 +1844,13 @@ function volume_helper(no)
ka = -pa/qa;
else
ka = NaN;
-end;
+end
if ka<0
ka = NaN;
-end;
+end
if ka>maxka
ka = NaN;
-end;
+end
%Line b
qb = lbdir*(zdirno');
@@ -1531,13 +1859,13 @@ function volume_helper(no)
kb = -pb/qb;
else
kb = NaN;
-end;
+end
if kb<0
kb = NaN;
-end;
+end
if kb>maxkb
kb = NaN;
-end;
+end
%Line c
qc = lcdir*(zdirno');
@@ -1546,13 +1874,13 @@ function volume_helper(no)
kc = -pc/qc;
else
kc = NaN;
-end;
+end
if kc<0
kc = NaN;
-end;
+end
if kc>maxkc
kc = NaN;
-end;
+end
%Line d
qd = lddir*(zdirno');
@@ -1561,13 +1889,13 @@ function volume_helper(no)
kd = -pd/qd;
else
kd = NaN;
-end;
+end
if kd<0
kd = NaN;
-end;
+end
if kd>maxkd
kd = NaN;
-end;
+end
% zeropos
% +- => ka --+ => ImageOrientation(1:3)
@@ -1596,13 +1924,13 @@ function volume_helper(no)
global SET
-if isequal(no,0);
- no = 1;
-end;
+if isequal(no,0)
+ no = 1;
+end
if nargin<2
z = SET(no).ZSize;
-end;
+end
switch z
case 1
@@ -1621,12 +1949,12 @@ function volume_helper(no)
otherwise
rows = round(sqrt(z));
cols = ceil(z/rows);
-end;
+end
%-------------------------------------------------
function [xofs,yofs] = calcoffset(z,type,no,panel)
%-------------------------------------------------
-%Calculate offset required to plot coordinates in viewing
+%Calculate offset required to plot coordinates in viewing
%mode specified by type.
global DATA SET NO
@@ -1639,14 +1967,14 @@ function volume_helper(no)
end
if nargin<2 || isempty(type)
type = DATA.ViewPanelsType{panel};
-end;
+end
if panel > numel(DATA.ViewPanelsMatrix) || ...
isempty(DATA.ViewPanelsMatrix{panel})
[rows,cols] = calcrowscols(no);
DATA.ViewPanelsMatrix{panel}(1) = rows;
DATA.ViewPanelsMatrix{panel}(2) = cols;
-end;
+end
switch type
case {'montage','montagerow','montagefit'}
@@ -1672,10 +2000,10 @@ function volume_helper(no)
case 'montagesegmented'
slicestoinclude = segment_main('getmontagesegmentedslices',no);
if ismember(z,slicestoinclude)
- c = 1+mod(z-slicestoinclude(1),DATA.ViewPanelsMatrix{panel}(2));
- r = ceil((z-slicestoinclude(1)+1)/DATA.ViewPanelsMatrix{panel}(2));
- yofs = (c-1)*SET(no).YSize;
- xofs = (r-1)*SET(no).XSize;
+ c = 1+mod(z-slicestoinclude(1),DATA.ViewPanelsMatrix{panel}(2));
+ r = ceil((z-slicestoinclude(1)+1)/DATA.ViewPanelsMatrix{panel}(2));
+ yofs = (c-1)*SET(no).YSize;
+ xofs = (r-1)*SET(no).XSize;
else
yofs = nan;
xofs = nan;
@@ -1683,13 +2011,12 @@ function volume_helper(no)
otherwise
xofs = 0;
yofs = 0;
-end;
+end
%------------------------------------------------------
function [cellx,celly] = calcoffsetcells(no,panel,type) %#ok
%------------------------------------------------------
-%Same as calculateoffset, but returns cells, used in
-%updatemodeldisplay.
+%Same as calculateoffset, but returns cells, used in
global DATA SET NO
if nargin < 2
@@ -1697,7 +2024,7 @@ function volume_helper(no)
end
if nargin==0
no = NO;
-end;
+end
if nargin < 3
type = DATA.ViewPanelsType{panel};
end
@@ -1751,7 +2078,7 @@ function volume_helper(no)
otherwise
cellx = num2cell(zeros(SET(no).ZSize,1));
celly = num2cell(zeros(SET(no).ZSize,1));
-end;
+end
%-------------------------------------------------
@@ -1766,7 +2093,7 @@ function volume_helper(no)
spacedist = sqrt(...
((SET(no).Mmode.Lx*SET(no).Mmode.M1-SET(no).Mmode.Lx*SET(no).Mmode.M2)*SET(no).ResolutionY).^2+...
((SET(no).Mmode.Ly*SET(no).Mmode.M1-SET(no).Mmode.Ly*SET(no).Mmode.M2)*SET(no).ResolutionX).^2);
-
+
if ~isrectilinear(SET(no).TimeVector)
timedist = abs(...
SET(no).TimeVector(round(SET(no).Mmode.T1))-...
@@ -1786,7 +2113,7 @@ function volume_helper(no)
%DATA.DATASETPREVIEW. Size of the thumbnails is given by
%DATA.GUISettings.ThumbnailSize. It is stored as a RGB image.
-global DATA SET
+global DATA SET
%Reserve memory
DATA.DATASETPREVIEW = repmat(uint8(0),...
@@ -1808,19 +2135,19 @@ function volume_helper(no)
% zero padding, elegantly done, no? :) /JU
sz=size(tempim);
tempim=padarray(tempim,round((length(tempim)-sz(1:2))/2));
-
+
tempim = imresize(tempim,DATA.GUISettings.ThumbnailSize*[1 1],'bilinear');
-
+
%Downsample
-% xind = round(linspace(1,size(tempim,1),64));
-% yind = round(linspace(1,size(tempim,2),64));
-% tempim = tempim(xind,:);
-% tempim = tempim(:,yind);
+ % xind = round(linspace(1,size(tempim,1),64));
+ % yind = round(linspace(1,size(tempim,2),64));
+ % tempim = tempim(xind,:);
+ % tempim = tempim(:,yind);
%Store, vertically
DATA.DATASETPREVIEW((noloop-1)*DATA.GUISettings.ThumbnailSize+(1:DATA.GUISettings.ThumbnailSize),:,:) = tempim;
-end;
+end
%----------------------------------------------------------
function [outim,slicestoinclude] = calcmontageviewim(no,matrix,segmentedonly,cmap,c,b,im,tfs,oneextraslice,slices) %#ok
@@ -1834,7 +2161,7 @@ function volume_helper(no)
matrix = [rows cols];
end
-if nargin < 3
+if nargin < 3 || isempty(segmentedonly)
segmentedonly = false;
end
@@ -1844,63 +2171,57 @@ function volume_helper(no)
if nargin < 8 || isempty(tfs)
tfs = 1:SET(no).TSize;
end
+
+%Set number of timeframes
+TSize = length(tfs);
+
if nargin < 9 || isempty(oneextraslice)
oneextraslice = true;
end
%Decide which slices to view
if nargin < 10 || isempty(slices)
-if segmentedonly %and currentslice
- slicestoinclude = segment('getmontagesegmentedslices',no);
-% slicestoincludeendo = find(findfunctions('findslicewithendo',no,tfs))';
-% slicestoincludeepi = find(findfunctions('findslicewithepi',no,tfs))';
-% slicestoincludervendo = find(findfunctions('findslicewithrvendo',no,tfs))';
-% slicestoinclude = unique([slicestoincludeendo slicestoincludeepi slicestoincludervendo]);
-% if min(slicestoinclude) > 1 && oneextraslice
-% slicestoinclude = [min(slicestoinclude)-1 slicestoinclude];
-% end
-% if max(slicestoinclude) < SET(no).ZSize && oneextraslice
-% slicestoinclude = [slicestoinclude max(slicestoinclude)+1];
-% end
-else
- slicestoinclude = 1:SET(no).ZSize;
-end
+ if segmentedonly %and currentslice
+ slicestoinclude = segment('getmontagesegmentedslices',no);
+ else
+ slicestoinclude = 1:SET(no).ZSize;
+ end
else
slicestoinclude = slices;
end
%Add papillary visualization
-stateandicon=segment('iconson','hidelv');
+stateandicon=viewfunctions('iconson','hidelv');
if not(stateandicon{1}) %not(isempty(SET(no).PapillaryIM)) && isequal(get(DATA.Handles.hidepapicon,'state'),'off')
im(SET(no).PapillaryIM)=DATA.GUISettings.PapilarColor;
end
%Create space
-if nargin >= 6 && ~isempty(cmap) && ~isempty(c) && ~isempty(b)
- outim = repmat(uint8(0),[SET(no).XSize*matrix(1) SET(no).YSize*matrix(2) SET(no).TSize 3]);
+if nargin >= 6 && ~isempty(cmap) && ~isempty(c) && ~isempty(b)
+ outim = repmat(uint8(0),[SET(no).XSize*matrix(1) SET(no).YSize*matrix(2) TSize 3]);
elseif isempty(SET(no).Colormap)
- outim = repmat(uint8(0),[SET(no).XSize*matrix(1) SET(no).YSize*matrix(2) SET(no).TSize]);
+ outim = repmat(uint8(0),[SET(no).XSize*matrix(1) SET(no).YSize*matrix(2) TSize]);
else
- outim = repmat(uint8(0),[SET(no).XSize*matrix(1) SET(no).YSize*matrix(2) SET(no).TSize 3]);
+ outim = repmat(uint8(0),[SET(no).XSize*matrix(1) SET(no).YSize*matrix(2) TSize 3]);
end
-for tloop=1:SET(no).TSize
+for tloop=1:TSize
for i=1:numel(slicestoinclude)
zloop = slicestoinclude(i);
col = 1+mod(i-1,matrix(2));
r = ceil(i/matrix(2));
- if nargin >= 6 && ~isempty(cmap) && ~isempty(c) && ~isempty(b)
+ if nargin >= 6 && ~isempty(cmap) && ~isempty(c) && ~isempty(b)
outim(...
(1+(r-1)*SET(no).XSize):(r*SET(no).XSize),...
- (1+(col-1)*SET(no).YSize):(col*SET(no).YSize),tloop,:) = remapuint8( ...
- im(:,:,tloop,zloop),no,cmap,c,b);
+ (1+(col-1)*SET(no).YSize):(col*SET(no).YSize),tloop,:) = repmat(remapuint8( ...
+ im(:,:,tfs(tloop),zloop),no,cmap,c,b),[1,1,1,size(outim,4)]);
else
outim(...
(1+(r-1)*SET(no).XSize):(r*SET(no).XSize),...
(1+(col-1)*SET(no).YSize):(col*SET(no).YSize),tloop,:) = remapuint8( ...
- im(:,:,tloop,zloop),no);
+ im(:,:,tfs(tloop),zloop),no);
end
- end;
-end;
+ end
+end
%--------------------------------------------------------------------------
function [linex,liney] = calcmontageviewline(no,matrix,inputx,inputy,tf,segmentedonly,tfs,oneextraslice) %#ok
@@ -2005,7 +2326,7 @@ function volume_helper(no)
% Remap according to indexed grayscape
% Unless:
% An external colormap has been supplied, then use that.
-% This is used to force truecolor grayscale, by passing
+% This is used to force truecolor grayscale, by passing
% true to RETURNMAPPING.
% c,b are contrast/brightness settings, used by contrast_Callback when
% doing realtime update during mouse motion.
@@ -2035,7 +2356,7 @@ function volume_helper(no)
b = SET(no).IntensityMapping.Brightness;
if isempty(c)
c = SET(SET(no).Parent).IntensityMapping.Contrast;
- b = SET(SET(no).Parent).IntensityMapping.Brightness;
+ b = SET(SET(no).Parent).IntensityMapping.Brightness;
end
end
@@ -2054,7 +2375,7 @@ function volume_helper(no)
end
if isempty(d)
- d=1;
+ d=1;
end
if d<0.1
@@ -2070,59 +2391,59 @@ function volume_helper(no)
sz = [size(im,1) size(im,2) size(im,3) size(im,4)];
if isa(im,'single')||isa(im,'double')
%im = c*im(:)+(b-0.5);
-% try
-if d~=1
- try
- im = c.*nthroot(im(:),d)+b-0.5;
- catch
+ % try
+ if d~=1
+ try
+ im = c.*nthroot(im(:),d)+b-0.5;
+ catch
+ im = c.*im(:)+b-0.5;
+ end
+ else
im = c.*im(:)+b-0.5;
- end
-else
- im = c.*im(:)+b-0.5;
-end%c*255.*(im(:)./255+b-0.5).^(1./d);
-% catch
-% %first lift im so that it is between 0 and 1
-% im=abs(min(im(:)))+im;
-% im = c.*nthroot(im(:),d)+b-0.5;%c*255.*(im(:)./255+b-0.5).^(1./d);
-% end
+ end%c*255.*(im(:)./255+b-0.5).^(1./d);
+ % catch
+ % %first lift im so that it is between 0 and 1
+ % im=abs(min(im(:)))+im;
+ % im = c.*nthroot(im(:),d)+b-0.5;%c*255.*(im(:)./255+b-0.5).^(1./d);
+ % end
z = max(min(round(cmax*im),cmax),cmin);
-elseif isa(im,'int16'),
+elseif isa(im,'int16')
if ~isfield(SET(no),'minValue')||isempty(SET(no).minValue)||...
~isfield(SET(no),'maxValue')||isempty(SET(no).maxValue)
SET(no).minValue = single(min(SET(no).IM(:)));
SET(no).maxValue = single(max(SET(no).IM(:)));
end
- mi = SET(no).minValue;
- ma = SET(no).maxValue;
-
- im = single(im(:));
- %im=c*im+(b-0.5);%TODO: should scale
-
- z = floor((im-mi)/(ma-mi)*cmax);
- if d~=1
- z = uint8(c.*nthroot(z(:),d)+b-0.5)+1;%uint8(c*z+(b-0.5)*256)+1; %
- else
- z = uint8(c.*z(:)+b-0.5)+1;
- end;
- %z = max(min(round(c*z+(b-0.5)),cmax),cmin);
+ mi = SET(no).minValue;
+ ma = SET(no).maxValue;
+
+ im = single(im(:));
+ %im=c*im+(b-0.5);%TODO: should scale
+
+ z = floor((im-mi)/(ma-mi)*cmax);
+ if d~=1
+ z = uint8(single(c).*nthroot(z(:),d)+single(b)-0.5)+1;%uint8(c*z+(b-0.5)*256)+1; %
+ else
+ z = uint8(single(c).*z(:)+single(b)-0.5)+1;
+ end
+ %z = max(min(round(c*z+(b-0.5)),cmax),cmin);
else
myfailed(dprintf('Segment does not (yet) support type:%s',class(im)));
return;
end
if (size(cmap,2) == 3)
- % Extract r,g,b components
- z3 = repmat(uint8(0),[size(z) 3]);
- z3(:,1) = cmap(z,1);
- z3(:,2) = cmap(z,2);
- z3(:,3) = cmap(z,3);
- z = reshape(z3,[sz 3]);
+ % Extract r,g,b components
+ z3 = repmat(uint8(0),[size(z) 3]);
+ z3(:,1) = cmap(z,1);
+ z3(:,2) = cmap(z,2);
+ z3(:,3) = cmap(z,3);
+ z = reshape(z3,[sz 3]);
else
- %Index color
- z3 = repmat(uint8(0),size(z));
- z3(:) = cmap(z(:),1);
- z = reshape(z3,sz);
+ %Index color
+ z3 = repmat(uint8(0),size(z));
+ z3(:) = cmap(z(:),1);
+ z = reshape(z3,sz);
end
%-------------------------------------------------------------------
@@ -2130,7 +2451,7 @@ function volume_helper(no)
%-------------------------------------------------------------------
%General helper fcn to resample a closed curve.
if nargin<4
- method='linear';%used to be linear*
+ method='linear';%used to be linear*
distributed = 'same';
end
if nargin < 5
@@ -2144,7 +2465,7 @@ function volume_helper(no)
ynew = interp1(y,linspace(1,size(y,1),n),method);
case 'evenly'
- %Remve duplicate points
+ %Remve duplicate points
d = [0;cumsum(sqrt(diff(x).^2+diff(y).^2))];
ind = [1;diff(d)]>1e-3;
uniquex = x(ind);
@@ -2181,17 +2502,17 @@ function volume_helper(no)
%to different number of points (n).
if nargin<4
- method='linear';%used to be linear*
+ method='linear';%used to be linear*
distributed = 'same';
end
-if nargin < 5
+if nargin < 5
distributed = 'same';
end
xnew = nan(n,size(x,2),size(x,3));
ynew = xnew;
-for zloop=1:size(x,3)
+for zloop=1:size(x,3)
for tloop=1:size(x,2)
if not(isnan(x(1,tloop,zloop)))
[tempx,tempy] = resampleclosedcurve(...
@@ -2200,16 +2521,16 @@ function volume_helper(no)
xnew(:,tloop,zloop) = tempx;
ynew(:,tloop,zloop) = tempy;
end
- end;
-end;
+ end
+end
+
-
%--------------------------------------------------------------------------
function [meanint,defectextent,varargout] = calcintensityanddefect(im,...
tf,numpoints,numsectors,nprofiles,pos, ...
no,endox,endoy,epix,epiy,sz,resolution,defect,numwidth,timeresolved) %#ok
%--------------------------------------------------------------------------
-%Calculates the mean intensity within sectors as a preperation to
+%Calculates the mean intensity within sectors as a preperation to
%generate a bullseye plot.
%
%-im image
@@ -2222,7 +2543,7 @@ function volume_helper(no)
%sz: size of image stack
%resolution: resolution of image stack
%defect: (EH: I do not know what it is, works if empty)
-%numwidth: specify if it should calculate several sectors across
+%numwidth: specify if it should calculate several sectors across
% wallthickness. If a scalar it
% specifices the number of
% layers in the myocardium. If a
@@ -2251,13 +2572,13 @@ function volume_helper(no)
numslices = length(pos);
meanint = zeros(numsectors,numslices);
-%Added EH: If numwidth is a vector then it is interpreted as
+%Added EH: If numwidth is a vector then it is interpreted as
%[perencentendo percent epi].
if length(numwidth)>1
numlayers = length(numwidth)-1;
else
numlayers = numwidth;
-end;
+end
%Check if we should return the mask and the sectors
if nargout>2
@@ -2265,13 +2586,13 @@ function volume_helper(no)
maskcell = cell(numslices,numsectors,numlayers);
else
storemask = false;
-end;
+end
if nargout>3
storesector = true;
sectorcell = cell(numslices,numsectors,numlayers,2);
else
storesector = false;
-end;
+end
%Upsample model
if not(nprofiles == size(endox,1))
@@ -2282,14 +2603,14 @@ function volume_helper(no)
mask = zeros(sz(1),sz(2));
defectextent = zeros(numsectors,numslices);
for sloop = 1:numslices
- if not(isnan(epix(1,tf,pos(sloop))))
-
+ if not(isempty(epix)) && not(isnan(epix(1,tf,pos(sloop))))
+
%Find sectors
[~,~,episectors] = findmeaninsectorslice('epi',numpoints,tf,pos(sloop),numsectors,no, ...
endox(:,tf,pos(sloop)),endoy(:,tf,pos(sloop)),epix(:,tf,pos(sloop)),epiy(:,tf,pos(sloop)));
if not(isnan(endox(1,tf,pos(sloop))))
- [~,~,endosectors] = findmeaninsectorslice('endo',numpoints,tf,pos(sloop),numsectors,no, ...
- endox(:,tf,pos(sloop)),endoy(:,tf,pos(sloop)),epix(:,tf,pos(sloop)),epiy(:,tf,pos(sloop)));
+ [~,~,endosectors] = findmeaninsectorslice('endo',numpoints,tf,pos(sloop),numsectors,no, ...
+ endox(:,tf,pos(sloop)),endoy(:,tf,pos(sloop)),epix(:,tf,pos(sloop)),epiy(:,tf,pos(sloop)));
else
endosectors = episectors;
end
@@ -2298,7 +2619,7 @@ function volume_helper(no)
xdiffslice = abs(endox(:,tf,pos(sloop))-epix(:,tf,pos(sloop)));
ydiffslice = abs(endoy(:,tf,pos(sloop))-epiy(:,tf,pos(sloop)));
wallthicknessinslice = mean(sqrt((xdiffslice*resolution(1)).^2+(ydiffslice*resolution(2)).^2));
-
+
N = nprofiles;
for loop=1:numsectors
if episectors(loop)
+warning off;
for tloop=1:numtf
for zloop=1:nslices
for loop=1:numsectors
@@ -2646,27 +2967,27 @@ function volume_helper(no)
idx = [...
sectors(loop,zloop,tloop):(numpoints-1) ...
1:sectors(loop+1,zloop,tloop)];
- end;
+ end
res(loop,zloop,tloop) = mean(inp(idx,tloop,pos(zloop)));
maxres(loop,zloop,tloop) = max(inp(idx,tloop,pos(zloop)));
- end;
- end;
-end;
+ end
+ end
+end
warning(warnstat);
varargout = cell(1,nargout-1);
if nargout>=2
varargout{1} = meanx;
-end;
+end
if nargout>=3
varargout{2} = meany;
-end;
+end
if nargout>=4
varargout{3} = sectors;
-end;
+end
if nargout>=5
varargout{4} = maxres;
-end;
+end
%--------------------------------------------------------------------------
function [varargout] = findmeaninsectorslice(type,numpoints,tf,slice,...
@@ -2679,11 +3000,11 @@ function volume_helper(no)
if nargin<5
numsectors = 6;
-end;
+end
if nargin<6
no = NO;
-end;
+end
if nargin < 7 || (nargin==11 && isempty(endox))
if ~isempty(SET(no).EndoX)
@@ -2710,7 +3031,7 @@ function volume_helper(no)
isendo=1;
else
isendo=0;
-end;
+end
%Upsample model
if not(numpoints==DATA.NumPoints)
@@ -2719,13 +3040,13 @@ function volume_helper(no)
else
endox = nan(numpoints,length(tf),length(slice));
endoy = endox;
- end;
+ end
if ~isempty(epix)
[epix,epiy] = resamplemodel(epix,epiy,numpoints);
else
epix = nan(numpoints,length(tf),length(slice));
- epiy = epix;
- end;
+ epiy = epix;
+ end
end
%Find center
@@ -2735,7 +3056,7 @@ function volume_helper(no)
else
x = mean(epix);
y = mean(epiy);
-end;
+end
meanx = mean(x(:));
meany = mean(y(:));
@@ -2749,7 +3070,7 @@ function volume_helper(no)
ang = angle(complex(...
epiy(1:(end-1))-meany,...
epix(1:(end-1))-meanx));
-end;
+end
ang = ang*180/pi;
wantangles = linspace(-180,180,numsectors+1);
wantangles = wantangles+rotation;
@@ -2761,24 +3082,24 @@ function volume_helper(no)
if trash2=1
varargout{1} = meanx;
-end;
+end
if nargout>=2
varargout{2} = meany;
-end;
+end
if nargout>=3
varargout{3} = sectors;
-end;
+end
%-----------------------------------------------------------------------
function [pos,xdir,ydir,zdir] = getimageposandorientation(no,slice,type)
@@ -2790,9 +3111,9 @@ function volume_helper(no)
if nargin < 3
type = 'one';
end
-if nargin<2
+if nargin < 2 || isempty(slice)
slice = SET(no).CurrentSlice;
-end;
+end
if SET(no).Rotated
%Rotated
@@ -2800,18 +3121,18 @@ function volume_helper(no)
rotdir = SET(no).ImageOrientation(4:6);
r1dir = SET(no).ImageOrientation(1:3);
r2dir = cross(rotdir,r1dir);
-
+
%Calculate radius to center
radius = SET(no).RotationCenter*SET(no).ResolutionY;
-
+
%Calculate center of rotation
center = pos+radius*r1dir;
-
+
alpha = (pi/(SET(no).ZSize))*(slice-1);
pos = center+(...
radius*cos(alpha)*r1dir-...
radius*sin(alpha)*r2dir);
-
+
%Find orientation
xdir = rotdir;
ydir = -(pos-center); %new position - center of rotation
@@ -2820,9 +3141,8 @@ function volume_helper(no)
else
%Normal cartesian coordinates
xdir = SET(no).ImageOrientation(4:6);
- ydir = SET(no).ImageOrientation(1:3);
+ ydir = SET(no).ImageOrientation(1:3);
zdir = cross(ydir,xdir);
-
if strcmp(type,'hla')
temp = xdir;
@@ -2853,12 +3173,12 @@ function volume_helper(no)
pos = SET(no).ImagePosition-...
zdir*(SET(no).SliceThickness+SET(no).SliceGap)*(slice-1);
-% %for multiple slices (future improvement)
-% pos = repmat(SET(no).ImagePosition,length(slice),1)-...
-% (diag(zdir*(SET(no).SliceThickness+SET(no).SliceGap))*repmat(slice-1,3,1))';
+ % %for multiple slices (future improvement)
+ % pos = repmat(SET(no).ImagePosition,length(slice),1)-...
+ % (diag(zdir*(SET(no).SliceThickness+SET(no).SliceGap))*repmat(slice-1,3,1))';
end
-end;
+end
%------------------------
function z = econvn(im,f)
@@ -2868,24 +3188,24 @@ function volume_helper(no)
case 4
z = im;
if size(im,3)~=1
- for loop=1:size(im,4);
+ for loop=1:size(im,4)
z(:,:,:,loop) = econv3(im(:,:,:,loop),f);
- end;
+ end
else
- for loop=1:size(im,4);
+ for loop=1:size(im,4)
z(:,:,1,loop) = conv2(im(:,:,:,loop),f,'same');
- end;
- end;
+ end
+ end
case 3
z = econv3(im,f);
case 2
z = conv2(im,f,'same');
otherwise
error('Number of dimensions not supported.');
-end;
+end
%---------------------------------------
-function [pos] = rlapfh2xyz(no,rl,ap,fh)
+function [pos] = rlapfh2xyz(no,rl,ap,fh) %#ok
%---------------------------------------
%Convert from RL,AP,FH coordinates to Segment internal coordinate system.
global DATA SET
@@ -2894,10 +3214,10 @@ function volume_helper(no)
myfailed('Not yet implemented for rotated image stacks.',DATA.GUI.Segment);
else
xdir = SET(no).ImageOrientation(4:6)';
- ydir = SET(no).ImageOrientation(1:3)';
+ ydir = SET(no).ImageOrientation(1:3)';
zdir = cross(...
SET(no).ImageOrientation(1:3),...
- SET(no).ImageOrientation(4:6))';
+ SET(no).ImageOrientation(4:6))';
rl = rl(:)'-SET(no).ImagePosition(1); %Translate corner of box to 0,0,0
ap = ap(:)'-SET(no).ImagePosition(2);
@@ -2906,31 +3226,32 @@ function volume_helper(no)
pos = [xdir ydir -zdir]\[rl;ap;fh];
pos(1,:) = pos(1,:)/SET(no).ResolutionX+1;
pos(2,:) = pos(2,:)/SET(no).ResolutionY+1;
- pos(3,:) = pos(3,:)/(SET(no).SliceGap+SET(no).SliceThickness)+1;
+ pos(3,:) = pos(3,:)/(SET(no).SliceGap+SET(no).SliceThickness)+1;
-end;
+end
%------------------------------------
function [pos] = xyz2rlapfh(no,x,y,z)
%------------------------------------
%Converts from segment coordinate system to RL,AP,FH coordinate system.
-global DATA SET
+global SET
if SET(no).Rotated
pos = [];
- myfailed('Not yet implemented for rotated image stacks.',DATA.GUI.Segment);
+ myfailed('Not yet implemented for rotated image stacks.')%,DATA.GUI.Segment);
else
zdir = cross(...
SET(no).ImageOrientation(1:3),...
- SET(no).ImageOrientation(4:6));
+ SET(no).ImageOrientation(4:6));
+
x = (x(:)-1)*SET(no).ResolutionX;
y = (y(:)-1)*SET(no).ResolutionY;
z = (z(:)-1)*(SET(no).SliceThickness+SET(no).SliceGap);
- pos = repmat(SET(no).ImagePosition,length(x),1)+...
- repmat(SET(no).ImageOrientation(4:6),length(x),1).*repmat(x,1,3)+...
- repmat(SET(no).ImageOrientation(1:3),length(x),1).*repmat(y,1,3)-... %was minus
- repmat(zdir,length(x),1).*repmat(z,1,3);
-end;
+ pos = SET(no).ImagePosition +...
+ SET(no).ImageOrientation(4:6).*x+...
+ SET(no).ImageOrientation(1:3).*y-... %was minus
+ zdir.*z;
+end
%-------------------------------------
function [impos,ormat] = calcormat(no) %#ok
@@ -2948,7 +3269,7 @@ function volume_helper(no)
cross(SET(no).ImageOrientation(4:6),SET(no).ImageOrientation(1:3))'];
%------------------------------------------------------------------
-function [x,y,z] = cyl2cart(xin,yin,slice,numslices,rotationcenter)
+function [x,y,z] = cyl2cart(xin,yin,slice,numslices,rotationcenter) %#ok
%------------------------------------------------------------------
%Convert from cylindrical to cartesian coordinates
@@ -2959,7 +3280,7 @@ function volume_helper(no)
y = rad.*cos(angle)+rotationcenter;
%--------------------------------------------------------
-function [window,level] = con2win(contrast,brightness,no)
+function [window,level] = con2win(contrast,brightness,no) %#ok
%--------------------------------------------------------
%Convert from contrast to window & level
@@ -2984,7 +3305,7 @@ function volume_helper(no)
end
%--------------------------------------------------------
-function [contrast,brightness] = win2con(window,level,no)
+function [contrast,brightness] = win2con(window,level,no) %#ok
%--------------------------------------------------------
%Inverse of con2win
@@ -3016,7 +3337,7 @@ function volume_helper(no)
(xi-SET(no).GLA.x0)*sin(ang)*SET(no).ResolutionX);
%-----------------------------------
-function [x,y,z] = gla2sax(xi,yi,no)
+function [x,y,z] = gla2sax(xi,yi,no) %#ok
%-----------------------------------
%Convert image coordinates from GLA to short-axis view
global SET
@@ -3026,11 +3347,10 @@ function volume_helper(no)
x = SET(no).GLA.x0 + sin(SET(no).GLA.angle)*yi*res/SET(no).ResolutionX;
y = SET(no).GLA.y0 + cos(SET(no).GLA.angle)*yi*res/SET(no).ResolutionY;
-
%-------------------------------------------
-function [mantelarea, sliceMantelArea] = calcmantelarea(no)
+function [mantelarea, sliceMantelArea] = calcmantelarea(no) %#ok
%-------------------------------------------
-%Calculate the mantel area in cm^2 of the LV endocardium in each timeframe.
+%Calculate the mantel area in cm^2 of the LV endocardium in each timeframe.
global SET
if sum(findfunctions('findslicewithendo',no))==0
@@ -3054,6 +3374,90 @@ function volume_helper(no)
sliceMantelArea=mantelarea';
mantelarea=sum(mantelarea,2)';
+%--------------------
+function calcflowinroi(no) %#ok
+%--------------------
+%calculates flow from current ROI
+global SET
+
+nom = SET(no).Flow.MagnitudeNo;
+nop = SET(nom).Flow.PhaseNo;
+
+warnedempty = false;
+outsize = [SET(nom).XSize SET(nom).YSize];
+roinbr = SET(nom).RoiCurrent;
+
+if length(SET(nom).Roi(roinbr).T)==1 %For non-time resolved Phase Contrast images
+ SET(nom).TIncr=1;
+end
+mask = false([SET(nom).XSize SET(nom).YSize SET(nom).Roi(roinbr).T]);
+%create mask for all time frames
+for tloop = SET(nom).Roi(roinbr).T
+ %Create mask
+ tempmask = logical(segment('createmask',...
+ outsize,...
+ SET(nom).Roi(roinbr).Y(:,tloop),...
+ SET(nom).Roi(roinbr).X(:,tloop)));
+ mask(:,:,tloop) = tempmask;
+end
+%Extract phase image
+phasedata = SET(nop).IM(:,:,:,SET(nom).Roi(roinbr).Z);
+
+%If empty phasecorr, the do not add phase correction.
+if isempty(SET(nop).Flow.PhaseCorr)
+ veldata = SET(nom).Roi(roinbr).Sign*...
+ (phasedata-0.5)*2*SET(nop).VENC;
+else
+ %Phase correction
+ if SET(nop).Flow.PhaseCorrTimeResolved
+ %Time resolved phase correction
+ veldata = SET(nom).Roi(roinbr).Sign*...
+ (phasedata-0.5-SET(nop).Flow.PhaseCorr(:,:,:,SET(nom).Roi(roinbr).Z))*2*SET(nop).VENC;
+ else
+ %Stationary phase correction
+ phasecorr = squeeze(SET(nop).Flow.PhaseCorr(:,:,1,SET(nom).Roi(roinbr).Z));
+ correctiondata = repmat(phasecorr,[1 1 SET(nom).Roi(roinbr).T 1]);
+ veldata = SET(nom).Roi(roinbr).Sign*...
+ (phasedata-0.5-correctiondata)*2*SET(nop).VENC;
+ end
+end
+
+veldata = veldata(mask);
+if isempty(veldata)
+ veldata = nan;
+ posveldata = nan;
+ negveldata = nan;
+else
+ posveldata = veldata(veldata>0);
+ negveldata = veldata(veldata<0);
+end
+
+SET(nom).Flow.Result(roinbr).velmean(:) = squeeze(mean(veldata,[1 2]));
+SET(nom).Flow.Result(roinbr).velstd(:) = squeeze(std(veldata,0,[1 2]));
+SET(nom).Flow.Result(roinbr).velmax(:) = squeeze(max(veldata,[],[1 2]));
+SET(nom).Flow.Result(roinbr).velmin(:) = squeeze(min(veldata,[],[1 2]));
+SET(nom).Flow.Result(roinbr).kenergy(:) = squeeze(sum((veldata/100).^3/2*(SET(nom).ResolutionX*SET(nom).ResolutionY/1e6)*1060, [1 2])); %kg/m^3
+SET(nom).Flow.Result(roinbr).area(:) = SET(nom).ResolutionX*SET(nom).ResolutionY*squeeze(sum(mask, [1 2]))/100; %cm^2
+% % SET(nom).Flow.Result(roinbr).netflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(veldata); %cm^3
+% % SET(nom).Flow.Result(roinbr).posflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(posveldata); %cm^3
+% % SET(nom).Flow.Result(roinbr).negflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(negveldata); %cm^3
+
+%Add flow results to regular Roi areas
+% % SET(nom).Roi(roinbr).Area = SET(nom).Flow.Result(roinbr).area;
+% %
+% % SET(nom).Flow.Result(roinbr).diameter = NaN;
+% % hr = (60/(SET(nom).TSize*SET(nom).TIncr));
+% %
+% % netflow = SET(nom).Flow.Result(roinbr).netflow;
+% % timeframes = SET(nom).Roi(roinbr).T;%1:SET(nom).TSize;
+% % TIncr = SET(nom).TIncr;
+% %
+% % %Sum
+% % SET(nom).Flow.Result(roinbr).nettotvol = nansum(netflow(timeframes))*TIncr;
+% % SET(nom).Flow.Result(roinbr).netforwardvol = nansum(netflow(timeframes).*(netflow(timeframes)>0))*TIncr;
+% % SET(nom).Flow.Result(roinbr).netbackwardvol = nansum(netflow(timeframes).*(netflow(timeframes)<0))*TIncr;
+% % SET(nom).Flow.Result(roinbr).regfrac = abs(100*SET(nom).Flow.Result(roinbr).netbackwardvol/SET(nom).Flow.Result(roinbr).netforwardvol);
+% % SET(nom).Flow.Result(roinbr).sv = SET(nom).Flow.Result(roinbr).nettotvol/hr*60;
%--------------------
function calcflow(no) %#ok
@@ -3068,12 +3472,39 @@ function calcflow(no) %#ok
warnedempty = false;
outsize = [SET(nom).XSize SET(nom).YSize];
roinbr = SET(nom).RoiCurrent;
+if isempty(roinbr)
+ myfailed('No ROIs available.',DATA.GUI.Segment);
+ return
+end
-if length(SET(nom).Roi(roinbr).T)==1 %For non-time resolved Phase Contrast images
- SET(nom).TIncr=1;
+if DATA.DoThisFrameOnly
+ tvec = SET(nom).CurrentTimeFrame;
+else
+ tvec = SET(nom).Roi(roinbr).T;
end
-for tloop = SET(nom).Roi(roinbr).T
+numtimeframes = length(SET(nom).Roi(roinbr).T);
+if (numtimeframes - sum(isnan(SET(nom).Roi(roinbr).Mean))) == 1 %ROI is drawn in only one time frame
+ if numtimeframes == 1 %For non-time resolved Phase Contrast images
+ SET(nom).TIncr=1; %Continue to flow calculation based on only one time frame
+ else
+ %Skip flow calculation since the ROI is drawn in only one time frame
+ return
+ end
+end
+%initialize with NaN
+% initvalues = nan(1,SET(nom).TSize);
+% SET(nom).Flow.Result(roinbr).velmean = initvalues;
+% SET(nom).Flow.Result(roinbr).velstd = initvalues;
+% SET(nom).Flow.Result(roinbr).velmax = initvalues;
+% SET(nom).Flow.Result(roinbr).velmin = initvalues;
+% SET(nom).Flow.Result(roinbr).kenergy = initvalues;
+% SET(nom).Flow.Result(roinbr).area = initvalues;
+% SET(nom).Flow.Result(roinbr).netflow = initvalues;
+% SET(nom).Flow.Result(roinbr).posflow = initvalues;
+% SET(nom).Flow.Result(roinbr).negflow = initvalues;
+
+for tloop = tvec
%Create mask
mask = logical(segment('createmask',...
outsize,...
@@ -3097,35 +3528,50 @@ function calcflow(no) %#ok
%Stationary phase correction
veldata = SET(nom).Roi(roinbr).Sign*...
(temp-0.5-SET(nop).Flow.PhaseCorr(:,:,1,SET(nom).Roi(roinbr).Z))*2*SET(nop).VENC;
- end;
- end;
+ end
+ end
veldata = veldata(mask);
if isempty(veldata)
- if not(warnedempty)
- mywarning('Empty ROI detected. Should not occur.',DATA.GUI.Segment);
- end;
- warnedempty = true;
+ veldata = nan;
+ posveldata = nan;
+ negveldata = nan;
else
posveldata = veldata(veldata>0);
negveldata = veldata(veldata<0);
- SET(nom).Flow.Result(roinbr).velmean(tloop) = mean(veldata);
- SET(nom).Flow.Result(roinbr).velstd(tloop) = std(veldata);
- SET(nom).Flow.Result(roinbr).velmax(tloop) = max(veldata);
- SET(nom).Flow.Result(roinbr).velmin(tloop) = min(veldata);
- SET(nom).Flow.Result(roinbr).kenergy(tloop) = sum((veldata/100).^3/2*(SET(nom).ResolutionX*SET(nom).ResolutionY/1e6)*1060); %kg/m^3
- SET(nom).Flow.Result(roinbr).area(tloop) = SET(nom).ResolutionX*SET(nom).ResolutionY*sum(mask(:))/100; %cm^2
- SET(nom).Flow.Result(roinbr).netflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(veldata); %cm^3
- SET(nom).Flow.Result(roinbr).posflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(posveldata); %cm^3
- SET(nom).Flow.Result(roinbr).negflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(negveldata); %cm^3
- end;
-end;
+ end
+ % if isempty(veldata)
+ % if not(warnedempty)
+ % mywarning('Empty ROI detected. Should not occur.',DATA.GUI.Segment);
+ % end
+ % warnedempty = true;
+ % else
+ %posveldata = veldata(veldata>0);
+ %negveldata = veldata(veldata<0);
+ SET(nom).Flow.Result(roinbr).velmean(tloop) = mean(veldata);
+ SET(nom).Flow.Result(roinbr).velstd(tloop) = std(veldata);
+ SET(nom).Flow.Result(roinbr).velmax(tloop) = max(veldata);
+ SET(nom).Flow.Result(roinbr).velmin(tloop) = min(veldata);
+ SET(nom).Flow.Result(roinbr).kenergy(tloop) = sum((veldata/100).^3/2*(SET(nom).ResolutionX*SET(nom).ResolutionY/1e6)*1060); %kg/m^3
+ SET(nom).Flow.Result(roinbr).area(tloop) = SET(nom).ResolutionX*SET(nom).ResolutionY*sum(mask(:))/100; %cm^2
+ SET(nom).Flow.Result(roinbr).netflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(veldata); %cm^3
+ SET(nom).Flow.Result(roinbr).posflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(posveldata); %cm^3
+ SET(nom).Flow.Result(roinbr).negflow(tloop) = (10/1000)*SET(nom).ResolutionX*SET(nom).ResolutionY*sum(negveldata); %cm^3
+ % end
+ %Add flow results to regular Roi areas
+ SET(nom).Roi(roinbr).Area(tloop) = SET(nom).Flow.Result(roinbr).area(tloop);
+end
+
+% %Add flow results to regular Roi areas
+% SET(nom).Roi(roinbr).Area = SET(nom).Flow.Result(roinbr).area;
+
SET(nom).Flow.Result(roinbr).diameter = NaN;
hr = (60/(SET(nom).TSize*SET(nom).TIncr));
netflow = SET(nom).Flow.Result(roinbr).netflow;
timeframes = SET(nom).Roi(roinbr).T;%1:SET(nom).TSize;
TIncr = SET(nom).TIncr;
+
%Sum
SET(nom).Flow.Result(roinbr).nettotvol = nansum(netflow(timeframes))*TIncr;
SET(nom).Flow.Result(roinbr).netforwardvol = nansum(netflow(timeframes).*(netflow(timeframes)>0))*TIncr;
@@ -3151,7 +3597,9 @@ function clearflow(no,roinbr) %#ok
if length(SET(no).Flow.Result) == 1
clearallflow(no);
else
- SET(no).Flow.Result(roinbr) = [];
+ if ~(length(SET(no).Flow.Result)< roinbr)
+ SET(no).Flow.Result(roinbr) = [];
+ end
end
end
end
@@ -3159,7 +3607,7 @@ function clearflow(no,roinbr) %#ok
%------------------------
-function clearallflow(no)
+function clearallflow(no)
%------------------------
%clear all ROI flow from no
global SET
@@ -3171,3 +3619,502 @@ function clearallflow(no)
if ~isempty(SET(no).Flow)
SET(no).Flow.Result = [];
end
+
+%-------------------------------------------
+function varargout = calclvvolumeAVPD(no,docomp)
+%-------------------------------------------
+% this function is the old version of calclvvolume that is used on github
+% and is needed for AVPD calculation
+%Calculate LV volume. Docomp if to use longaxis motion, see below.
+%Uses area*(thickness+slicedist)
+%NOTE: the exported LVM do NOT include Papillary volume (PV)
+
+global DATA SET
+
+if nargin<2
+ docomp=true;
+elseif SET(no).Longaxis > 1%SET(NO).Longaxis > 1
+ docomp = true;
+end
+
+if SET(no).Rotated
+ calclvvolumepolar(no);
+ return;
+end
+
+ind = (findfunctions('findslicewithendo',no))|(findfunctions('findslicewithepi',no)); %Accepts empty endo and epi if exist
+
+if ~any(ind)
+ SET(no).LVV = nan(1,SET(no).TSize);
+ SET(no).EPV = SET(no).LVV;
+ SET(no).LVM = SET(no).LVV;
+ SET(no).PV = zeros(size(SET(no).LVV));
+ SET(no).PFR = 0;
+ SET(no).PER = 0;
+ SET(no).PFRT = 1;
+ SET(no).PERT = 1;
+ SET(no).ESV = 0;
+ SET(no).EDV = 0;
+ SET(no).EF = 0;
+ SET(no).SV = 0;
+ if nargout>0
+ varargout = cell(1,1);
+ varargout{1} = [];
+ end
+ if nargout>1
+ varargout{2} = [];
+ end
+ return;
+end
+
+%Find what slices to do
+if SET(no).ZSize>1
+ pos = find(ind);
+else
+ pos = 1;
+end
+LVVall = zeros(length(pos),SET(no).TSize);
+EPVall = zeros(length(pos),SET(no).TSize);
+
+% if isempty(SET(no).EndoX)
+% %This far then create
+% SET(no).EndoX = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% SET(no).EndoY = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% end;
+%
+% if isempty(SET(no).EpiX)
+% %This far then create
+% SET(no).EpiX = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% SET(no).EpiY = nan(DATA.NumPoints,SET(no).TSize,SET(no).ZSize);
+% end;
+
+%Loop over all segmented slices
+for sloop=1:length(pos)
+ for tloop=1:SET(no).TSize
+ if ~isempty(SET(no).EndoX)&&~isnan(SET(no).EndoX(1,tloop,pos(sloop)))
+ A = stablepolyarea(...
+ SET(no).ResolutionY*SET(no).EndoY(1:end-1,tloop,pos(sloop)),...
+ SET(no).ResolutionX*SET(no).EndoX(1:end-1,tloop,pos(sloop)));
+ LVVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000; %to cm3
+ end
+ if ~isempty(SET(no).EpiX)&&~isnan(SET(no).EpiX(1,tloop,pos(sloop)))
+ A = stablepolyarea(...
+ SET(no).ResolutionY*SET(no).EpiY(1:end-1,tloop,pos(sloop)),...
+ SET(no).ResolutionX*SET(no).EpiX(1:end-1,tloop,pos(sloop)));
+ EPVall(sloop,tloop)=A*(SET(no).SliceThickness+SET(no).SliceGap)/1000; %to cm3
+ end
+ end
+end
+
+%Sum to get total volume
+if length(pos)>1
+ SET(no).LVV = sum(LVVall);
+ SET(no).EPV = sum(EPVall);
+else
+ SET(no).LVV = LVVall;
+ SET(no).EPV = EPVall;
+end
+SET(no).LVM = SET(no).EPV-SET(no).LVV+SET(no).PV;
+
+if nargout>0
+ varargout = cell(1,1);
+ varargout{1} = LVVall;
+end
+
+if nargout>1
+ varargout{2} = EPVall;
+end
+
+if nargout>2
+ varargout{3} = 1.05*(EPVall-LVVall); %LVM in g, NOTE not include Papillary volume (PV)
+end
+
+%Update EDV,ESV
+SET(no).EDV = SET(no).LVV(SET(no).EDT);
+if ~isequal(SET(no).EDT,SET(no).EST)
+ SET(no).ESV = SET(no).LVV(SET(no).EST);
+else
+ SET(no).ESV = NaN;
+end
+
+if (SET(no).ZSize>2)&&docomp
+ LVVnocomp = SET(no).LVV;
+ EPVnocomp = SET(no).EPV;
+
+ for rloop=1:1 %Converges very quickly
+
+ %Calculate compensation mechanism
+ if (SET(no).LVV(SET(no).EDT)-SET(no).LVV(SET(no).EST)~=0)
+ pp = SET(no).LVV;
+ pp = pp-SET(no).LVV(SET(no).EST);
+ pp = pp./(SET(no).LVV(SET(no).EDT)-SET(no).LVV(SET(no).EST));
+ pp = 1-pp;
+ pp = min(max(pp,0),1);
+ else
+ pp = ones(size(SET(no).LVV));
+ end
+ err = zeros(1,20);
+
+ %Compensate
+ %pp = pp.*pp;
+
+ %Check if autodetect
+ if SET(no).AutoLongaxis
+ for loop=1:20
+
+ %Calculate slices
+ slices = (loop-1); %Convert to mm
+ slices = slices/(SET(no).SliceThickness+SET(no).SliceGap); %Convert to slices
+
+ sloop=1;
+ SET(no).LVV = LVVnocomp; %Restore
+ SET(no).EPV = EPVnocomp;
+ while (slices>0)&&(sloop 1mm between, first is zero
+ slices = (SET(no).Longaxis-1);
+ if isempty(slices)
+ slices = 0;
+ end
+ slices = slices/(SET(no).SliceThickness+SET(no).SliceGap);
+
+ %Compensate the last time, now store it!
+ sloop=1;
+ SET(no).LVV = LVVnocomp; %Restore
+ SET(no).EPV = EPVnocomp;
+
+ %Check if need to fix with outline
+ if ~isempty(SET(no).EndoX)
+ zloop = find(not(isnan(SET(no).EndoX(1,SET(no).CurrentTimeFrame,:))));
+ elseif ~isempty(SET(no).EpiX)
+ zloop = find(not(isnan(SET(no).EpiX(1,SET(no).CurrentTimeFrame,:))));
+ else
+ zloop = [];
+ end
+ if isempty(zloop)
+ slices = 0;
+ zloop = SET(no).CurrentSlice;
+ else
+ zloop = zloop(1);
+ end
+
+ %Make sure that it is updated
+ %if docomp
+ % updatemodeldisplay;
+ %end;
+
+ while (slices>0)&&(sloop<=size(LVVall,1))
+ %Remove whole slice or fraction of it.
+ SET(no).LVV = SET(no).LVV-min(slices,1)*LVVall(sloop,:).*pp;
+ SET(no).EPV = SET(no).EPV-min(slices,1)*EPVall(sloop,:).*pp;
+
+ [xofs,yofs] = calcoffset(zloop,'montage');
+
+ %Need to fix with outline?
+ if 0%get(DATA.Handles.volumeoutlinecheckbox,'value')
+ for tloop=1:SET(no).TSize
+ if ~isempty(SET(no).EndoX)
+ SET(no).EndoXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ (SET(no).EndoX(:,tloop,zloop)-SET(no).CenterX)*(1-pp(tloop)*min(1,slices))+SET(no).CenterX+xofs;
+ SET(no).EndoYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ (SET(no).EndoY(:,tloop,zloop)-SET(no).CenterY)*(1-pp(tloop)*min(1,slices))+SET(no).CenterY+yofs;
+ end
+ if ~isempty(SET(no).EpiX)
+ SET(no).EpiXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ (SET(no).EpiX(:,tloop,zloop)-SET(no).CenterX)*(1-pp(tloop)*min(1,slices))+SET(no).CenterX+xofs;
+ SET(no).EpiYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ (SET(no).EpiY(:,tloop,zloop)-SET(no).CenterY)*(1-pp(tloop)*min(1,slices))+SET(no).CenterY+yofs;
+ end
+ end
+ else
+ for tloop=1:SET(no).TSize
+ if ~isempty(SET(no).EndoX)
+ SET(no).EndoXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ SET(no).EndoX(:,tloop,zloop)+xofs;
+ SET(no).EndoYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ SET(no).EndoY(:,tloop,zloop)+yofs;
+ end
+ if ~isempty(SET(no).EpiX)
+ SET(no).EpiXView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ SET(no).EpiX(:,tloop,zloop)+xofs;
+ SET(no).EpiYView((1+(zloop-1)*(DATA.NumPoints+1)):(zloop*(DATA.NumPoints+1)-1),tloop) = ...
+ SET(no).EpiY(:,tloop,zloop)+yofs;
+ end
+ end
+ end
+ zloop = zloop+1;
+ slices = slices-1;
+ sloop = sloop+1;
+ end
+ end %rloop
+
+ if DATA.Silent
+ return;
+ end
+
+ for loop=1:length(DATA.ViewPanels)
+ if isequal(no,DATA.ViewPanels(loop))
+ if 0%isequal(get(DATA.Handles.volumeoutlinecheckbox,'value'),1) &&...
+ ismember(DATA.ViewPanelsType{DATA.CurrentPanel},{'montage','montagerow','montagefit','sax3'})
+ set(DATA.Handles.endocontour(loop),'LineStyle',':');
+ set(DATA.Handles.epicontour(loop),'LineStyle',':');
+ else
+ set(DATA.Handles.endocontour(loop),'LineStyle','-');
+ set(DATA.Handles.epicontour(loop),'LineStyle','-');
+ end
+ end
+ end
+
+end %If docompensation
+
+%-------------------------------------------
+function [xofs,yofs] = calcoffsetmodified(z,cols,sz)
+%-------------------------------------------
+%Calculate offset required to plot coordinates in viewing mode specified by
+%type.
+%This is a copy of spect.spectperfusionsegmentation('calcoffset') in order
+%to avoid using spect package
+
+c = 1+mod(z-1,cols);
+r = ceil(z/cols);
+yofs = (c-1)*sz(2);
+xofs = (r-1)*sz(1);
+
+%-------------------------------
+function z = remapuint8modified(im,cmap) %#ok
+%-------------------------------
+%Remap from image data to true color using color lookup.
+%Function modified from calcufunctions.m to not be dependent on NO
+%This is a copy of spect.spectperfusionsegmentation('remapuint8') in order
+%to avoid using spect package
+
+warning off all;
+cmap = uint8(255*cmap);
+cmax = length(cmap);
+cmin = 1;
+
+sz = size(im);
+if isa(im,'single')||isa(im,'double')
+ z = max(min(round(cmax*im(:)),cmax),cmin);
+elseif isa(im,'int16')
+ mi = min(im(:));
+ ma = max(im(:));
+ im = single(im(:));
+ z = uint8(floor((im-mi)/(ma-mi)*256));
+ z = uint8(z)+1;
+else
+ myfailed(dprintf('Segment does not (yet) support type:%s',class(im)));
+end
+
+if (size(cmap,2)==3)
+ % Extract r,g,b components
+ z3 = repmat(uint8(0),[size(z) 3]);
+ z3(:,1) = cmap(z,1);
+ z3(:,2) = cmap(z,2);
+ z3(:,3) = cmap(z,3);
+ z = reshape(z3,[sz 3]);
+else
+ %Index color
+ z3 = repmat(uint8(0),size(z));
+ z3(:) = cmap(z(:),1);
+ z = reshape(z3,sz);
+end
+
+%----------------
+function colorname = rgb2colorshortname(rgbtripple) %#ok
+%----------------
+% function to get Matlab color short name from RGB tripplet
+num = bin2dec(num2str(rgbtripple));
+switch num
+ case 5
+ colorname = 'm'; % magenta
+ case 3
+ colorname = 'c'; % cyan
+ case 2
+ colorname = 'g'; % green
+ case 4
+ colorname = 'r'; % red
+ case 0
+ colorname = 'k'; % black
+ case 7
+ colorname = 'w'; % white
+ case 1
+ colorname = 'b'; % blue
+ otherwise
+ colorname = 'y';
+end
+
+%----------------
+function [interpX, interpY] = resetinterpolationpoints(type) %#ok
+%----------------
+% this function recalculates new coordinates for existing interpolation
+% points based on their distance to the new contour
+global SET NO
+no = NO;
+interpX = SET(no).([type,'InterpX']){SET(no).CurrentTimeFrame,SET(no).CurrentSlice};
+interpY = SET(no).([type,'InterpY']){SET(no).CurrentTimeFrame,SET(no).CurrentSlice};
+
+contourX = SET(no).([type,'X']){SET(no).CurrentTimeFrame,SET(no).CurrentSlice};
+contourY = SET(no).([type,'Y']){SET(no).CurrentTimeFrame,SET(no).CurrentSlice};
+
+for point = 1:length(interpX)
+ % calc distance
+ distx = min(contourX-interpX(point));
+ disty = min(contourY-interpY(point));
+ interpX(point) = interpX(point)-distx;
+end
+
+%----------------
+function updatemarandscar(no) %#ok
+%----------------
+% this function recalculates MaR and Scar if those exist
+global SET
+if not(isempty(SET(no).Scar))
+ %update scar calculation
+ viability('viabilitycalc');
+end
+if not(isempty(SET(no).MaR)) % redo MaR segmentation since LV was changed
+ if not(isempty(SET(no).MaR.MR.Artery))
+ t2wmarsegmentation('domarsegmentation_Callback');
+ else
+ mymsgbox('Set culprit artery and redo the automatic MaR')
+ mar('auto_Callback');
+ end
+end
+
+%----------------
+function d = calcdistpointoline(pt,xpoints,ypoints) %#ok
+%----------------
+% this function calculates distance from clicked point to a line give by
+% two points v1 and v2
+v1 = [xpoints(1) ypoints(1) 0];
+v2 = [xpoints(2) ypoints(2) 0];
+a = v1 - v2;
+b = pt - v2;
+d = norm(cross(a,b)) / norm(a);
+
+
+%----------------
+function [xpoints,ypoints] = calcpointsoutsideLV(xpoints,ypoints,no) %#ok
+%----------------
+% this function replaces RV endo points that lie inside LV with points that
+% are outside LV
+global SET
+% get current LV Epi data
+curtf = SET(no).CurrentTimeFrame;
+curslice = SET(no).CurrentSlice;
+if ~isempty(SET(no).EpiX) && ~isempty(SET(no).EpiY)
+ epix = SET(no).EpiX(:,curtf,curslice);
+ epiy = SET(no).EpiY(:,curtf,curslice);
+ if not(any(isnan(epix)) || any(isnan(epiy)))
+ % Here we slightly expand LV Epi contour used for calculation of
+ % the new point location so that RV Endo points are not exactly on
+ % the Epi contour but slightly outside (code borrowed from
+ % expand/contract function)
+ %f = 1.03;
+ f=1; %RV should lie on EPI-LV in septal part
+ sz = size(SET(no).EpiX,1);
+ mx = repmat(mean(epix),sz,1);
+ my = repmat(mean(epiy),sz,1);
+ epix = mx+f*(epix-mx);
+ epiy = my+f*(epiy-my);
+ % get cursor points inside and on LV epi
+ [inlvepi, onlvepi] = inpolygon(xpoints,ypoints,epix,epiy);
+ inlvepi = inlvepi + onlvepi;
+ if any(inlvepi)
+ % if there points inside, the replace them with LV Epi points with the
+ % shortest distance
+ for curpoint = 1:length(inlvepi) % go over all points
+ if inlvepi(curpoint)
+ % get index of the point that is closest to RV Endo in expanded
+ % Epi and replace the coordinates with this point
+ [~, ind] = findfunctions('dist2contour','Epi',no,xpoints(curpoint),ypoints(curpoint),curslice,curtf);
+ xpoints(curpoint) = epix(ind);
+ ypoints(curpoint) = epiy(ind);
+ end
+ end
+ end
+ end
+end
+
+%----------------
+function imP = imtopolar(imR, rMin, rMax, M, N) %#ok
+%----------------
+%IMTOPOLAR converts rectangular image to polar form. The output image is
+% an MxN image with M points along the r axis and N points along the theta
+% axis. The origin of the image is assumed to be at the center of the given
+% image. The image is assumed to be grayscale.
+% Bilinear interpolation is used to interpolate between points not exactly
+% in the image.
+%
+% rMin and rMax should be between 0 and 1 and rMin < rMax. r = 0 is the
+% center of the image and r = 1 is half the width or height of the image.
+%
+% V0.1 7 Dec 2007 (Created), Prakash Manandhar pmanandhar@umassd.edu
+
+[Mr, Nr] = size(imR); % size of rectangular image
+Om = (Mr+1)/2; % co-ordinates of the center of the image
+On = (Nr+1)/2;
+sx = (Mr-1)/2; % scale factors
+sy = (Nr-1)/2;
+
+imP = zeros(M,N);
+
+delR = (rMax - rMin)/(M-1);
+delT = 2*pi/N;
+
+for ri = 1:M
+ for ti = 1:N
+ r = rMin + (ri - 1)*delR;
+ t = (ti - 1)*delT;
+ x = r*cos(t);
+ y = r*sin(t);
+ xR = x*sx + Om;
+ yR = y*sy + On;
+ imP(ri, ti) = interpolate(imR, xR, yR);
+ end
+end
+
+%----------------
+function v = interpolate(imR, xR, yR)
+%----------------
+%INTERPOLATE used in IMTOPOLAR
+%
+% V0.1 7 Dec 2007 (Created), Prakash Manandhar pmanandhar@umassd.edu
+
+xf = floor(xR);
+xc = ceil(xR);
+yf = floor(yR);
+yc = ceil(yR);
+if xf == xc && yc == yf
+ v = imR(xc,yc);
+elseif xf == xc
+ v = imR(xf,yf) + (yR - yf)*(imR(xf,yc) - imR(xf,yf));
+elseif yf == yc
+ v = imR(xf,yf) + (xR - xf)*(imR(xc,yf) - imR(xf,yf));
+else
+ A = [ xf yf xf*yf 1
+ xf yc xf*yc 1
+ xc yf xc*yf 1
+ xc yc xc*yc 1 ];
+ r = [ imR(xf, yf)
+ imR(xf,yc)
+ imR(xc,yf)
+ imR(xc,yc) ];
+ a = A\double(r);
+ w = [xR yR xR*yR 1];
+ v = w*a;
+end
\ No newline at end of file
diff --git a/source/callbackfunctions.m b/source/callbackfunctions.m
new file mode 100644
index 0000000..aba5807
--- /dev/null
+++ b/source/callbackfunctions.m
@@ -0,0 +1,1869 @@
+function callbackfunctions(varargin)
+% This .m file has the ambition of containing all Callback functions
+
+% Split out by Klas
+
+%Invoke subfunction
+macro_helper(varargin{:}); %future macro recording use
+feval(varargin{:}); % FEVAL switchyard
+
+%---------------------
+function orthoview_Callback %#ok
+%-----------------------
+global SET NO
+%First we check so that there are any slices because if not there is no
+%point
+
+if SET(NO).ZSize==1
+ myfailed('To few slices for orthogonal view.')
+ return
+end
+
+%this sets all necessary fields
+viewfunctions('orthoview',NO);
+
+%This updates the view.
+viewfunctions('setview',2,2,ones(1,4)*NO,{'orth','hla','vla','gla'})
+
+%------------------------------
+function viewviewport_Callback %#ok
+%------------------------------
+%Displays viewport in one panel
+
+global DATA
+
+segment3dp.tools('storetoobject');
+
+viewfunctions('setview',1,1,[],{'speedim'})
+
+DATA.drawlist = [];
+DATA.drawlist{1} = {'segment3dp.tools(''helprender'');'};
+
+drawfunctions('setxynan',1);
+
+run = true;
+DATA.Handles.configiconholder.indent('view3d',run);
+
+segment3dp.tools('helprender');
+
+DATA.LevelSet.ViewPort.panelhandle.Position = DATA.Handles.imageaxes(1).Position;
+
+%------------------------------
+function view4panel3dp_Callback %#ok
+%------------------------------
+global DATA
+
+%indent(DATA.Handles.configiconholder,'view4',1);
+
+segment3dp.tools('storetoobject');
+
+viewfunctions('setview',2,2,[],{'trans3DP','speedim','sag3DP','cor3DP'})
+
+if DATA.Handles.configiconholder.findindented('view3d')
+ %Update the size
+ DATA.LevelSet.ViewPort.panelhandle.Position = DATA.Handles.imageaxes(2).Position;
+ DATA.drawlist{2} = {'segment3dp.tools(''helprender'');'};
+end
+
+%----------------------------
+function selectpanel_Callback(name) %#ok
+%----------------------------
+%Select the panel with name
+
+global DATA SET
+
+selpanel = [];
+for loop = 1:length(DATA.ViewPanelsType)
+ if isequal(DATA.ViewPanelsType{loop},name)
+ selpanel = loop;
+ end
+end
+
+%if ~isempty(selpanel)
+% segment('switchtopanel',selpanel)
+%end
+
+if ~isempty(selpanel)
+ DATA.CurrentPanel = selpanel;
+ no = DATA.ViewPanels(selpanel);
+ switch name
+ case 'trans3DP'
+ SET(no).LevelSet.Pen.Color = 'r';
+ case 'sag3DP'
+ SET(no).LevelSet.Pen.Color = 'g';
+ case 'cor3DP'
+ SET(no).LevelSet.Pen.Color = 'b';
+ end
+
+ for loop = 1:length(DATA.ViewPanelsType)
+ if isequal(DATA.ViewPanelsType{loop},name)
+ DATA.CurrentPanel = loop;
+ end
+ end
+
+ %Graphical update
+ drawfunctions('drawselectedframe',selpanel)
+ speedimpanel = find(strcmp(DATA.ViewPanelsType,'speedim'));
+ if isempty(speedimpanel)
+ return
+ end
+ drawfunctions('drawpanel',speedimpanel);
+ viewfunctions('updatezoomandaspectratio',speedimpanel);
+end
+
+%------------------------
+function viewhelper(type)
+%------------------------
+%Set a two panel view with anatomical and speed image
+global DATA SET NO
+
+segment3dp.tools('storetoobject');
+
+speedpanel = 2; %currently is always panel number2
+
+switch type
+ case 'trans3DP'
+ SET(NO).LevelSet.Pen.Color = 'r';
+ case 'sag3DP'
+ SET(NO).LevelSet.Pen.Color = 'g';
+ case 'cor3DP'
+ SET(NO).LevelSet.Pen.Color = 'b';
+end
+
+if DATA.Handles.configiconholder.findindented('view3d')
+
+ %Clear all graphics function from drawlist
+ drawfunctions('setxynan',2)
+ viewfunctions('setview',1,2,[],{type,'viewport'})
+
+ %Update the size
+ DATA.LevelSet.ViewPort.panelhandle.Position = DATA.Handles.imageaxes(2).Position;
+
+ DATA.drawlist{speedpanel} = {'segment3dp.tools(''helprender'');'};
+
+else
+ viewfunctions('setview',1,2,[],{type,'speedim'})
+ %viewfunctions('updatezoomandaspectratio',1);
+ %viewfunctions('updatezoomandaspectratio',2);
+end
+
+%----------------------------
+function viewtransversal_Callback %#ok
+%----------------------------
+viewhelper('trans3DP');
+
+%----------------------------
+function viewcoronal_Callback %#ok
+%----------------------------
+viewhelper('cor3DP');
+
+%----------------------------
+function viewsagittal_Callback %#ok
+%----------------------------
+viewhelper('sag3DP');
+
+%----------------------------
+function reset3d_Callback %#ok
+%----------------------------
+%Reset 3D view
+
+global DATA
+
+if segment3dp.isviewportalive
+ %3D display on rotate
+ volshowobject = DATA.LevelSet.ViewPort.getvolshowobject;
+
+ %Reset to
+ newpos = [0 -4 0];
+
+ %Set the new camera position
+ ax = DATA.LevelSet.ViewPort.getaxeshandle;
+ volshowobject.CameraPosition = newpos;
+ volshowobject.CameraUpVector = [0 0 -1];
+ ax.CameraPosition = newpos;
+ ax.CameraUpVector = [0 0 -1];
+end
+
+%------------------------------------------
+function set3dvieworientation_Callback(view) %#ok
+%------------------------------------------
+%Set predefined views
+
+global DATA
+
+newposition = [];
+newvector = [];
+
+%Check if viewport is active
+if segment3dp.isviewportalive
+
+ d = 4;
+
+ switch view
+ case 'transversal'
+ newposition = [0 0 -d];
+ newvector = [0 -1 0];
+ case 'sagittal'
+ newposition = [-d 0 0];
+ newvector = [0 0 -1];
+ case 'coronal'
+ newposition = [0 -d 0];
+ newvector = [0 0 -1];
+ end
+
+ %Make the update
+ if ~isempty(newposition)
+ DATA.LevelSet.ViewPort.setcameraposition(newposition);
+ end
+
+ if ~isempty(newvector)
+ DATA.LevelSet.ViewPort.setcameraupvector(newvector);
+ end
+
+ DATA.LevelSet.ViewPort.updatepoints;
+end
+
+%-----------------------------------
+function set3dviewotherside_Callback %#ok
+%-----------------------------------
+%Set predefined views
+
+global DATA
+
+%Check if viewport is active
+if segment3dp.isviewportalive
+ p = DATA.LevelSet.ViewPort.getcameraposition;
+ DATA.LevelSet.ViewPort.setcameraposition(-p);
+ DATA.LevelSet.ViewPort.updatepoints;
+end
+
+%----------------------------
+function zoomin3d_Callback(f) %#ok
+%----------------------------
+%Zoom in viewpanel
+
+global DATA
+
+if segment3dp.isviewportalive
+ pos = DATA.LevelSet.ViewPort.getvolshowobject.CameraPosition;
+ DATA.LevelSet.ViewPort.setcameraposition(pos*(1+f));
+ DATA.LevelSet.ViewPort.updatepoints;
+end
+
+%--------------------------------------
+function rotate3d_Callback(dtheta,dphi) %#ok
+%--------------------------------------
+%Rotate 3D view with dtheta, and dphi degrees
+%Obs this function is not defined from RLAPFH coordinate system
+
+global DATA
+
+if segment3dp.isviewportalive
+
+ %3D display on rotate
+ volshowobject = DATA.LevelSet.ViewPort.getvolshowobject;
+ pos = volshowobject.CameraPosition;
+
+ r = sqrt(sum(pos.*pos));
+ theta = acos(pos(3)/r);
+ phi = atan2(pos(2),pos(1));
+
+ theta = theta+dtheta/180*pi;
+ phi = phi+dphi/180*pi;
+
+ newpos = [...
+ r*sin(theta)*cos(phi) ...
+ r*sin(theta)*sin(phi) ...
+ r*cos(theta)];
+
+ %Set the new camera position
+ ax = DATA.LevelSet.ViewPort.getaxeshandle;
+ volshowobject.CameraPosition = newpos;
+ ax.CameraPosition = newpos;
+
+end
+
+%----------------------
+function lasso_Callback %#ok
+%----------------------
+%Lasso placeholder
+
+myfailed('Lasso not yet available.');
+
+%---------------------
+function mmode_Callback %#ok
+%-----------------------
+myfailed('This functions is no longer available.')
+
+%---------------------
+function play_Callback(panels) %#ok
+%-----------------------
+global DATA SET
+
+if nargin == 0
+ panels = find(DATA.ViewPanels>0);
+end
+
+maxt = 0;
+for loop=DATA.ViewPanels(panels)
+ if SET(loop).TSize>maxt
+ maxt = SET(loop).TSize;
+ end
+end
+
+if maxt == 1
+ myfailed('Need a time resolved image stack')
+ undent(DATA.Handles.permanenticonholder,'play',0)
+ return
+end
+
+%Try different approach where all stacks are played after NO
+startframes = SET(DATA.ViewPanels(panels(1))).CurrentTimeFrame;
+starttime = now;
+beattime = SET(DATA.ViewPanels(panels(1))).BeatTime;
+
+%prior to running the following graphics objects are turned 'off' by
+%setting xdata and ydata to nan. This is because these objects need to be
+%many in order to e.g draw text at multiple locations.
+for p = panels
+ % % % for c = 'cygmkwrb'
+ % % % set(DATA.Handles.([c,'roitext'])(p,:),'Position',[nan,nan])
+ % % % end
+ set(DATA.Handles.roitext(p,:),'Position',[nan,nan])
+ set(DATA.Handles.measurementtext(p,:),'Position',[nan,nan])
+ set(DATA.Handles.pointtext(p,:),'Position',[nan,nan])
+
+ %interps not necessary when playing
+ type = {'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp'};
+ for t = 1:length(type)
+ DATA.Handles.(lower(type{t}))(p).XData = nan;
+ DATA.Handles.(lower(type{t}))(p).YData = nan;
+ end
+end
+
+synchronize = findindented(DATA.Handles.hideiconholder,'synchronize');
+
+DATA.Run=1;
+t = maxt;
+while DATA.Run%true
+ %stopping criteria
+ if ~findindented(DATA.Handles.permanenticonholder,'play')
+ DATA.Run=0;
+ end
+
+ for p = panels
+ no = DATA.ViewPanels(p);
+ if SET(no).TSize>1
+ if DATA.Record
+ t = 1+mod(t,maxt);
+ else
+ t = 1+mod(floor(rem(now-starttime,1)*24*3600/(beattime/maxt)+startframes),maxt);
+ end
+ SET(DATA.ViewPanels(p)).CurrentTimeFrame = max(min(round(SET(no).TSize*(t/maxt)),SET(no).TSize),1);
+ drawfunctions('drawpanel',p);
+ end
+ end
+
+ %also update the timebars!
+ viewfunctions('updatetimebars',synchronize)
+ drawnow %limitrate
+ if DATA.Record %For Automatic Record Movie functionality
+ %drawnow;
+ gui = DATA.GUI.Segment;
+ DATA.MovieFrame = mygetframe(gui.fig);
+ DATA.MovieFrame.colormap=colormap(gui.fig);
+ %DATA.MovieFrame = mygetframe(gui.handles.imageaxes);
+ export('exportmovierecorder_Callback','newframe');
+ end
+end
+
+%---------------------
+function play_Callback2(panels) %#ok
+%-----------------------
+global DATA SET NO
+
+if nargin == 0
+ %panels = 1:length(DATA.ViewPanels);
+ panels = find(DATA.ViewPanels>0);%1:length(DATA.ViewPanels);
+end
+
+maxt = 0;
+for loop=DATA.ViewPanels(panels)
+ if SET(loop).TSize>maxt
+ maxt = SET(loop).TSize;
+ end
+end
+
+if maxt == 1
+ myfailed('Need a time resolved image stack')
+ undent(DATA.Handles.permanenticonholder,'play',0)
+ return
+end
+
+%Try different approach where all stacks are played after NO
+%startframes = SET(DATA.ViewPanels(panels(1))).CurrentTimeFrame;
+%starttime = now;
+%beattime = SET(DATA.ViewPanels(panels(1))).BeatTime;
+
+%prior to running the following graphics objects are turned 'off' by
+%setting xdata and ydata to nan. This is because these objects need to be
+%many in order to e.g draw text at multiple locations.
+for p = panels
+ set(DATA.Handles.roitext(p,:),'Position',[nan,nan])
+ set(DATA.Handles.measurementtext(p,:),'Position',[nan,nan])
+ set(DATA.Handles.pointtext(p,:),'Position',[nan,nan])
+ set(DATA.Handles.pointtext(p),'Position',[nan,nan])
+
+ %interps not necessary when playing
+ type = {'EndoInterp','EpiInterp','RVEndoInterp','RVEpiInterp'};
+ for t = 1:length(type)
+ DATA.Handles.(lower(type{t}))(p).XData = nan;
+ DATA.Handles.(lower(type{t}))(p).YData = nan;
+ end
+end
+
+DATA.Run=1;
+while DATA.Run%true
+ %stopping criteria
+ tic
+ if ~findindented(DATA.Handles.permanenticonholder,'play')
+ DATA.Run=0;
+ end
+
+ %Update current timeframe in NO
+ if SET(NO).CurrentTimeFrame < SET(NO).TSize
+ SET(NO).CurrentTimeFrame = SET(NO).CurrentTimeFrame+1;
+ else
+ SET(NO).CurrentTimeFrame = 1;
+ end
+
+ for p = panels
+ no = DATA.ViewPanels(p);
+ if SET(no).TSize>1
+ %t = 1+mod(floor(rem(now-starttime,1)*24*3600/(beattime/maxt)+startframes),maxt);
+ %SET(DATA.ViewPanels(p)).CurrentTimeFrame = max(min(round(SET(no).TSize*(t/maxt)),SET(no).TSize),1);
+
+ %find the closest matching phase to the currenttimeframe in NO
+ [~,t]= min((SET(NO).TimeVector(SET(NO).CurrentTimeFrame)/SET(NO).TimeVector(end)-SET(no).TimeVector/SET(no).TimeVector(end)).^2);
+
+ %if t~=SET(no).CurrentTimeFrame || no ~=NO
+ SET(no).CurrentTimeFrame = t;
+ drawfunctions('drawpanel',p);
+ %end
+ end
+ end
+
+ %also update the timebars!
+ viewfunctions('updatetimebars')
+ drawnow
+
+ %then we get the spent time rendering and pause for the residual
+ t_time = toc;
+ if t_time
+%-------------------------------------------
+%Clear all LV segmentation, both endo and epi
+
+global DATA
+
+if nargin==1
+ if ~yesno('Do you really want to remove all LV segmentation ?',[],DATA.GUI.Segment)
+ % myfailed('Aborted by user.',DATA.GUI.Segment);
+ return;
+ end
+end
+
+segmentation('clearalllv_Callback');
+
+%-------------------------------------------
+function segmentclearallrv_Callback %#ok
+%-------------------------------------------
+%Clear all RV segmentation, both endo and epi
+
+global DATA
+
+if nargin==1
+ if ~yesno('Do you really want to remove all RV segmentation ?',[],DATA.GUI.Segment)
+ % myfailed('Aborted by user.',DATA.GUI.Segment);
+ return;
+ end
+end
+
+segmentation('clearallrv_Callback');
+
+%-------------------------------------------------------
+function segmentclearalllvbutsystolediastole_Callback %#ok
+%-------------------------------------------------------
+%Clears all LV segmentation except in systole and diastole.
+
+global SET NO DATA
+
+if SET(NO).TSize<2
+ myfailed('Not timeresolved data, aborting.',DATA.GUI.Segment);
+ return;
+end
+
+if isequal(SET(NO).EDT,SET(NO).EST)
+ myfailed('Systole and diastole occurs at the same time frame, aborting.',DATA.GUI.Segment);
+ return;
+end
+
+%Create index structure
+ind = true(1,SET(NO).TSize);
+ind(SET(NO).EDT) = false;
+ind(SET(NO).EST) = false;
+arg = struct('endo',true,'epi',true,'rvendo',false,'rvepi',false);
+indarg = struct('endoind',ind,'epiind',ind,'rvendoind',ind,'rvepiind',ind);
+segmentation('removeallinterp_Callback',true,[],arg,indarg);
+
+%Create index structure
+ind = true(1,SET(NO).TSize);
+ind(SET(NO).EDT) = false;
+ind(SET(NO).EST) = false;
+
+if ~isempty(SET(NO).EndoX)
+ SET(NO).EndoX(:,ind,:) = NaN;
+ SET(NO).EndoY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).EpiX)
+ SET(NO).EpiX(:,ind,:) = NaN;
+ SET(NO).EpiY(:,ind,:) = NaN;
+end
+
+SET(NO).EndoDraged(ind,:) = false;
+SET(NO).EpiDraged(ind,:) = false;
+
+lvsegchanged = true; segment('updatevolume',lvsegchanged);
+drawfunctions('drawcontours', DATA.CurrentPanel)
+drawfunctions('drawinterp', DATA.CurrentPanel)
+
+
+%-------------------------------------------------------
+function segmentclearallrvbutsystolediastole_Callback %#ok
+%-------------------------------------------------------
+%Clears all RV segmentation except in systole and diastole.
+
+global SET NO DATA
+
+if SET(NO).TSize<2
+ myfailed('Not timeresolved data, aborting.',DATA.GUI.Segment);
+ return;
+end
+
+if isequal(SET(NO).EDT,SET(NO).EST)
+ myfailed('Systole and diastole occurs at the same time frame, aborting.',DATA.GUI.Segment);
+ return;
+end
+
+%Create index structure
+ind = true(1,SET(NO).TSize);
+ind(SET(NO).EDT) = false;
+ind(SET(NO).EST) = false;
+arg = struct('endo',false,'epi',false,'rvendo',true,'rvepi',true);
+indarg = struct('endoind',ind,'epiind',ind,'rvendoind',ind,'rvepiind',ind);
+segmentation('removeallinterp_Callback',true,[],arg,indarg);
+
+if ~isempty(SET(NO).RVEndoX)
+ SET(NO).RVEndoX(:,ind,:) = NaN;
+ SET(NO).RVEndoY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).RVEpiX)
+ SET(NO).RVEpiX(:,ind,:) = NaN;
+ SET(NO).RVEpiY(:,ind,:) = NaN;
+end
+
+SET(NO).EndoDraged(ind,:) = false;
+SET(NO).EpiDraged(ind,:) = false;
+
+segment('updatevolume');
+drawfunctions('drawcontours',DATA.CurrentPanel)
+drawfunctions('drawinterp',DATA.CurrentPanel)
+
+%-----------------------------------------
+function contextloadno_Callback(viewpanelstype) %#ok
+%-----------------------------------------
+%Loads imagestack no with the desired viewmode
+global DATA
+
+no = DATA.LastObject;
+%Already out then switch to it and change viewmode
+if any(no==DATA.ViewPanels)
+ viewfunctions('switchimagestack',no,viewpanelstype)
+else %add to first
+ viewfunctions('addno2panel',1,no,viewpanelstype)
+end
+
+DATA.LastObject = [];
+
+
+%-----------------------------------------
+function pointdeletethis_Callback %#ok
+%-----------------------------------------
+%remove point closest to click
+global DATA SET
+no = DATA.ViewPanels(DATA.CurrentPanel);
+pointind = DATA.LastObject(1);
+slice = DATA.LastObject(2);
+tf = DATA.LastObject(3);
+
+SET(no).Point.X(pointind) = [];
+SET(no).Point.Y(pointind) = [];
+SET(no).Point.T(pointind) = [];
+SET(no).Point.Z(pointind) = [];
+SET(no).Point.Label(pointind) = [];
+
+drawfunctions('drawno',no);
+
+%-----------------------------------------
+function pointrenamethis_Callback %#ok
+%-----------------------------------------
+%rename point closest to click
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if noobjectshelper
+ return
+end
+
+pointind = DATA.LastObject(1);
+if strcmp(DATA.ProgramName, 'Segment 3DPrint')
+ s = myinputdlg({'Enter name'},'Name',1,{sprintf('%s',SET(no).Point.Label{pointind})});
+ if isempty(s) || isempty(s{1})
+ return;
+ else
+ SET(no).Point.Label{pointind} = s{1};
+ end
+else
+ % in other programs show a pre-defined set of names
+ menuitems = {...
+ 'Apex',...
+ 'RV insertion',...
+ 'RV insertion Anterior',...
+ 'RV insertion Inferior',...
+ 'AV plane',...
+ 'TV plane',...
+ 'P1',...
+ 'P2',...
+ 'General',...
+ 'Sector start',...
+ 'User defined ...'};
+
+ % s = myinputdlg({'Enter name'},'Name',1,{sprintf('%s',SET(no).Point.Label{pointind})});
+
+ s = mymenu(strcat(dprintf('Select a new name for the point')),menuitems,DATA.GUI.Segment);
+ if isempty(s)
+ myfailed('Invalid name.',DATA.GUI.Segment);
+ return;
+ elseif s == 0 % cancel was clicked
+ return
+ elseif s == length(menuitems)
+ % user defined name
+ name = myinputdlg({'Enter name'},'Name',1,{sprintf('%s',SET(no).Point.Label{pointind})});
+ if isempty(name) || isempty(name{1})
+ return;
+ else
+ SET(no).Point.Label{pointind} = name{1};
+ end
+ else
+ SET(no).Point.Label{pointind} = menuitems{s};
+ end
+end
+
+drawfunctions('drawno',no);
+
+%-----------------------------------------
+function pointclearall_Callback %#ok
+%-----------------------------------------
+%remove all points
+
+global DATA SET NO
+
+no = NO;%DATA.ViewPanels(DATA.CurrentPanel);
+
+SET(no).Point.X = [];
+SET(no).Point.Y = [];
+SET(no).Point.T = [];
+SET(no).Point.Z = [];
+SET(no).Point.Label = {};
+
+drawfunctions('drawno',no);
+if any(strcmp(DATA.ProgramName,{'Segment 3DPrint'}))
+ if segment3dp.isviewportalive
+ DATA.LevelSet.ViewPort.setpoints(NaN,NaN,NaN)
+ end
+end
+
+%-----------------------------------------
+function pointmaketimeresolvedthis_Callback %#ok
+%-----------------------------------------
+%make point closest to click timeresolved
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if noobjectshelper
+ return
+end
+
+pointind = DATA.LastObject(1);
+
+%nan means timeresolved.
+SET(no).Point.T(pointind) = nan;
+
+drawfunctions('drawno',no);
+
+%-----------------------------------------
+function pointshowthisframeonly_Callback %#ok
+%-----------------------------------------
+%remove point closest to click
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if noobjectshelper
+ return
+end
+
+pointind = DATA.LastObject(1);
+tf = DATA.LastObject(3);
+
+SET(no).Point.T(pointind) = tf;
+
+drawfunctions('drawno',no);
+
+%-----------------------------------------
+function interpdeletepoint %#ok
+%-----------------------------------------
+%remove interpolation point closest to click
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if noobjectshelper
+ return
+end
+
+pointind = DATA.LastObject(1);
+slice = DATA.LastObject(2);
+tf = DATA.LastObject(3);
+pointtype = DATA.LastObjectType;
+
+SET(no).([pointtype,'X']){tf,slice}(pointind) = [];
+SET(no).([pointtype,'Y']){tf,slice}(pointind) = [];
+
+%do resampling of curve when deleting single point.
+X = SET(no).([pointtype,'X']){tf,slice};
+Y = SET(no).([pointtype,'Y']){tf,slice};
+%removes duplicate points and resamples the contour
+[x,y] = calcfunctions('resamplecurve',X,Y,DATA.NumPoints-1);
+SET(no).([pointtype(1:end-6),'Y'])(:,tf,slice)=[y,y(1)];
+SET(no).([pointtype(1:end-6),'X'])(:,tf,slice)=[x,x(1)];
+
+drawfunctions('drawno',no);
+
+%-----------------------------------------
+function interpdeletepointthisslicephase %#ok
+%-----------------------------------------
+%remove interpolation point closest to click
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if noobjectshelper
+ return
+end
+
+pointind = DATA.LastObject(1);
+slice = DATA.LastObject(2);
+tf = DATA.LastObject(3);
+pointtype = DATA.LastObjectType;
+
+SET(no).([pointtype,'X']){tf,slice} = [];
+SET(no).([pointtype,'Y']){tf,slice} = [];
+
+drawfunctions('drawno',no);
+
+%-------------------------------------
+function measureclearthis_Callback(~) %#ok
+%-------------------------------------
+%Clear this measurement
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if nargin==0
+ if noobjectshelper
+ return
+ end
+ measureind = DATA.LastObject(1);
+else
+ %Ask
+ measureind = measureaskhelper;
+end
+
+if isequal(measureind,0)
+ % myfailed('Aborted.');
+ return;
+end
+
+SET(no).Measure(measureind) = [];
+drawfunctions('drawno',no);
+segment('updatemeasurement');
+
+%--------------------------------
+function measureclearall_Callback %#ok
+%--------------------------------
+%Clear all measurements
+
+global DATA SET
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+SET(no).Measure = [];
+drawfunctions('drawno',no);
+segment('updatemeasurement');
+
+%----------------------------
+function m = measureaskhelper
+%----------------------------
+%Helper function to select a measurement in a menu
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+m = 0;
+if isempty(SET(no).Measure)
+ myfailed('No measurements.');
+ return;
+end
+
+if length(SET(no).Measure)==1
+ m = 1;
+ return;
+end
+
+%Loop over names
+namecell = cell(1,length(SET(no).Measure));
+for loop = 1:length(namecell)
+ namecell{loop} = SET(no).Measure(loop).LongName;
+ if isempty(namecell{loop})
+ namecell{loop} = 'Empty name';
+ end
+end
+
+%ask
+m = mymenu('Select measurement',namecell);
+
+%-------------------------------------
+function measurerenamethis_Callback(~) %#ok
+%-------------------------------------
+%Rename measurement
+
+global DATA SET
+
+no = DATA.ViewPanels(DATA.CurrentPanel);
+
+if nargin==0
+ if noobjectshelper
+ return
+ end
+ measureind = DATA.LastObject(1);
+else
+ %ask
+ measureind = measureaskhelper;
+end
+
+if isequal(measureind,0)
+ % myfailed('Aborted.');
+ return;
+end
+
+tools('enableundo',no);
+
+%Get new name
+[stri,lstr] = measureasklabel(measureind);
+if ~isempty(stri)
+ SET(no).Measure(measureind).Name = stri;
+ SET(no).Measure(measureind).LongName = lstr;
+else
+ myfailed('Invalid name.',DATA.GUI.Segment);
+ return;
+end
+
+drawfunctions('drawno',no)
+segment('updatemeasurement');
+
+%----------------------------------
+function doreturn = noobjectshelper
+%----------------------------------
+%Helper function that checks for LastObject
+
+global DATA
+
+if isempty(DATA.LastObject)
+ myfailed('No objects');
+ doreturn = true;
+else
+ doreturn = false;
+end
+
+%------------------------------
+function [stri,lstr] = measureasklabel(measureind)
+%------------------------------
+%Asks for a label of a measurement.
+
+global DATA
+
+%Call overloaded method
+[stri,lstr] = DATA.measureasklabel(measureind);
+
+segment('updatemeasurement');
+
+
+%---------------------------------------
+function interpdeletepointall(pointtype)
+%---------------------------------------
+%remove interpolation point closest to click
+global DATA SET
+no = DATA.ViewPanels(DATA.CurrentPanel);
+if nargin < 1
+ pointtype = DATA.LastObjectType;
+end
+
+SET(no).([pointtype,'X']) = [];
+SET(no).([pointtype,'Y']) = [];
+
+drawfunctions('drawno',no);
+
+%-----------------------------------------
+function clearallslices_Callback %#ok
+%-----------------------------------------
+%Clear all segmentation, both endo and epi, lv and rv mar and scar.
+
+segmentation('clearslices_Callback');
+
+%-----------------------------------------
+function segmentclearall_Callback(silent) %#ok
+%-----------------------------------------
+%Clear all segmentation, both endo and epi, lv and rv mar and scar.
+
+global DATA
+
+if nargin == 0 || not(silent)
+ msg = dprintf('This removes all existing segmentation of LV, RV, ROI, MaR and scar. Are you sure?');
+ if ~yesno(msg,[],DATA.GUI.Segment)
+ return;
+ end
+end
+
+viability('viabilityclear_Callback');
+roi('roiclearall_Callback')
+segmentation('clearall_Callback');
+mar('clearall_Callback');
+
+
+%-----------------------------------------------------
+function segmentclearallbutsystolediastole_Callback
+%-----------------------------------------------------
+%Clears all segmentation in all timeframes but systole and diastole.
+global DATA SET NO
+
+if SET(NO).TSize<2
+ myfailed('Not timeresolved data, aborting.',DATA.GUI.Segment);
+ return;
+end
+
+if isequal(SET(NO).EDT,SET(NO).EST)
+ myfailed('Systole and diastole occurs at the same time frame, aborting.',DATA.GUI.Segment);
+ return;
+end
+
+%Create index structure
+ind = true(1,SET(NO).TSize);
+ind(SET(NO).EDT) = false;
+ind(SET(NO).EST) = false;
+arg = struct('endo',true,'epi',true,'rvendo',true,'rvepi',true);
+indarg = struct('endoind',ind,'epiind',ind,'rvendoind',ind,'rvepiind',ind);
+segmentation('removeallinterp_Callback',true,[],arg,indarg);
+
+if ~isempty(SET(NO).EndoX)
+ SET(NO).EndoX(:,ind,:) = NaN;
+ SET(NO).EndoY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).EpiX)
+ SET(NO).EpiX(:,ind,:) = NaN;
+ SET(NO).EpiY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).RVEndoX)
+ SET(NO).RVEndoX(:,ind,:) = NaN;
+ SET(NO).RVEndoY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).RVEpiX)
+ SET(NO).RVEpiX(:,ind,:) = NaN;
+ SET(NO).RVEpiY(:,ind,:) = NaN;
+end
+
+SET(NO).EndoDraged(ind,:) = false;
+SET(NO).EpiDraged(ind,:) = false;
+
+segment('updatevolume');
+drawfunctions('drawcontours',DATA.CurrentPanel);
+drawfunctions('drawinterp',DATA.CurrentPanel);
+
+%--------------------------------------------
+function segmentclearallbutdiastole_Callback
+%--------------------------------------------
+%Clears all segmentation in all timeframes but diastole.
+global DATA SET NO
+
+if SET(NO).TSize<2
+ myfailed('Not timeresolved data, aborting.',DATA.GUI.Segment);
+ return;
+end
+
+%Create index structure
+ind = true(1,SET(NO).TSize);
+ind(SET(NO).EDT) = false;
+arg = struct('endo',true,'epi',true,'rvendo',true,'rvepi',true);
+indarg = struct('endoind',ind,'epiind',ind,'rvendoind',ind,'rvepiind',ind);
+segmentation('removeallinterp_Callback',true,[],arg,indarg);
+
+if ~isempty(SET(NO).EndoX)
+ SET(NO).EndoX(:,ind,:) = NaN;
+ SET(NO).EndoY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).EpiX)
+ SET(NO).EpiX(:,ind,:) = NaN;
+ SET(NO).EpiY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).RVEndoX)
+ SET(NO).RVEndoX(:,ind,:) = NaN;
+ SET(NO).RVEndoY(:,ind,:) = NaN;
+end
+
+if ~isempty(SET(NO).RVEpiX)
+ SET(NO).RVEpiX(:,ind,:) = NaN;
+ SET(NO).RVEpiY(:,ind,:) = NaN;
+end
+
+SET(NO).EndoDraged(ind,:) = false;
+SET(NO).EpiDraged(ind,:) = false;
+
+segment('updatevolume');
+drawfunctions('drawcontours',DATA.CurrentPanel);
+drawfunctions('drawinterp',DATA.CurrentPanel);
+
+
+%------------------------------------
+function result = updateintersections_Callback(slices,no,type) %#ok
+%------------------------------------
+% Calculates the intersection of a endocardial segmentation
+% and SET(no) for
+% slices == 'all'
+% or
+% slices == 'current'
+%
+% Allowed segmenation 'type' is 'LVEndo' or 'RVEndo'
+%
+% Calculates intersection for SET(NO) if nargin==1.
+% Returns false if calculations fails
+
+% Marten Larsson, June, 2009
+
+global DATA NO SET
+
+if nargin == 1
+ no = NO;
+ type = 'LV Endocardial';
+end
+
+result = true;
+segno = [];
+
+switch type
+ case 'LV Endocardial'
+ % Find sets with LV endocardial segmentation
+ for i=1:length(SET)
+ if ~isempty(SET(i).EndoX) && any(any(any(~isnan(SET(i).EndoX))))
+ segno = [segno i]; %#ok
+ end
+ end
+ case 'RV Endocardial'
+ % Find sets with RV endocardial segmentation
+ for i=1:length(SET)
+ if ~isempty(SET(i).RVEndoX) && any(any(any(~isnan(SET(i).RVEndoX))))
+ segno = [segno i]; %#ok
+ end
+ end
+end
+
+if isempty(segno)
+ myfailed('No segmentation found',DATA.GUI.Segment);
+ result = false;
+ return;
+end
+
+if length(segno)>1
+ segstring = cell(length(segno),1);
+ for i = 1: length(segno)
+ segstring{i} = dprintf('Image stack %d - %s',segno(i),SET(segno(i)).ImageType);
+ end
+
+ [selected, ok] = listdlg('ListString',segstring,...
+ 'SelectionMode','single',...
+ 'PromptString','Chose image stack to use:',...
+ 'ListSize',[300 100]);
+
+ if ~ok
+ result = false;
+ return;
+ end
+ segno = segno(selected);
+end
+
+calcsegintersect(segno,no,slices,type);
+viewfunctions('setview'); %drawfunctions('drawall');
+
+
+%----------------------
+function selectlvmethod %#ok
+%----------------------
+%callback from 3DPrint auto LV icon to select if apply CT or MR auto LV seg
+
+global SET NO
+
+no = NO;
+ismr = strfind(SET(no).ImagingTechnique,'MR');
+isct = strfind(SET(no).ImagingTechnique,'CT');
+
+if not(isempty(ismr)) && isempty(isct)
+ lvsegmentation;
+elseif not(isempty(isct)) && isempty(ismr)
+ ct.ctlicensecheck('CTLVSegmentation');
+else
+ %user select if it is CT or MR or cancel
+ menuitems{1} = 'MR';
+ menuitems{2} = 'CT';
+ menuitems{3} = 'Other';
+ answer = mymenu('Select imaging technique for the selected image stack.',menuitems);
+ if answer
+ if answer == 1
+ lvsegmentation;
+ elseif answer == 2
+ ct.ctlicensecheck('CTLVSegmentation');
+ elseif answer == 3
+ myfailed('No automatic LV segmentation method for other imaging techniques avaliable.');
+ end
+ else
+ disp('LV segmentation canceled.');
+ end
+end
+
+%---------------------------------------------
+function calccalciummask_Callback
+%---------------------------------------------
+global SET NO
+sizesetstruct=size(SET);
+
+temp=[];
+tempCaSc=[];
+
+temp=[];
+tempCaSc=[];
+
+if sizesetstruct(1,2)==1
+ m=1;
+else
+ m=2;
+end
+
+for n=1:sizesetstruct(1,m)
+ temp=[temp isempty(SET(n).EndoX)==0];
+ tempCaSc=[tempCaSc contains(SET(n).SeriesDescription,'CaSc')];
+end
+sumtempCaSc= sum(tempCaSc);
+if sum(temp)==0
+ myfailed('there is no contrastimage')
+ return
+end
+if sum(temp)==1
+ seg= find(temp);
+elseif sum(temp)==2
+ findindex1=find(temp);
+ seg = mymenu('Choose segmentation stack',['Image stack no ' num2str(SET(findindex1(1)).Linked)], ['Image stack no ' num2str(SET(findindex1(2)).Linked)]);
+end
+
+if sumtempCaSc==0
+ myfailed('There is no Ca image')
+ return
+end
+if sumtempCaSc==1
+ no=find(tempCaSc);
+elseif sumtempCaSc==2
+ findindex=find(tempCaSc);
+ no = mymenu('In which image stack do you want to detect calcium?',['Image stack no ' num2str(SET(findindex(1)).Linked)], ['Image stack no ' num2str(SET(findindex(2)).Linked)]);
+ no=findindex(no);
+elseif sumtempCaSc==3
+ no = mymenu('In which image stack do you want to detect calcium?',['Image stack no ' num2str(SET(findindex(1)).Linked)], ['Image stack no ' num2str(SET(findindex(2)).Linked)], ['Image stack no ' num2str(SET(findindex(3)).Linked)]);
+ no=findindex(no);
+end
+
+callbackfunctions('calccalciummask',no,seg,0)
+
+%---------------------------------------------
+function splitcalciummask_Callback
+%---------------------------------------------?
+
+global SET NO
+sizesetstruct=size(SET);
+
+temp=[];
+tempCaSc=[];
+
+if sizesetstruct(1,2)==1
+ m=1;
+else
+ m=2;
+end
+
+for n=1:sizesetstruct(1,m)
+ temp=[temp isempty(SET(n).EndoX)==0];
+ tempCaSc=[tempCaSc contains(SET(n).SeriesDescription,'CaSc')];
+ %tempCaSc=[tempCaSc contains(SET(n).SeriesDescription,'CorASeq')];
+end
+sumtempCaSc= sum(tempCaSc);
+if sum(temp)==0
+ % myfailed('There is no contrast image')
+ seg=0;
+end
+if sum(temp)==1
+ seg= find(temp);
+elseif sum(temp)>1
+ %seg = mymenu('In which image stack do you want to use for the segmentation','e', 'e', 'Image stack no 3','Image stack no 4');
+ myfailed('several contrastimages')
+ return
+end
+
+if sumtempCaSc==0
+ myfailed('There is no Ca image')
+ return
+end
+if sumtempCaSc==1
+ no=find(tempCaSc);
+elseif sumtempCaSc==2
+ findindex=find(tempCaSc);
+ no = mymenu('In which image stack do you want to detect calcium?',['Image stack no ' num2str(SET(findindex(1)).Linked)], ['Image stack no ' num2str(SET(findindex(2)).Linked)]);
+ no=findindex(no);
+elseif sumtempCaSc==3
+ no = mymenu('In which image stack do you want to detect calcium?',['Image stack no ' num2str(SET(findindex(1)).Linked)], ['Image stack no ' num2str(SET(findindex(2)).Linked)],['Image stack no ' num2str(SET(findindex(3)).Linked)]);
+ no=findindex(no);
+
+end
+
+
+callbackfunctions('calccalciummask',no,seg,1)
+
+
+%---------------------------------------------
+function rawca_Callback
+%---------------------------------------------?
+
+global SET NO
+sizesetstruct=size(SET);
+
+temp=[];
+tempCaSc=[];
+
+if sizesetstruct(1,2)==1
+ m=1;
+else
+ m=2;
+end
+
+for n=1:sizesetstruct(1,m)
+
+ tempCaSc=[tempCaSc contains(SET(n).SeriesDescription,'CaSc')];
+
+end
+sumtempCaSc= sum(tempCaSc);
+
+seg=0;
+
+if sumtempCaSc==0
+ myfailed('There is no Ca image')
+ return
+end
+if sumtempCaSc==1
+ no=find(tempCaSc);
+elseif sumtempCaSc==2
+ findindex=find(tempCaSc);
+ no = mymenu('In which image stack do you want to detect calcium?',['Image stack no ' num2str(SET(findindex(1)).Linked)], ['Image stack no ' num2str(SET(findindex(2)).Linked)]);
+ no=findindex(no);
+elseif sumtempCaSc==3
+ no = mymenu('In which image stack do you want to detect calcium?',['Image stack no ' num2str(SET(findindex(1)).Linked)], ['Image stack no ' num2str(SET(findindex(2)).Linked)],['Image stack no ' num2str(SET(findindex(3)).Linked)]);
+ no=findindex(no);
+
+end
+
+
+callbackfunctions('calccalciummask',no,seg,1)
+
+
+
+%---------------------------
+function calccalciummask(no,seg,onORoff) %#ok
+%---------------------------
+%Computes calciummask, will be replace by code from Lisa
+radius1=[];
+global SET NO
+
+if nargin==0
+ no = NO;
+end
+%segim=SET(seg).IM;
+im=SET(no).IM;
+im = calcfunctions('calctruedata',im,no); %g?r om till Hounsfieldunits
+outputmask = uint8((im>=130));
+
+imbin = (im>=130); %allt ?ver 130 Hu r?knas som kalk
+imbin = squeeze(imbin);
+bw = bwconncomp(imbin);
+
+
+if bw.NumObjects>0
+ for k=1:bw.NumObjects
+ thislist=bw.PixelIdxList{1,k};
+ [R]=numel(thislist);
+ % Cascore i mm3
+ Cascore1 = R*SET(no).ResolutionX*SET(no).ResolutionY*(SET(no).SliceThickness+SET(no).SliceGap);
+ if Cascore1>3
+ outputmask(bw.PixelIdxList{k})=uint8(2);
+ end
+
+ end
+end
+
+SET(no).CT.CalciumMask = outputmask;
+if seg~=0
+lengthsofthisIm=[];
+% Pick outsets of 4 or more
+sizesetstruct=size(SET);
+
+threedvol=uint8(zeros(SET(seg).XSize,SET(seg).YSize,SET(seg).ZSize));
+threedvol2=uint8(zeros(SET(seg).XSize,SET(seg).YSize,SET(seg).ZSize));
+threedvolM=uint8(zeros(SET(seg).XSize,SET(seg).YSize,SET(seg).ZSize));
+threedvolA=uint8(zeros(SET(seg).XSize,SET(seg).YSize,SET(seg).ZSize));
+SET(no).CT.CalciumPenMask=uint8(zeros(SET(seg).XSize,SET(seg).YSize,SET(seg).ZSize));
+shortaxisImagelocation=0;
+EXlocation= 0;
+
+for n=1:sizesetstruct(1,2)
+
+ if strcmp(SET(n).ImageViewPlane,'Short-axis')==1 && contains(SET(n).SeriesDescription,'CaSc')==1
+ shortaxisImagelocation=n;
+ end
+
+ if isempty(SET(n).EndoX)==0
+ EXlocation= n;
+ else
+ EXlocation= seg;
+ end
+ if strcmp(SET(n).ImageViewPlane,'Transversal')==1 && contains(SET(n).SeriesDescription,'CorASeq')==1
+ transversalContrastLocation=n;
+ end
+end
+
+
+% kolla vid vilken slice k segmenteringen b?rjar
+
+sizeOfEndoSeg=size(SET(EXlocation).EndoX);
+for k=1:sizeOfEndoSeg(1,3)
+ if isnan(SET(EXlocation).EndoX(:,:,k))==0
+ hereIsNotNan=k;
+ break;
+ end
+end
+
+
+
+% Mask making
+
+meanX=mean(SET(EXlocation).EndoX(:,:,hereIsNotNan));
+meanY=mean(SET(EXlocation).EndoY(:,:,hereIsNotNan));
+
+%ta bild 8 snitt upp
+
+imbin1=[];
+imbin2=[];
+Cascore1=0;
+Cascore2=0;
+
+firstZslice=hereIsNotNan-8;
+lastZslice=hereIsNotNan+8;
+mitsizes=[];
+for slice=firstZslice:lastZslice
+
+ im1=imadjust(SET(EXlocation).IM(:,:,1,slice));
+
+ %ber?kna treshold
+ im1=calcfunctions('calctruedata',im1,EXlocation); %g?r om till Hounsfieldunits
+ iim=(im1+1024)/ max(max(im1+1024));
+ JJ=imhist(iim);
+ minloc=178+find(JJ(179:230)==min(JJ(179:230)));
+ maxloc=153+find(JJ(154:minloc(1))==max(JJ(154:minloc(1))));
+ if length(maxloc(end))>=1 && JJ(maxloc(end))>700
+ T1=round((maxloc(end)+minloc(1))/2)/256;
+ else
+ T1=minloc(1)/256;
+ end
+ T=T1*max(max(im1+1024))-1024;
+ im2=im1>T;
+ im2=imfill(im2, 'holes');
+
+ imageSizeX =SET(EXlocation).YSize;
+ imageSizeY = SET(EXlocation).XSize;
+ %om slice>=hereIsNotNan anv?nd befintlig lv segmentering
+ if slice>=hereIsNotNan
+ finalmitralmask=zeros(imageSizeY,imageSizeX);
+ endoX=round(SET(EXlocation).EndoX(:,:,slice));
+ endoY=round(SET(EXlocation).EndoY(:,:,slice));
+ for l=1:numel(SET(EXlocation).EndoY(:,:,slice))
+ finalmitralmask(endoX(l),endoY(l))=1;
+ end
+
+ se = strel('square',10);
+ finalmitralmask=(imdilate(finalmitralmask,se));
+ finalmitralmask=imfill(finalmitralmask);
+% figure
+% imshow(finalmitralmask)
+ else
+ %hitta kantpunkter
+ scanwidth=10;
+
+ for k=1:100
+ sumyXled=0;
+
+ sumyXled= sum(im2(round(meanX)-scanwidth:round(meanX)+scanwidth, round(meanY)+k));
+
+ if sumyXled/(scanwidth*2)<0.5
+ edgeX=round(meanY)+k;
+ break
+ end
+ end
+
+ isedgeYcreated=0;
+ for k=1:100
+ sumyYled=0;
+ sumyYled= sum(im2(round(meanX)+k, round(meanY)-scanwidth:round(meanY)+scanwidth));
+
+ if sumyYled/(scanwidth*2)<0.5
+ edgeY=round(meanX)+k;
+ isedgeYcreated=1;
+ break
+ end
+
+ end
+
+ isedgeY2created=0;
+ for k=1:100
+ sumyYled=0;
+ sumyYled= sum(im2(round(meanX)-k, round(meanY)-scanwidth:round(meanY)+scanwidth));
+
+ if sumyYled/(scanwidth*2)<0.5
+ edgeY2=round(meanX)-k;
+ isedgeY2created=1;
+ break
+ end
+ end
+
+ if isedgeY2created==0 || isedgeYcreated==0
+ newmeanX=meanX;
+ else
+ newmeanX=(edgeY+edgeY2)/2;
+ end
+ meanX=newmeanX;
+
+ %Create circlemask
+ imageSizeX =SET(EXlocation).YSize;
+ imageSizeY = SET(EXlocation).XSize;
+ [columnsInImage rowsInImage] = meshgrid(1:imageSizeX, 1:imageSizeY);
+ centerX = meanY;
+ centerY = meanX;
+ if isedgeYcreated==0
+ radius = round(max([edgeX-meanY meanX-edgeY2]));
+ else
+ radius = round(max([edgeX-meanY edgeY-meanX]));
+ end
+ radius1=[radius1; radius];
+ if radius<30
+ radius=30;
+ end
+ if radius>55
+ radius=55;
+ end
+ circlePixels = (rowsInImage - centerY).^2 ...
+ + (columnsInImage - centerX).^2 <= radius.^2;
+
+ immm=imfuse(im2,circlePixels);
+ immm=im2.*circlePixels;
+
+ linemask= columnsInImage> (round(meanY)-radius);
+
+
+
+ L=bwlabel(im2.*linemask);
+
+ centerpoints=[];
+ centerdists=[];
+ sizes=[];
+ for k=1:max(max(L))
+ [C,R]=find(L==k);
+ sizes= [sizes; length(R)];
+ centerpoints=[centerpoints; mean(R) mean(C)];
+ centerdists= [centerdists; sqrt((mean(R)-meanY)^2+(mean(C)-meanX)^2)];
+ end
+ maxsize=max(sizes);
+ bigobjindex=sizes>(maxsize/4);
+ O=find(bigobjindex);
+ centerdists2=centerdists(O);
+ centerpoints2=centerpoints(O,:);
+ EndoObjNbr=find(centerdists==min(centerdists2));
+ L= L==EndoObjNbr;
+ if maxsize>8000
+ L=circlePixels;
+ end
+ mitsizes=[mitsizes maxsize];
+
+% if sum(sum(L))>15000
+% [C,R]=find(L);
+% xline=mean(R);
+% linemask= columnsInImage> xline-radius;
+% L=L.*linemask;
+% L=bwlabel(L);
+% centerpoints=[];
+% centerdists=[];
+% sizes=[];
+% for k=1:max(max(L))
+% [C,R]=find(L==k);
+% sizes= [sizes; length(R)];
+% centerpoints=[centerpoints; mean(R) mean(C)];
+% centerdists= [centerdists; sqrt((mean(R)-meanY)^2+(mean(C)-meanX)^2)];
+% end
+% maxsize=max(sizes);
+% bigobjindex=sizes>(maxsize/2);
+% O=find(bigobjindex);
+% centerdists2=centerdists(O);
+% centerpoints2=centerpoints(O,:);
+% EndoObjNbr=find(centerdists==min(centerdists2));
+% L= L==EndoObjNbr;
+% end
+ finalmitralmask=L;
+
+ end
+ [yM,xM]=find(finalmitralmask);
+
+ % Aortamask
+
+ linemaskA= columnsInImage3000
+
+ se = strel('square',7);
+ L = imerode(L,se);
+ L=bwlabel(L>0);
+ iseroded=iseroded+1;
+ break
+ end
+ end
+ for k=1:max(max(L))
+ if sum(sum(L==k))>3000
+
+ se = strel('square',7);
+ L = imerode(L,se);
+ L=bwlabel(L>0);
+ iseroded=iseroded+1;
+ break
+ end
+ end
+ centerpoints=[];
+ centerdists=[];
+ sizes=[];
+ isitnegative=[];
+
+ for k=1:max(max(L))
+ [C,R]=find(L==k);
+ sizes= [sizes; length(R)];
+ centerpoints=[centerpoints; mean(R) mean(C)];
+ centerdists= [centerdists; sqrt((mean(R)-pointtolookfor)^2+(mean(C)-meanX)^2)];
+ isitnegative=[isitnegative; (mean(R)-pointtolookfor)<0];
+ end
+
+ maxsize=max(sizes);
+ bigobjindex=sizes>(maxsize/10);
+ O=find(bigobjindex);
+ centerdists2=centerdists(O);
+ centerpoints2=centerpoints(O,:);
+ if isitnegative(find(centerdists==min(centerdists2)))==0
+ centerdists2=sort(unique(centerdists2));
+ EndoObjNbr=find(centerdists==centerdists2(end-1));
+ else
+ EndoObjNbr=find(centerdists==min(centerdists2));
+ end
+ L2=L;
+ L= L==EndoObjNbr;
+
+ if sum(sum(L))>8000
+
+ centerX = pointtolookfor;
+ centerY = meanX;
+ radius = 50;
+ circlePixels = (rowsInImage - centerY).^2 ...
+ + (columnsInImage - centerX).^2 <= radius.^2;
+ finalaortamask=L.*circlePixels;
+ else
+ finalaortamask=L ;
+ end
+ while iseroded>0
+ finalaortamask= imdilate(finalaortamask,se);
+ iseroded=iseroded-1;
+ end
+
+ % check if the mask is bad
+
+ [RA,CA]=find(finalaortamask);
+ [RM,CM]=find(finalmitralmask);
+
+ lengthsofthisIm=[lengthsofthisIm sqrt((pointtolookfor-max(CA))^2 + (meanX-mean( RA(find(CA==max(CA)))))^2)];
+
+ for i=1:length(CA)
+ dist(i) = sqrt((pointtolookfor-CA(i))^2 + (meanX-RA(i))^2) ;
+ end
+
+
+
+
+ if mean(RA)>mean(RM)
+ centerdists2=sort(unique(centerdists2));
+ if length(centerdists2)>1
+ centerdists2(1)=200;
+ end
+ EndoObjNbr=find(centerdists==min(centerdists2));
+
+if sum(sum(L2==EndoObjNbr))>500 && min(dist(find(CA==max(CA))))>30
+ L= L2==EndoObjNbr;
+
+ if sum(sum(L))>8000
+
+ centerX = pointtolookfor;
+ centerY = meanX;
+ radius = 50;
+ circlePixels = (rowsInImage - centerY).^2 ...
+ + (columnsInImage - centerX).^2 <= radius.^2;
+ finalaortamask=L.*circlePixels;
+ else
+ finalaortamask=L ;
+ end
+ while iseroded>0
+ finalaortamask= imdilate(finalaortamask,se);
+ iseroded=iseroded-1;
+ end
+end
+ end
+ if min(dist(find(CA==max(CA))))>35 || slice>hereIsNotNan+3
+ finalaortamask= finalaortamask*0;
+ end
+ sizeoA(slice-firstZslice+1)= sum(sum(finalaortamask));
+% if sum(sum(finalaortamask))>5500
+% finalaortamask= finalaortamask*0;
+% end
+
+ [yA,xA]=find(finalaortamask);
+
+
+ % Save to mask & Dilate
+
+ outputmask2=uint8(((finalaortamask+finalmitralmask)>0));
+ outputmaskMitral=uint8(((finalmitralmask)>0));
+ outputmaskAortic=uint8(((finalaortamask)>0));
+
+
+ simm=SET(seg).IM;
+simm=squeeze(simm);
+% if slice>=(hereIsNotNan-8) && slice<(hereIsNotNan+8)
+% figure
+% subplot(1,2,1)
+% imagesc(simm(:,:,slice))
+% colormap('gray');
+% hold on
+%
+% [~,c] = contour((finalaortamask)>0);
+% c.LineColor= [0 0 1];
+%
+% [~,c] = contour((finalmitralmask)>0);
+% c.LineColor= [1 0 0];
+% slice
+% end
+
+
+ se = strel('square',20);
+ outputmask3=imfill(imdilate(outputmask2,se));
+ outputmask2=edge(imfill(imdilate(outputmask2,se)));
+
+ outputmaskMitral=imfill(imdilate(outputmaskMitral,se));
+ outputmaskAortic=imfill(imdilate(outputmaskAortic,se));
+
+ [yM,xM]=find(outputmaskMitral);
+ [yA,xA]=find(outputmaskAortic);
+
+ if isempty(max(xA))
+ linemaskA= uint8(columnsInImage < min(xM));
+ else
+ linemaskA= uint8(columnsInImage < max(xA));
+ end
+ linemaskM= uint8(~linemaskA);
+
+ threedvol(:,:,slice) = uint8(outputmask2);
+ threedvol2(:,:,slice) = uint8(outputmask3);
+ threedvolM(:,:,slice) = uint8(outputmask3.*linemaskM);
+ threedvolA(:,:,slice) = uint8(outputmask3.*linemaskA);
+
+% figure
+% imagesc(segim(:,:,1,slice))
+% colormap('gray');
+% hold on
+%
+% [~,c] = contour((outputmask3.*linemaskA)>0);
+% c.LineColor= [0 1 1]; [~,c] = contour((outputmask3.*linemaskM)>0);
+% c.LineColor= [0 0 1]; plot(pointtolookfor,meanX,'o');
+
+
+end
+h = waitbar(0,'Please wait.');
+
+threedvol=uint8(threedvol);
+outputmask2 = segment3dp.resamplestack(seg,no,threedvol,h); %edge
+threedvol2=uint8(threedvol2);
+outputmask3 = segment3dp.resamplestack(seg,no,threedvol2,h);
+threedvolM=uint8(threedvolM);
+outputmaskM = segment3dp.resamplestack(seg,no,threedvolM,h);
+threedvolA=uint8(threedvolA);
+outputmaskA = segment3dp.resamplestack(seg,no,threedvolA,h);
+
+close(h);
+
+[~,~,zet]=size(outputmask2);
+if onORoff==0
+ for i=1:zet
+ SET(no).CT.CalciumMask(:,:,1,i) =uint8(3)*uint8(uint8(SET(no).CT.CalciumMask(:,:,1,i))==2).*uint8(outputmask3(:,:,i))+ 4* uint8((outputmask2(:,:,i)));
+ end
+elseif onORoff==1
+ for i=1:zet
+ SET(no).CT.CalciumMask(:,:,1,i) =uint8(7)*uint8(uint8(SET(no).CT.CalciumMask(:,:,1,i))==2).*uint8(outputmaskM(:,:,i)) + uint8(6)*uint8(uint8(SET(no).CT.CalciumMask(:,:,1,i))==2).*uint8(outputmaskA(:,:,i)) + uint8(4)*uint8(outputmask2(:,:,i));
+ end
+end
+end
+
+
+disp('dsds');
+
+%---------------------------
+function removeallcalciumsegmentation_Callback
+%---------------------------
+%removes all calciumsegmentation
+
+global DATA SET NO
+no=NO;
+if ~isfield(SET(no).CT, 'CalciumMask')
+ myfailed('There is no calcium mask in this image stack');
+ return
+end
+
+threes=find (SET(no).CT.CalciumMask==3);
+sixs=find (SET(no).CT.CalciumMask==6);
+sevens=find(SET(no).CT.CalciumMask==7);
+eights=find (SET(no).CT.CalciumMask==8);
+
+CalciumMask=SET(no).CT.CalciumMask;
+
+if ~isempty(threes)
+ CalciumMask(threes)=5;
+end
+if ~isempty(sixs)
+ CalciumMask(sixs)=5;
+end
+if ~isempty(sevens)
+ CalciumMask(sevens)=5;
+end
+if ~isempty(eights)
+ CalciumMask(eights)=5;
+end
+
+SET(no).CT.CalciumMask=CalciumMask;
+
+
+DATA.ViewIM{DATA.CurrentPanel} = [];
+drawfunctions('drawimages',DATA.CurrentPanel);
+
+%---------------------------
+function removeallcalciumsegmentationonthisslice_Callback
+%---------------------------
+%removes all calciumsegmentation
+
+global DATA SET NO
+no=NO;
+if ~isfield(SET(no).CT,'CalciumMask')
+ myfailed('There is no calcium mask in this image stack');
+ return
+end
+
+slice=SET(no).CurrentSlice;
+threes=find (SET(no).CT.CalciumMask(:,:,1,slice)==3);
+sixs=find (SET(no).CT.CalciumMask(:,:,1,slice)==6);
+sevens=find(SET(no).CT.CalciumMask(:,:,1,slice)==7);
+eights=find (SET(no).CT.CalciumMask(:,:,1,slice)==8);
+
+CalciumMask=SET(no).CT.CalciumMask(:,:,1,slice);
+
+if ~isempty(threes)
+ CalciumMask(threes)=5;
+end
+if ~isempty(sixs)
+ CalciumMask(sixs)=5;
+end
+if ~isempty(sevens)
+ CalciumMask(sevens)=5;
+end
+if ~isempty(eights)
+ CalciumMask(eights)=5;
+end
+
+SET(no).CT.CalciumMask(:,:,1,slice)=CalciumMask;
+
+
+DATA.ViewIM{DATA.CurrentPanel} = [];
+drawfunctions('drawimages',DATA.CurrentPanel);
diff --git a/source/cessfpmarsegmentation.p b/source/cessfpmarsegmentation.p
index 5fac19e..d6b2e58 100644
Binary files a/source/cessfpmarsegmentation.p and b/source/cessfpmarsegmentation.p differ
diff --git a/source/changelog.p b/source/changelog.p
index e5c4eb3..1561768 100644
Binary files a/source/changelog.p and b/source/changelog.p differ
diff --git a/source/checkdatabaselicense.p b/source/checkdatabaselicense.p
index 840bcea..4cbc31d 100644
Binary files a/source/checkdatabaselicense.p and b/source/checkdatabaselicense.p differ
diff --git a/source/checkpath.m b/source/checkpath.m
index 2a682f3..9675a65 100644
--- a/source/checkpath.m
+++ b/source/checkpath.m
@@ -4,18 +4,74 @@ function checkpath(pathname)
%path.
%Einar Heiberg
-if nargin<1
- [pathname] = fileparts(which('segment_main'));
-end;
-%get current path
-p = path;
+global DATA
-if isempty(strfind(p,pathname))
- %Add to the path;
- addpath(pathname);
- if exist([pathname filesep 'tensorarray'],'dir')
- addpath([pathname filesep 'tensorarray']); %Required by Vortex methods
- addpath([pathname filesep 'tensorarray' filesep 'VortexMethods']); %Required by Vortex methods
+if isdeployed()
+
+ %Check if in correct path
+ if iscorrectpath(pathname)
+ return;
end
-end;
+
+ %--- Ok. Not correct look in program files
+ programfilesdir = getenv('programfiles');
+
+ programnamenospace = DATA.ProgramName;
+ programnamenospace = programnamenospace(programnamenospace~=' ');
+
+ softwarepath = [programfilesdir filesep 'Medviso' filesep programnamenospace filesep 'application'];
+ if iscorrectpath(softwarepath)
+ %Found it change path to this folder
+ cd(softwarepath);
+ return
+ end
+
+ myfailed('Software started from another folder than where it was installed. Please adjust shortcut path.');
+
+else
+
+ if nargin<1
+ [pathname] = fileparts(which('segment_main'));
+ end
+
+ %get current path
+ p = path;
+
+ if ~contains(p,pathname)
+ %Add to the path;
+ addpath(pathname);
+ if exist([pathname filesep 'tensorarray'],'dir')
+ addpath([pathname filesep 'tensorarray']); %Required by Vortex methods
+ addpath([pathname filesep 'tensorarray' filesep 'VortexMethods']); %Required by Vortex methods
+ end
+ end
+
+end
+
+%-----------------------------------------
+function correct = iscorrectpath(pathname)
+%-----------------------------------------
+%Check if we are in the correct folder
+global DATA
+
+correct = false;
+
+%--- Check if correct folder by finding ProgramName.exe
+namenospace = DATA.ProgramName;
+namenospace = namenospace(namenospace~=' ');
+wantfile = [namenospace '.exe'];
+f = dir(pathname);
+foundit = false;
+for loop = 1:length(f)
+ if ~f(loop).isdir
+ if strcmp(f(loop).name,wantfile)
+ foundit = true;
+ end
+ end
+end
+
+if foundit
+ %We seem to be in the correct folder
+ correct = true;
+end
diff --git a/source/checkversion.m b/source/checkversion.m
deleted file mode 100644
index 8aff87e..0000000
--- a/source/checkversion.m
+++ /dev/null
@@ -1,43 +0,0 @@
-function checkversion()
- if isdeployed()
- platform = mexext();
- else
- platform = 'source';
- end
-
- versionnbr = parseversionstr(changelog);
- try
- address = java.net.InetAddress.getLocalHost;
- IPaddress = char(address.getHostAddress);
- [online_version] = myurlread(sprintf( ...
- 'http://www.medviso.com/getversion.php?platform=%s&version=%d&ip=%s', ...
- platform,versionnbr,IPaddress),750); %750 is 750ms timeout
- catch %#ok
- return
- end
-
- online_version = str2double(online_version);
-
- try
- if online_version <= versionnbr
- return
- end
- catch %#ok
- return
- end
-
- c = mymenu('A new version is available', ...
- 'Update now', ...
- 'Ask again later');
- if c == 1
- mybrowser('http://www.medviso.com/products/segment/download/');
- end
-end
-
-function r = parseversionstr(vstr)
- tt = sscanf(vstr, '%d.%d R%d');
- if numel(tt) ~= 3
- error('SEGMENT:ERROR', 'Couldn''t parse version string');
- end
- r = tt(3);
-end
\ No newline at end of file
diff --git a/source/checkversion.p b/source/checkversion.p
new file mode 100644
index 0000000..2469810
Binary files /dev/null and b/source/checkversion.p differ
diff --git a/source/cinewindow.m b/source/cinewindow.m
index ab3a9b0..7a45c2e 100644
--- a/source/cinewindow.m
+++ b/source/cinewindow.m
@@ -8,7 +8,7 @@ function cinewindow(varargin)
else
macro_helper(varargin{:});
feval(varargin{:});
-end;
+end
%------------
function init
@@ -33,7 +33,7 @@ function cinewindow(varargin)
%Start the timer
start(DATA.CineTimer);
-end;
+end
%------------------------
function update(varargin)
@@ -47,20 +47,19 @@ function update(varargin)
%length is 2. When called on setup the length is zero.
try
- set(DATA.Handles.cinetoolicon,'state','off');
stop(DATA.CineTimer);
catch %#ok
- end;
+ end
DATA.CineTimer = [];
try
delete(DATA.Handles.cineaxes);
catch %#ok
- end;
+ end
s = [];
return;
-end;
+end
if isempty(s) || isempty(varargin)
%First call => init
@@ -74,8 +73,8 @@ function update(varargin)
try
delete(DATA.Handles.cineaxes);
catch
- end;
- end;
+ end
+ end
DATA.Handles.cineaxes = axes('position',...
[0.04 0.56 0.3 0.3],... %[0.05 0.68 0.3 0.3],...
@@ -108,7 +107,7 @@ function update(varargin)
%Buttondown
set(s.imagehandle,'ButtondownFcn','cinewindow(''update'',''kill'')');
return;
-end;
+end
%next update
s.count = s.count+1;
@@ -122,12 +121,12 @@ function update(varargin)
%Get next slice
f = 0.25;
s.slice = 1+round((SET(s.no).ZSize-1)*rem(now*3600*24*f,1));
-end;
+end
-if s.count>40000;
+if s.count>40000
update('kill');
return;
-end;
+end
%Check if is handle
if ishandle(s.imagehandle)
@@ -135,4 +134,4 @@ function update(varargin)
else
update('kill');
return;
-end;
+end
diff --git a/source/commandlinehelper.m b/source/commandlinehelper.m
new file mode 100644
index 0000000..233068c
--- /dev/null
+++ b/source/commandlinehelper.m
@@ -0,0 +1,143 @@
+function [varargout] = commandlinehelper(arg,varargin)
+%Helper function to handle commandline options
+
+%Einar Heiberg
+
+persistent s %store options in persistent variable
+
+%--- Define commandline options
+c = [];
+c(1).switch = 'StudiesFolder'; c(1).nargin = 1; c(1).default = ''; c(1).description = ': folder software reads input files (dicoms), each subfolder is one series';
+c(2).switch = 'DICOMStorageFolder'; c(2).nargin = 1; c(2).default = ''; c(2).description = ': folder where output dicom files are stored';
+c(3).switch = 'LogFolder'; c(3).nargin = 1; c(3).default = ''; c(3).description = ': folder where log-files are stored';
+c(4).switch = 'NoQuit'; c(4).nargin = 0; c(4).default = false; c(4).description = ': Disable quit options';
+c(5).switch = 'NoPopUp'; c(5).nargin = 0; c(5).default = false; c(5).description = ': Disable pop-up when starting';
+c(6).switch = 'License'; c(6).nargin = 1; c(6).default = ''; c(6).description = ': License file';
+c(7).switch = 'TempStorageFolder'; c(7).nargin = 1; c(7).default = ''; c(7).description = ': folder for temporal file storage';
+c(8).switch = 'UseDefaultStudiesFolder'; c(8).nargin = 0; c(8).default = false; c(8).description = ': Create studies folder if it not existing according to default preference settings';
+c(9).switch = 'UseComputerAETitle'; c(9).nargin = 0; c(9).default = false; c(9).description = ': Use computer AETitle in case if in segpref was different one assigned';
+switch arg
+ case 'parse'
+ %do nothing here, do later after switch clause
+ case 'getparameters'
+ %return parameters
+ varargout = cell(1,1);
+ varargout{1} = s;
+ return
+ case 'storetopref'
+ %store settings to prefstruct
+ storetopref(s);
+ return;
+ case 'reset'
+ %reset persistent variable
+ s = [];
+ for loop = 1:length(c)
+ s.(c(loop).switch) = c(loop).default;
+ end
+ otherwise
+ error('Invalid options to commandlinehelper');
+end
+
+%--- parse clause
+
+if isempty(varargin)
+ return
+end
+
+disp('------------------------------');
+disp('Parsing commandline options');
+
+%Initialize s
+s = [];
+for loop = 1:length(c)
+ s.(c(loop).switch) = c(loop).default;
+end
+
+%Add -help
+n = length(c)+1;
+c(n).switch = 'help'; c(n).nargin = 0; c(n).default = '';
+
+%--- parse options
+parameters = varargin;
+
+while ~isempty(parameters)
+ found = false;
+ thisparameter = parameters{1}; %first of parameters
+ if isequal(thisparameter,'-help')
+ displayhelp(c);
+ parameters = parameters(2:end);
+ else
+ %loop over to find
+ for loop = 1:length(c)
+ if isequal(['-' lower(c(loop).switch)],lower(thisparameter))
+ found = true;
+ numargs = c(loop).nargin;
+ option = c(loop).switch;
+ if numargs==1
+ arg = cleanstring(parameters{2}); %more than one argument not yet implemented
+ parameters = parameters(3:end);
+ disp(sprintf(' * %s=%s',c(loop).switch,arg)); %#ok
+ else
+ arg = true; %to indicate that it is found
+ parameters = parameters(2:end);
+ disp(sprintf(' * %s=true',c(loop).switch)); %#ok
+ end
+
+ end
+ end
+
+ if found
+ s.(option) = arg; %store it
+ else
+ %warn user
+ disp(sprintf(' * option %s not recognized, ignored.',thisparameter)); %#ok
+ parameters = parameters(2:end); %Remove parameters
+ end
+
+
+ end
+
+end
+
+disp('------------------------------');
+
+%----------------------
+function displayhelp(c)
+%----------------------
+%Displays helptext
+
+disp(sprintf('Help information, version %s',changelog)); %#ok
+disp(' ');
+for loop = 1:(length(c)-1)
+ disp(sprintf('-%s %s',lower(c(loop).switch),c(loop).description)); %#ok
+ disp(' ');
+end
+
+%----------------------
+function storetopref(s)
+%----------------------
+%Store settings to pref struct (DATA.Pref)
+
+global DATA
+
+if isempty(s)
+ return
+end
+
+f = fieldnames(s);
+
+for loop = 1:length(f)
+ DATA.Pref.(f{loop}) = s.(f{loop});
+end
+
+%--------------------------------
+function stri = cleanstring(stri)
+%--------------------------------
+%Cleans string from " signs
+
+%Remove "
+stri = stri(stri~='"');
+
+%Remove '
+c = '''';
+stri = stri(stri~=c);
diff --git a/source/communicate.p b/source/communicate.p
index e36b49c..c212676 100644
Binary files a/source/communicate.p and b/source/communicate.p differ
diff --git a/source/createfunctions.m b/source/createfunctions.m
new file mode 100644
index 0000000..f52ff8c
--- /dev/null
+++ b/source/createfunctions.m
@@ -0,0 +1,839 @@
+function [varargout] = createfunctions(varargin)
+% Functions for creating graphicsobjects and content in image panels
+% Klas
+%Invoke subfunction
+macro_helper(varargin{:}); %future macro recording use
+if (nargout)
+ [varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
+else
+ feval(varargin{:}); % FEVAL switchyard
+end
+
+%----------------------------------------------
+function addcolorbar(panel,contrast,brightness) %#ok
+%----------------------------------------------
+%Add colorbar to axes in panel
+global DATA SET
+
+if DATA.GUISettings.ShowColorbar
+ no = DATA.ViewPanels(panel);
+ if nargin < 2
+ contrast = SET(no).IntensityMapping.Contrast;
+ brightness = SET(no).IntensityMapping.Brightness;
+ end
+ %addcolorbar
+ h = colorbar(DATA.Handles.imageaxes(panel),'East');
+
+ [win, level] = calcfunctions('con2win',contrast, brightness, no);
+ if ~isempty(win) && ~isempty(level)
+ set(DATA.Handles.imageaxes(panel),'CLim',[(level-win/2) (level+win/2)])
+ else
+ colorbar(DATA.Handles.imageaxes(panel),'off')
+ return;
+ end
+ if isempty(SET(no).Colormap)
+ colormap(h,'gray');
+ else
+ colormap(h,SET(no).Colormap);
+ end
+ h.Color = DATA.GUISettings.ForegroundColor;
+ %h.Limits =
+else
+ %removecolorbar
+ colorbar(DATA.Handles.imageaxes(panel),'off')
+end
+
+%---------------------
+function createplotoverlay %#ok
+%-----------------------
+%Creates graphical objects in volume and flow axes.
+global DATA
+
+
+DATA.Handles.volumeaxes.FontSmoothing = 'off';
+DATA.Handles.flowaxes.FontSmoothing = 'off';
+DATA.Handles.timebaraxes.FontSmoothing = 'off';
+
+
+volax = DATA.Handles.volumeaxes;
+flowax = DATA.Handles.flowaxes;
+timeax = DATA.Handles.timebaraxes;
+
+lc = DATA.GUISettings.BarColor;
+
+%time plot
+ylim(DATA.Handles.timebaraxes, [0,1]); %always between 0 and 1
+DATA.Handles.timebar = line('Parent',timeax,'XData',nan,'YData',nan,'Color',lc,'linewidth',2);
+DATA.Handles.timebaraxeshelpers=line('Parent',timeax,'XData',nan,'YData',nan,'Color','k');
+DATA.Handles.edtimebartext=text('Parent',timeax,'position',[nan nan],'color',lc,'String','ED');
+DATA.Handles.estimebartext=text('Parent',timeax,'position',[nan nan],'color',lc,'String','ES');
+DATA.Handles.edtimebarline=line('Parent',timeax,'XData',nan,'YData',nan,'Color',lc,'linewidth',2);
+DATA.Handles.estimebarline=line('Parent',timeax,'XData',nan,'YData',nan,'Color',lc,'linewidth',2);
+set([DATA.Handles.estimebartext DATA.Handles.estimebarline],'ButtonDownFcn','segment(''esedtimebar_Buttondown'',''es'')');
+set([DATA.Handles.edtimebartext DATA.Handles.edtimebarline],'ButtonDownFcn','segment(''esedtimebar_Buttondown'',''ed'')');
+set([DATA.Handles.timebar,timeax,DATA.Handles.timebaraxeshelpers],'buttondownFcn','segment(''timebar_Buttondown'')');
+set(timeax,'ytick',[])
+xlabel(timeax,dprintf('Time [ms]'),'color',DATA.GUISettings.VolumeAxesColor,'units','normalized');
+set(volax,...
+ 'XColor',DATA.GUISettings.VolumeAxesColor,...
+ 'YColor',DATA.GUISettings.VolumeAxesColor);
+
+%volume plot
+DATA.Handles.timebarlv = line('Parent',volax,'XData',nan,'YData',nan,'Color',lc,'linewidth',2);
+DATA.Handles.volumecurve = line('Parent',volax,'XData',nan,'YData',nan,'Color','r','markersize',5,'linestyle','-.');
+DATA.Handles.masscurve = line('Parent',volax,'XData',nan,'YData',nan,'Color','b','markersize',5,'linestyle','-.');
+DATA.Handles.rvvcurve = line('Parent',volax,'XData',nan,'YData',nan,'Color','m','markersize',5,'linestyle','-.');
+DATA.Handles.volumeaxeshelpers = line('Parent',volax,'XData',nan,'YData',nan,'Color','k');
+DATA.Handles.estext=text('Parent',volax,'position',[nan nan],'color',lc,'String','ES');
+DATA.Handles.edtext=text('Parent',volax,'position',[nan nan],'color',lc,'String','ED');
+DATA.Handles.esline= line('Parent',volax,'XData',nan,'YData',nan,'Color',lc);
+DATA.Handles.edline= line('Parent',volax,'XData',nan,'YData',nan,'Color',lc);
+DATA.Handles.lvmtext=text('Parent',volax,'position',[nan nan],'color','b','fontsize',8,'String','LVM','verticalalignment','bottom');
+set([DATA.Handles.estext,DATA.Handles.esline],'buttondownFcn','segment(''esed_Buttondown'',''es'')')
+set([DATA.Handles.edtext,DATA.Handles.edline],'buttondownFcn','segment(''esed_Buttondown'',''ed'')')
+set([volax, DATA.Handles.timebarlv,DATA.Handles.volumecurve,DATA.Handles.masscurve,DATA.Handles.rvvcurve,DATA.Handles.volumeaxeshelpers],...
+ 'buttondownFcn','segment(''volumeaxes_Buttondown'')')
+ylabel(volax,dprintf('Volume [ml]'),'color',DATA.GUISettings.VolumeAxesColor,'units','normalized');
+xlabel(volax,dprintf('Time [ms]'),'color',DATA.GUISettings.VolumeAxesColor,'units','normalized');
+set(volax,...
+ 'XColor',DATA.GUISettings.VolumeAxesColor,...
+ 'YColor',DATA.GUISettings.VolumeAxesColor);
+
+%flow plot
+DATA.Handles.timebarflow = line('Parent',flowax,'XData',nan,'YData',nan,'Color',lc,'linewidth',2);
+DATA.Handles.outerbarsflow = line('Parent',flowax,'XData',nan,'YData',nan,'Color',lc,'linewidth',2);
+DATA.Handles.zerolineflow = line('parent', flowax,'xdata',[0 10000000],'ydata',[0 0],'color','k','linestyle',':');
+DATA.Handles.flowcurve = line('Parent',flowax,'XData',nan,'YData',nan,'Color','b','markersize',5,'linestyle','-.');
+DATA.Handles.flowtext = text(nan,nan,'[Eddy]', ...
+ 'Parent',flowax,'FontSize',10,'HorizontalAlignment','right','VerticalAlignment','top','Color',DATA.GUISettings.ForegroundColor);
+DATA.Handles.flowaxeshelpers = line('Parent',flowax,'XData',nan,'YData',nan,'Color','k');
+set([flowax,DATA.Handles.zerolineflow,DATA.Handles.flowcurve,DATA.Handles.flowaxeshelpers,DATA.Handles.outerbarsflow],...
+ 'ButtonDownFcn','segment(''flowaxes_Buttondown'')');
+ylabel(flowax,dprintf('Flow [ml/s]'),'color',DATA.GUISettings.VolumeAxesColor,'units','normalized');
+xlabel(flowax,dprintf('Time [ms]'),'color',DATA.GUISettings.VolumeAxesColor,'units','normalized');
+set(flowax,...
+ 'XColor',DATA.GUISettings.VolumeAxesColor,...
+ 'YColor',DATA.GUISettings.VolumeAxesColor);
+
+%---------------------
+function createaxes(rows,cols) %#ok
+%-----------------------
+%Creates imageaxes and boxaxes. The field boxaxes is probably unnecessary.
+global DATA
+
+%Create 2 imageaxes
+left = DATA.GUISettings.LeftGapWidth; %0.12;
+right = 1-DATA.GUISettings.RightGapWidth-0.02; %Based on that the report panel can never be more than 220.
+bottom = DATA.GUISettings.BottomGapHeight; %0.013;
+top = 1-DATA.GUISettings.TopGapHeight;
+width = right-left;
+height = top-bottom;
+
+%Create image area with grid for boxes.
+DATA.Handles.boxaxes = axes('position',...
+ [left bottom width height],...
+ 'parent',DATA.fig,'visible','off');
+
+%2 => 0.5
+%3 => 0.333 0.666
+h = [];
+hold(DATA.Handles.boxaxes,'on');
+for rloop=1:(rows-1)
+ h = [h;plot(DATA.Handles.boxaxes,[0 1],[1/rows*rloop 1/rows*rloop])];%,DATA.GUISettings.BoxAxesLineSpec)]; %#ok
+end
+
+for cloop=1:(cols-1)
+ h = [h;plot(DATA.Handles.boxaxes,[1/cols*cloop 1/cols*cloop],[0 1])]; %#ok
+end
+
+h = [h;plot(DATA.Handles.boxaxes,[0 1],[0 0])];
+h = [h;plot(DATA.Handles.boxaxes,[0 1],[1 1])];
+h = [h;plot(DATA.Handles.boxaxes,[0 0],[0 1])];
+h = [h;plot(DATA.Handles.boxaxes,[1 1],[0 1])];
+hold(DATA.Handles.boxaxes,'off');
+axis(DATA.Handles.boxaxes,'off');
+set(h,'color',[0.1,0.1,0.1],'linewidth',2);
+
+h = [];
+for rloop=(rows-1):-1:0
+ for cloop=0:(cols-1)
+ h = [h axes('position',...
+ [left+cloop*width/cols bottom+rloop*height/rows width/cols height/rows],...
+ 'parent',DATA.fig,'visible','off')]; %#ok
+ end
+end
+
+%Store handles
+axis(h,'ij')
+set(h,'fontsmoothing','off')
+DATA.Handles.imageaxes = h;
+
+%---------------------
+function createaxesandimagehandles(maxnumaxes) %#ok
+%-----------------------
+%Creates the maximum used imageaxes and boxaxes in segment. The field boxaxes is probably unnecessary.
+global DATA
+
+% %Sizes in which we place the panels
+% left = DATA.GUISettings.LeftGapWidth; %0.12;
+% right = 1-DATA.GUISettings.RightGapWidth-0.02; %Based on that the report panel can never be more than 220.
+% bottom = DATA.GUISettings.BottomGapHeight; %0.013;
+% top = 1-DATA.GUISettings.TopGapHeight;
+% width = right-left;
+% height = top-bottom;
+
+%Create image area with grid for boxes.
+DATA.Handles.boxaxes = axes('position',...
+ [0 0 0 0],'color',[0.1,0.1,0.1],...
+ 'parent',DATA.fig,'visible','off');
+
+%This is the line in boxaxes which actually makeup the box around all the panels
+DATA.Handles.box = line('parent',DATA.Handles.boxaxes,'XData',nan,'YData',nan,'linewidth',2);
+
+%create empty axes
+h = [];
+for i = 1:maxnumaxes
+ h = [h axes('position',...
+ [0 0 0 0],...
+ 'parent',DATA.fig,'visible','off')]; %#ok
+end
+
+%Store handles
+axis(h,'ij')
+set(h,'fontsmoothing','off')
+DATA.Handles.imageaxes = h;
+
+%Initiate imagehandles in all axes
+DATA.Handles.imagehandles = gobjects(1,maxnumaxes);
+for i = 1:maxnumaxes
+ DATA.Handles.imagehandles(i) = image('parent',DATA.Handles.imageaxes(i),'cdata',[]);
+end
+
+%Create sliders (used in 3DPrint for scrolling)
+h = [];
+for i = 1:maxnumaxes
+ h = [h uicontrol('Style','slider','parent',DATA.fig,'visible','off')]; %#ok
+end
+DATA.Handles.sliders = h;
+
+%-----------------------------------
+function create3dpoverlay %#ok |