├── .gitignore ├── README.md ├── ReadMe.txt ├── TCIA_Menu_Test_Output.html ├── TCIA_Menu_Test_Output.txt ├── menu.py ├── sample.py └── tciaclient.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | README 2 | The Cancer Imaging Archive 3 | TCIA Interactive Menu 4 | Version 3 5 | Contents 6 | -------- 7 | 8 | * Introduction 9 | * TCIA Menu Setup 10 | * Useful Tips 11 | * Sample Property File 12 | * User Requirements 13 | * Sample Test Cases 14 | * Troubleshooting 15 | * Bug Reports and Feedback 16 | 17 | 18 | Introduction 19 | ------------ 20 | 21 | The TCIA interactive menu is designed to provide users of The Cancer Imaging 22 | Archive with the ability to easily interact with the TCIA Programmatic Interface 23 | (REST API). This version is designed to be compatible with version 3 of the API. 24 | Users of the TCIA menu will be able to call any existing method available in the 25 | API, as well as keep existing TCIA Collections and Patients synchronized locally. 26 | 27 | The TCIA menu uses the same directory structure as the Java Web Start download 28 | options currently available on the TCIA wiki site found at: 29 | 30 | https://wiki.cancerimagingarchive.net/display/Public/Wiki 31 | 32 | To make best use of the TCIA menu, it's recommended to configure a %TCIA_HOME% 33 | system environment variable and create a TCIA properties file, as described below. 34 | 35 | 36 | TCIA Menu Setup 37 | ------------------------------------------------------- 38 | 39 | 1. Checkout all files available on the TCIA GitHub page. 40 | 2. Follow instructions below in User Requirements section. 41 | 3. To take advantage of certain features of the TCIA menu, configure a system 42 | environment variable called "TCIA_HOME" and point it at the directory 43 | that contains all of your local TCIA directories and files. 44 | 4. To reduce the need to enter repetitive user input, create a properties 45 | file in your TCIA_HOME directory as described below in Useful Tips. 46 | 47 | 48 | Useful Tips 49 | ------------------------------------------------------- 50 | 51 | 1. Configure a system environment variable called "TCIA_HOME" and point it at 52 | the directory that contains all of your local TCIA directories and files. 53 | When the menu asks for a directory, just click the key, and the 54 | application will automatically search for a directory with the name of the 55 | Collection or Patient to be updated. 56 | If no %TCIA_HOME% environment variable is configured, the application will 57 | use the current working directory as the home directory. 58 | 2. Create a properties file in your %TCIA_HOME% directory. Use this file to 59 | store repetitive information to avoid having to manually enter. The only 60 | name requirements for the file are the ".properties" extension. 61 | Optional properties: 62 | (a) api_key: When asked to enter an API_KEY, just hit the key, and 63 | the application will automatically search for one in your properties file. 64 | (b) collections: For #18 in the menu, this property is expected to be configured 65 | with a comma-delimited list of valid Collection names to be updated. 66 | (c) patients: For #19 in the menu, this property is expected to be configured 67 | with a comma-delimited list of valid Patient IDs to be updated. 68 | 69 | 70 | Sample Property File 71 | ------------------------------------------------------- 72 | 73 | #TCIA User Configuration File; 74 | #Tue Apr 11 03:29:31 EST 2017 75 | api_key=12345678-1234-9876-a5a5-1h84hd84j234 76 | collections=Lung Phantom,RIDER Breast MRI 77 | patients=4482356,RIDER-2217584661 78 | 79 | 80 | User Requirements 81 | ----------------- 82 | 83 | 1. Install Python 3.3 or later 84 | 2. Install pip 9.0.1 85 | 3. Install pydicom 0.9.9 86 | Use command: pip install pydicom 87 | 88 | 89 | Sample Test Cases 90 | ----------------- 91 | 92 | Coming Soon. 93 | 94 | 95 | Troubleshooting 96 | ------------------------ 97 | 98 | Coming Soon. 99 | 100 | 101 | Bug Reports and Feedback 102 | ------------------------ 103 | 104 | Please report any bugs and feedback to: 105 | * Phone (voice or text): +1 385-275-8242 (ASK-TCIA) 106 | * Email:help@cancerimagingarchive.net 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | README 2 | The Cancer Imaging Archive 3 | TCIA Interactive Menu 4 | Version 3 5 | Contents 6 | -------- 7 | 8 | * Introduction 9 | * TCIA Menu Setup 10 | * Useful Tips 11 | * Sample Property File 12 | * User Requirements 13 | * Sample Test Cases 14 | * Troubleshooting 15 | * Bug Reports and Feedback 16 | 17 | 18 | Introduction 19 | ------------ 20 | 21 | The TCIA interactive menu is designed to provide users of The Cancer Imaging 22 | Archive with the ability to easily interact with the TCIA Programmatic Interface 23 | (REST API). This version is designed to be compatible with version 3 of the API. 24 | Users of the TCIA menu will be able to call any existing method available in the 25 | API, as well as keep existing TCIA Collections and Patients synchronized locally. 26 | 27 | The TCIA menu uses the same directory structure as the Java Web Start download 28 | options currently available on the TCIA wiki site found at: 29 | 30 | https://wiki.cancerimagingarchive.net/display/Public/Wiki 31 | 32 | To make best use of the TCIA menu, it's recommended to configure a %TCIA_HOME% 33 | system environment variable and create a TCIA properties file, as described below. 34 | 35 | 36 | TCIA Menu Setup 37 | ------------------------------------------------------- 38 | 39 | 1. Checkout all files available on the TCIA GitHub page. 40 | 2. Follow instructions below in User Requirements section. 41 | 3. To take advantage of certain features of the TCIA menu, configure a system 42 | environment variable called "TCIA_HOME" and point it at the directory 43 | that contains all of your local TCIA directories and files. 44 | 4. To reduce the need to enter repetitive user input, create a properties 45 | file in your TCIA_HOME directory as described below in Useful Tips. 46 | 47 | 48 | Useful Tips 49 | ------------------------------------------------------- 50 | 51 | 1. Configure a system environment variable called "TCIA_HOME" and point it at 52 | the directory that contains all of your local TCIA directories and files. 53 | When the menu asks for a directory, just click the key, and the 54 | application will automatically search for a directory with the name of the 55 | Collection or Patient to be updated. 56 | If no %TCIA_HOME% environment variable is configured, the application will 57 | use the current working directory as the home directory. 58 | 2. Create a properties file in your %TCIA_HOME% directory. Use this file to 59 | store repetitive information to avoid having to manually enter. The only 60 | name requirements for the file are the ".properties" extension. 61 | Optional properties: 62 | (a) api_key: When asked to enter an API_KEY, just hit the key, and 63 | the application will automatically search for one in your properties file. 64 | (b) collections: For #18 in the menu, this property is expected to be configured 65 | with a comma-delimited list of valid Collection names to be updated. 66 | (c) patients: For #19 in the menu, this property is expected to be configured 67 | with a comma-delimited list of valid Patient IDs to be updated. 68 | 69 | 70 | Sample Property File 71 | ------------------------------------------------------- 72 | 73 | #TCIA User Configuration File; 74 | #Tue Apr 11 03:29:31 EST 2017 75 | #Key below is not valid 76 | 77 | api_key=12345678-1234-9876-a5a5-1h84hd84j234 78 | collections=Lung Phantom,RIDER Breast MRI 79 | patients=4482356,RIDER-2217584661 80 | 81 | 82 | User Requirements 83 | ----------------- 84 | 85 | 1. Install Python 3.3 or later 86 | 2. Install pip 9.0.1 87 | 3. Install pydicom 0.9.9 88 | Use command: pip install pydicom 89 | 90 | 91 | Sample Test Cases 92 | ----------------- 93 | 94 | Coming Soon. 95 | 96 | 97 | Troubleshooting 98 | ------------------------ 99 | 100 | Coming Soon. 101 | 102 | 103 | Bug Reports and Feedback 104 | ------------------------ 105 | 106 | Please report any bugs and feedback to: 107 | * Phone (voice or text): +1 385-275-8242 (ASK-TCIA) 108 | * Email:help@cancerimagingarchive.net 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /TCIA_Menu_Test_Output.txt: -------------------------------------------------------------------------------- 1 | Microsoft Windows [Version 6.1.7601] 2 | 3 | hilfikerp@FR-N-S079396 C:\tcia 4 | > cd .. 5 | 6 | hilfikerp@FR-N-S079396 C:\ 7 | > cd temp 8 | 9 | hilfikerp@FR-N-S079396 C:\temp 10 | > echo %TCIA_HOME% 11 | C:\tcia 12 | 13 | hilfikerp@FR-N-S079396 C:\temp 14 | > python C:\workspace\TCIA-API-SDK-master\tcia-rest-client-python\src\menu.py 15 | 16 | 17 | Welcome to the TCIA Request Application. 18 | Please refer to the ReadMe file for useful tips on how to simplify repetitive requests. 19 | 20 | 21 | Please supply an API_KEY to access the TCIA data (Press key to load from properties file): 22 | 23 | Searching in %TCIA_HOME% = 'C:\tcia' 24 | 25 | Searching for TCIA properties file in 'C:\tcia'. 26 | TCIA properties loaded from 'C:\tcia\tcia.properties'. 27 | API_KEY successfully loaded from properties file. 28 | 29 | 30 | 1) Get Collection Values 31 | 2) Get Modality Values 32 | 3) Get Body Part Values 33 | 4) Get Manufacturer Values 34 | 5) Get Patient 35 | 6) Patients By Modality 36 | 7) Get Patient Study 37 | 8) Get Series 38 | 9) Get Series Size 39 | 10) Get Image 40 | 11) New Patients in Collection 41 | 12) New Studies in Patient Collection 42 | 13) Get SOP Instance UIDs 43 | 14) Get Single Image 44 | 15) Contents By Name 45 | 16) Update Collection 46 | 17) Update Patient 47 | 18) Update All Collections (No Prompts) 48 | 19) Update All Patients (No Prompts) 49 | 50 | 51 | Which action (Type 'q' to quit)? 18 52 | 53 | Searching in %TCIA_HOME% = 'C:\tcia' 54 | 55 | Searching for TCIA properties file in 'C:\tcia'. 56 | TCIA properties loaded from 'C:\tcia\tcia.properties'. 57 | Collections successfully loaded from properties file. 58 | 59 | Searching in %TCIA_HOME% = 'C:\tcia' 60 | Searching in 'C:\tcia' 61 | 62 | Current collection = 'Lung Phantom' 63 | Searching for directory with the name 'Lung Phantom'. 64 | Found directory: C:\tcia\Lung Phantom 65 | C:\tcia\Lung Phantom\ 66 | 67 | Collecting remote series... 68 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getSeries?Collection=Lung+Phantom&format=json 69 | 109 remote series found. 70 | 71 | Collecting local series... 72 | 89 local series found. 73 | 74 | Downloading the 20 missing series to 'C:\tcia\Lung Phantom\'... 75 | 76 | Downloading 1.2.276.0.7230010.3.1.3.0.21757.1437749726.319319... 77 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.21757.1437749726.319319 78 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.21757.1437749726.319319\ 79 | Extracted 1.2.276.0.7230010.3.1.3.0.21757.1437749726.319319 80 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.21757.1437749726.31 81 | 9319 82 | 83 | Downloading 1.2.276.0.7230010.3.1.3.0.32115.1424660059.231627... 84 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.32115.1424660059.231627 85 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.32115.1424660059.231627\ 86 | Extracted 1.2.276.0.7230010.3.1.3.0.32115.1424660059.231627 87 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.32115.1424660059.23 88 | 1627 89 | 90 | Downloading 1.2.276.0.7230010.3.1.3.0.32464.1424660724.400766... 91 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.32464.1424660724.400766 92 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.32464.1424660724.400766\ 93 | Extracted 1.2.276.0.7230010.3.1.3.0.32464.1424660724.400766 94 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.32464.1424660724.40 95 | 0766 96 | 97 | Downloading 1.2.276.0.7230010.3.1.3.0.32604.1424661001.369942... 98 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.32604.1424661001.369942 99 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.32604.1424661001.369942\ 100 | Extracted 1.2.276.0.7230010.3.1.3.0.32604.1424661001.369942 101 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.32604.1424661001.36 102 | 9942 103 | 104 | Downloading 1.2.276.0.7230010.3.1.3.0.32669.1424671831.707479... 105 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.32669.1424671831.707479 106 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.32669.1424671831.707479\ 107 | Extracted 1.2.276.0.7230010.3.1.3.0.32669.1424671831.707479 108 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.32669.1424671831.70 109 | 7479 110 | 111 | Downloading 1.2.276.0.7230010.3.1.3.0.32739.1424684894.783234... 112 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.32739.1424684894.783234 113 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.32739.1424684894.783234\ 114 | Extracted 1.2.276.0.7230010.3.1.3.0.32739.1424684894.783234 115 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.32739.1424684894.78 116 | 3234 117 | 118 | Downloading 1.2.276.0.7230010.3.1.3.0.32981.1424692434.488952... 119 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.32981.1424692434.488952 120 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.32981.1424692434.488952\ 121 | Extracted 1.2.276.0.7230010.3.1.3.0.32981.1424692434.488952 122 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.32981.1424692434.48 123 | 8952 124 | 125 | Downloading 1.2.276.0.7230010.3.1.3.0.33074.1424692583.78137... 126 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33074.1424692583.78137 127 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33074.1424692583.78137\ 128 | Extracted 1.2.276.0.7230010.3.1.3.0.33074.1424692583.78137 129 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33074.1424692583.78 130 | 137 131 | 132 | Downloading 1.2.276.0.7230010.3.1.3.0.33413.1424693150.449270... 133 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33413.1424693150.449270 134 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33413.1424693150.449270\ 135 | Extracted 1.2.276.0.7230010.3.1.3.0.33413.1424693150.449270 136 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33413.1424693150.44 137 | 9270 138 | 139 | Downloading 1.2.276.0.7230010.3.1.3.0.33494.1424693300.5451... 140 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33494.1424693300.5451 141 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33494.1424693300.5451\ 142 | Extracted 1.2.276.0.7230010.3.1.3.0.33494.1424693300.5451 143 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33494.1424693300.54 144 | 51 145 | 146 | Downloading 1.2.276.0.7230010.3.1.3.0.33514.1424693332.840704... 147 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33514.1424693332.840704 148 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33514.1424693332.840704\ 149 | Extracted 1.2.276.0.7230010.3.1.3.0.33514.1424693332.840704 150 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33514.1424693332.84 151 | 0704 152 | 153 | Downloading 1.2.276.0.7230010.3.1.3.0.33554.1424693410.307122... 154 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33554.1424693410.307122 155 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33554.1424693410.307122\ 156 | Extracted 1.2.276.0.7230010.3.1.3.0.33554.1424693410.307122 157 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33554.1424693410.30 158 | 7122 159 | 160 | Downloading 1.2.276.0.7230010.3.1.3.0.33594.1424693484.359510... 161 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33594.1424693484.359510 162 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33594.1424693484.359510\ 163 | Extracted 1.2.276.0.7230010.3.1.3.0.33594.1424693484.359510 164 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33594.1424693484.35 165 | 9510 166 | 167 | Downloading 1.2.276.0.7230010.3.1.3.0.33676.1424693607.913924... 168 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33676.1424693607.913924 169 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33676.1424693607.913924\ 170 | Extracted 1.2.276.0.7230010.3.1.3.0.33676.1424693607.913924 171 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33676.1424693607.91 172 | 3924 173 | 174 | Downloading 1.2.276.0.7230010.3.1.3.0.33785.1424693780.719180... 175 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33785.1424693780.719180 176 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33785.1424693780.719180\ 177 | Extracted 1.2.276.0.7230010.3.1.3.0.33785.1424693780.719180 178 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33785.1424693780.71 179 | 9180 180 | 181 | Downloading 1.2.276.0.7230010.3.1.3.0.33909.1424694018.731110... 182 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33909.1424694018.731110 183 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33909.1424694018.731110\ 184 | Extracted 1.2.276.0.7230010.3.1.3.0.33909.1424694018.731110 185 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33909.1424694018.73 186 | 1110 187 | 188 | Downloading 1.2.276.0.7230010.3.1.3.0.33929.1424694053.69084... 189 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.33929.1424694053.69084 190 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.33929.1424694053.69084\ 191 | Extracted 1.2.276.0.7230010.3.1.3.0.33929.1424694053.69084 192 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.33929.1424694053.69 193 | 084 194 | 195 | Downloading 1.2.276.0.7230010.3.1.3.0.34180.1424694502.380883... 196 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.34180.1424694502.380883 197 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.34180.1424694502.380883\ 198 | Extracted 1.2.276.0.7230010.3.1.3.0.34180.1424694502.380883 199 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.34180.1424694502.38 200 | 0883 201 | 202 | Downloading 1.2.276.0.7230010.3.1.3.0.34220.1424694565.324590... 203 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.276.0.7230010.3.1.3.0.34220.1424694565.324590 204 | Extracting to C:\tcia\Lung Phantom\1.2.276.0.7230010.3.1.3.0.34220.1424694565.324590\ 205 | Extracted 1.2.276.0.7230010.3.1.3.0.34220.1424694565.324590 206 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.276.0.7230010.3.1.3.0.34220.1424694565.32 207 | 4590 208 | 209 | Downloading 1.2.840.113619.2.55.3.1930041893.617.1308206442.326.4... 210 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.2.840.113619.2.55.3.1930041893.617.1308206442.326.4 211 | Extracting to C:\tcia\Lung Phantom\1.2.840.113619.2.55.3.1930041893.617.1308206442.326.4\ 212 | Extracted 1.2.840.113619.2.55.3.1930041893.617.1308206442.326.4 213 | Files have been moved to C:\tcia\Lung Phantom\4482356\1.2.840.113745.101000.1186002.40721.8111.13846623\1.2.840.113619.2.55.3.1930041893.617.13082064 214 | 42.326.4 215 | 216 | 20 new series have been added to your collection. 217 | Update is complete for collection 'Lung Phantom' 218 | 219 | Current collection = 'RIDER Breast MRI' 220 | Searching for directory with the name 'RIDER Breast MRI'. 221 | Found directory: C:\tcia\RIDER Breast MRI 222 | C:\tcia\RIDER Breast MRI\ 223 | 224 | Collecting remote series... 225 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getSeries?Collection=RIDER+Breast+MRI&format=json 226 | 40 remote series found. 227 | 228 | Collecting local series... 229 | 32 local series found. 230 | 231 | Downloading the 8 missing series to 'C:\tcia\RIDER Breast MRI\'... 232 | 233 | Downloading 1.3.6.1.4.1.9328.50.7.148672602024447894354071561047112702722... 234 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.14867260202444789435407156104711270 235 | 2722 236 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.148672602024447894354071561047112702722\ 237 | Extracted 1.3.6.1.4.1.9328.50.7.148672602024447894354071561047112702722 238 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-1125105682\1.3.6.1.4.1.9328.50.7.311404225345463417485233488684291825227\1.3.6.1.4.1.9328.50. 239 | 7.148672602024447894354071561047112702722 240 | 241 | Downloading 1.3.6.1.4.1.9328.50.7.191673935644190628295928690330231030013... 242 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.19167393564419062829592869033023103 243 | 0013 244 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.191673935644190628295928690330231030013\ 245 | Extracted 1.3.6.1.4.1.9328.50.7.191673935644190628295928690330231030013 246 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-2217584661\1.3.6.1.4.1.9328.50.7.259395779545810898886784449342040659687\1.3.6.1.4.1.9328.50. 247 | 7.191673935644190628295928690330231030013 248 | 249 | Downloading 1.3.6.1.4.1.9328.50.7.230119312665956757099613872111624026018... 250 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.23011931266595675709961387211162402 251 | 6018 252 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.230119312665956757099613872111624026018\ 253 | Extracted 1.3.6.1.4.1.9328.50.7.230119312665956757099613872111624026018 254 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-2217584661\1.3.6.1.4.1.9328.50.7.25822134974772330945514880449913240573\1.3.6.1.4.1.9328.50.7 255 | .230119312665956757099613872111624026018 256 | 257 | Downloading 1.3.6.1.4.1.9328.50.7.249404516468709022103298368762340791245... 258 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.24940451646870902210329836876234079 259 | 1245 260 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.249404516468709022103298368762340791245\ 261 | Extracted 1.3.6.1.4.1.9328.50.7.249404516468709022103298368762340791245 262 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-1125105682\1.3.6.1.4.1.9328.50.7.166645751600387952750352410320599553837\1.3.6.1.4.1.9328.50. 263 | 7.249404516468709022103298368762340791245 264 | 265 | Downloading 1.3.6.1.4.1.9328.50.7.259598666695126728515803051266073690786... 266 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.25959866669512672851580305126607369 267 | 0786 268 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.259598666695126728515803051266073690786\ 269 | Extracted 1.3.6.1.4.1.9328.50.7.259598666695126728515803051266073690786 270 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-2217584661\1.3.6.1.4.1.9328.50.7.25822134974772330945514880449913240573\1.3.6.1.4.1.9328.50.7 271 | .259598666695126728515803051266073690786 272 | 273 | Downloading 1.3.6.1.4.1.9328.50.7.261772317324041365541450388603508531852... 274 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.26177231732404136554145038860350853 275 | 1852 276 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.261772317324041365541450388603508531852\ 277 | Extracted 1.3.6.1.4.1.9328.50.7.261772317324041365541450388603508531852 278 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-2217584661\1.3.6.1.4.1.9328.50.7.25822134974772330945514880449913240573\1.3.6.1.4.1.9328.50.7 279 | .261772317324041365541450388603508531852 280 | 281 | Downloading 1.3.6.1.4.1.9328.50.7.29171872502655886851585593434125289620... 282 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.29171872502655886851585593434125289 283 | 620 284 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.29171872502655886851585593434125289620\ 285 | Extracted 1.3.6.1.4.1.9328.50.7.29171872502655886851585593434125289620 286 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-5423859857\1.3.6.1.4.1.9328.50.7.176646703930190023758817646227898154473\1.3.6.1.4.1.9328.50. 287 | 7.29171872502655886851585593434125289620 288 | 289 | Downloading 1.3.6.1.4.1.9328.50.7.321446612661984907899823865234605992349... 290 | https://services.cancerimagingarchive.net/services/v3/TCIA/query/getImage?SeriesInstanceUID=1.3.6.1.4.1.9328.50.7.32144661266198490789982386523460599 291 | 2349 292 | Extracting to C:\tcia\RIDER Breast MRI\1.3.6.1.4.1.9328.50.7.321446612661984907899823865234605992349\ 293 | Extracted 1.3.6.1.4.1.9328.50.7.321446612661984907899823865234605992349 294 | Files have been moved to C:\tcia\RIDER Breast MRI\RIDER-2217584661\1.3.6.1.4.1.9328.50.7.25822134974772330945514880449913240573\1.3.6.1.4.1.9328.50.7 295 | .321446612661984907899823865234605992349 296 | 297 | 8 new series have been added to your collection. 298 | Update is complete for collection 'RIDER Breast MRI' 299 | 300 | Update request is complete. 301 | 302 | 303 | 1) Get Collection Values 304 | 2) Get Modality Values 305 | 3) Get Body Part Values 306 | 4) Get Manufacturer Values 307 | 5) Get Patient 308 | 6) Patients By Modality 309 | 7) Get Patient Study 310 | 8) Get Series 311 | 9) Get Series Size 312 | 10) Get Image 313 | 11) New Patients in Collection 314 | 12) New Studies in Patient Collection 315 | 13) Get SOP Instance UIDs 316 | 14) Get Single Image 317 | 15) Contents By Name 318 | 16) Update Collection 319 | 17) Update Patient 320 | 18) Update All Collections (No Prompts) 321 | 19) Update All Patients (No Prompts) 322 | 323 | 324 | Which action (Type 'q' to quit)? q 325 | Thank you. You have exited the TCIA Request Application. 326 | 327 | 328 | 329 | hilfikerp@FR-N-S079396 C:\temp 330 | > 331 | -------------------------------------------------------------------------------- /menu.py: -------------------------------------------------------------------------------- 1 | from tciaclient import TCIAClient 2 | import os, urllib.request, urllib.error, urllib.parse, urllib.request, urllib.parse, urllib.error, sys 3 | 4 | 5 | #################################### Function to print server response ####### 6 | def printServerResponse(response): 7 | if response.getcode() == 200: 8 | print("Server Returned:\n") 9 | print(response.read()) 10 | print("\n") 11 | else: 12 | print("Error: " + str(response.getcode())) 13 | 14 | def validate(date_text): 15 | try: 16 | datetime.datetime.strptime(date_text, '%Y-%m-%d') 17 | except ValueError: 18 | raise ValueError("Incorrect data format, should be YYYY-MM-DD.\n") 19 | 20 | def find_dir_by_name(rootDirectory = None, directoryName = None): 21 | if rootDirectory == None or rootDirectory == "": 22 | rootDirectory = os.getcwd() 23 | if directoryName == None: 24 | return None 25 | for dirName, subdirList, fileList in os.walk(rootDirectory): 26 | if directoryName == os.path.basename(dirName): 27 | print('Found directory: %s' % dirName) 28 | return os.path.join(dirName,'') 29 | print("Not found.") 30 | return None 31 | 32 | def load_tcia_properties(): 33 | tciaHome = find_tcia_home() 34 | print("\nSearching for TCIA properties file in '" + tciaHome + "'.") 35 | 36 | for (path, dirs, files) in os.walk(tciaHome, topdown=True, onerror=False): 37 | for name in files: #Read the current directory 38 | if name.endswith('.properties'): #Check for .properties files 39 | tciaPropertyFile = os.path.join(path, name) 40 | tcia_properties = {} 41 | with open(tciaPropertyFile) as f: 42 | for line in f: 43 | tokens = line.split('=') 44 | tcia_properties[tokens[0].lower()] = '='.join(tokens[1:]) 45 | print("TCIA properties loaded from '" + tciaPropertyFile + "'.") 46 | return tcia_properties 47 | print("Property file not found.\n") 48 | return None 49 | 50 | def find_tcia_home(): 51 | tcia_home = os.path.expandvars("%TCIA_HOME%") 52 | if (tcia_home == "%TCIA_HOME%"): 53 | print("\nSearching in current working directory = '" + os.getcwd() + "'") 54 | return os.getcwd() 55 | else: 56 | print("\nSearching in %TCIA_HOME% = '" + tcia_home + "'") 57 | return tcia_home 58 | 59 | 60 | def main(): 61 | 62 | print("\n") 63 | print ("Welcome to the TCIA Request Application.") 64 | print ("Please refer to the ReadMe file for useful tips on how to simplify repetitive requests.") 65 | print("\n") 66 | api_key_found = 0 67 | while api_key_found == 0: 68 | api_key_string = input("Please supply an API_KEY to access the TCIA data (Press key to load from properties file):") 69 | if (api_key_string == None or api_key_string == ""): 70 | tcia_properties = load_tcia_properties() 71 | if tcia_properties == None: 72 | print("Unable to locate an API_KEY value.\n") 73 | else: 74 | api_key_string = tcia_properties["api_key"].strip() 75 | print("API_KEY successfully loaded from properties file.") 76 | api_key_found = 1 77 | else: 78 | api_key_found = 1 79 | 80 | while menu(api_key_string) == 1: pass 81 | print 82 | 83 | def menu(api_key_string = None): 84 | 85 | tcia_client = TCIAClient(apiKey = api_key_string,baseUrl="https://services.cancerimagingarchive.net/services/v3",resource = "TCIA") 86 | tcia_client2 = TCIAClient(apiKey = api_key_string,baseUrl="https://services.cancerimagingarchive.net/services/v3",resource="SharedList") 87 | 88 | print("\n") 89 | print ("1) Get Collection Values") 90 | print ("2) Get Modality Values") 91 | print ("3) Get Body Part Values") 92 | print ("4) Get Manufacturer Values") 93 | print ("5) Get Patient") 94 | print ("6) Patients By Modality") 95 | print ("7) Get Patient Study") 96 | print ("8) Get Series") 97 | print ("9) Get Series Size") 98 | print ("10) Get Image") 99 | print ("11) New Patients in Collection") 100 | print ("12) New Studies in Patient Collection") 101 | print ("13) Get SOP Instance UIDs") 102 | print ("14) Get Single Image") 103 | print ("15) Contents By Name") 104 | print ("16) Update Collection") 105 | print ("17) Update Patient") 106 | print ("18) Update All Collections (No Prompts)") 107 | print ("19) Update All Patients (No Prompts)") 108 | print("\n") 109 | 110 | actionString = input("Which action (Type 'q' to quit)? ") 111 | if (actionString == "" or actionString.lower() == 'q' or actionString.lower() == "quit"): 112 | print("Thank you. You have exited the TCIA Request Application.") 113 | print("\n") 114 | return 0 115 | 116 | try: 117 | action = int(actionString) 118 | if action < 1 or action > 19: 119 | raise ValueError("Invalid action.") 120 | except: 121 | print("Not a valid action. Press or type 'quit' to exit TCIA menu.") 122 | return 1 123 | 124 | if action == 11 or action == 12: 125 | validDate = 0 126 | while validDate == 0: 127 | dateString = input("Enter the First Date (YYYY-MM-DD) to be included in this search: ") 128 | try: 129 | validate(date_text) 130 | validDate = 1 131 | except ValueError as err: 132 | print(err.read) 133 | 134 | if action == 2 or action == 3 or action == 4 or action == 5 or action == 6 or action == 7 or action == 8 or action == 11 or action == 12 or action == 16: 135 | collectionString = input("Enter the Collection: ") 136 | if (collectionString == ""): 137 | collectionString = None 138 | 139 | if action == 7 or action == 8: 140 | studyInstanceUIDString = input("Enter the Study Instance UID: ") 141 | if (studyInstanceUIDString == ""): 142 | studyInstanceUIDString = None 143 | 144 | if action == 7 or action == 8 or action == 17: 145 | patientIDString = input("Enter the Patient ID: ") 146 | if (patientIDString == ""): 147 | patientIDString = None 148 | 149 | if action == 8 or action == 9 or action == 10 or action == 13 or action == 14: 150 | seriesInstanceUIDString = input("Enter the Series Instance UID: ") 151 | if (seriesInstanceUIDString == ""): 152 | seriesInstanceUIDString = None 153 | 154 | if action == 3 or action == 4 or action == 6 or action == 8: 155 | modalityString = input("Enter the Modality: ") 156 | if (modalityString == ""): 157 | modalityString = None 158 | 159 | if action == 2 or action == 4 or action == 8: 160 | bodyPartExaminedString = input("Enter the Body Part Examined: ") 161 | if (bodyPartExaminedString == ""): 162 | bodyPartExaminedString = None 163 | 164 | if action == 8: 165 | manufacturerModelNameString = input("Enter the Manufacturer Model Name: ") 166 | if (manufacturerModelNameString == ""): 167 | manufacturerModelNameString = None 168 | 169 | if action == 8: 170 | manufacturerString = input("Enter the Manufacturer: ") 171 | if (manufacturerString == ""): 172 | manufacturerString = None 173 | 174 | if action == 14: 175 | sopInstanceUIDString = input("Enter the SOP Instance UID: ") 176 | if (sopInstanceUIDString == ""): 177 | sopInstanceUIDString = None 178 | 179 | if action == 15: 180 | nameString = input("Enter the Name: ") 181 | if (nameString == ""): 182 | nameString = None 183 | 184 | if action != 10 and action != 13 and action != 14 and action < 16: 185 | outputFormatString = input("Enter the desired Output Format (CSV, HTML, XML, JSON): ") 186 | if (outputFormatString == ""): 187 | outputFormatString = "JSON" 188 | 189 | if action == 10 or action == 14: 190 | filePath = input("Enter the desired path of the download file: ") 191 | if (filePath == ""): 192 | filePath = os.getcwd() 193 | else: 194 | filePath = os.path.join(filePath.translate({ord(i):None for i in '\"\''}).strip(), '') 195 | 196 | if action == 10: 197 | fileName = input("Enter the desired name of the download file: ") 198 | if (fileName == ""): 199 | fileName = "TCIA_Images.zip" 200 | 201 | if action == 14: 202 | fileName = input("Enter the desired name of the download file: ") 203 | if (fileName == ""): 204 | fileName = "TCIA_SingleImage.dcm" 205 | 206 | if action == 16: 207 | validDir = 0 208 | while validDir == 0: 209 | rootDirectoryString = input("Enter the root directory containing the images for the Collection (Press key to search for directory): ") 210 | if (rootDirectoryString == None or rootDirectoryString == ""): 211 | print("\nSearching for directory with the name '" + collectionString + "'.") 212 | tcia_home = find_tcia_home() 213 | collectionDir = find_dir_by_name(rootDirectory = tcia_home, directoryName = collectionString) 214 | if collectionDir == None or collectionDir == "": 215 | print("Unable to locate a directory with the name '" + collectionString + "'.") 216 | else: 217 | rootDirectoryString = collectionDir 218 | validDir = 1 219 | else: 220 | try: 221 | print(rootDirectoryString) 222 | rootDirectoryString = os.path.join(rootDirectoryString.translate({ord(i):None for i in '\"\''}).strip(), '') 223 | validDir = 1 224 | except: 225 | print("Invalid directory.\n") 226 | 227 | if action == 17: 228 | validDir = 0 229 | while validDir == 0: 230 | rootDirectoryString = input("Enter the root directory containing the images for the Patient (Press key to search for directory): ") 231 | if (rootDirectoryString == None or rootDirectoryString == ""): 232 | print("\nSearching for directory with the name '" + patientIDString + "'.") 233 | tcia_home = find_tcia_home() 234 | patientDir = find_dir_by_name(rootDirectory = tcia_home, directoryName = patientIDString) 235 | if patientDir == None or patientDir == "": 236 | print("Unable to locate a directory with the name '" + patientIDString + "'.\n") 237 | else: 238 | rootDirectoryString = patientDir 239 | validDir = 1 240 | else: 241 | try: 242 | print(rootDirectoryString) 243 | rootDirectoryString = os.path.join(rootDirectoryString.translate({ord(i):None for i in '\"\''}).strip(), '') 244 | validDir = 1 245 | except: 246 | print("Invalid directory.\n") 247 | 248 | 249 | 250 | if action == 1 : 251 | 252 | # Execute get_collection_values 253 | try: 254 | response = tcia_client.get_collection_values(outputFormat = outputFormatString) 255 | #print("\nQuery TCIA - getCollectionValues(outputFormat)") 256 | printServerResponse(response); 257 | except: 258 | print("Error executing program. Please verify input.\n") 259 | 260 | elif action == 2: 261 | 262 | # Execute get_modality_values with query Parameter 263 | try: 264 | response = tcia_client.get_modality_values(collection = collectionString,bodyPartExamined = bodyPartExaminedString,outputFormat = outputFormatString) 265 | #print("\nQuery TCIA - getModalityValues(null, BRAIN, JSON)") 266 | printServerResponse(response); 267 | except: 268 | print("Error executing program. Please verify input.\n") 269 | 270 | elif action == 3: 271 | 272 | # Execute get_body_part_values with query Parameter 273 | try: 274 | response = tcia_client.get_body_part_values(collection = collectionString,modality = modalityString,outputFormat = outputFormatString) 275 | #print("\nQuery TCIA - getBodyPartValues(TCA-GBM, null, JSON)") 276 | printServerResponse(response); 277 | except: 278 | print("Error executing program. Please verify input.\n") 279 | 280 | elif action == 4: 281 | 282 | # Execute get_manufacturer_values no query parameters 283 | try: 284 | response = tcia_client.get_manufacturer_values(collection = collectionString, 285 | bodyPartExamined = bodyPartExaminedString, 286 | modality = modalityString, 287 | outputFormat = outputFormatString) 288 | #print("\nQuery TCIA - getManufacturerValues(Null, Null, Null, JSON)") 289 | printServerResponse(response); 290 | except: 291 | print("Error executing program. Please verify input.\n") 292 | 293 | elif action == 5: 294 | 295 | # Execute get_patient with collection query parameter 296 | try: 297 | response = tcia_client.get_patient(collection = collectionString, 298 | outputFormat = outputFormatString) 299 | #print("\nQuery TCIA - getPatient(TCGA-GBM, JSON)") 300 | printServerResponse(response); 301 | except: 302 | print("Error executing program. Please verify input.\n") 303 | 304 | elif action == 6: 305 | 306 | # Execute patients_by_modality with collection and modality query parameter 307 | try: 308 | response = tcia_client.patients_by_modality(collection = collectionString, 309 | modality = modalityString, 310 | outputFormat = outputFormatString) 311 | #print("\nQuery TCIA - PatientsByModality(TCGA-GBM, MR, JSON)") 312 | printServerResponse(response); 313 | except: 314 | print("Error executing program. Please verify input.\n") 315 | 316 | elif action == 7: 317 | 318 | # Execute get_patient_study with collection and patientId query parameter 319 | try: 320 | response = tcia_client.get_patient_study(collection = collectionString, 321 | patientId = patientIDString, 322 | studyInstanceUid = studyInstanceUIDString, 323 | outputFormat = outputFormatString) 324 | #print("\nQuery TCIA - getPatientStudy(TCGA-GBM, TCGA-08-0244, Null, JSON)") 325 | printServerResponse(response); 326 | except: 327 | print("Error executing program. Please verify input.\n") 328 | 329 | elif action == 8: 330 | 331 | # Execute get_series with collection and patientId query parameter 332 | try: 333 | response = tcia_client.get_series(collection = collectionString, 334 | studyInstanceUid = studyInstanceUIDString, 335 | patientId = patientIDString, 336 | seriesInstanceUid = seriesInstanceUIDString, 337 | modality = modalityString, 338 | bodyPartExamined = bodyPartExaminedString, 339 | manufacturerModelName = manufacturerModelNameString, 340 | manufacturer = manufacturerString, 341 | outputFormat = outputFormatString) 342 | #print("\nQuery TCIA - getSeries(TCGA-GBM, TCGA-08-0244, Null, Null, Null, Null, Null, JSON)") 343 | printServerResponse(response); 344 | except: 345 | print("Error executing program. Please verify input.\n") 346 | 347 | elif action == 9: 348 | 349 | # Execute get_series_size 350 | try: 351 | response = tcia_client.get_series_size(SeriesInstanceUID=seriesInstanceUIDString, outputFormat = outputFormatString) 352 | #print("\nQuery TCIA - getSeriesSize(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440)") 353 | printServerResponse(response); 354 | except: 355 | print("Error executing program. Please verify input.\n") 356 | 357 | elif action == 10: 358 | 359 | # Execute get_image. 360 | # NOTE: Image response consumed differently 361 | try: 362 | response = tcia_client.get_image(seriesInstanceUid = seriesInstanceUIDString, downloadPath = filePath, zipFileName = fileName); 363 | #print("\nQuery TCIA - getImage(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440, DownloadPath, FileLocation)") 364 | print(response); 365 | except: 366 | print("Error executing program. Please verify input.\n") 367 | 368 | elif action == 11: 369 | 370 | # Execute new_patients_in_collection with collection and date query parameter 371 | try: 372 | response = tcia_client.new_patients_in_collection(collection = collectionString, date = dateString, outputFormat = outputFormatString) 373 | #print("\nQuery TCIA - NewPatientsInCollection(TCGA-GBM, 2014-06-01, JSON)") 374 | printServerResponse(response); 375 | except: 376 | print("Error executing program. Please verify input.\n") 377 | 378 | elif action == 12: 379 | 380 | # Execute new_studies_in_patient_collection with collection and date query parameter 381 | try: 382 | response = tcia_client.new_studies_in_patient_collection(collection = collectionString, date = dateString, patientId = patientIDString, outputFormat = outputFormatString) 383 | #print("\nQuery TCIA - NewStudiesInPatientCollection(TCGA-GBM, 2014-06-01, JSON)") 384 | printServerResponse(response); 385 | except: 386 | print("Error executing program. Please verify input.\n") 387 | 388 | elif action == 13: 389 | 390 | # Execute get_sop_instance_uids with SeriesInstanceUID query parameter 391 | try: 392 | response = tcia_client.get_sop_instance_uids(SeriesInstanceUID = seriesInstanceUIDString, outputFormat = outputFormatString) 393 | #print("\nQuery TCIA - getSeriesInstanceUIDs(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440, JSON)") 394 | printServerResponse(response); 395 | except: 396 | print("Error executing program. Please verify input.\n") 397 | 398 | elif action == 14: 399 | 400 | # Execute get_single_image with SeriesInstanceUID and SOPInstanceUID query parameter 401 | try: 402 | response = tcia_client.get_single_image(SeriesInstanceUID = seriesInstanceUIDString, 403 | SOPInstanceUID = sopInstanceUIDString, 404 | downloadPath = filePath, 405 | fileName = fileName) 406 | #print("\nQuery TCIA - getSingleImage(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440, 1.3.6.1.4.1.14519.5.2.1.7695.4001.152032524561037056647374573281, SingleImage.dcm)") 407 | print(response); 408 | except: 409 | print("Error executing program. Please verify input.\n") 410 | 411 | elif action == 15: 412 | 413 | # Execute content_by_name 414 | try: 415 | response = tcia_client2.contents_by_name(name = nameString) 416 | #print("\nQuery TCIA - getContentsByName(sharedListApiUnitTest)") 417 | printServerResponse(response); 418 | except: 419 | print("Error executing program. Please verify input.\n") 420 | 421 | elif action == 16: 422 | 423 | # Execute update_collection 424 | try: 425 | missingSeries = tcia_client.find_missing_series_collection(collection = collectionString, 426 | rootDirectory = rootDirectoryString) 427 | if (len(missingSeries) < 1): 428 | print("Collection '" + collectionString + "' is up-to-date.") 429 | return 1 430 | 431 | proceedWithDownload = input("Would you like to download the " + str(len(missingSeries)) + " missing series to '" + rootDirectoryString + "' (Y or N)? ") 432 | if (proceedWithDownload.lower() != "y" and proceedWithDownload.lower() != "yes"): 433 | print("Collection update request has been cancelled.") 434 | else: 435 | downloadedSeries = tcia_client.downloadAndExtractToCollection(rootDirectory = rootDirectoryString, seriesInstanceUids = missingSeries) 436 | print("\n" + str(downloadedSeries) + " new series have been added to your collection.") 437 | print('Update is complete.') 438 | except: 439 | print("Error executing program. Please verify input.\n") 440 | 441 | elif action == 17: 442 | 443 | # Execute update_patient 444 | try: 445 | missingSeries = tcia_client.find_missing_series_patient(patientID = patientIDString, 446 | rootDirectory = rootDirectoryString) 447 | if (len(missingSeries) < 1): 448 | print("Patient '" + patientIDString + "' is up-to-date.") 449 | return 1 450 | 451 | proceedWithDownload = input("Would you like to download the " + str(len(missingSeries)) + " missing series to '" + rootDirectoryString + "' (Y or N)? ") 452 | if (proceedWithDownload.lower() != "y" and proceedWithDownload.lower() != "yes"): 453 | print("Collection update request has been cancelled.") 454 | else: 455 | downloadedSeries = tcia_client.downloadAndExtractToPatient(rootDirectory = rootDirectoryString, seriesInstanceUids = missingSeries) 456 | print("\n" + str(downloadedSeries) + " new series have been added to your collection.") 457 | print('Update is complete.') 458 | except: 459 | print("Error executing program. Please verify input.\n") 460 | 461 | elif action == 18: 462 | tcia_properties = load_tcia_properties() 463 | if tcia_properties == None: 464 | print("Unable to locate a Collections list. Please refer to ReadMe file to use this feature.\n") 465 | else: 466 | collections_string = tcia_properties["collections"] 467 | print("Collections successfully loaded from properties file.") 468 | 469 | tcia_home = find_tcia_home() 470 | print("Searching in '" + tcia_home + "'") 471 | 472 | collection_list = collections_string.split(",") 473 | for collection in collection_list: 474 | collectionString = collection.strip() 475 | print("\nCurrent collection = '" + collectionString + "'") 476 | print("Searching for directory with the name '" + collectionString + "'.") 477 | 478 | collectionDir = find_dir_by_name(rootDirectory = tcia_home, directoryName = collectionString) 479 | if collectionDir == None or collectionDir == "": 480 | print("Unable to locate a directory with the name '" + collectionString + "'.") 481 | print("Update not executed for collection '" + collectionString + "'") 482 | continue 483 | else: 484 | rootDirectoryString = collectionDir 485 | try: 486 | print(rootDirectoryString) 487 | rootDirectoryString = os.path.join(rootDirectoryString.translate({ord(i):None for i in '\"\''}).strip(), '') 488 | except: 489 | print("Invalid directory: '" + rootDirectoryString + "'") 490 | print("Update not executed for collection '" + collectionString + "'") 491 | continue 492 | 493 | # Execute update_collection 494 | try: 495 | missingSeries = tcia_client.find_missing_series_collection(collection = collectionString, 496 | rootDirectory = rootDirectoryString) 497 | if (len(missingSeries) > 0): 498 | print("Downloading the " + str(len(missingSeries)) + " missing series to '" + rootDirectoryString + "'...") 499 | downloadedSeries = tcia_client.downloadAndExtractToCollection(rootDirectory = rootDirectoryString, seriesInstanceUids = missingSeries) 500 | print("\n" + str(downloadedSeries) + " new series have been added to your collection.") 501 | print("Update is complete for collection '" + collectionString + "'") 502 | else: 503 | print("Collection '" + collectionString + "' is up-to-date.") 504 | except: 505 | print("Error executing program. Update not executed for collection '" + collectionString + "'") 506 | print("\nUpdate request is complete.") 507 | 508 | elif action == 19: 509 | tcia_properties = load_tcia_properties() 510 | if tcia_properties == None: 511 | print("Unable to locate a Patients list. Please refer to ReadMe file to use this feature.\n") 512 | else: 513 | patients_string = tcia_properties["patients"] 514 | print("Patients successfully loaded from properties file.") 515 | 516 | tcia_home = find_tcia_home() 517 | print("Searching in '" + tcia_home + "'") 518 | 519 | patient_list = patients_string.split(",") 520 | for patient in patient_list: 521 | patientIDString = patient.strip() 522 | print("\nCurrent patient = '" + patientIDString + "'") 523 | print("Searching for directory with the name '" + patientIDString + "'.") 524 | 525 | patientDir = find_dir_by_name(rootDirectory = tcia_home, directoryName = patientIDString) 526 | if patientDir == None or patientDir == "": 527 | print("Unable to locate a directory with the name '" + patientIDString + "'.") 528 | print("Update not executed for patient '" + patientIDString + "'") 529 | continue 530 | else: 531 | rootDirectoryString = patientDir 532 | try: 533 | print(rootDirectoryString) 534 | rootDirectoryString = os.path.join(rootDirectoryString.translate({ord(i):None for i in '\"\''}).strip(), '') 535 | except: 536 | print("Invalid directory: '" + rootDirectoryString + "'") 537 | print("Update not executed for patient '" + patientIDString + "'") 538 | continue 539 | 540 | # Execute update_patient 541 | try: 542 | missingSeries = tcia_client.find_missing_series_patient(patientID = patientIDString, 543 | rootDirectory = rootDirectoryString) 544 | if (len(missingSeries) > 0): 545 | print("Downloading the " + str(len(missingSeries)) + " missing series to '" + rootDirectoryString + "'...") 546 | downloadedSeries = tcia_client.downloadAndExtractToPatient(rootDirectory = rootDirectoryString, seriesInstanceUids = missingSeries) 547 | print("\n" + str(downloadedSeries) + " new series have been added to your collection.") 548 | print("Update is complete for patient '" + patientIDString + "'") 549 | else: 550 | print("Patient '" + patientIDString + "' is up-to-date.") 551 | except: 552 | print("Error executing program. Update not executed for patient '" + patientIDString + "'") 553 | print("\nUpdate request is complete.") 554 | 555 | 556 | return 1 557 | 558 | main() 559 | -------------------------------------------------------------------------------- /sample.py: -------------------------------------------------------------------------------- 1 | from tciaclient import TCIAClient 2 | import urllib.request, urllib.error, urllib.parse, urllib.request, urllib.parse, urllib.error,sys 3 | import json 4 | 5 | 6 | #################################### Function to print server response ####### 7 | def printServerResponse(response): 8 | if response.getcode() == 200: 9 | print("Server Returned:\n") 10 | print(response.read()) 11 | print("\n") 12 | else: 13 | print("Error: " + str(response.getcode())) 14 | 15 | #################################### Create Clients for Two Different Resources #### 16 | tcia_client = TCIAClient(apiKey = "7ad8c98d-74f9-4ebf-a59c-c3de09550db4",baseUrl="https://services.cancerimagingarchive.net/services/v3",resource = "TCIA") 17 | tcia_client2 = TCIAClient(apiKey ="7ad8c98d-74f9-4ebf-a59c-c3de09550db4",baseUrl="https://services.cancerimagingarchive.net/services/v3",resource="SharedList") 18 | 19 | 20 | 21 | # Test get_collection_values 22 | try: 23 | response = tcia_client.get_collection_values() 24 | print("\nQuery TCIA - getCollectionValues()") 25 | printServerResponse(response); 26 | except urllib.error.HTTPError as err: 27 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 28 | 29 | 30 | 31 | # Test get_modality_values with query Parameter 32 | try: 33 | response = tcia_client.get_modality_values(collection = None,bodyPartExamined = "BRAIN",outputFormat = "json") 34 | print("\nQuery TCIA - getModalityValues(null, BRAIN, JSON)") 35 | printServerResponse(response); 36 | except urllib.error.HTTPError as err: 37 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 38 | 39 | 40 | 41 | # Test get_modality_values with query Parameter 42 | try: 43 | response = tcia_client.get_modality_values(collection = "TCGA-GBM",bodyPartExamined = None,outputFormat = "json") 44 | print("\nQuery TCIA - getModalityValues(TCA-GBM, null, JSON)") 45 | printServerResponse(response); 46 | except urllib.error.HTTPError as err: 47 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 48 | 49 | 50 | 51 | # Test get_body_part_values with query Parameter 52 | try: 53 | response = tcia_client.get_body_part_values(collection = "TCGA-GBM",modality = None,outputFormat = "json") 54 | print("\nQuery TCIA - getBodyPartValues(TCA-GBM, null, JSON)") 55 | printServerResponse(response); 56 | except urllib.error.HTTPError as err: 57 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 58 | 59 | 60 | 61 | # Test get_body_part_values with query Parameter 62 | try: 63 | response = tcia_client.get_body_part_values(collection = None,modality = "MR",outputFormat = "json") 64 | print("\nQuery TCIA - getBodyPartValues(null, MR, JSON)") 65 | printServerResponse(response); 66 | except urllib.error.HTTPError as err: 67 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 68 | 69 | 70 | 71 | # Test get_manufacturer_values no query parameters 72 | try: 73 | response = tcia_client.get_manufacturer_values(collection = 74 | None,bodyPartExamined = 75 | None,modality = 76 | None,outputFormat = "json") 77 | print("\nQuery TCIA - getManufacturerValues(Null, Null, Null, JSON)") 78 | printServerResponse(response); 79 | except urllib.error.HTTPError as err: 80 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 81 | 82 | 83 | 84 | # Test get_manufacturer_values with collection query parameter 85 | try: 86 | response = tcia_client.get_manufacturer_values(collection = "TCGA-GBM", 87 | bodyPartExamined = None, 88 | modality = None, 89 | outputFormat = "json") 90 | print("\nQuery TCIA - getManufacturerValues(TCGA-GBM, Null, Null, JSON)") 91 | printServerResponse(response); 92 | except urllib.error.HTTPError as err: 93 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 94 | 95 | 96 | 97 | # Test get_manufacturer_values with modality query parameter 98 | try: 99 | response = tcia_client.get_manufacturer_values(collection = None, 100 | bodyPartExamined = None, 101 | modality = "MR", 102 | outputFormat = "json") 103 | print("\nQuery TCIA - getManufacturerValues(Null, Null, MR, JSON)") 104 | printServerResponse(response); 105 | except urllib.error.HTTPError as err: 106 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 107 | 108 | 109 | 110 | # Test get_manufacturer_values with body_part_examined query parameter 111 | try: 112 | response = tcia_client.get_manufacturer_values(collection = None, 113 | bodyPartExamined = "BRAIN", 114 | modality = None, 115 | outputFormat = "json") 116 | print("\nQuery TCIA - getManufacturerValues(Null, BRAIN, Null, JSON)") 117 | printServerResponse(response); 118 | except urllib.error.HTTPError as err: 119 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 120 | 121 | 122 | 123 | # Test get_patient with collection query parameter 124 | try: 125 | response = tcia_client.get_patient(collection = "TCGA-GBM", 126 | outputFormat = "json") 127 | print("\nQuery TCIA - getPatient(TCGA-GBM, JSON)") 128 | printServerResponse(response); 129 | except urllib.error.HTTPError as err: 130 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 131 | 132 | 133 | 134 | # Test patients_by_modality with collection and modality query parameter 135 | try: 136 | response = tcia_client.patients_by_modality(collection = "TCGA-GBM", 137 | modality = "MR", 138 | outputFormat = "json") 139 | print("\nQuery TCIA - PatientsByModality(TCGA-GBM, MR, JSON)") 140 | printServerResponse(response); 141 | except urllib.error.HTTPError as err: 142 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 143 | 144 | 145 | 146 | # Test get_patient_study with collection and patientId query parameter 147 | try: 148 | response = tcia_client.get_patient_study(collection = "TCGA-GBM", 149 | patientId = "TCGA-08-0244", 150 | studyInstanceUid = None, 151 | outputFormat = "json") 152 | print("\nQuery TCIA - getPatientStudy(TCGA-GBM, TCGA-08-0244, Null, JSON)") 153 | printServerResponse(response); 154 | except urllib.error.HTTPError as err: 155 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 156 | 157 | 158 | 159 | # Test get_series with collection and patientId query parameter 160 | try: 161 | response = tcia_client.get_series(collection = "TCGA-GBM", 162 | studyInstanceUid = None, 163 | patientId = "TCGA-08-0244", 164 | seriesInstanceUid = None, 165 | modality = None, 166 | bodyPartExamined = None, 167 | manufacturerModelName = None, 168 | manufacturer = None, 169 | outputFormat = "json") 170 | print("\nQuery TCIA - getSeries(TCGA-GBM, TCGA-08-0244, Null, Null, Null, Null, Null, JSON)") 171 | string = response.read().decode('utf-8') 172 | json_obj = json.loads(string) 173 | print(json_obj.pop()['SeriesInstanceUID']) 174 | #data = json.load(response) 175 | #print(list(data.keys)) 176 | printServerResponse(response); 177 | except urllib.error.HTTPError as err: 178 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 179 | 180 | 181 | 182 | # Test get_series_size 183 | try: 184 | response = tcia_client.get_series_size(SeriesInstanceUID="1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440") 185 | print("\nQuery TCIA - getSeriesSize(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440)") 186 | printServerResponse(response); 187 | except urllib.error.HTTPError as err: 188 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 189 | 190 | 191 | 192 | # Test get_image. 193 | # NOTE: Image response consumed differently 194 | try: 195 | response = tcia_client.get_image(seriesInstanceUid ="1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440" , downloadPath ="./", zipFileName ="images.zip"); 196 | print("\nQuery TCIA - getImage(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440, DownloadPath, FileLocation)") 197 | print(response); 198 | except urllib.error.HTTPError as err: 199 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 200 | 201 | 202 | 203 | # Test new_patients_in_collection with collection and date query parameter 204 | try: 205 | response = tcia_client.new_patients_in_collection(collection = "TCGA-GBM", date = "2014-06-01", outputFormat = "json") 206 | print("\nQuery TCIA - NewPatientsInCollection(TCGA-GBM, 2014-06-01, JSON)") 207 | printServerResponse(response); 208 | except urllib.error.HTTPError as err: 209 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 210 | 211 | 212 | 213 | # Test new_studies_in_patient_collection with collection and date query parameter 214 | try: 215 | response = tcia_client.new_studies_in_patient_collection(collection = "TCGA-GBM", date = "2014-06-01", patientId = None, outputFormat = "json") 216 | print("\nQuery TCIA - NewStudiesInPatientCollection(TCGA-GBM, 2014-06-01, JSON)") 217 | printServerResponse(response); 218 | except urllib.error.HTTPError as err: 219 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 220 | 221 | 222 | 223 | # Test new_studies_in_patient_collection with collection, date, and patientId query parameter 224 | try: 225 | response = tcia_client.new_studies_in_patient_collection(collection = "TCGA-GBM", date = "2014-06-01", patientId = "TCGA-08-0244", outputFormat = "json") 226 | print("\nQuery TCIA - NewStudiesInPatientCollection(TCGA-GBM, 2014-06-01, TCGA-08-0244, JSON)") 227 | printServerResponse(response); 228 | except urllib.error.HTTPError as err: 229 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 230 | 231 | 232 | 233 | # Test get_sop_instance_uids with SeriesInstanceUID query parameter 234 | try: 235 | response = tcia_client.get_sop_instance_uids(SeriesInstanceUID="1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440", outputFormat = "json") 236 | print("\nQuery TCIA - getSeriesInstanceUIDs(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440, JSON)") 237 | printServerResponse(response); 238 | except urllib.error.HTTPError as err: 239 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 240 | 241 | 242 | 243 | # Test get_single_image with SeriesInstanceUID and SOPInstanceUID query parameter 244 | try: 245 | response = tcia_client.get_single_image(SeriesInstanceUID="1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440", 246 | SOPInstanceUID="1.3.6.1.4.1.14519.5.2.1.7695.4001.152032524561037056647374573281", 247 | downloadPath ="./", 248 | fileName ="SingleImage.dcm") 249 | print("\nQuery TCIA - getSingleImage(1.3.6.1.4.1.14519.5.2.1.7695.4001.306204232344341694648035234440, 1.3.6.1.4.1.14519.5.2.1.7695.4001.152032524561037056647374573281, SingleImage.dcm)") 250 | print(response); 251 | except urllib.error.HTTPError as err: 252 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 253 | 254 | 255 | 256 | # Test content_by_name 257 | try: 258 | response = tcia_client2.contents_by_name(name = "sharedListApiUnitTest") 259 | print("\nQuery TCIA - getContentsByName(sharedListApiUnitTest)") 260 | printServerResponse(response); 261 | except urllib.error.HTTPError as err: 262 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) -------------------------------------------------------------------------------- /tciaclient.py: -------------------------------------------------------------------------------- 1 | import os 2 | import urllib.request, urllib.error, urllib.parse 3 | import urllib.request, urllib.parse, urllib.error 4 | import shutil 5 | import dicom 6 | import json 7 | import zipfile 8 | import errno 9 | 10 | 11 | # 12 | # Refer https://wiki.cancerimagingarchive.net/display/Public/REST+API+Usage+Guide for complete list of API 13 | # 14 | class TCIAClient: 15 | GET_COLLECTION_VALUES = "getCollectionValues" 16 | GET_MODALITY_VALUES = "getModalityValues" 17 | GET_BODY_PART_VALUES = "getBodyPartValues" 18 | GET_MANUFACTURER_VALUES = "getManufacturerValues" 19 | GET_PATIENT = "getPatient" 20 | PATIENTS_BY_MODALITY = "PatientsByModality" 21 | GET_PATIENT_STUDY = "getPatientStudy" 22 | GET_SERIES = "getSeries" 23 | GET_SERIES_SIZE = "getSeriesSize" 24 | GET_IMAGE = "getImage" 25 | NEW_PATIENTS_IN_COLLECTION = "NewPatientsInCollection" 26 | NEW_STUDIES_IN_PATIENT_COLLECTION = "NewStudiesInPatientCollection" 27 | GET_SOP_INSTANCE_UIDS = "getSOPInstanceUIDs" 28 | GET_SINGLE_IMAGE = "getSingleImage" 29 | CONTENTS_BY_NAME = "ContentsByName" 30 | 31 | 32 | def __init__(self, apiKey , baseUrl, resource): 33 | self.apiKey = apiKey 34 | self.baseUrl = baseUrl + "/" + resource 35 | 36 | def execute(self, url, queryParameters={}): 37 | queryParameters = dict((k, v) for k, v in queryParameters.items() if v) 38 | headers = {"api_key" : self.apiKey } 39 | queryString = "?%s" % urllib.parse.urlencode(queryParameters) 40 | requestUrl = url + queryString 41 | print(requestUrl) 42 | request = urllib.request.Request(url=requestUrl , headers=headers) 43 | resp = urllib.request.urlopen(request) 44 | return resp 45 | 46 | def execute_download(self, url, fileName, queryParameters={}): 47 | try: 48 | queryParameters = dict((k, v) for k, v in queryParameters.items() if v) 49 | headers = {"api_key" : self.apiKey } 50 | queryString = "?%s" % urllib.parse.urlencode(queryParameters) 51 | requestUrl = url + queryString 52 | print(requestUrl) 53 | request = urllib.request.Request(url=requestUrl , headers=headers) 54 | # Download the file from `url` and save it locally under `file_name`: 55 | with urllib.request.urlopen(request) as response, open(fileName, 'wb') as out_file: 56 | shutil.copyfileobj(response, out_file) 57 | out_file.close 58 | except urllib.error.HTTPError as e: 59 | print("HTTP Error:",e.code , requestUrl) 60 | return False 61 | except urllib.error.URLError as e: 62 | print("URL Error:",e.reason , requestUrl) 63 | return False 64 | return True 65 | 66 | 67 | 68 | def get_collection_values(self,outputFormat = "json" ): 69 | serviceUrl = self.baseUrl + "/query/" + self.GET_COLLECTION_VALUES 70 | queryParameters = { "format" : outputFormat } 71 | resp = self.execute(serviceUrl , queryParameters) 72 | return resp 73 | 74 | 75 | def get_modality_values(self,collection = None , bodyPartExamined = None , modality = None , outputFormat = "json" ): 76 | serviceUrl = self.baseUrl + "/query/" + self.GET_MODALITY_VALUES 77 | queryParameters = {"Collection" : collection , "BodyPartExamined" : bodyPartExamined , "Modality" : modality , "format" : outputFormat } 78 | resp = self.execute(serviceUrl , queryParameters) 79 | return resp 80 | 81 | 82 | def get_body_part_values(self,collection = None , bodyPartExamined = None , modality = None , outputFormat = "json" ): 83 | serviceUrl = self.baseUrl + "/query/" + self.GET_BODY_PART_VALUES 84 | queryParameters = {"Collection" : collection , "BodyPartExamined" : bodyPartExamined , "Modality" : modality , "format" : outputFormat } 85 | resp = self.execute(serviceUrl , queryParameters) 86 | return resp 87 | 88 | 89 | def get_manufacturer_values(self,collection = None , bodyPartExamined = None, modality = None , outputFormat = "json"): 90 | serviceUrl = self.baseUrl + "/query/" + self.GET_MANUFACTURER_VALUES 91 | queryParameters = {"Collection" : collection , "BodyPartExamined" : bodyPartExamined , "Modality" : modality , "format" : outputFormat } 92 | resp = self.execute(serviceUrl , queryParameters) 93 | return resp 94 | 95 | 96 | def get_patient(self,collection = None , outputFormat = "json" ): 97 | serviceUrl = self.baseUrl + "/query/" + self.GET_PATIENT 98 | queryParameters = {"Collection" : collection , "format" : outputFormat } 99 | resp = self.execute(serviceUrl , queryParameters) 100 | return resp 101 | 102 | 103 | def patients_by_modality(self,collection = None , modality = None, outputFormat = "json" ): 104 | serviceUrl = self.baseUrl + "/query/" + self.PATIENTS_BY_MODALITY 105 | queryParameters = {"Collection" : collection , "Modality" : modality, "format" : outputFormat } 106 | resp = self.execute(serviceUrl , queryParameters) 107 | return resp 108 | 109 | 110 | def get_patient_study(self,collection = None , patientId = None , studyInstanceUid = None , outputFormat = "json" ): 111 | serviceUrl = self.baseUrl + "/query/" + self.GET_PATIENT_STUDY 112 | queryParameters = {"Collection" : collection , "PatientID" : patientId , "StudyInstanceUID" : studyInstanceUid , "format" : outputFormat } 113 | resp = self.execute(serviceUrl , queryParameters) 114 | return resp 115 | 116 | 117 | def get_series(self, 118 | collection = None , 119 | studyInstanceUid = None , 120 | patientId = None , 121 | seriesInstanceUid = None , 122 | modality = None , 123 | bodyPartExamined = None , 124 | manufacturerModelName = None, 125 | manufacturer = None, 126 | outputFormat = "json" ): 127 | serviceUrl = self.baseUrl + "/query/" + self.GET_SERIES 128 | queryParameters = {"Collection" : collection , 129 | "StudyInstanceUID" : studyInstanceUid , 130 | "PatientID" : patientId , 131 | "SeriesInstanceUID" : seriesInstanceUid , 132 | "Modality" : modality , 133 | "BodyPartExamined" : bodyPartExamined , 134 | "ManufacturerModelName" : manufacturerModelName , 135 | "Manufacturer" : manufacturer , 136 | "format" : outputFormat } 137 | resp = self.execute(serviceUrl , queryParameters) 138 | return resp 139 | 140 | 141 | def get_series_size(self, SeriesInstanceUID = None, outputFormat = "json"): 142 | serviceUrl = self.baseUrl + "/query/" + self.GET_SERIES_SIZE 143 | queryParameters = {"SeriesInstanceUID" : SeriesInstanceUID, "format" : 144 | outputFormat} 145 | resp = self.execute(serviceUrl, queryParameters) 146 | return resp 147 | 148 | 149 | def get_image(self , seriesInstanceUid , downloadPath, zipFileName): 150 | serviceUrl = self.baseUrl + "/query/" + self.GET_IMAGE 151 | queryParameters = { "SeriesInstanceUID" : seriesInstanceUid } 152 | os.umask(0o002) 153 | try: 154 | file = os.path.join(downloadPath, zipFileName) 155 | resp = self.execute( serviceUrl , queryParameters) 156 | downloaded = 0 157 | CHUNK = 256 * 10240 158 | with open(file, 'wb') as fp: 159 | while True: 160 | chunk = resp.read(CHUNK) 161 | downloaded += len(chunk) 162 | if not chunk: break 163 | fp.write(chunk) 164 | except urllib.error.HTTPError as e: 165 | print("HTTP Error:",e.code , serviceUrl) 166 | return False 167 | except urllib.error.URLError as e: 168 | print("URL Error:",e.reason , serviceUrl) 169 | return False 170 | return True 171 | 172 | 173 | def new_patients_in_collection(self, 174 | date = None , 175 | collection = None , 176 | outputFormat = "json" ): 177 | serviceUrl = self.baseUrl + "/query/" + self.NEW_PATIENTS_IN_COLLECTION 178 | queryParameters = {"Date" : date , 179 | "Collection" : collection , 180 | "format" : outputFormat } 181 | resp = self.execute(serviceUrl , queryParameters) 182 | return resp 183 | 184 | 185 | def new_studies_in_patient_collection(self, 186 | date = None , 187 | collection = None , 188 | patientId = None , 189 | outputFormat = "json" ): 190 | serviceUrl = self.baseUrl + "/query/" + self.NEW_STUDIES_IN_PATIENT_COLLECTION 191 | queryParameters = {"Date" : date , 192 | "Collection" : collection , 193 | "PatientID" : patientId , 194 | "format" : outputFormat } 195 | resp = self.execute(serviceUrl , queryParameters) 196 | return resp 197 | 198 | 199 | def get_sop_instance_uids(self, SeriesInstanceUID = None, outputFormat = "json"): 200 | serviceUrl = self.baseUrl + "/query/" + self.GET_SOP_INSTANCE_UIDS 201 | queryParameters = {"SeriesInstanceUID" : SeriesInstanceUID, "format" : 202 | outputFormat} 203 | resp = self.execute(serviceUrl, queryParameters) 204 | return resp 205 | 206 | 207 | def get_single_image(self, SeriesInstanceUID, SOPInstanceUID, downloadPath, fileName): 208 | serviceUrl = self.baseUrl + "/query/" + self.GET_SINGLE_IMAGE 209 | queryParameters = {"SeriesInstanceUID" : SeriesInstanceUID, 210 | "SOPInstanceUID" : SOPInstanceUID} 211 | file = os.path.join(downloadPath, fileName) 212 | resp = self.execute_download(url=serviceUrl, fileName=file, queryParameters=queryParameters) 213 | return resp 214 | 215 | 216 | def contents_by_name(self, name = None): 217 | serviceUrl = self.baseUrl + "/query/" + self.CONTENTS_BY_NAME 218 | queryParameters = {"name" : name} 219 | resp = self.execute(serviceUrl,queryParameters) 220 | return resp 221 | 222 | 223 | def dump(self, obj): 224 | for attr in dir(obj): 225 | if hasattr( obj, attr ): 226 | print( "obj.%s = %s" % (attr, getattr(obj, attr))) 227 | 228 | def mkdir_p(self, path): 229 | try: 230 | os.makedirs(path) 231 | except OSError as exc: # Python >2.5 232 | if exc.errno == errno.EEXIST and os.path.isdir(path): 233 | pass 234 | else: raise 235 | 236 | def safe_open_w(self, path): 237 | ''' Open "path" for writing, creating any parent directories as needed. 238 | ''' 239 | self.mkdir_p(path = os.path.dirname(path)) 240 | return path 241 | 242 | 243 | def get_collection(self, rootDirectory = None): 244 | print('Reading .dcm files...') 245 | if rootDirectory == None: 246 | rootDirectory = os.getcwd() 247 | for (path, dirs, files) in os.walk(rootDirectory, topdown=True, onerror=False): 248 | for name in files: #Read the current directory 249 | if name.endswith('.dcm'): #Check for .dcm files 250 | dcmfile = dicom.read_file(os.path.join(path, name)) #if found, then read data 251 | print(type(dcmfile)) 252 | #print (dcmfile.SeriesInstanceUID) 253 | #print(dcmfile.SOPInstanceUID) 254 | self.dump(obj=dcmfile) 255 | return None 256 | return None 257 | 258 | 259 | def get_series_path(self, rootDirectory = None, downloadPath = None): 260 | for (path, dirs, files) in os.walk(downloadPath, topdown=True, onerror=False): 261 | for name in files: #Read the current directory 262 | if name.endswith('.dcm'): #Check for .dcm files 263 | dcmfile = dicom.read_file(os.path.join(path, name)) #if found, then read data 264 | return os.path.join(rootDirectory, dcmfile.PatientID, dcmfile.StudyInstanceUID, '') 265 | 266 | def get_patient_series_path(self, rootDirectory = None, downloadPath = None): 267 | for (path, dirs, files) in os.walk(downloadPath, topdown=True, onerror=False): 268 | for name in files: #Read the current directory 269 | if name.endswith('.dcm'): #Check for .dcm files 270 | dcmfile = dicom.read_file(os.path.join(path, name)) #if found, then read data 271 | return os.path.join(rootDirectory, dcmfile.StudyInstanceUID, '') 272 | 273 | def get_local_series(self, rootDirectory = None): 274 | localSeries = [] 275 | rootDirectory = os.path.join(rootDirectory, '') 276 | for (path, dirs, files) in os.walk(rootDirectory, topdown=True, onerror=False): 277 | for name in files: #Read the current directory 278 | if name.endswith('.dcm'): #Check for .dcm files 279 | dcmfile = dicom.read_file(os.path.join(path, name)) #if found, then read data 280 | localSeries.append(dcmfile.SeriesInstanceUID) 281 | break 282 | localSeries = list(set(localSeries)) #Remove duplicates from list 283 | localSeries.sort() 284 | return localSeries 285 | 286 | def get_remote_series(self, collection = None, patientID = None, studyInstanceUID = None): 287 | response = self.get_series(collection = collection, 288 | studyInstanceUid = studyInstanceUID, 289 | patientId = patientID, 290 | seriesInstanceUid = None, 291 | modality = None, 292 | bodyPartExamined = None, 293 | manufacturerModelName = None, 294 | manufacturer = None, 295 | outputFormat = "json") 296 | remoteSeriesObj = json.load(response) 297 | remoteSeries = [] 298 | for series in remoteSeriesObj: 299 | remoteSeries.append(series["SeriesInstanceUID"]) 300 | remoteSeries = list(set(remoteSeries)) #Remove duplicates from list 301 | remoteSeries.sort() 302 | return remoteSeries 303 | 304 | def downloadMissing(self, rootDirectory = None, seriesInstanceUids = None): 305 | for seriesInstanceUid in seriesInstanceUids: 306 | response = self.get_sop_instance_uids(seriesInstanceUid) 307 | responseSopObj = json.load(response) 308 | sopInstanceUids = [] 309 | 310 | for uid in responseSopObj: 311 | sopInstanceUids.append(uid["sop_instance_uid"]) 312 | sopInstanceUids = list(set(sopInstanceUids)) 313 | sopInstanceUids.sort() 314 | print(sopInstanceUids) 315 | 316 | response = self.get_series(seriesInstanceUid = seriesInstanceUid) 317 | seriesLst = json.load(response) 318 | series = seriesLst[0] 319 | print(series) 320 | 321 | print('Downloading ' + series["SeriesDate"] + '-' + series["SeriesDescription"] + '...') 322 | numberOfImages = len(sopInstanceUids) 323 | for idx, sopInstanceUid in enumerate(sopInstanceUids): 324 | print('Downloading ' + str(idx) + ' of ' + str(numberOfImages) + '...') 325 | downloadPath = os.path.join(rootDirectory, series["SeriesDate"] + '_' + series["SeriesDescription"], '') 326 | self.get_single_image(SeriesInstanceUID = seriesInstanceUid, 327 | SOPInstanceUID = sopInstanceUid, 328 | downloadPath = downloadPath, 329 | fileName = format(idx, '06d') + '.dcm') 330 | return len(seriesInstanceUids) 331 | 332 | def downloadAndExtractToCollection(self, rootDirectory = None, seriesInstanceUids = None): 333 | for seriesInstanceUid in seriesInstanceUids: 334 | print("\nDownloading " + seriesInstanceUid + "...") 335 | downloadPath = os.path.join(rootDirectory, seriesInstanceUid, '') 336 | zipFileName = seriesInstanceUid + '.zip' 337 | self.get_image(seriesInstanceUid = seriesInstanceUid, 338 | downloadPath = self.safe_open_w(path = downloadPath), 339 | zipFileName = zipFileName) 340 | zipf = os.path.join(downloadPath, zipFileName) 341 | print("Extracting to " + downloadPath) 342 | with zipfile.ZipFile(zipf, "r") as z: 343 | z.extractall(downloadPath + seriesInstanceUid) 344 | os.remove(zipf) 345 | print("Extracted " + seriesInstanceUid) 346 | 347 | seriesPath = self.get_series_path(rootDirectory = rootDirectory, downloadPath = downloadPath) 348 | self.safe_open_w(path = seriesPath) 349 | destPath = shutil.move(src = downloadPath + seriesInstanceUid, dst = seriesPath) 350 | shutil.rmtree(downloadPath) 351 | print("Files have been moved to " + destPath) 352 | 353 | return len(seriesInstanceUids) 354 | 355 | def downloadAndExtractToPatient(self, rootDirectory = None, seriesInstanceUids = None): 356 | for seriesInstanceUid in seriesInstanceUids: 357 | print("\nDownloading " + seriesInstanceUid + "...") 358 | downloadPath = os.path.join(rootDirectory, seriesInstanceUid, '') 359 | zipFileName = seriesInstanceUid + '.zip' 360 | self.get_image(seriesInstanceUid = seriesInstanceUid, 361 | downloadPath = self.safe_open_w(path = downloadPath), 362 | zipFileName = zipFileName) 363 | zipf = os.path.join(downloadPath, zipFileName) 364 | print("Extracting to " + downloadPath) 365 | with zipfile.ZipFile(zipf, "r") as z: 366 | z.extractall(downloadPath + seriesInstanceUid) 367 | os.remove(zipf) 368 | print("Extracted " + seriesInstanceUid) 369 | 370 | seriesPath = self.get_patient_series_path(rootDirectory = rootDirectory, downloadPath = downloadPath) 371 | self.safe_open_w(path = seriesPath) 372 | destPath = shutil.move(src = downloadPath + seriesInstanceUid, dst = seriesPath) 373 | shutil.rmtree(downloadPath) 374 | print("Files have been moved to " + destPath) 375 | 376 | return len(seriesInstanceUids) 377 | 378 | def find_missing_series_collection(self, rootDirectory = None, collection = None): 379 | try: 380 | rootDirectory = os.path.join(rootDirectory,'') 381 | if collection == None : #If user doesn't specify a collection, find it in a DCM file 382 | #collection = self.get_collection(rootDirectory) 383 | return None 384 | 385 | print("\nCollecting remote series...") 386 | remoteSeries = self.get_remote_series(collection = collection) 387 | print(str(len(remoteSeries)) + " remote series found.") 388 | 389 | print("\nCollecting local series...") 390 | localSeries = self.get_local_series(rootDirectory = rootDirectory) 391 | print(str(len(localSeries)) + " local series found.\n") 392 | 393 | missingSeries = list(set(remoteSeries) - set(localSeries)) 394 | missingSeries.sort() 395 | 396 | return missingSeries 397 | 398 | except urllib.error.HTTPError as err: 399 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) 400 | 401 | 402 | def find_missing_series_patient(self, rootDirectory = None, patientID = None): 403 | try: 404 | rootDirectory = os.path.join(rootDirectory,'') 405 | if patientID == None : #If user doesn't specify a collection, find it in a DCM file 406 | #collection = self.get_collection(rootDirectory) 407 | return None 408 | 409 | print("\nCollecting remote series...") 410 | remoteSeries = self.get_remote_series(patientID = patientID) 411 | print(str(len(remoteSeries)) + " remote series found.") 412 | 413 | print("\nCollecting local series...") 414 | localSeries = self.get_local_series(rootDirectory = rootDirectory) 415 | print(str(len(localSeries)) + " local series found.\n") 416 | 417 | missingSeries = list(set(remoteSeries) - set(localSeries)) 418 | missingSeries.sort() 419 | 420 | return missingSeries 421 | 422 | except urllib.error.HTTPError as err: 423 | print("Error executing program:\nError Code: ", str(err.code), "\nMessage:", err.read()) --------------------------------------------------------------------------------