Code covered by the BSD License  

Highlights from
VMAT QA

image thumbnail
from VMAT QA by James Kerns
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