Update 13/5/2019

This commit is contained in:
João Narciso 2019-05-13 10:15:01 +02:00
parent 8d23210865
commit cb821f8848
6 changed files with 197 additions and 77 deletions

View File

@ -1,8 +1,13 @@
classdef CardiacPhase < Phase
properties
FullPhase = Phase;
IMF = uint32(0);
SystolePositions = [];
DiastolePositions = [];
end
properties % (GetAccess = private) should become private
SystoleTreshold = double(0);
DiastoleTreshold = double(0);
end
@ -12,32 +17,30 @@ classdef CardiacPhase < Phase
if nargin==0;return;end
% gets properties of superclass
obj.FullPhase = Phase.ModePhases;
obj.WorkLoad = Phase.WorkLoad;
obj.Video = Phase.Video;
end
%
% methods %set methods
% % function set.ToBeSetByUser(obj,val)
% % if ~isboolean(val);error('provide a boolean value please');end
% % obj.ToBeSetByUser=val;
% % end
% end
%
% Choose the correct IMF depending on the work load
function SelectPhase(obj)
if strcmp(obj.WorkLoad,'Rest')
imf_number = 3;
else if strcmp(obj.WorkLoad,'Exercise')
imf_number = 2;
else if strcmp(obj.WorkLoad,'Continuous Acquisition')
imf_number = 3;
end
end
prompt = {'Choose the IMF representing cardiac phase:','Combine with additional IMF:'};
dlgtitle = 'Cardiac Phase';
dims = [1 60];
definput = {'3',''};
opts.Interpreter = 'tex';
answer = inputdlg(prompt,dlgtitle,dims,definput,opts);
obj.IMF = str2num(answer{1});
if length(answer{2}) > 0.
new_imf = obj.FullPhase(obj.IMF,:) + obj.FullPhase(str2num(answer{2}),:); % if the IMFs are unorthogonal combine them into one IMF
obj.FullPhase(obj.IMF,:) = new_imf;
obj.FullPhase(str2num(answer{2}),:) = [];
Complot(obj.FullPhase);
end
% SHOULD TRY TO USE GETPHASE FUNCTION
% obj.IMF = imf_number;
% GetPhase@Phase(obj.FullPhase,obj.IMF);
obj.Values = obj.FullPhase(imf_number,:); % Phase corresponding to the cardiac phase
obj.Values = obj.FullPhase(obj.IMF,:); %Phase corresponding to respiratory phase
end
% Detects the frame's positions of diastolic events

41
Code/Complot.m Normal file
View File

@ -0,0 +1,41 @@
function [] = Complot(varargin)
error(nargchk(1,2,nargin));
[msg,x,S] = Cplotchk(varargin);
error(msg)
% Get some spacing between the various signals
alpha = mean(max(S')-min(S'));
% save alpha alpha
% load alpha alpha
for i = 1:size(S,1)
SS(i,:) = S(i,:) - alpha*(i-1)*ones(size(S(1,:)));
end
% Plotting per se
if nargin == 1
plot(SS')
else
plot(x,SS')
end
axis([x(1) x(length(SS)) min(min(SS)) max(max(SS)) ])
% axis([0 x(length(SS)) min(min(SS)) max(max(SS)) ])
set(gca,'YTick',-size(S,1)*alpha:alpha:0);
set(gca,'YTicklabel',size(S,1)+1:-1:1);
% Reading routine
function [msg,x,S] = Cplotchk(P);
msg = [];
if length(P) > 2
msg = 'Too many inputs.';
else
if length(P) == 1
S = P{1};
x = 1:length(S);
end
if length(P) == 2
x = P{1};
S = P{2};
end
end

View File

@ -3,10 +3,11 @@ classdef Phase < handle
properties
MeanIntensity = [];
Video = [];
WorkLoad = '';
IMFs = [];
ModePhases = [];
Values = [];
NumberOfSlices = uint32(0);
CurrentSlice = uint32(0);
end
properties % (GetAccess = private) should become private
@ -25,37 +26,54 @@ classdef Phase < handle
end
end
methods %set methods
function set.WorkLoad(obj,str)
obj.WorkLoad = str;
% if indx == 1
% obj.WorkLoad = 'Rest';
% else if indx == 2
% obj.WorkLoad = 'Exercise';
% else
% obj.WorkLoad = 'Continuous Acquisition';
% end
end
end
methods
% Extracts the image sequence from the folder
function GetData(obj)
directory = uigetdir(obj.InitialDirectory); % Choose the cineMRI folder
dicomFiles = dir(fullfile(directory, '*.dcm' ));
obj.nFrames = length(dicomFiles); % Number of frames of the cineMRI
info = dicominfo(fullfile(directory,dicomFiles(1).name));
obj.xImageSize = info.Width; % Image width
obj.yImageSize = info.Height; % Image height
obj.Video = zeros(obj.xImageSize, obj.yImageSize, 1, obj.nFrames, 'uint8');
for p=1:obj.nFrames
filename = fullfile(directory, dicomFiles(p).name );
Info=dicominfo(filename);
if Info.Width~=obj.xImageSize || Info.Height~=obj.yImageSize
error('invalid image dimensions')
end
obj.Video(:,:,1,p) = dicomread(filename); % Read the DICOM files in the folder
end
prompt = {'Number of slices:'};
dlgtitle = 'Slice';
dims = [1 60];
definput = {'1'};
opts.Interpreter = 'tex';
answer = inputdlg(prompt,dlgtitle,dims,definput,opts);
obj.NumberOfSlices = str2num(answer{1});
if obj.NumberOfSlices == 1
obj.Video = zeros(obj.xImageSize, obj.yImageSize, 1, obj.nFrames, 'uint8');
for p=1:obj.nFrames
filename = fullfile(directory, dicomFiles(p).name );
Info=dicominfo(filename);
if Info.Width~=obj.xImageSize || Info.Height~=obj.yImageSize
error('invalid image dimensions')
end
obj.Video(:,:,1,p) = dicomread(filename); % Read the DICOM files in the folder
end
else
list_array = 2:1:obj.NumberOfSlices;
list = {'2','3','4','5','6'};
[indx,tf] = listdlg('ListString',list);
obj.CurrentSlice = indx;
obj.nFrames = obj.nFrames/obj.NumberOfSlices;
obj.Video = zeros(obj.xImageSize, obj.yImageSize, 1, obj.nFrames, 'uint8');
for p=1:obj.nFrames
shift = (obj.CurrentSlice-1)*obj.nFrames;
filename = fullfile(directory, dicomFiles(shift+p).name );
Info=dicominfo(filename);
if Info.Width~=obj.xImageSize || Info.Height~=obj.yImageSize
error('invalid image dimensions')
end
obj.Video(:,:,1,p) = dicomread(filename); % Read the DICOM files in the folder
end
end
end
% Gets the mean intensity value of the image sequence usin the
@ -63,12 +81,21 @@ classdef Phase < handle
function GetSignal(obj)
d2IFT = ifft2(obj.Video); % performs Inverse Fourier Transform
d2IFT_shifted = fftshift(d2IFT);
% video = implay(abs(d2IFT_shifted));
% set(video.Parent, 'Name', '2D IFT of the Images Sequence along time');
for i=1:obj.nFrames
obj.MeanIntensity(:,i) = d2IFT_shifted(floor(obj.yImageSize/2),floor(obj.xImageSize/2),i); % extracts intensity of the central point in k-space for every frame
end
obj.MeanIntensity = abs(obj.MeanIntensity);
end
function DisplayIntensity(obj)
plot(obj.MeanIntensity,'-s','LineWidth',0.8,'MarkerSize',4);
end
% Perfomrs Empirical Mode Decomposition
function GetEMD(obj)
obj.IMFs = rParabEmd__L(obj.MeanIntensity,40,40,1);
@ -99,7 +126,7 @@ classdef Phase < handle
set(video.Parent, 'Name', title);
end
function Display(obj)
function DisplayValues(obj)
plot(obj.Values,'-s','LineWidth',0.8,'MarkerSize',4);
end

View File

@ -1,12 +1,12 @@
classdef RespiratoryPhase < Phase
properties
FullPhase = Phase;
IMF = uint32(0);
InspirationPositions = [];
ExpirationPositions = [];
end
properties % (GetAccess = private) should become private
IMF = uint32(0);
InspirationTreshold = double(0);
ExpirationTreshold = double(0);
MaxRespPhase = double(0);
@ -18,25 +18,23 @@ classdef RespiratoryPhase < Phase
if nargin==0;return;end
% gets properties of superclass
obj.FullPhase = Phase.ModePhases;
obj.WorkLoad = Phase.WorkLoad;
% obj.WorkLoad = Phase.WorkLoad;
obj.Video = Phase.Video;
end
% Choose the correct IMF depending on the work load
function SelectPhase(obj)
if strcmp(obj.WorkLoad,'Rest')
imf_number = 5;
else if strcmp(obj.WorkLoad,'Exercise')
imf_number = 4;
else if strcmp(obj.WorkLoad,'Continuous Acquisition')
imf_number = 5;
end
end
end
prompt = {'Choose the IMF representing respiratory phase:'};
dlgtitle = 'Respiratory Phase';
dims = [1 60];
definput = {'5'};
opts.Interpreter = 'tex';
answer = inputdlg(prompt,dlgtitle,dims,definput,opts);
obj.IMF = str2num(answer{1})
% SHOULD TRY TO USE GETPHASE FUNCTION
% obj.IMF = imf_number;
% GetPhase@Phase(obj.FullPhase,obj.IMF);
obj.Values = obj.FullPhase(imf_number,:); %Phase corresponding to respiratory phase
obj.Values = obj.FullPhase(obj.IMF,:); %Phase corresponding to respiratory phase
end
% Detects the frame's positions of inspiration moments

View File

@ -1,3 +1,6 @@
% This function was extracted from https://nl.mathworks.com/matlabcentral/fileexchange/21409-empirical-mode-decomposition
% Authors: Raul Rato (rtr@uninova.DOT.pt) and Manuel Ortigueira (mdortigueira@uninova.pt or mdo@fct.unl.pt)
function rParabEmd = rParabEmd__L (x, qResol, qResid, qAlfa)
dbstop if warning
if(nargin~=4), error('rParabEmd__L: Use with 4 inputs.'), end

View File

@ -1,9 +1,6 @@
% Test Script
% TO DO LIST:
% - Heart beat reconstruction with steady respiratory phase
% - Multislice analysis
% - Choose IMF based on Instantaneous Frequency
% - Error messages and robustness of the methods
clear classes
@ -12,33 +9,53 @@ clear classes
phase = Phase; % creates a Phase object
phase.GetData; % extracts data
%% Visualize data
phase.ShowFrames(:,'cine Images');
%% Time Information
time = 0:1:phase.nFrames-1;
repetitionTime = (1/15); % time between samples
repetitionTime = (1/13); % time between samples
time = repetitionTime*time; % sampling moments in time
%% Workload information
% Should become a set method
% User sets the workload, important to choose the correct IMF
list = {'Rest','Exercise','Continuous Acquisition'};
[indx,tf] = listdlg('ListString',list);
str = list{indx};
phase.WorkLoad = str;
%% Instantaneous Phase Extraction (cardiac ad respiratory)
%% Instantaneous Phase Extraction (cardiac and respiratory)
phase.GetSignal; % gets mean intensity level of the images
% phase.DisplayIntensity;
% title('Mean Intensity Value');
% te=repetitionTime;
% xt=get(gca,'xtick');
% set(gca,'xticklabel',arrayfun(@num2str,xt*te,'un',0)); % adjust x axis to time values
% xlabel('Time (sec)');
phase.GetEMD; % decompose the siganl using EMD
% Complot(phase.IMFs);
% te=repetitionTime;
% xt=get(gca,'xtick');
% set(gca,'xticklabel',arrayfun(@num2str,xt*te,'un',0)); % adjust x axis to time values
% title('Empirical Mode Decomposition');
% xlabel('Time (sec)');
% legend('IMF1','IMF2','IMF3','IMF4','IMF5','IMF6','IMF7');
phase.GetModes; % turn the modes into phase information
figure
Complot(phase.ModePhases)
title('IMF Phases');
te=repetitionTime;
xt=get(gca,'xtick');
set(gca,'xticklabel',arrayfun(@num2str,xt*te,'un',0)); % adjust x axis to time values
xlabel('Time (sec)');
cardiac_phase = CardiacPhase(phase); % creates a CradiacPhase object
cardiac_phase.SelectPhase; % choose the right imf besed on the work load IMPROVE
cardiac_phase.SelectPhase; % choose the cardiac imf
respiratory_phase = RespiratoryPhase(phase); % creates a RespiratoryPhase object
respiratory_phase.SelectPhase; % choose the right imf based on the work load IMPROVE
respiratory_phase.SelectPhase; % choose the respiratory imf
cardiac_phase.Display
figure
cardiac_phase.DisplayValues
hold on
respiratory_phase.Display
respiratory_phase.DisplayValues
% hold on
% hline = refline([0 cardiac_phase.SystoleTreshold]); % Reference line for systole treshold phase
% hline.Color = 'b';
@ -63,6 +80,10 @@ set(gca,'xticklabel',arrayfun(@num2str,xt*te,'un',0)); % adjust x axis to time v
xlabel('Time (sec)');
ylabel('Phase(rad)');
%% File with Cardiac and Respiratory Phase
file_matrix = [cardiac_phase.Values; respiratory_phase.Values];
csvwrite('phase_file.csv',file_matrix);
%% Cardiac and Respiratory events
cardiac_phase.Diastole % detects diastolic events
cardiac_phase.Systole % detects systolic events
@ -75,10 +96,41 @@ DI = intersect(cardiac_phase.DiastolePositions,respiratory_phase.InspirationPosi
DE = intersect(cardiac_phase.DiastolePositions,respiratory_phase.ExpirationPositions); % diastole in expiration
% Show frames of the different cardiac/respiratory events
phase.ShowFrames(SI,'End-systolic frames in inpiration');
phase.ShowFrames(SI,'End-systolic frames in inpiration');
directory = 'Systole in Inspiration'
mkdir(directory);
for i=1:length(SI)
baseFileName = sprintf('SI%d.dcm', i);
fullFileName = fullfile(directory, baseFileName);
dicomwrite(phase.Video(:,:,1,SI(i)), fullFileName);
end
phase.ShowFrames(SE,'End-systolic frames in expiration');
directory = 'Systole in Expiration'
mkdir(directory);
for i=1:length(SE)
baseFileName = sprintf('SE%d.dcm', i);
fullFileName = fullfile(directory, baseFileName);
dicomwrite(phase.Video(:,:,1,SE(i)), fullFileName);
end
phase.ShowFrames(DI,'End-diastolic frames in inpiration');
directory = 'Diastole in Inspiration'
mkdir(directory);
for i=1:length(DI)
baseFileName = sprintf('DI%d.dcm', i);
fullFileName = fullfile(directory, baseFileName);
dicomwrite(phase.Video(:,:,1,DI(i)), fullFileName);
end
phase.ShowFrames(DE,'End-diastolic frames in expiration');
directory = 'Diastole in Expiration'
mkdir(directory);
for i=1:length(DE)
baseFileName = sprintf('DE%d.dcm', i);
fullFileName = fullfile(directory, baseFileName);
dicomwrite(phase.Video(:,:,1,DE(i)), fullFileName);
end
%% Heart Beat Reconstruction
n_ranges = 30; % number of phase ranges
@ -98,9 +150,5 @@ for i=1:1:n_ranges
j = oredered_index{i};
new_index{i} = k(j); % ordered indexes
end
selected_range = n_ranges-2;
selected_range = n_ranges-2; % optional range
phase.ShowFrames(new_index{selected_range},'Heart Beat Reconstruction');
% c = ImageSequence
% c.ToBeSetByUser=15
% c.ToBeSetByUser=true