diff --git a/README.md b/README.md index c62e7f7..e365ae6 100755 --- a/README.md +++ b/README.md @@ -1,203 +1,219 @@ # Shoulder Database handling and measurements ## Introduction This repository contains Matlab codes to import anonymised clinical cases in a shoulder database (shoulderDB), and update this database with complementary clinical, radiological, morphological, or biomechanical data. This project is a collaboration between Laboratory of Biomechanical Orthopedics of the Ecole Polytechnique Federal de Lausanne (EPFL-LBO), the ARTORG center of the University of Bern, the Orthopedic Service of the University Hospital of Lausanne (CHUV-OTR), and the Radiological Department of the University Hospital of Lausanne (CHUV-RAD). ## Setup ### Download Clone or download this repository. Open MATLAB, set the working directory to be the downloaded repository and run setup.m. This setup() function will create a config.json file that is detailed below. ### Write the config file The base folder must contain a "config.json" with the following keys: * maxSCaseIDDigits: This is the maximum allowed number of digits in the SCase IDs. "maxSCaseIDDigits": 3 -> 'P123' is a valid ID, 'P1234' is not valid. * SCaseIDValidTypes: These are the allowed letters used as a prefix in the SCase IDs. "SCaseIDValidTypes": ["N", "P"] -> 'P123' is a valid ID, 'Z123' is not valid. * pythonDir: This is the path to the rotator cuff segmentation system. * dataDir: This is the root path to the data used i.e. "/shoulder/dataDev" or "/shoulder/data" on lbovenus.epfl.ch * casesToMeasure: Array of cases ID to be measured when executing measureSCase() (with no argument). "casesToMeasure": "*" -> measureSCase() will measure all the cases found in the database. "casesToMeasure": "P1" -> measureSCase() will measure P1 if it's in the database. "casesToMeasure": ["P1", "P2"] -> measureSCase() will measure P1 and P" if they are found in the database. * shouldersToMeasure: Hash table used by measureSCase() where keys correspond to the four available shoulders of a case and values are booleans allowing the shoulders to be measured. For example: "shouldersToMeasure" { "rightAuto": true, "rightManual": false, "leftAuto": true, "leftManual": false } * standardMeasurementsToRun: Hash table used by measureSCase() where keys correspond to the standard measurement steps of measureSCase() and values are booleans allowing the steps to be run. For example: "standardMeasurementsToRun":{ "loadData":true, "morphology":true, "measureFirst":true, "measureSecond":false } These standard measurements are built in a way that the next measurement needs the results of the former measurement, e.g "morphology" needs to be run after "loadData". The successive standard measurements are "loadData", "morphology", "measureFirst", "measureSecond". * specialMeasurementsToRun: Hash table used by measureSCase() where keys correspond to specific SCase functions and values are booleans allowing these functions to be called. For example: "specialMeasurementsToRun":{ "sliceAndSegment":true, "calcDensity":false } All the special measurements are called after the execution of the standard measurements. The special measurements SCase functions are recursively called in a Shoulder object and all the objects within. * specialMeasurementsArguments: Hash table used by measureSCase() where keys correspond to the specific SCase functions listed in "specialMeasurementsToRun" and values are arrays of arguments to give to the functions for their execution. For example: "specialMeasurementsArguments":{ "sliceAndSegment":[], "calcDensity":[] } * numberOfMuscleSubdivisions: Hash table used by measureSCase() where keys correspond to the muscle divisions dimensions and values are the number of these divisions. For example: "numberOfMuscleSubdivisions":{ "radial": 10, "angular": 10 } * overwriteMeasurements: Boolean that will tell measureSCase() to create an empty SCase (true) or to load an existing SCase (false) before measuring it. * saveMeasurements: Boolean used by measureSCase() to save or not each individual SCase.mat after measurements. * saveAllMeasurementsInOneFile: Boolean used by measureSCase() to save all the SCase.mat loaded from the whole database into one file in dataDir/matlab/SCaseDB.mat. This won't take into account the last measurements if "saveMeasurements" is false. ## How to use There are five main features within this system. Be sure to add this system's folders and subfolders to your MATLAB path. #### Access data Data are restricted to authorised users, in a dedicated EPFL server. The data related to a specific case can be accessed thanks to the ShoulderCaseLoader class. For example: database = ShoulderCaseLoader(); SCase = database.loadCase('P527'); Will load the data related to the case 'P527' into the variable SCase. The function loadSCase() will do the same even more directly: SCase = loadSCase('P527'); The ShoulderCaseLoader class features several other methods to access the data. To get the list of all the available cases run: database = ShoulderCaseLoader(); SCaseList = database.getAllCasesIDs(); To load all the available cases in an cell array run: database = ShoulderCaseLoader(); AllTheSCases = database.loadAllCases(); #### Visualize data All the measured data are directly available in a loaded ShoulderCase's properties. To observe and interact with a cases's data run: database = ShoulderCaseLoader(); SCase = database.loadCase('P527'); SCase.plot(); or plotSCase('P527'); #### Update data To update the measured values of the shoulder cases use the function measureSCase(). Refer to the function's documentation for further informations. #### Import new data To import new cases (basically add a CT-files folder at the right place) use the importSCase GUI. The importSCase code is located in the sub-directory importSCase. Its description is detailed there. It currently only work for Windows. #### Export data For a loaded SCase, you can have all of the measurements by calling getTableOfData method of ShoulderCase.m as: SCase.getTableOfData(); The result will be a table with all of the information and measurements for the SCase. Also you can have all of the information and measurements for all of the SCases by calling exportSCaseData function as: exportSCaseData("SCaseList", "*", "saveInFile", filename); The filename is your specified csv or excel file where all the measurements will be exported. Refer to the function docstring for more details. +The summary of every exported variable definition is given below. +WARNING: The following variables descriptions apply for v2.0.0 of present code. + +id: ShoulderCase.id is the id of the shoulder case as it appears in the database [NP][0-9]{1,3} +diagnosis: ShoulderCase.diagnosis is the given diagnosis (found in REDCap export) +treatment: ShoulderCase.treatment is the given treatment +data_ct_path: ShoulderCase.dataCTPath is the path to the folder containing the dicom folder and other data related to the case (Amira/3DSlicer segmentations, rotator cuff segmentations, matlab measurements,...) +patient_id: Patient.id is the id in the anonymised database (id DUPLICATE) +patient_id_med: Patient.idMed is the id of the medical center DEADVAR +patient_gender: Patient.gender is the patient's gender found in dicom metadata +patient_age: Patient.age is the patient's age at time of preoperative CT scan found in dicom metadata +patient_ethnicity: Patient.ethnicity is a medical metadata DEADVAR +patient_weight: Patient.weight is the patient's height found in dicom metadata +patient_height: Patient.height is the patient's weight found in dicom metadata +patient_BMI: Patient.BMI is the patient's Body Mass Index computed with dicom metadata (BMI = weight / height^2) +patient_comment = Patient.comment DEADVAR ## Documentation Should be added here: * datastructure design * class diagram ## Files/Folders ### Folders - **./anatomy** contains scripts used by Amira manual measurements and what looks like deprecated scripts that are now part of the Scapula class. - **./ShoulderCase** contains the class and scripts used to update and access to the data. See here [how are organized class files and folders](https://ch.mathworks.com/help/matlab/matlab_oop/class-files-and-folders.html). - **./ImportSCase** contains the GUI used to import new data into the database. - **./Generated_Amira_TCL_Scripts** used to store TCL scripts. Not tracked by git. - **./log** contains log files. - **./XLS_MySQL_DB** contains scripts used to read data in .xls files and write in SQL database. - **./upsert** contains a script to update and insert data in a database. Looks like it's an external not LBO-made feature. ### Files - *config.json* is mandatory. - *csv2xlxSCase.m* Matlab script to transform CSV files into XLS files - *dicominfoSCase.m* Matlab script used after new SCase importations. Check utility in ImportSCase SOP - *listSCase.m* Matlab script that create a list of SCases. Deprecated, should be replaced by ShoulderCaseLoader methods everywhere. - *loadDicomCTscan* Looks like a worksheet. Probably removable. - *measureSCase.m* Matlab Script used to update data. (check SOP for more details) - *openConfigFile.m* Deprecated, should be replaced by the ConfigFileExtractor methods everywhere. - *openLogFile.m* Deprecated, should be replaced by the Logger methods everywhere. - *plotSCase.m* Deprecated, should be replaced by ShoulderCase.plot() method everywhere. - *statSCase.m* Statistical analysis on all the cases. Probably deprecated. ## Version Current version is 1.0.5 ## Contributors * Alexandre Terrier, 2012-now * Julien Ston, 2012-2014 * Antoine Dewarrat, 2014-2015 * Raphael Obrist, 2015-2017 * Killian Cosendey, 2017 * Valérie Malfroy Camine, 2017 * Jorge Solana-Muñoz, 2018-2019 * Bharath Narayanan, 2018 * Paul Cimadomo, 2018 * Lore Hoffmann, 2019 * Nathan Donini, 2019 * Benoit Delecourt, 2019 * Amirsiavosh Bashardoust, 2020 * Matthieu Boubat, 2019-now * Pezhman Eghbalishamsabadi, 2021-now ## License EPFL CC BY-NC-SA 4.0 Int.