Code covered by the BSD License  

Highlights from
VMAT QA

image thumbnail

VMAT QA

by

 

10 Apr 2013 (Updated )

Analyzes VMAT quality assurance EPID images for routine Varian linac QA.

VMAT(varargin)
function varargout = VMAT(varargin)
% VMAT MATLAB code for VMAT.fig
%      This program will analyze Volumetric-Modulated Arc Therapy (VMAT) QA
%      EPID images and automatically calculate results.
% 
%       The images should follow the patterns described in Jorgensen et al
%       (2011) in Medical Physics. Two tests are provided:
% 
%       --Gantry Speed
%       &
%       --Dose Rate MLC Speed
% 
%       A settings panel accesible through the File menu allows personal 
%       setting of the allowable tolerance.
% 
%       Questions/bugs/feature requests: jkerns100@gmail.com

% Edit the above text to modify the response to help VMAT

% Last Modified by GUIDE v2.5 23-Apr-2013 10:58:00

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @VMAT_OpeningFcn, ...
                   'gui_OutputFcn',  @VMAT_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before VMAT is made visible.
function VMAT_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to VMAT (see VARARGIN)

% Choose default command line output for VMAT
handles.output = hObject;
axis([handles.Openfieldplot handles.DMLCplot],'off')
handles.ratiotol = LoadOrSetPref('VMATsettings','ratiotol',3,false);
handles.isprocessed = false;
guidata(hObject, handles);


% --- Executes on button press in loadMLCimage.
function loadMLCimage_Callback(hObject, eventdata, handles)
% hObject    handle to loadMLCimage (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filename, path]=uigetfile('*.dcm',...
    'Select the VMAT DMLC image','Multiselect','off');
if filename == 0 % if user hits cancel
    return
end

handles.DMLC = dicomread(fullfile(path,filename));
axes(handles.DMLCplot);
imshow(handles.DMLC,[]);
set(handles.Results,'BackgroundColor','w') %sets to white in case processing has made it green/red from previous computation
handles.isprocessed = false;
guidata(hObject,handles)

% --- Executes on button press in loadOpenfield.
function loadOpenfield_Callback(hObject, eventdata, handles)
% hObject    handle to loadOpenfield (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filename, path]=uigetfile('*.dcm',...
    'Select the Open field image','Multiselect','off');
if filename == 0 % if user hits cancel
    return
end
cd(path) % matlab doesn't like this for deployed apps, but I don't know of another good way to do this, nor have I had problems so far
handles.OPEN = dicomread(fullfile(path,filename));
axes(handles.Openfieldplot);
imshow(handles.OPEN,[]);
set(handles.Results,'BackgroundColor','w')
handles.isprocessed = false;
guidata(hObject,handles)


%% Structure Field Initialization & grab user test choice

% --- Executes on button press in ProcessImages.
function ProcessImages_Callback(hObject, eventdata, handles)
% hObject    handle to ProcessImages (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

%error check if both images haven't been loaded
if ~isfield(handles,'DMLC') || ~isfield(handles,'OPEN')
    warndlg('Both images have not yet been loaded in. Please do so before proceeding.','Load Images First')
    return
end

axes(handles.DMLCplot);
imshow(handles.DMLC,[]);
% empties out matrices in event processing is done twice.
[handles.roi,handles.roistd,handles.hrect,handles.hresult] = deal([]);

%get test choice
choicelist = cellstr(get(handles.TestChoice,'String'));
handles.testchoice = choicelist(get(handles.TestChoice,'Value'));

%% MLC Speed Test 
if strcmp(handles.testchoice,choicelist{2}); %2 = MLC Speed
    
    % Positions of ROIs in DMLC image. These are the values to use if the Jorgensen
    % test is performed.
    handles.DmlcPos = {[150 10 45 370],[207 10 45 370],[265 10 45 370],[325 10 45 370]};
    
    % Pull DMLC and Open ROIs out of DMLC Image. Also draws rectangles on DMLC
    % image
    [RawROIs, handles.hrect] = PullRois(handles);
    
    % Actual calculation of individual ROI DMLC to OPEN ratio value and stand. dev.
    [roi, roistd] = CalcRois(RawROIs);
    handles.roi = roi; handles.roistd = roistd;
    
    % Drawing of rectangles on DMLC image
    handles.hresult{1} = text(173,90,sprintf('1.6 cm/s: %4.3f +/- %4.3f',roi{1},roistd{1}),'Rotation',-90,'Color','g','FontSize',14);
    handles.hresult{2} = text(230,90,sprintf('2.4 cm/s: %4.3f +/- %4.3f',roi{2},roistd{2}),'Rotation',-90,'Color','g','FontSize',14);
    handles.hresult{3} = text(288,90,sprintf('0.8 cm/s: %4.3f +/- %4.3f',roi{3},roistd{3}),'Rotation',-90,'Color','g','FontSize',14);
    handles.hresult{4} = text(348,90,sprintf('0.4 cm/s: %4.3f +/- %4.3f',roi{4},roistd{4}),'Rotation',-90,'Color','g','FontSize',14);
    
    % Displaying of results
    string = sprintf('Results (Tol. +/-%1.0f%%):\n 1.6cm/s: %4.3f +/- %4.3f \n 2.4cm/s: %4.3f +/- %4.3f \n 0.8cm/s: %4.3f +/- %4.3f \n 0.4cm/s: %4.3f +/- %4.3f',...
        handles.ratiotol,roi{1},roistd{1},roi{2},roistd{2},roi{3},roistd{3},roi{4},roistd{4});
    set(handles.Results,'String',string)
    
    % Check of ROI results to see if they pass tolerance. Turns text red for
    % ROIs that fail    
    checkROIs(handles)
    
%% Dose-Rate Gantry-Speed Test    
elseif strcmp(handles.testchoice,choicelist{1}); %1 = DRGS
    
    % Positions of ROIs in DMLC image. These are static values if the Jorgensen
    % test is performed. 
    handles.DmlcPos = {[148 10 26 370],[186 10 27 370],[224 10 27 370],[262 10 27 370],...
        [300 10 27 370],[338 10 27 370],[377 10 27 370]};
    
    % Pull DMLC and Open ROIs out of DMLC Image. Also draws rectangles on DMLC
    % image
    [RawROIs, handles.hrect] = PullRois(handles);
    
    % Actual calculation of individual ROI DMLC to OPEN ratio value and stand. dev.
    [roi, roistd] = CalcRois(RawROIs);
    handles.roi = roi; handles.roistd = roistd;

    % Drawing of text on DMLC image
    handles.hresult{1} = text(162,100,sprintf('105 MU/min: %4.3f +/- %4.3f',roi{1},roistd{1}),'Rotation',-90,'Color','g','FontSize',12);
    handles.hresult{2} = text(200,100,sprintf('210 MU/min: %4.3f +/- %4.3f',roi{2},roistd{2}),'Rotation',-90,'Color','g','FontSize',12);
    handles.hresult{3} = text(238,100,sprintf('314 MU/min: %4.3f +/- %4.3f',roi{3},roistd{3}),'Rotation',-90,'Color','g','FontSize',12);
    handles.hresult{4} = text(276,100,sprintf('417 MU/min: %4.3f +/- %4.3f',roi{4},roistd{4}),'Rotation',-90,'Color','g','FontSize',12);
    handles.hresult{5} = text(314,100,sprintf('524 MU/min: %4.3f +/- %4.3f',roi{5},roistd{5}),'Rotation',-90,'Color','g','FontSize',12);
    handles.hresult{6} = text(352,100,sprintf('592 MU/min: %4.3f +/- %4.3f',roi{6},roistd{6}),'Rotation',-90,'Color','g','FontSize',12);
    handles.hresult{7} = text(390,100,sprintf('600 MU/min: %4.3f +/- %4.3f',roi{7},roistd{7}),'Rotation',-90,'Color','g','FontSize',12);
    
    % Displaying of results    
    string = sprintf('Results (Tol. +/-%1.0f%%):\n 105MU/min: %4.3f +/- %4.3f \n 210MU/min: %4.3f +/- %4.3f \n 314MU/min: %4.3f +/- %4.3f \n 417MU/min: %4.3f +/- %4.3f \n 524MU/min: %4.3f +/- %4.3f \n 592MU/min: %4.3f +/- %4.3f \n 600MU/min: %4.3f +/- %4.3f',...
        handles.ratiotol,roi{1},roistd{1},roi{2},roistd{2},roi{3},roistd{3},roi{4},roistd{4},roi{5},roistd{5},roi{6},roistd{6},roi{7},roistd{7});
    set(handles.Results,'String',string)
    
    % Check of ROI results to see if they pass tolerance. Turns text red for
    % ROIs that fail
    checkROIs(handles)
end
handles.isprocessed = true;
guidata(hObject,handles)

%% Pull ROIs out of Images
function [RawROIs, recthandles] = PullRois(handles)
% Pull DMLC and Open ROIs out of DMLC Image. Also draws rectangles on DMLC
% image
for i=1:numel(handles.DmlcPos)
    RawROIs.dmlc.roi{i} = double(imcrop(handles.DMLC,handles.DmlcPos{i}));
    RawROIs.open.roi{i} = double(imcrop(handles.OPEN,handles.DmlcPos{i}));
    recthandles{i} = rectangle('Position',handles.DmlcPos{i},'EdgeColor','g');
end

% Calculate overall DMLC and OPEN image ROI average
RawROIs.dmlc.mean = mean(mean([RawROIs.dmlc.roi{:}]));
RawROIs.open.mean = mean(mean([RawROIs.open.roi{:}]));

%% Calculate ROI ratios and st. dev.
function [roi, roistd] = CalcRois(RawROIs)
% This function finds the ratio of mean response of the DMLC image to the
% response of the Open image. This ratio is then normalized to the overall
% ratio of normalized response of all ROIs of each the DMLC and Open image.

% Overall image normalization
ImageNorm = RawROIs.dmlc.mean/RawROIs.open.mean;

% Preallocation
[roi, roistd] = deal(cell(1,numel(RawROIs.dmlc.roi)));

% Since function is used for both MLC Speed and DRGS there are varying 
% numbers of elements in RawROIs, thus a for loop for all elements
for i=1:numel(RawROIs.dmlc.roi)
    roi{i} = mean(RawROIs.dmlc.roi{i}(:))/mean(RawROIs.open.roi{i}(:))/ImageNorm;
    s = (RawROIs.dmlc.roi{i}./RawROIs.open.roi{i})/ImageNorm;
    roistd{i} = std(s(:));
end

%% Check results for pass/fail
function checkROIs(handles)
if any([handles.roi{:}] < 1-handles.ratiotol/100 | [handles.roi{:}] > 1+handles.ratiotol/100)
    B = find([handles.roi{:}] < 1-handles.ratiotol/100 | [handles.roi{:}] > 1+handles.ratiotol/100);
    for i=1:numel(B)
        set(handles.hresult{B(i)},'Color','r')
        set(handles.hrect{B(i)},'EdgeColor','r')
    end
    set(handles.Results,'BackgroundColor','r')
else
    set(handles.Results,'BackgroundColor','g')
end

%% Save to PDF
% --- Executes on button press in savetopdf.
function savetopdf_Callback(hObject, eventdata, handles)
% hObject    handle to savetopdf (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

%error check that images have been processed
if handles.isprocessed == false
    warndlg('Images have not yet been loaded or processed. Please do so before continuing.')
    return
end


[fileoutput, pathname] = uiputfile({'*.pdf','PDF (*.pdf)'},'Save VMAT QA Results...',['VMAT QA - ' date()]);
if fileoutput == 0 % if user hits cancel
    return
end


if exist('export_fig') == 2 % if user has export_fig function...
    export_fig(fullfile(pathname,fileoutput),'-painters','-q101','-pdf')
else
    print(gcf,'-dpdf','-opengl','-r400','-loose',fullfile(pathname,fileoutput)); %#ok<MCPRT>
end

msgbox(['Report saved successively at ' fullfile(pathname,fileoutput)],'Report Saved','help')

% --------------------------------------------------------------------
function settings_Callback(hObject, eventdata, handles)
% hObject    handle to settings (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
h = VMAT_settings;
waitfor(h);
handles.ratiotol = getappdata(0,'ratiotol');
guidata(hObject,handles)


%% GUI initialization and unused functions


% --- Executes during object creation, after setting all properties.
function TestChoice_CreateFcn(hObject, eventdata, handles)
% hObject    handle to TestChoice (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: listbox controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes during object creation, after setting all properties.
function Results_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Results (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Outputs from this function are returned to the command line.
function varargout = VMAT_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;



% --------------------------------------------------------------------
function File_Callback(hObject, eventdata, handles)
% hObject    handle to File (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on selection change in TestChoice.
function TestChoice_Callback(hObject, eventdata, handles)
% hObject    handle to TestChoice (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns TestChoice contents as cell array
%        contents{get(hObject,'Value')} returns selected item from TestChoice


% --- Executes when user attempts to close figure1.
function figure1_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to figure1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: delete(hObject) closes the figure
delete(hObject);

Contact us