Exemplo n.º 1
0
    def determineScannerID(self, cs):
        """
        Tries to identify machine model, used filter, and energy presentation
        """
        dicomfields = [
            ["0008,1090", "ModelName"],
            ["0018,7050", "FilterMaterialLT"],
            ["0019,10C1",
             "MICRODOSE IMAGE CONTENT"]  #---: SUM FOR PRESENTATION
        ]

        # 1. Try to id Scanner
        cs.scannername = lit.stUnknown
        dicomvalue = wadwrapper_lib.readDICOMtag(
            dicomfields[0][0], cs.dcmInfile)  # Manufacturer's Model Name
        dicomvalue = str(dicomvalue).lower()
        if dicomvalue.find("l50") > -1:
            cs.scannername = lit.stL50
        elif dicomvalue.find("lorad selenia") > -1:
            cs.guessScanner = lit.stSelenia
        elif dicomvalue.find("dimensions") > -1:
            cs.guessScanner = lit.stDimensions

        # 2. Try to id Filter
        cs.filtername = wadwrapper_lib.readDICOMtag(dicomfields[1][0],
                                                    cs.dcmInfile)  # Filtername

        # 3. Try to id EnergyPresentation
        cs.energypresentation = wadwrapper_lib.readDICOMtag(
            dicomfields[2][0], cs.dcmInfile)
Exemplo n.º 2
0
    def determineScannerID(self,cs):
        """
        Tries to identify machine model, used filter, and energy presentation
        """
        dicomfields = [
            ["0008,1090",  "ModelName"],
            ["0018,7050",  "FilterMaterialLT"],
            ["0019,10C1",  "MICRODOSE IMAGE CONTENT"] #---: SUM FOR PRESENTATION
        ]


        # 1. Try to id Scanner
        cs.scannername = lit.stUnknown
        dicomvalue = wadwrapper_lib.readDICOMtag(dicomfields[0][0],cs.dcmInfile) # Manufacturer's Model Name
        dicomvalue = str(dicomvalue).lower()
        if dicomvalue.find("l50")>-1:
            cs.scannername = lit.stL50
        elif dicomvalue.find("lorad selenia")>-1:
            cs.guessScanner = lit.stSelenia
        elif dicomvalue.find("dimensions")>-1:
            cs.guessScanner = lit.stDimensions

        # 2. Try to id Filter
        cs.filtername = wadwrapper_lib.readDICOMtag(dicomfields[1][0],cs.dcmInfile) # Filtername

        # 3. Try to id EnergyPresentation
        cs.energypresentation = wadwrapper_lib.readDICOMtag(dicomfields[2][0],cs.dcmInfile)
Exemplo n.º 3
0
def DICOMInfo(cs, info='dicom', imslice=0):
    """
    Return some characteristic information from the dicom headers
    """
    if info == "dicom":
        dicomfields = [
            ["0010,0010", "Patients Name"],  # PIQT
            ["0018,1030", "Protocol Name"],  # QA1S:MS,SE
            ["0008,0021", "Series Date"],
            ["0008,0031",
             "Series Time"],  # no ScanTime 0008,0032 in EnhancedDicom
            ["0018,1250", "Receive Coil Name"],  # Q-Body
            ["0018,1251", "Transmit Coil Name"],  # B
            ["0018,0095", "Pixel Bandwidth"],  # 219
            ["0018,0020", "Scanning Sequence"],  # SE
            ["0018,0021", "Scanning Variant"],  # SS
            ["2005,1011", "Image_Type"],  # M
            ["0018,0081", "Echo Time"],  # 50
            ["0020,0012", "Acquisition Number"],  # 5
            ["0018,0086", "Echo Number(s)"],  # 1
            ["2001,1081", "Dyn_Scan_No"],  # ?1
            ["0020,0013", "Instance Number"],  # 1 slice no?
            ["2001,105f,2005,1079", "Dist_sel"],  # -16.32
            ["2001,1083", "Central_freq"],  # 63.895241 (MHz)
            ["0018,1020", "SoftwareVersions"],
        ]

    results = []
    for df in dicomfields:
        key = df[0]
        value = wadwrapper_lib.readDICOMtag(key, cs.dcmInfile, imslice)
        if key == "0018,1020" and len(value) > 1:
            value = '_'.join(value)
        results.append((df[1], value))

    return results
Exemplo n.º 4
0
    def DICOMInfo(self,cs,info='dicom'):
        """
        Extract some info from the DICOM header. <info> is either 'dicom' (extensive list) or 'qc' (short list).
        Returns list of <tag description>,<tag value>
        """
        # Different from ImageJ version; tags "0008","0104" and "0054","0220"
        #  appear to be part of sequences. This gives problems (cannot be found
        #  or returning whole sequence blocks)
        # Possibly this can be solved by using if(type(value) == type(dicom.sequence.Sequence()))
        #  but I don't see the relevance of these tags anymore, so set them to NO

        self.determineScannerID(cs)
        if(info == "dicom"):
            dicomfields = [ ["0008,0021",  "Series Date"],
                            ["0008,0031",  "Series Time"],
                            ["0008,0070",  "Manufacturer"],
                            ["0008,0080",  "InstitutionName"],
                            ["0008,1010",  "StationName"],
                            ["0008,1030",  "StudyDescription"],
                            ["0008,103E",  "SeriesDescription"],
                            ["0008,1070",  "Operator"],
                            ["0010,0020",  "PatientID"],
                            ["0018,0060",  "kVp"],
                            ["0018,1000",  "DeviceSerialNumber"],
                            ["0018,1020",  "SoftwareVersions"],
                            ["0018,1110",  "DistanceSourceToDetector"],
                            ["0018,1111",  "DistanceSourceToPatient"],
                            ["0018,1150",  "ExposureTime_(ms)"],
                            ["0018,1151",  "TubeCurrent_(mA)"],
                            ["0018,1153",  "muAs"],
                            ["0018,1164",  "ImagerPixelSpacing"],
                            ["0018,1166",  "Grid"],
                            ["0018,1190",  "FocalSpot"],
                            ["0018,1191",  "AnodeTargetMaterial"],
                            ["0018,11A0",  "BodyPartThickness"],
                            ["0018,11A2",  "CompressionForce"],
                            ["0018,1405",  "RelativeXRayExposure"],
                            ["0018,700A",  "DetectorID"],
                            ["0018,700C",  "DateOfLastDetectorCalibration"],
                            ["0018,7050",  "FilterMaterialLT"],
                            ["0019,1029",  "---"],
                            ["0028,0101",  "BitsStored"],
                            ["0028,1040",  "PixelensityRelationship"],
                            ["0028,1052",  "Rescaleercept"],
                            ["0028,1053",  "RescaleSlope"],
                            ["0028,1054",  "RescaleType"],
                            ["0040,0302",  "EntranceDose"],
                            ["0040,0314",  "HalfValueLayer_(mm)"],
                            ["0040,0316",  "OrganDose"],
                            ["0040,8302",  "EntranceDose_(mGy)"],
                            ["0000,0000",  "NOViewCodeSequence"],
                            ["0000,0000",  "NOViewCodeMeaning"]]
            if cs.scannername == lit.stL50:
                dicomfields[0] = ["0008,0022",  "Acquisition Date"]
                dicomfields[1] = ["0008,0030",  "Acquisition Time"]

        elif(info == "qc"):
            dicomfields = [["0008,0021",  "Series Date"],
                           ["0008,1010",  "StationName"],
                           ["0008,1070",  "Operator"],
                           ["0018,0060",  "kVp"],
                           ["0018,1020",  "SoftwareVersions"],
                           ["0018,1030",  "ProtocolName"],
                           ["0018,1110",  "DistanceSourceToDetector"],
                           ["0018,1111",  "DistanceSourceToPatient"],
                           ["0018,1153",  "muAs"],
                           ["0018,1166",  "Grid"],
                           ["0018,1190",  "FocalSpot"],
                           ["0018,1191",  "AnodeTargetMaterial"],
                           ["0018,11A0",  "BodyPartThickness"],
                           ["0018,11A2",  "CompressionForce"],
                           ["0018,700A",  "DetectorID"],
                           ["0018,700C",  "DateOfLastDetectorCalibration"],
                           ["0018,7050",  "FilterMaterialLT"],
                           ["0040,0314",  "HalfValueLayer_(mm)"],
                           ["0040,0316",  "OrganDose"],
                           ["0040,8302",  "EntranceDose_(mGy)"]]
            if cs.scannername == lit.stL50:
                dicomfields[0] = ["0008,0022",  "Acquisition Date"]
                dicomfields.append( ["0019,10c1",  "EnergyComponent"] )

        results = []
        for df in dicomfields:
            key = df[0]
            value = ""
            try:
                value = wadwrapper_lib.readDICOMtag(key,cs.dcmInfile)
            except:
                value = ""

            results.append( (df[1],value) )

        return results
Exemplo n.º 5
0
    def DICOMInfo(self, cs, info='dicom'):
        """
        Extract some info from the DICOM header. <info> is either 'dicom' (extensive list) or 'qc' (short list).
        Returns list of <tag description>,<tag value>
        """
        # Different from ImageJ version; tags "0008","0104" and "0054","0220"
        #  appear to be part of sequences. This gives problems (cannot be found
        #  or returning whole sequence blocks)
        # Possibly this can be solved by using if(type(value) == type(dicom.sequence.Sequence()))
        #  but I don't see the relevance of these tags anymore, so set them to NO

        self.determineScannerID(cs)
        if (info == "dicom"):
            dicomfields = [["0008,0021", "Series Date"],
                           ["0008,0031", "Series Time"],
                           ["0008,0070", "Manufacturer"],
                           ["0008,0080", "InstitutionName"],
                           ["0008,1010", "StationName"],
                           ["0008,1030", "StudyDescription"],
                           ["0008,103E", "SeriesDescription"],
                           ["0008,1070", "Operator"],
                           ["0010,0020", "PatientID"], ["0018,0060", "kVp"],
                           ["0018,1000", "DeviceSerialNumber"],
                           ["0018,1020", "SoftwareVersions"],
                           ["0018,1110", "DistanceSourceToDetector"],
                           ["0018,1111", "DistanceSourceToPatient"],
                           ["0018,1150", "ExposureTime_(ms)"],
                           ["0018,1151", "TubeCurrent_(mA)"],
                           ["0018,1153", "muAs"],
                           ["0018,1164", "ImagerPixelSpacing"],
                           ["0018,1166", "Grid"], ["0018,1190", "FocalSpot"],
                           ["0018,1191", "AnodeTargetMaterial"],
                           ["0018,11A0", "BodyPartThickness"],
                           ["0018,11A2", "CompressionForce"],
                           ["0018,1405", "RelativeXRayExposure"],
                           ["0018,700A", "DetectorID"],
                           ["0018,700C", "DateOfLastDetectorCalibration"],
                           ["0018,7050", "FilterMaterialLT"],
                           ["0019,1029", "---"], ["0028,0101", "BitsStored"],
                           ["0028,1040", "PixelensityRelationship"],
                           ["0028,1052", "Rescaleercept"],
                           ["0028,1053", "RescaleSlope"],
                           ["0028,1054", "RescaleType"],
                           ["0040,0302", "EntranceDose"],
                           ["0040,0314", "HalfValueLayer_(mm)"],
                           ["0040,0316", "OrganDose"],
                           ["0040,8302", "EntranceDose_(mGy)"],
                           ["0000,0000", "NOViewCodeSequence"],
                           ["0000,0000", "NOViewCodeMeaning"]]
            if cs.scannername == lit.stL50:
                dicomfields[0] = ["0008,0022", "Acquisition Date"]
                dicomfields[1] = ["0008,0030", "Acquisition Time"]

        elif (info == "qc"):
            dicomfields = [["0008,0021", "Series Date"],
                           ["0008,1010", "StationName"],
                           ["0008,1070", "Operator"], ["0018,0060", "kVp"],
                           ["0018,1020", "SoftwareVersions"],
                           ["0018,1030", "ProtocolName"],
                           ["0018,1110", "DistanceSourceToDetector"],
                           ["0018,1111", "DistanceSourceToPatient"],
                           ["0018,1153", "muAs"], ["0018,1166", "Grid"],
                           ["0018,1190", "FocalSpot"],
                           ["0018,1191", "AnodeTargetMaterial"],
                           ["0018,11A0", "BodyPartThickness"],
                           ["0018,11A2", "CompressionForce"],
                           ["0018,700A", "DetectorID"],
                           ["0018,700C", "DateOfLastDetectorCalibration"],
                           ["0018,7050", "FilterMaterialLT"],
                           ["0040,0314", "HalfValueLayer_(mm)"],
                           ["0040,0316", "OrganDose"],
                           ["0040,8302", "EntranceDose_(mGy)"]]
            if cs.scannername == lit.stL50:
                dicomfields[0] = ["0008,0022", "Acquisition Date"]
                dicomfields.append(["0019,10c1", "EnergyComponent"])

        results = []
        for df in dicomfields:
            key = df[0]
            value = ""
            try:
                value = wadwrapper_lib.readDICOMtag(key, cs.dcmInfile)
            except:
                value = ""

            results.append((df[1], value))

        return results
Exemplo n.º 6
0
def sfnrTest(data,results,params):
    """
    MRI_fBIRN Checks: fBIRN QA
      Signal-to-Fluctuation-Noise Ratio (SFNR)
      ... (more tests to come eventually)

    Workflow:
        1. Read image or sequence
        2. Run test
        3. Build output
    """

    #(1) Reads input file(s) list as a series (scan) single DICOM object
    #    returns DICOM header, raw pizelData object scaled and type of current DICOM object { 2D, 3D, ... }
    #dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareInput(data.series_filelist[0],headers_only=False,logTag=logTag())

    #------------------------------------------------------------------
    pixeldataIn = None

    if ( len(data.series_filelist[0]) > 1 ) or ( len(data.series_filelist[0]) == 1 and os.path.isdir(data.series_filelist[0][0]) ):
        
        fileList = data.series_filelist[0]
        if len(data.series_filelist[0]) == 1 :
            fileList = data.series_filelist[0][0]
        # read/load a list of DICOM files
        seriesDataList = pydicom_series.read_files(fileList,showProgress=True, readPixelData=True,skipNonImageFiles=True)

        # check number of series in the array/list
        if len(seriesDataList) != 1:
            raise ValueError("{} Such test is supposed to apply solely to a single series/scan. Something went wrong...".format(logTag))

        seriesData = seriesDataList[0]

        nTemporalPositions = int(seriesData.info["0020","0105"].value)

        # Image pixeldata seems to be transposed when read using wadwrapper_lib methods...
        pixeldataIn = seriesData.get_pixel_array()
        pixeldataIn = np.transpose(pixeldataIn)
        new3rdDimension = int(pixeldataIn.shape[2])/nTemporalPositions
        print '[Debug] Image dimensions: ' +  str(pixeldataIn.shape)
        print '[Debug] New dimensions: (%s, %s, %s, %s)' %(str(pixeldataIn.shape[0]),str(pixeldataIn.shape[1]),str(new3rdDimension),str(nTemporalPositions))
        pixeldataIn = np.reshape(pixeldataIn, (pixeldataIn.shape[0],pixeldataIn.shape[1],new3rdDimension,nTemporalPositions))

    elif ( len(data.series_filelist[0]) == 1) and ( wadwrapper_lib.testIfEnhancedDICOM(data.series_filelist[0][0]) ):
         # read/load a single DICOM file
        dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareEnhancedInput(data.series_filelist[0][0],headers_only=False)

        # DICOM keeps NumberOfTemporalPositions nested in sequence items/subitems. And DCM4CHEE seems not to keep them at all (!?).
        # Workaround: Use Philips private tag, should be read as a bit string and converted to string/integer/whatever
        if 'PHILIPS' not in (wadwrapper_lib.readDICOMtag("0008,0070",dcmInfile)).upper():
            raise ValueError("{} Input enhanced dataset type not suitable --> no dynamics/temporal information found".format(logTag))

        nSlicesRaw = wadwrapper_lib.readDICOMtag("2001,1018",dcmInfile)
        try:
            nSlices = struct.unpack("<L",nSlicesRaw)[0]
        except:
            nSlices = nSlicesRaw
        nTemporalPositions = int(pixeldataIn.shape[0])/int(nSlices)

        # Image pixeldata seems to be transposed when read using wadwrapper_lib methods...
        pixeldataIn = np.transpose(pixeldataIn)
        new3rdDimension = int(pixeldataIn.shape[2])/nTemporalPositions
        print '[Debug] Image dimensions: ' + str(pixeldataIn.shape)
        print '[Debug] New dimensions: (%s, %s, %s, %s)' %(str(pixeldataIn.shape[0]),str(pixeldataIn.shape[1]),str(new3rdDimension),str(nTemporalPositions))
        pixeldataIn = np.reshape(pixeldataIn, (pixeldataIn.shape[0],pixeldataIn.shape[1],new3rdDimension,nTemporalPositions))

    else:
        raise ValueError("{} Input dataset type cannot be determined or is not compatible".format(logTag))

    #(2)

    #if 'BIRN' not in options['seriesDesc'] or 'BIRN' not in options['protocolName']:
    #   raise ValueError("{} Input dataset type not suitable".format(logTag))
    # OR
    #   print '[Warning] Not an fBIRN scan --> do nothing'

    #Check if pixeldataIn is actually a numpy array
    if type(pixeldataIn).__module__ != np.__name__ :
        raise ValueError("{} Unable to pull out the pixel data of the incomming DICOM file(s)".format(logTag))

    output = fBIRN_lib.fBIRN_SFNR(pixeldataIn,plot_data=False)

    #(3)

    results.addFloat('mean_SNR', np.mean(output['imgsnr']), quantity='SNR', level=2) #quantity is actually magnitude in the WAD-QC app
    results.addFloat('mean_SFNR', output['meansfnr'], quantity='SFNR', level=2) #quantity is actually magnitude in the WAD-QC app

    #print '[info] SNR, %f'%np.mean(output['imgsnr'])
    #print '[info] SFNR, %f'%output['meansfnr']
    #print '[info] drift, %f'%output['trend'].params[1]
    #if len(output['spikes']) > 0:
        #print '[info] nspikes,%d'%len(output['spikes'])
    if len(output['spikes']) > 0:
        results.addBool('spikes', True, level=2) #Spikes detected
    else :
        results.addBool('spikes', False, level=2) #No spikes detected
Exemplo n.º 7
0
def sfnrTest(data, results, params):
    """
    MRI_fBIRN Checks: fBIRN QA
      Signal-to-Fluctuation-Noise Ratio (SFNR)
      ... (more tests to come eventually)

    Workflow:
        1. Read image or sequence
        2. Run test
        3. Build output
    """

    #(1) Reads input file(s) list as a series (scan) single DICOM object
    #    returns DICOM header, raw pizelData object scaled and type of current DICOM object { 2D, 3D, ... }
    #dcmInfile,pixeldataIn,dicomMode = wadwrapper_lib.prepareInput(data.series_filelist[0],headers_only=False,logTag=logTag())

    #------------------------------------------------------------------
    pixeldataIn = None

    if (len(data.series_filelist[0]) > 1) or (len(data.series_filelist[0]) == 1
                                              and os.path.isdir(
                                                  data.series_filelist[0][0])):

        fileList = data.series_filelist[0]
        if len(data.series_filelist[0]) == 1:
            fileList = data.series_filelist[0][0]
        # read/load a list of DICOM files
        seriesDataList = pydicom_series.read_files(fileList,
                                                   showProgress=True,
                                                   readPixelData=True,
                                                   skipNonImageFiles=True)

        # check number of series in the array/list
        if len(seriesDataList) != 1:
            raise ValueError(
                "{} Such test is supposed to apply solely to a single series/scan. Something went wrong..."
                .format(logTag))

        seriesData = seriesDataList[0]

        nTemporalPositions = int(seriesData.info["0020", "0105"].value)

        # Image pixeldata seems to be transposed when read using wadwrapper_lib methods...
        pixeldataIn = seriesData.get_pixel_array()
        pixeldataIn = np.transpose(pixeldataIn)
        new3rdDimension = int(pixeldataIn.shape[2]) / nTemporalPositions
        print '[Debug] Image dimensions: ' + str(pixeldataIn.shape)
        print '[Debug] New dimensions: (%s, %s, %s, %s)' % (
            str(pixeldataIn.shape[0]), str(pixeldataIn.shape[1]),
            str(new3rdDimension), str(nTemporalPositions))
        pixeldataIn = np.reshape(pixeldataIn,
                                 (pixeldataIn.shape[0], pixeldataIn.shape[1],
                                  new3rdDimension, nTemporalPositions))

    elif (len(data.series_filelist[0])
          == 1) and (wadwrapper_lib.testIfEnhancedDICOM(
              data.series_filelist[0][0])):
        # read/load a single DICOM file
        dcmInfile, pixeldataIn, dicomMode = wadwrapper_lib.prepareEnhancedInput(
            data.series_filelist[0][0], headers_only=False)

        # DICOM keeps NumberOfTemporalPositions nested in sequence items/subitems. And DCM4CHEE seems not to keep them at all (!?).
        # Workaround: Use Philips private tag, should be read as a bit string and converted to string/integer/whatever
        if 'PHILIPS' not in (wadwrapper_lib.readDICOMtag(
                "0008,0070", dcmInfile)).upper():
            raise ValueError(
                "{} Input enhanced dataset type not suitable --> no dynamics/temporal information found"
                .format(logTag))

        nSlicesRaw = wadwrapper_lib.readDICOMtag("2001,1018", dcmInfile)
        try:
            nSlices = struct.unpack("<L", nSlicesRaw)[0]
        except:
            nSlices = nSlicesRaw
        nTemporalPositions = int(pixeldataIn.shape[0]) / int(nSlices)

        # Image pixeldata seems to be transposed when read using wadwrapper_lib methods...
        pixeldataIn = np.transpose(pixeldataIn)
        new3rdDimension = int(pixeldataIn.shape[2]) / nTemporalPositions
        print '[Debug] Image dimensions: ' + str(pixeldataIn.shape)
        print '[Debug] New dimensions: (%s, %s, %s, %s)' % (
            str(pixeldataIn.shape[0]), str(pixeldataIn.shape[1]),
            str(new3rdDimension), str(nTemporalPositions))
        pixeldataIn = np.reshape(pixeldataIn,
                                 (pixeldataIn.shape[0], pixeldataIn.shape[1],
                                  new3rdDimension, nTemporalPositions))

    else:
        raise ValueError(
            "{} Input dataset type cannot be determined or is not compatible".
            format(logTag))

    #(2)

    #if 'BIRN' not in options['seriesDesc'] or 'BIRN' not in options['protocolName']:
    #   raise ValueError("{} Input dataset type not suitable".format(logTag))
    # OR
    #   print '[Warning] Not an fBIRN scan --> do nothing'

    #Check if pixeldataIn is actually a numpy array
    if type(pixeldataIn).__module__ != np.__name__:
        raise ValueError(
            "{} Unable to pull out the pixel data of the incomming DICOM file(s)"
            .format(logTag))

    output = fBIRN_lib.fBIRN_SFNR(pixeldataIn, plot_data=False)

    #(3)

    results.addFloat(
        'mean_SNR', np.mean(output['imgsnr']), quantity='SNR',
        level=2)  #quantity is actually magnitude in the WAD-QC app
    results.addFloat(
        'mean_SFNR', output['meansfnr'], quantity='SFNR',
        level=2)  #quantity is actually magnitude in the WAD-QC app

    #print '[info] SNR, %f'%np.mean(output['imgsnr'])
    #print '[info] SFNR, %f'%output['meansfnr']
    #print '[info] drift, %f'%output['trend'].params[1]
    #if len(output['spikes']) > 0:
    #print '[info] nspikes,%d'%len(output['spikes'])
    if len(output['spikes']) > 0:
        results.addBool('spikes', True, level=2)  #Spikes detected
    else:
        results.addBool('spikes', False, level=2)  #No spikes detected
Exemplo n.º 8
0
 def readDICOMtag(self, cs_mam, key, imslice=0):  # slice=2 is image 3
     value = wadwrapper_lib.readDICOMtag(key, cs_mam.dcmInfile, imslice)
     return value
Exemplo n.º 9
0
 def readDICOMtag(self,cs_mam,key,imslice=0): # slice=2 is image 3
     value = wadwrapper_lib.readDICOMtag(key,cs_mam.dcmInfile,imslice)
     return value