Closed marcheschi closed 5 years ago
Hi, So, we've had the same issue in my company, in order to resolve this we make a little node.js server which is responsible in get a vector of dcms files and return the formated JSON. We put it in a server because it is used by more than one application, so we keep everything separate. I'll put the code of the parser, feel free to copy and modify. We used the parseDicom from cornerstone to get the data from the dcm files. After this function, we sort the series and instances.
function parseAndInsertFile(content, url, finalJSON) {
return new Promise(function(resolve, reject){
var dataSet;
//mount the JSON
dataSet = ctrlParser.parseDicom(content);
var fileJSON = {};
fileJSON['transactionId'] = 'img';
fileJSON['fileDate'] = dataSet.string('x00080012');
fileJSON['fileTime'] = dataSet.string('x00080013');
fileJSON['studies'] = [];
var study = {};
study['studyInstanceUid'] = dataSet.string('x0020000d');
study['studyDescription'] = dataSet.string('x00081030');
study['studyDate'] = dataSet.string('x00080020');
study['studyTime'] = dataSet.string('x00080030');
var patient = {}
patient['patientName'] = dataSet.string('x00100010');
var age = dataSet.string('x00101010');
var units = ((age.slice(-1) == 'Y')? 'Anos': (age.slice(-1) == 'M')?'Meses':'Dias');
patient['patientAge'] = age.slice(0,3) + ' ' + units;
patient['patientAllergies'] = dataSet.string('x00102110')
patient['patientBirthDate'] = dataSet.string('x00100030');
patient['patientId'] = dataSet.string('x00100020');
patient['patientSex'] = dataSet.string('x00100040');
study['patient'] = patient;
var equipament = {};
equipament['manufacturer'] = dataSet.string('x00080070');
equipament['model'] = dataSet.string('x00081090');
equipament['stationName'] = dataSet.string('x00081010');
equipament['AETitle'] = dataSet.string('x00020016');
equipament['institutionName'] = dataSet.string('x00080080');
equipament['softwareVersion'] = dataSet.string('x00181020');
equipament['implementationVersionName'] = dataSet.string('x00020013');
study['equipament'] = equipament;
var physician = {}
physician['name'] = dataSet.string('x00080090');
physician['identification'] = dataSet.string('x00080092');
study['physician'] = physician
study['seriesList'] = [];
var serie = {};
serie['seriesDescription'] = dataSet.string('x0008103e');
serie['seriesInstanceUid'] = dataSet.string('x0020000e');
serie['seriesBodyPart'] = dataSet.string('x00180015');
serie['seriesNumber'] = dataSet.string('x00200011');
serie['seriesDate'] = dataSet.string('x00080021');
serie['seriesTime'] = dataSet.string('x00080031');
serie['seriesModality'] = dataSet.string('x00080060');
serie['instances'] = [];
var instance = {};
instance['columns'] = dataSet.uint16('x00280011');
instance['rows'] = dataSet.uint16('x00280010');
instance['instanceNumber'] = (dataSet.string('x00200013'));
instance['acquisitionNumber'] = dataSet.string('x00200012');
instance['photometricInterpretation'] = dataSet.string('x00280004');
instance['bitAllocated'] = dataSet.uint16('x00280100');
instance['bitsStored'] = dataSet.uint16('x00280101');
instance['pixelRepresentation'] = dataSet.uint16('x00280103');
instance['samplesPerPixel'] = dataSet.uint16('x00280002');
instance['pixelSpacing'] = dataSet.string('x00280030');
instance['highBit'] = dataSet.uint16('x00280102');
instance['rescaleSlope'] = dataSet.string('x00281053');
instance['rescaleIntercept'] = dataSet.string('x00281052');
instance['imageOrientationPatient'] = dataSet.string('x00200037');
instance['imagePositionPatient'] = dataSet.string('x00200032');
instance['imageType'] = dataSet.string('x00080008');
instance['sopInstanceUid'] = dataSet.string('x00080018');
url = url.replace('http', 'wadouri')
instance['url'] = url;
serie['instances'].push(instance);
study['seriesList'].push(serie);
fileJSON['studies'].push(study);
//console.log(dataSetJSON);
//Insert
if(isEmpty(finalJSON)){
//primeiro arquivo
finalJSON = fileJSON;
finalJSON['transactionId'] = finalJSON.studies[0].studyDescription;
} else {
//já foi inserido um estudo
var isValid = validateFile(fileJSON, finalJSON);
if (isValid){
//Insere o DICOM na sua respectiva serie
var fileStudy = fileJSON.studies[0];
var fileSerie = fileJSON.studies[0].seriesList[0];
var fileInstance = fileSerie.instances[0];
var studyIndex = finalJSON.studies.findIndex(function(study, i){
return study.studyInstanceUid === fileStudy.studyInstanceUid;
})
if (studyIndex >=0){
//estudo já existe
var serieIndex = finalJSON.studies[studyIndex].seriesList.findIndex(function(serie, i){
return serie.seriesInstanceUid === fileSerie.seriesInstanceUid;
});
if (serieIndex >= 0 ){
//já há instancias desta serie inclusas, incluindo mais uma
finalJSON.studies[studyIndex].seriesList[serieIndex].instances.push(fileInstance);
}else{
//primeira instancia desta serie
finalJSON.studies[studyIndex].seriesList.push(fileSerie);
}
} else {
finalJSON.studies.push(fileStudy);
}
}
}
resolve(finalJSON);
});
};
Hi This is a very interesting approach. I'll try to implement something like this . Thank you for the code Paolo
Hi guys,
The JSON approach was initially an experiment when the standalone viewer was created. I honestly didn't expect so many people to start using it. I think we want to move towards something more standard for launching the viewer, like the DICOM JSON response to WADO-RS RetrieveMetadata for example.
For example, if you run this (sorry @pieper for using your server):
curl -H 'Accept: application/json' quantome.org:8080/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.3.12.2.14.19.81.4.1402019790780585883468456314383507/metadata | python -m json.tool
(remove the | python stuff if you don't want it pretty-printed)
you will get the DICOM JSON example.
We might also consider supporting the "Normalized DICOM JSON" approach as well, since it's a bit less verbose than typical DICOM JSON. @pieper - I can't seem to find the live example for that, so if you have it feel free to post it.
Some open questions (up for discussion):
How do we make this transition? Just add another query string param? (?url = old format, ?dicomUrl= DICOM JSON format, nddUrl = Normalized DICOM format?)
Do we want to make the standalone viewer accept a DICOMWeb server URL instead (?server = quantome.org:8080&studyInstanceUids=XYZ,ABC,DEF)?
How do we suggest users handle authentication?
The best option would be that we would look in the users localstorage/cookies for an existing token (e.g. from Keycloak) and use that when making all requests. For cases where no token is already present, it could be passed in the query parameters. The standalone viewer has no logic to do token refreshing, though. This might be fine temporarily, but it will be an issue if users need to save results.
@swederik no problem using the quantome.org server for demos (of course there's no uptime assurance for it!).
To get an idea of "NDD" format see here: https://github.com/pieper/dcmjs/wiki/NDD-Format
To try it on your data, you can drag and drop dicom files to this example page:
https://pieper.github.io/dcmjs/examples/display/index.html
(There's also a button to download sample data from a public server but if you click it be patient since it takes a minute or so to download).
By the way, it's been on my TODO list for a while to provide some node-based command line tools as part of the DCMJS npm package but I haven't had a chance to work on it. PRs welcome 😄
For what it's worth, here's another script to make the JSON files, courtesy of the SAKE Viewer team:
https://github.com/capstone-mgh/SAKE/blob/master/parsemetadata.py#L1
Very interesting Thank you Paolo
And here's another one, which just adds the file stuff on top of @MuriloSchaefer's script: https://gist.github.com/swederik/b7901bd933e6497720783e532616eec0
Hi! I'm trying to run this script (https://gist.github.com/swederik/b7901bd933e6497720783e532616eec0) to generate the JSON file from my DICOM file but when trying to use it from the Standalone Viewer the following error is prompt in my browser:
Error: loadImageFromImageLoader: no image loader for imageId at loadImageFromImageLoader (ohif_cornerstone.js?hash=b2d4f3d201840adb2975e3fbc1f00e4786b64831:6133) at Module.loadAndCacheImage (ohif_cornerstone.js?hash=b2d4f3d201840adb2975e3fbc1f00e4786b64831:6199)
This is the JSON that I was able to generate from my DCM file using the above JS script { "transactionId": "study", "studies": [ { "studyInstanceUid": "1.2.826.0.1.3680043.2.1208.154494870514920191158835635", "studyDate": "20180817", "studyTime": "080835.000000", "patientName": "PERES PEPE", "patientBirthDate": "20050226", "patientId": "NO ID", "patientSex": "F", "seriesList": [ { "seriesInstanceUid": "1.2.826.0.1.3680043.2.1208.254494870514920191158835642", "seriesBodyPart": "SPINE LUMBAR", "seriesNumber": "0001", "seriesDate": "20180817", "seriesTime": "080835.000000", "seriesModality": "OT", "instances": [ { "columns": 3610, "rows": 4400, "instanceNumber": "0001", "photometricInterpretation": "MONOCHROME2", "bitAllocated": 16, "bitsStored": 12, "pixelRepresentation": 0, "samplesPerPixel": 1, "highBit": 11, "rescaleSlope": "1.00", "rescaleIntercept": "0.00", "imageType": "ORIGINAL\PRIMARY\OTHER", "sopInstanceUid": "1.2.826.0.1.3680043.2.1208.354494870514920191158835644", "url": "file://Users/johannamussolini/code/Viewers/StandaloneViewer/StandaloneViewer/private/testData/examples/1.2.826.0.1.3680043.2.1208.154494870514920191158835635/1.2.826.0.1.3680043.2.1208.254494870514920191158835642/1.2.826.0.1.3680043.2.1208.354494870514920191158835644.dcm" } ] } ] } ] }
Is there any problem with the DICOM image file? Is it not supported? How can I know the ImageId? Any help would be really appreciated! thanks!
the protocol that you used in your url is 'file', try to use the 'dicomweb' protocol. So the file url would be something like: 'dicomweb://Users/johannamussolini/code...'
that's because my file is located locally and I'm running the Standalone viewer locally... do you think that's the issue? should I've to upload my images in the web so I can generate the JSON with an URL?
you can start a local server and then you can call the url like: "dicomweb:/localhost/folder1...".
I used the npm library called http-server. So to start a server is like:
http-server . -p 5000 --cors
this way you start a server in some folder using the port 5000
this issue is related to the protocol that you're using.
oh ok, so I did that, started the server and updated the url parameter in my JSON file: "url": "dicomweb:/localhost:5000/1.2.826.0.1.3680043.2.1208.354494870514920191158835644.dcm" , but now the error is: "An error occurred when loading image: dicomweb:/localhost:5000/1.2.826.0.1.3680043.2.1208.354494870514920191158835644.dcm Details: [object: Object]"
So, I'm not sure, maybe the JSON was wrongly generated and for some reason the StandaloneViewer cannot display it?
Thanks again!
can you find out what these details are?
I've just figured out...It was a cosmetic issue in the url you sent me above,... my bad sorry: the correct url has double / like this, and now the file was loaded:
dicomweb://localhost:5000/1.2.826.0.1.3680043.2.1208.354494870514920191158835644.dcm
worked great! thanks so much for your help!
Just another concern... My DICOM files are generated under a folder which have this structure: 1.2.826.0.1.3680043.2.1208.1544948705149201921111140813 (root folder) -> 1.2.826.0.1.3680043.2.1208.25449487051492019211111426 --> 1.2.826.0.1.3680043.2.1208.35449487051492019211111427.dcm -> 1.2.826.0.1.3680043.2.1208.25449487051492019211111435 --> 1.2.826.0.1.3680043.2.1208.35449487051492019211111435.dcm and so on.... several others folders inside
When I was trying to use the script (https://gist.github.com/swederik/b7901bd933e6497720783e532616eec0) it seems that only takes DCM files under only one folder (maybe I did something wrong)... so I cannot get this script to generate the JSON correctly ...Anyway... what I tried to do is to put all DCM files under the root folder and ran the script to see how the JSON would be generated... however it generated only one serie per file and the frames are not displayed... so I'm not sure what I'm doing wrong.
Again, any guidance would be really appreciated. Thanks!
@MuriloSchaefer: disregard,.. I was able to do it by using this:
const readdir = require('readdir-enhanced');
instead of fs.readdir and changing some code by:
readdir(testFolder, {filter: myFilter, deep: true, basePath: absPath}, function(err, files){ ... script code here with some changes } function myFilter(stats) { return stats.isFile() && (stats.path.replace(/^.*?.([a-zA-Z0-9]+)$/, "$1") === 'dcm'); }
by doing this I just get all .dcm files (which are under 'testFolder' and its subfolders recursively and I can just parse those files only).
Thanks for your help!
We're getting ready to formally announce version 2 of the OHIF Viewer. After the announcement, version 1 issues will receive lower priority support. As this issue is a bit stale, I'm going to close it for now.
Hi, So, we've had the same issue in my company, in order to resolve this we make a little node.js server which is responsible in get a vector of dcms files and return the formated JSON. We put it in a server because it is used by more than one application, so we keep everything separate. I'll put the code of the parser, feel free to copy and modify. We used the parseDicom from cornerstone to get the data from the dcm files. After this function, we sort the series and instances.
function parseAndInsertFile(content, url, finalJSON) { return new Promise(function(resolve, reject){ var dataSet; //mount the JSON dataSet = ctrlParser.parseDicom(content); var fileJSON = {}; fileJSON['transactionId'] = 'img'; fileJSON['fileDate'] = dataSet.string('x00080012'); fileJSON['fileTime'] = dataSet.string('x00080013'); fileJSON['studies'] = []; var study = {}; study['studyInstanceUid'] = dataSet.string('x0020000d'); study['studyDescription'] = dataSet.string('x00081030'); study['studyDate'] = dataSet.string('x00080020'); study['studyTime'] = dataSet.string('x00080030'); var patient = {} patient['patientName'] = dataSet.string('x00100010'); var age = dataSet.string('x00101010'); var units = ((age.slice(-1) == 'Y')? 'Anos': (age.slice(-1) == 'M')?'Meses':'Dias'); patient['patientAge'] = age.slice(0,3) + ' ' + units; patient['patientAllergies'] = dataSet.string('x00102110') patient['patientBirthDate'] = dataSet.string('x00100030'); patient['patientId'] = dataSet.string('x00100020'); patient['patientSex'] = dataSet.string('x00100040'); study['patient'] = patient; var equipament = {}; equipament['manufacturer'] = dataSet.string('x00080070'); equipament['model'] = dataSet.string('x00081090'); equipament['stationName'] = dataSet.string('x00081010'); equipament['AETitle'] = dataSet.string('x00020016'); equipament['institutionName'] = dataSet.string('x00080080'); equipament['softwareVersion'] = dataSet.string('x00181020'); equipament['implementationVersionName'] = dataSet.string('x00020013'); study['equipament'] = equipament; var physician = {} physician['name'] = dataSet.string('x00080090'); physician['identification'] = dataSet.string('x00080092'); study['physician'] = physician study['seriesList'] = []; var serie = {}; serie['seriesDescription'] = dataSet.string('x0008103e'); serie['seriesInstanceUid'] = dataSet.string('x0020000e'); serie['seriesBodyPart'] = dataSet.string('x00180015'); serie['seriesNumber'] = dataSet.string('x00200011'); serie['seriesDate'] = dataSet.string('x00080021'); serie['seriesTime'] = dataSet.string('x00080031'); serie['seriesModality'] = dataSet.string('x00080060'); serie['instances'] = []; var instance = {}; instance['columns'] = dataSet.uint16('x00280011'); instance['rows'] = dataSet.uint16('x00280010'); instance['instanceNumber'] = (dataSet.string('x00200013')); instance['acquisitionNumber'] = dataSet.string('x00200012'); instance['photometricInterpretation'] = dataSet.string('x00280004'); instance['bitAllocated'] = dataSet.uint16('x00280100'); instance['bitsStored'] = dataSet.uint16('x00280101'); instance['pixelRepresentation'] = dataSet.uint16('x00280103'); instance['samplesPerPixel'] = dataSet.uint16('x00280002'); instance['pixelSpacing'] = dataSet.string('x00280030'); instance['highBit'] = dataSet.uint16('x00280102'); instance['rescaleSlope'] = dataSet.string('x00281053'); instance['rescaleIntercept'] = dataSet.string('x00281052'); instance['imageOrientationPatient'] = dataSet.string('x00200037'); instance['imagePositionPatient'] = dataSet.string('x00200032'); instance['imageType'] = dataSet.string('x00080008'); instance['sopInstanceUid'] = dataSet.string('x00080018'); url = url.replace('http', 'wadouri') instance['url'] = url; serie['instances'].push(instance); study['seriesList'].push(serie); fileJSON['studies'].push(study); //console.log(dataSetJSON); //Insert if(isEmpty(finalJSON)){ //primeiro arquivo finalJSON = fileJSON; finalJSON['transactionId'] = finalJSON.studies[0].studyDescription; } else { //já foi inserido um estudo var isValid = validateFile(fileJSON, finalJSON); if (isValid){ //Insere o DICOM na sua respectiva serie var fileStudy = fileJSON.studies[0]; var fileSerie = fileJSON.studies[0].seriesList[0]; var fileInstance = fileSerie.instances[0]; var studyIndex = finalJSON.studies.findIndex(function(study, i){ return study.studyInstanceUid === fileStudy.studyInstanceUid; }) if (studyIndex >=0){ //estudo já existe var serieIndex = finalJSON.studies[studyIndex].seriesList.findIndex(function(serie, i){ return serie.seriesInstanceUid === fileSerie.seriesInstanceUid; }); if (serieIndex >= 0 ){ //já há instancias desta serie inclusas, incluindo mais uma finalJSON.studies[studyIndex].seriesList[serieIndex].instances.push(fileInstance); }else{ //primeira instancia desta serie finalJSON.studies[studyIndex].seriesList.push(fileSerie); } } else { finalJSON.studies.push(fileStudy); } } } resolve(finalJSON); }); };
cloud you share me your full html/js files, thank you very much! 2684717679@qq.com
Dear OHIF Viewer team,
I am currently using the OHIF Viewer in my web application and I am experiencing an issue with playing all frames of a DICOM file when loading studies through my ASP.NET Core API using JSON. While this functionality works fine in local mode, it seems to be malfunctioning when the studies are loaded via my API.
I have followed the official documentation of OHIF Viewer closely and cannot seem to identify the missing segment causing the issue.
I would greatly appreciate your guidance in resolving this matter. Could you please advise me on what I may be missing or what steps I can take to troubleshoot this issue?
Thank you for your assistance.
We recently added several recipes for implementing authentication with Keycloak in OHIF. You can find them here:
这是来自QQ邮箱的假期自动回复邮件。 您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
Hi do you have a script in order to create such json files , for example from a dicom query to the pacs ? In order to create a package for a single real world study? I mean something createStudyJson.sh aet[@host[:port]] -Accnum="MystudyAccnumb" -o Mystudy.json
Thank you Paolo