Closed chenkenkone closed 1 year ago
It looks like you are on the right track. As mentioned in the thread you linked, the generate.js example creates just a dummy file with nonsense data (an image with the value 100 at every pixel using the fill(100)
command. Instead you need to put the real jpg image you read using the library into the PixelData
element. Also you. need to adjust the other header tags to match, like you did with the Rows
and Columns
. My suggestion from #85 is still what I would suggest: generate a valid Secondary Capture image using another tool and use it as the template for creating a new dicom dataset in dcmjs with your header values and pixel data. Please post if you come up with a complete solution or better yet add a pull request with working code in the form of a software test.
I am able to generate DICOM file from Jpeg image using below code:
` import dcmjs from 'dcmjs'; // eslint-disable-next-line @typescript-eslint/no-var-requires const jpeg = require('jpeg-js');
async createDicomFromImageAndAddToZip(zipUpdated: any, fileData: any, caseData: CaseData): Promise<void> {
logger.info('update patient details, Uuids and image pixel data of Dicom generated from X-Ray image');
// Get dicom template data
const dataset = JSON.parse(CommonConstants.DICOM_META_TEMPLATE);
// Get json data as dcmjs dicom dictionary
const dicomDict = dcmjs.data.datasetToDict(dataset);
// Get jpeg image pixels
const rawImageData = jpeg.decode(fileData, { formatAsRGBA: false });
// 1. Set Pixel data with var type Other Bytes
dicomDict.dict['7FE00010'] = {
vr: 'OB',
Value: [rawImageData.data.buffer]
}
// Parse the byte array to get a DataSet object that has the parsed contents
const parsedDataSet = dcmjs.data.DicomMetaDictionary.naturalizeDataset(dicomDict.dict);
// 2. Set image data rows and columns
parsedDataSet.Columns = rawImageData.width;
parsedDataSet.Rows = rawImageData.height;
// 3. Alter StudyInstanceUID
const oldStudyInstanceUID = parsedDataSet.StudyInstanceUID;
const oldStudyInstanceUIDArray = oldStudyInstanceUID.split('.');
oldStudyInstanceUIDArray[oldStudyInstanceUIDArray.length - 1] = caseData.id.toString();
oldStudyInstanceUIDArray[oldStudyInstanceUIDArray.length - 2] = this.getRndInteger(1000, 10000)
const newStudyInstanceUID = oldStudyInstanceUIDArray.join('.');
parsedDataSet.StudyInstanceUID = newStudyInstanceUID;
// 4. Alter SeriesInstanceUID
const oldSeriesInstanceUID = parsedDataSet.SeriesInstanceUID;
const oldSeriesInstanceUIDArray = oldSeriesInstanceUID.split('.');
oldSeriesInstanceUIDArray[oldSeriesInstanceUIDArray.length - 1] = caseData.id.toString();
oldSeriesInstanceUIDArray[oldSeriesInstanceUIDArray.length - 2] = this.getRndInteger(10000, 100000)
const newSeriesInstanceUID = oldSeriesInstanceUIDArray.join('.');
parsedDataSet.SeriesInstanceUID = newSeriesInstanceUID;
// 5. Alter SOPInstanceUID
const oldInstanceUID = parsedDataSet.SOPInstanceUID;
const oldInstanceUIDArray = oldInstanceUID.split('.');
oldInstanceUIDArray[oldInstanceUIDArray.length - 1] = caseData.id.toString();
oldInstanceUIDArray[oldInstanceUIDArray.length - 2] = this.getRndInteger(100000, 1000000)
const newInstanceUID = oldInstanceUIDArray.join('.');
parsedDataSet.SOPInstanceUID = newInstanceUID;
// 6. Update Patient Details
// Patient ID
parsedDataSet.PatientID = caseData.patient.mrNumber ? `${caseData.patient.mrNumber}` : `${caseData.patient.id}`;
// Patient Name
parsedDataSet.PatientName = `${caseData.patient.firstName} ${caseData.patient.lastName}`;
// Patient Gender
parsedDataSet.PatientSex = caseData.patient.gender == 'male' ? 'M' : (caseData.patient.gender == 'female' ? 'F' : 'O');
// Patient DoB
parsedDataSet.PatientBirthDate = utils.getDateAsDicomMetaDate(caseData.patient.dob as any);
// Patient Age
parsedDataSet.PatientAge = this.calculateAge(new Date(caseData.patient.dob));
// Set updated content back to dicom dict
dicomDict.dict = dcmjs.data.DicomMetaDictionary.denaturalizeDataset(parsedDataSet);
const updatedDicomArrayBuffer = dicomDict.write();
const updatedDicomBuffer = Buffer.from(updatedDicomArrayBuffer);
// add altered dicom to zip
zipUpdated.addFile('image-' + this.getRndInteger(100, 10000), updatedDicomBuffer);
}
`
static readonly DICOM_META_TEMPLATE = { "AccessionNumber": "", "AcquisitionMatrix": [ 256, 0, 0, 192 ], "AcquisitionNumber": "8", "BitsAllocated": "8", "BitsStored": "8", "Columns": "256", "ContentDate": "20020628", "ContentTime": "164936.0", "ContrastBolusAgent": "", "DeviceSerialNumber": "4168496325", "EchoTime": "6", "EchoTrainLength": "1", "FlipAngle": "3", "FrameOfReferenceUID": "2.16.840.1.113662.4.4168496325.1025305873.7118351817185979330", "HighBit": "7", "ImageComments": "Picture of X-ray", "ImageOrientationPatient": [ "0.00000e+00", "1.00000e+00", "-0.00000e+00", "-0.00000e+00", "0.00000e+00", "-1.00000e+00" ], "ImagePositionPatient": [ "6.454490e+01", "-1.339286e+02", "1.167857e+02" ], "ImageType": [ "ORIGINAL", "PRIMARY", "OTHER" ], "ImagesInAcquisition": "1", "ImagingFrequency": "6.37165e+01", "InstanceNumber": "1", "InstitutionName": "MyOrganization", "LossyImageCompression": "00", "MRAcquisitionType": "", "MagneticFieldStrength": "1.5", "Manufacturer": "MyOrganization", "ManufacturerModelName": "MyOrganization 1.5T", "Modality": "DX", "NumberOfAverages": "1", "NumberOfFrames": "1", "NumberOfTemporalPositions": "1", "OperatorsName": "NA", "PatientAge": "023Y", "PatientBirthDate": "20000101", "PatientID": "0000000", "PatientName": "NA", "PatientPosition": "HFS", "PatientSex": "O", "PatientWeight": "99.773300", "PercentPhaseFieldOfView": "91.4062", "PhotometricInterpretation": "RGB", "PixelRepresentation": 0, "PixelSpacing": [ "0.1171875", "0.1171875" ], "PlanarConfiguration": "0", "PositionReferenceIndicator": "BRAIN", "ProtocolName": "SAG/RF-FAST/VOL/FLIP 3", "ReceiveCoilName": "HEAD", "ReferencedImageSequence": { "ReferencedSOPClassUID": "1.2.840.10008.5.1.4.1.1.4", "ReferencedSOPInstanceUID": "2.16.840.1.113662.4.4168496325.1025306066.995213515550827262", "_vrMap": {} }, "ReferringPhysicianName": "", "RepetitionTime": "20", "Rows": 256, "SOPClassUID": "1.2.840.10008.5.1.4.1.1.4", "SOPInstanceUID": "2.16.840.1.113662.4.4168496325.1025307679.1207625440068523197", "SamplesPerPixel": 3, "ScanOptions": "", "ScanningSequence": "GR", "SequenceVariant": [ "SS", "SP" ], "SeriesDate": "20020628", "SeriesDescription": "L Spine", "SeriesInstanceUID": "2.16.840.1.113662.4.4168496325.1025307678.3494705239865384161", "SeriesNumber": "1", "SeriesTime": "164118.0", "SliceLocation": "64.544899", "SliceThickness": "1.300000e+00", "SoftwareVersions": "VIA2.0E.003", "SpecificCharacterSet": "ISO_IR 100", "StationName": "ba187_ws", "StudyDate": "20230101", "StudyDescription": "SPINE", "StudyID": "14024", "StudyInstanceUID": "2.16.840.1.113662.4.4168496325.1025305873.7118351817185979330", "StudyTime": "160956.0", "TemporalPositionIdentifier": "1", "TemporalResolution": "458660", "_meta": { "FileMetaInformationVersion": { "Value": [ { "0": 0, "1": 1 } ], "vr": "OB" }, "ImplementationClassUID": { "Value": [ "1.2.840.113819.7.1.1997.1.0" ], "vr": "UI" }, "ImplementationVersionName": { "Value": [ "SENSORSYSTEMS1.0" ], "vr": "SH" }, "MediaStorageSOPClassUID": { "Value": [ "1.2.840.10008.5.1.4.1.1.4" ], "vr": "UI" }, "MediaStorageSOPInstanceUID": { "Value": [ "2.16.840.1.113662.4.4168496325.1025307679.1207625440068523197" ], "vr": "UI" }, "TransferSyntaxUID": { "Value": [ "1.2.840.10008.1.2" ], "vr": "UI" } }, "_vrMap": { "PixelData": "OB" } };
Excellent - thanks for sharing it. If you have a chance, it would be great if you could convert this into a test so that others can easily discover and learn from it, and so we can confirm that this keeps working in future versions.
Sure Steve @pieper, I'll do it.
Looks like there is an issue when setting dataset.PixelData
using Tag name. The var type is not set correctly.
As a workaround I used
dicomDict.dict['7FE00010'] = { vr: 'OB', Value: [rawImageData.data.buffer] }
to set PixelData
Sure Steve @pieper, I'll do it.
That's great 👍
Looks like there is an issue when setting
dataset.PixelData
using Tag name. The var type is not set correctly.
If you think that's an error in the way PixelData is handled generally maybe it's fixable. I don't think generating datasets from scratch like this has gotten a lot of testing compared to read or read/modify/write.
Having problem in converting .jpg to .dcm. I've read about Convert jpeg file ( .jpeg ) to dicom file ( .dcm ) #85 and try it out. However there are few things I can't solve.
Q1: For the first one, I can't figure it out how this generate.js convert .jpg file to .dcm file? Isn't it just create a object and make it as the configuration dataset? And the store in buffer? There is no source or output file directory infomation in metioned article or code, that's why I got confused.
Q2: So, I tried this(most simply compy from the generate.js, I need to successfully create dicom file first and then to match my business logics later), the concept is concat the Dataset()Buffer and Image(.jpg)Buffer together to create a file, not sure is it a right way.
I can create a .dcm file successfully. But using ezDICOM open the .dcm I got
LoadData: Error reading image.
, using DICOM_Parser_Rubo I gotNo DICOM Header detected
. So I tried to find something for this issue, I found this #315 https://github.com/dcmjs-org/dcmjs/blob/914b3dccd1a9e9fd19f2ac94be6e02a82a6316ec/src/DicomDict.js#L20-L24 So dcmjs will add the header. But I don't understand why I got NO DICOM HEADER detected. And did the "Preamble" exist in the header already too?Q3: I got this notice. However, when I altered it to
const dcmjs = require("dcmjs/build/dcmjs");
the notice was gone. I don't know which would be correct.Q4: Why use Int16Array? and Why .fill(100)
Thank you for reply.