Code covered by the BSD License  

Highlights from
DICOM server connection

DICOM server connection

by

 

This script connects to a DICOM server and transfer the a dicom series to the MATLAB workspace

dcmserver_connection(dcmaet,dcmaec,dcmhost,dcmport)
function  [imaVOL dcminfo scaninfo StudyListFull StudyList] = dcmserver_connection(dcmaet,dcmaec,dcmhost,dcmport)
% [imaVOL dcminfo] =  dcmserver_connection(dcmaet,dcmaec,dcmhost,dcmport)
%
% DCMSERVER_CONNECTION enables to connect to a DICOM server and creates a list  
% of the available DICOM studies and the related series. These lists will
% be shown up on a GUI and the user can select the DICOM series to transfer 
% the corresponding DICOM slices. At the end of the transfer the 
% DCMSERVER_CONNECTION creates a 3D array image volume (imaVOL) including 
% the dcm slices and a structure (dcminfo) containing the the dicom header 
% info relating to the dicom series. 
% 
% All functionality are based on the "DICOM Toolkit" (http://dicom.offis.de/dcmtk.php.en),
% thus you need to properly configure your computer (as DICOM client) and 
% the required DICOM server, as well. See the installation hints hereinafter.
%
% Inputs:
%   dcmaet  - calling AE title 
%   dcmaec  - called AE title of peer
%   dcmhost - hostname of DICOM peer
%   dcmport - tcp/ip port number of peer
%   
% Outputs:
%   imaVOL    - 3D array of the transfered dcm slices
%   dcminfo   - dicom header structure relating to
%               the last image slice 
%
%
% Starting the transfer:
%  1. run the "dcm_server_local_start.bat" script from the MATLAB_DCM_PATH
%       (see later). To run this file double click on the filename, it starts
%       a new Win command window (DCMTK local server win). DO NOT close it,
%       (this is the local dim server win) but you can minmize it 
%       if you want. It would be better to show up, in that way you can monitor
%       the moving process of the dicom slices when the dcmserver_connection
%       function transfer the files.
%  2. check the local DICOM server status using the "dcmserver_localtest.m"
%       (optional, see the related help of dcmserver_localtest.m)    
%  3. check the remote DICOM server status using the "dcmserver_remotetest.m" 
%       (optional, see the related help of dcmserver_remotetest.m)
%  4. start the dcmserver_connection function
%       Example:  
%           dcmaet = 'MATLAB';
%           dcmaec = 'PET-CT_HOST031';
%           dcmport = '104';
%           dcmhost = '192.168.114.2';
%           [imaVOL dcminfo]=dcmserver_connection(dcmaet,dcmaec,dcmhost,dcmport);
% 
%  Hints:   After completing the DICOM transfers, you may close the "DCMTK 
%           local server win" and could delete the temporary files under
%           the working directory (StorageArea) of the local DICOM server.
%           This directory has to be defined in the "dcmqrscp.cfg" file as 
%           "StorageArea" at the "AETable" section. (see the Configuration)
%           
%
% Installation and configuration requirements
%
% 1. Installation:
% The following matlab files have to be under the same directory 
% (called as MATLAB_DCM_PATH in this help),
%   - dcmserver_connection.m
%   - dcmserver_change_sortordering.m
%   - dcmserver_getseriesinfo.m
%   - dcmserver_localtest.m
%   - dcmserver_remotetest.m
%   - loaddcm.m
%   - progbar.m
% and the MATLAB_DCM_PATH needs to add to the MATLAB PATH.
%
% You should install "DICOM Toolkit" binary version on your computer from
% the http://dicom.offis.de/dcmtk.php.en site 
%                   OR 
% at least you need to copy the following "DICOM Toolkit" executables in the
% MATLAB_DCM_PATH directory:
%   - dcmqrscp.exe
%   - echoscu.exe
%   - findscu.exe
%   - movescu.exe
%   - dcm_server_local_start.bat
%   - dcmqrscp.cfg
% These files can be downloded with a zip file from
% http://pet.dote.hu/~balkay/matlabdcmsrv/matlab_dcmsrvconn_etc.zip
% This help presumes you choose the second option. If you install the whole
% "DICOM Toolkit", the setting, configuration and running will be 
% your resposibility. 
%
% 2. Configuration:
%
% For connecting to a DICOM server you have to appropriately setup the "HostTable",
% "VendorTable"  and "AETable" sections in the "dcmqrscp.cfg" file. See 
% the prepared "dcmqrscp.cfg" default file in the matlab_dcmsrvconn_etc.zip.
% The dcmserver_connection.m function use the first line of the AETable 
% section in the "dcmqrscp.cfg". Do not change the "MATLAB" called AET 
% keyword in the line of
%           MATLAB       D:\tmp      RW  (200, 1024mb) dcmsrv1, localpc
% You can change the StorageArea, Access, Quota and Peers 
% (excluding the "localpc") variables. The "StorageArea" define the working 
% directory, where dcmqrscp.exe dicom server will store the database (the 
% index.dat file and the transfered dicom files). In the previous example 
% the "StorageArea" is the "D:\tmp" directory. You need to set up this directory
% in accordance with the file size of the transferring DICOM slices. 
% You should also rename the "localhost" variable to the hostname 
% of your PC in the line of
%           localpc  = (MatlabTest, localhost, 104)
%
% For more details see the "dcmqrscp_officialexample.cfg" and "dcmqrcnf.txt"
% files, or the documentations in the http://dicom.offis.de/dcmtk.php.en site. 
%
% For the DICOM communication the "dcm_server_local_start.bat" script and 
% the "dcmqrscp.cfg" config file use the port of 104. You should enable 
% this port number if you use any firewall service.
%
% This program is distributed in the hope that it will be useful, 
% but not all situation has been checked. I wrote it for fun 
% (I always enjoy working with matlab).


% University of Debrecen, Institute of Nuclear Medicine
% Author: Laszlo Balkay/2010

imaVOL = []; dcminfo = []; scaninfo = []; StudyListFull = []; StudyList = [];  
dcmtmpfile1 = [tempdir,filesep,'matlab_dcmstudies_tmpfile.txt'];
dcmtmpfile2 = [tempdir,filesep,'matlab_dcmseries_tmpfile.txt'];
dcmtmpfile3 = [tempdir,filesep,'matlab_dcmimage_tmpfile.txt'];
dcmtmpfile4 = [tempdir,filesep,'matlab_dcmmovescu_tmpfile.txt'];
localhost = 0;

if nargin == 0
      dcmaet = 'MatlabTest';
      dcmaec = 'MATLAB';
      dcmhost = '%computername%';
      dcmport = '104';
      localhost = 1;
%     dcmaet = 'MATLAB';
%     dcmaec = 'PET-CT_HOST031';
%     dcmhost = '192.168.114.2';
%     dcmport = '104';
%     dcmaec = 'MEDISOdcmserv';
%     dcmhost = '192.168.89.20';
%     dcmport = '104';
end

opcommand1 = ['findscu.exe -aet ',dcmaet,' -aec ',dcmaec,' --study '];
opcommand2 = ['-k 0008,0052=STUDY -k 0010,0010 -k 0020,000D -k 0008,0020 -k 0008,0061', ...
    ' -k 0008,1030 -k 0020,0010 -k 0008,0030 -k 0010,0020 -k 0010,1030 -k 0008,0090 -k 0008,0062 -k 0010,0030'];
opcommand3 = [' -v ',dcmhost,' ',dcmport ];

opcommand_findstudies = [opcommand1,opcommand2,opcommand3,' > ',dcmtmpfile1];

% Show up message window and set the cursor type to "watch"  
hm = msgbox('Connecting to the Dicom Server. It takes time. Please wait!','dcmServer_connection Info' );
SetData=setptr('watch');set(hm,SetData{:});
hmc = (get(hm,'children'));
set(hmc(2),'enable','inactive');

dcmtlk_path = fileparts(which('echoscu.exe'));
curr_path = cd;
cd(dcmtlk_path);
[sys_status, sys_result] = system(opcommand_findstudies);
cd(curr_path);
delete(hm);
    
if sys_status; 
    disp('Error on dicom study query'); 
    disp(' ');
    disp('Error on connecting to the dicom server!');
    disp('Warnings from the findscu.exe process:');
    disp(' ');
    type(dcmtmpfile1);
    disp(' ');
    delete(dcmtmpfile1);
    return; 
end

fid  = fopen(dcmtmpfile1,'r');
dcmstudy_list = char(fread(fid,'char'));
fclose(fid);
dcm_startpos = findstr(dcmstudy_list','RESPONSE: 1 ');
if isempty(dcm_startpos);
    disp(' ');
    disp('Na data or error on getting data from the dicom server!');
    disp('Warnings from the findscu.exe process:');
    disp(' ');
    type(dcmtmpfile1);
    disp(' ');
    delete(dcmtmpfile1);
    return; 
end
%edit(dcmtmpfile1);
delete(dcmtmpfile1);

dcm_datepos = findstr(dcmstudy_list(dcm_startpos+1 : end)','0008,0020');
dcm_timepos = findstr(dcmstudy_list(dcm_startpos+1 : end)','0008,0030');
dcm_modalitypos = findstr(dcmstudy_list(dcm_startpos+1 : end)','0008,0061');
dcm_studydescrpos = findstr(dcmstudy_list(dcm_startpos+1 : end)','0008,1030');
dcm_patnamepos = findstr(dcmstudy_list(dcm_startpos+1 : end)','0010,0010');
dcm_studyinstUIDpos = findstr(dcmstudy_list(dcm_startpos+1 : end)','0020,000d');

value_distance = 15;
date_length = 8;
time_length = 6;
num_of_study = length(dcm_datepos);
StudyList = cell(num_of_study,7);
StudyListFull = cell(num_of_study,1);

for i=1:num_of_study
    
    % get the date
    pos1 = dcm_startpos + dcm_datepos(i)+value_distance;
    pos2 = dcm_startpos+dcm_datepos(i)+value_distance+date_length-1;
    date_value = dcmstudy_list(pos1 :pos2)';
    
    % get the time
    pos1 = dcm_startpos + dcm_timepos(i)+value_distance;
    pos2 = dcm_startpos+dcm_timepos(i)+value_distance+time_length-1;
    time_value = dcmstudy_list(pos1 :pos2)';
    
    % get the patient name 
    % find the next closing bracket at the patient name row /~using 70 char/
    pos1 = dcm_startpos + dcm_patnamepos(i) + value_distance;
    pos2 = dcm_startpos + dcm_patnamepos(i) + 70;
    next_bracket = findstr(dcmstudy_list(pos1 : pos2)',']');
    patname_value = dcmstudy_list(pos1 : pos1 + next_bracket(1) -2)';
    
    % get the modality type
    % find the next closing bracket at the patient name row /~using 70 char/
    if ~isempty(dcm_modalitypos)
        pos1 = dcm_startpos + dcm_modalitypos(i) + value_distance;
        pos2 = dcm_startpos + dcm_modalitypos(i) + 70;
        next_bracket = findstr(dcmstudy_list(pos1 : pos2)',']');
        if isempty(next_bracket)
            next_bracket = findstr(dcmstudy_list(pos1 : pos2)',')');
        end 
        modality_value = dcmstudy_list(pos1 : pos1 + next_bracket(1) -2)';
    else
        modality_value = 'no value';
    end
    
    % get the study description
    % find the next closing bracket at the patient name row /~using 70 char/
    pos1 = dcm_startpos + dcm_studydescrpos(i) + value_distance;
    pos2 = dcm_startpos + dcm_studydescrpos(i) + 70;
    next_bracket = findstr(dcmstudy_list(pos1 : pos2)',']');
    if ~isempty(next_bracket)
        studydescription_value = dcmstudy_list(pos1 : pos1 + next_bracket(1) -2)';
    else
        studydescription_value = 'no value';
    end
    
    % get the studyinstUID value
    % find the next closing bracket at the studyinstUID row /~using 90 char/
    pos1 = dcm_startpos + dcm_studyinstUIDpos(i) + value_distance;
    pos2 = dcm_startpos + dcm_studyinstUIDpos(i) + 90;
    next_bracket = findstr(dcmstudy_list(pos1 : pos2)',']');
    studyinstUID_value = dcmstudy_list(pos1 : pos1 + next_bracket(1) -2)';
    
    StudyList{i,1} = date_value;
    StudyList{i,2} = time_value;
    StudyList{i,3} = patname_value;
    StudyList{i,4} = modality_value;
    StudyList{i,5} = studydescription_value;
    StudyList{i,6} = studyinstUID_value;
    StudyList{i,7} = datenum([date_value,time_value],'yyyymmddHHMMSS');
    StudyListFull{i} = [date_value,'  ',time_value, blanks(10), modality_value, blanks(30-length(modality_value)), ...
        ' ',patname_value,blanks(70-length(patname_value)), studydescription_value];
end

% create popupmenu for dicomstudies
global SelectedStudyInstanceUID dcmSeriesListVal SeriesList;

dcmCommonData.StudyList = StudyList;
dcmCommonData.StudyListFull = StudyListFull;
dcmCommonData.dcmaet = dcmaet;
dcmCommonData.dcmaec = dcmaec;
dcmCommonData.dcmhost = dcmhost;
dcmCommonData.dcmport =dcmport;
dcmCommonData.dcmtmpfile2 = dcmtmpfile2;
dcmCommonData.SeriesList=[];

dcmdirlistfh = figure('menubar','none','NumberTitle','off','name','dcmServer info','position', ...
    [250   300   760   520], 'UserData',dcmCommonData,'tag','dcmStudyList_info');

% create the Series ListBox
SerLh = uicontrol('Style','listbox','units','normalized','Position',[0.02 0.09 0.95 0.25],'tag','dcmSeriesList_popupmenu');
dcmCommonData.SerLh = SerLh;
set(dcmdirlistfh,'UserData',dcmCommonData);

% create the Study ListBox
ClickCallback = ['dcmserver_getseriesinfo(get(findobj(''tag'',''dcmStudyList_popupmenu''),''value''))'];
StadLh = uicontrol('Style','listbox','units','normalized','Position',[0.02 0.42 0.95 0.455], ...
    'tag','dcmStudyList_popupmenu','Callback',ClickCallback);


% create buttons for Study Date sort ordering
ClickCallback = ['dcmserver_change_sortordering(1)'];
uicontrol('Style','pushbutton','String','DateTime', ...
    'units','normalized','Position',[0.03 0.912 0.1 0.05], 'Callback', ClickCallback, ...
    'TooltipString','Sorting by Study Date');
% create edit box for Study Date
EnterCallback = ['dcmserver_change_sortordering(11)'];
uicontrol('Style','edit', 'tag','dcmStudyList_DateTimeVal', ...
    'units','normalized','Position',[0.03 0.88 0.1 0.03], ...
    'TooltipString','Type the Date to filter, then press <Enter>','Callback', EnterCallback);

% create buttons for Modality sort ordering
ClickCallback = ['dcmserver_change_sortordering(2)'];
uicontrol('Style','pushbutton','String','Modality', ...
    'units','normalized','Position',[0.16 0.912 0.1 0.05], 'Callback', ClickCallback, ...
    'TooltipString','Sorting by Modality');
% % create edit box for Modality 
% uicontrol('Style','edit', 'tag','dcmStudyList_modalityVal', ...
%     'units','normalized','Position',[0.16 0.88 0.1 0.03], ...
%     'TooltipString','Type to filter the Modality, then press <Enter>');

% create buttons for Patient Name sort ordering
ClickCallback = ['dcmserver_change_sortordering(3)'];
uicontrol('Style','pushbutton','String','Patient Name', ...
    'units','normalized','Position',[0.36 0.912 0.15 0.05], 'Callback', ClickCallback, ...
    'TooltipString','Sorting by Patient Name');
% create edit box for Patient Name
EnterCallback = ['dcmserver_change_sortordering(13)'];
uicontrol('Style','edit', 'tag','dcmStudyList_PatientNameVal', ...
    'units','normalized','Position',[0.36 0.88 0.15 0.03], ...
    'TooltipString','Type the Patient Name to filter, then press <Enter>','Callback', EnterCallback);

% create buttons for Study description sort ordering
ClickCallback = ['dcmserver_change_sortordering(4)'];
uicontrol('Style','pushbutton','String','Study description', ...
    'units','normalized','Position',[0.64 0.912 0.15 0.05], 'Callback', ClickCallback, ...
    'TooltipString','Sorting by the Study Description');
% % create edit box for Study description
% uicontrol('Style','edit', 'tag','dcmStudyList_StudyDescriptionVal', ...
%     'units','normalized','Position',[0.64 0.88 0.15 0.03], ...
%     'TooltipString','Type to filter the Study Descripition, then press <Enter>');

% create text labels for Series List box 
uicontrol('Style','text','String','DateTime', ...
    'units','normalized','Position',[0.03 0.35 0.1 0.03]);
uicontrol('Style','text','String','Modality', ...
    'units','normalized','Position',[0.16 0.35 0.1 0.03]);
uicontrol('Style','text','String','Protocol name', ...
    'units','normalized','Position',[0.3 0.35 0.12 0.03]);
uicontrol('Style','text','String','Series description', ...
    'units','normalized','Position',[0.5 0.35 0.12 0.03]);
uicontrol('Style','text','String','Series number', ...
    'units','normalized','Position',[0.64 0.35 0.1 0.03]);

% create Title text labels for Series and Study List box 
uicontrol('Style','text','String','Study List','FontWeight','bold', ...
    'units','normalized','Position',[0.4 0.97 0.15 0.025]);
uicontrol('Style','text','String','Series List','FontWeight','bold', ...
    'units','normalized','Position',[0.4 0.388 0.15 0.025]);

% create the OK,Cancel buttons 
OKCallback = ['global dcmSeriesListVal; dcmSeriesListVal = get(findobj(''tag'',''dcmSeriesList_popupmenu''),''value'');',...
    'delete(findobj(''tag'',''dcmStudyList_info''));'];
CancelCallback = 'global dcmSeriesListVal; delete(findobj(''tag'',''dcmStudyList_info'')); dcmSeriesListVal = -1;';
OK_h = uicontrol('Style', 'pushbutton', 'String', 'OK','units','normalized', ...
    'Position', [0.78 0.019 0.1 0.058], 'Callback', OKCallback);
Cancel_h = uicontrol('Style', 'pushbutton', 'String', 'Cancel','units','normalized', ...
    'Position', [0.65 0.019 0.1 0.058], 'Callback', CancelCallback);

% sorting the study list by datetime
[sorted_datetime,indexes] = sort(cell2mat(StudyList(:,7)),'descend');
dcmCommonData.indexes = indexes;
set(dcmdirlistfh,'UserData',dcmCommonData);
dcmserver_getseriesinfo(get(findobj('tag','dcmStudyList_popupmenu'),'value'));
set(StadLh,'string',StudyListFull(indexes));

uiwait(dcmdirlistfh);
% if cancel was pressed
if dcmSeriesListVal == -1
    return;
end
    

% 
% Moving (if the selected Series are on a remote dcmServer) the images to the local dcmServer
% and reading the images from the local dcmServer 
%
SelectedSeriesInstanceUID = SeriesList{dcmSeriesListVal,8};

% Show up message window and set the cursor type to "watch"  
hm = msgbox('Movinging the selected series from Dicom Server. Please wait!','dcmServer_connection Info' );
SetData=setptr('watch');set(hm,SetData{:});
hmc = (get(hm,'children'));
set(hmc(2),'enable','inactive');

% Getting the SOPInstanceUID list of the images. These used for getting the relating file names 
% from the index.dat file
QueryRetrieveLevel = 'IMAGE';
opcommand2a = ['-k 0008,0052=',QueryRetrieveLevel,' -k 0020,000D=',SelectedStudyInstanceUID,''];
opcommand2b = [' -k 0020,000E=',SelectedSeriesInstanceUID,' ','-k 0008,0018 '];
opcommand_getimage_SOPInstanceUID = [opcommand1,opcommand2a,opcommand2b,opcommand3,' > ',dcmtmpfile3];

dcmtlk_path = fileparts(which('echoscu.exe'));
curr_path = cd;
cd(dcmtlk_path);
[sys_status, sys_result] = system(opcommand_getimage_SOPInstanceUID);
cd(curr_path);
if sys_status
    disp(' ');
    disp('Error on getting the image SOPInstanceUIDs from the dcmServer'); 
    disp('Related Logs from the findscu.exe process:');
    disp(' ');
    type(dcmtmpfile3);
    disp(' ');
    clear global SelectedStudyInstanceUID dcmSeriesListVal SeriesList;
    return;
    %delete(dcmtmpfile3);
end

% Open the resulted image list file and get the image related SOPInstanceUID values
fid  = fopen(dcmtmpfile3,'r');
dcmimage_list = char(fread(fid,'char'));
fclose(fid);
dcm_startpos = findstr(dcmimage_list','RESPONSE: 1 ');
if isempty(dcm_startpos);
    disp(' ');
    disp('Error on getting data from image list!');
    disp('Warnings from the findscu.exe process:');
    disp(' ');
    type(dcmtmpfile3);
    disp(' ');
    delete(dcmtmpfile3);
    return; 
end
delete(dcmtmpfile3);
dcm_SOPInstanceUIDpos = findstr(dcmimage_list(dcm_startpos+1 : end)','0008,0018');
value_distance = 15;
num_of_image = length(dcm_SOPInstanceUIDpos);
ImageList = cell(num_of_image,1);
for i=1:num_of_image
    % get the SOPInstanceUID value
    % find the next closing bracket at the SOPInstanceUID row /~using 90 char/
    pos1 = dcm_startpos + dcm_SOPInstanceUIDpos(i) + value_distance;
    pos2 = dcm_startpos + dcm_SOPInstanceUIDpos(i) + 90;
    next_bracket = findstr(dcmimage_list(pos1 : pos2)',']');
    SOPInstanceUID_value = dcmimage_list(pos1 : pos1 + next_bracket(1) -2)';
    ImageList{i} = SOPInstanceUID_value; 
end

% If the dcmServer is not the local one, move the selected Series relating images from 
% the remote dcmServer to the local dcmServer   
if ~localhost
    QueryRetrieveLevel = 'SERIES';
    opcommand1b = ['movescu.exe -aet ',dcmaet,' -aec ',dcmaec,' --study '];
    %opcommand1b = ['movescu.exe -aet ',dcmaet,' -aec ',dcmaec,' --study -ta 5 -to 5 -td 5 '];
    opcommand2a = ['-k 0008,0052=',QueryRetrieveLevel,' -k 0020,000D=',SelectedStudyInstanceUID,''];
    opcommand2b = [' -k 0020,000E=',SelectedSeriesInstanceUID,' -k 0008,0018 '];
    opcommand_getseries = [opcommand1b,opcommand2a,opcommand2b,opcommand3,' > ',dcmtmpfile4];
    %disp([opcommand1b,opcommand2a,opcommand2b,opcommand3]);
    
    dcmtlk_path = fileparts(which('echoscu.exe'));
    curr_path = cd;
    cd(dcmtlk_path);
    [sys_status, sys_result] = system(opcommand_getseries);
    cd(curr_path);
    if sys_status
        disp(' ');
        disp('Error on moving series from the dcmServer'); 
        disp('Related Logs from the movescu.exe process:');
        disp(' ');
        type(dcmtmpfile4);
        disp(' ');
        delete(dcmtmpfile4);
        delete(hm);
        return;
    end
end
delete(hm);

% Read the dcm images
%
%indexdat_path='D:\data\dicomdb_matlab\petct';
localdcm_config = which('dcmqrscp.cfg');
if isempty(localdcm_config)
    disp('MATLAB can not find the dcmqrscp.cfg config file to the local dcmserver!');
    return;
else
    fid = fopen(localdcm_config,'r');
end
ldcmcfg = fscanf(fid, '%c', [1 inf]);
fclose(fid);
kk = strfind(ldcmcfg,[sprintf('\n'),'MATLAB ']);
kkk = strfind(ldcmcfg(kk:end),sprintf('\n'));
matlab_line = ldcmcfg(kk+1:kk+kkk(2)-1);
space_location = find(diff(isspace(matlab_line)));
indexdat_path = matlab_line(space_location(2)+1:space_location(3));
%indexdat_path='D:\tmp\dcmtmp';

indexdat = [indexdat_path,filesep,'index.dat'];
fid = fopen(indexdat,'r');
indexdat_content = char(fread(fid));
FileNames = cell(num_of_image,1);
for i=1:num_of_image
    pos2=strfind(indexdat_content',ImageList{i});
    startpos = pos2-3649 + length(indexdat_path)+1;
    stoppos = startpos+22;
    FileNames{i} = indexdat_content(startpos:stoppos)';
end
dir_path = [indexdat_path,filesep];
[imaVOL, scaninfo, dcminfo] = loaddcm(FileNames,dir_path);

clear global SelectedStudyInstanceUID dcmSeriesListVal SeriesList;

Contact us