示例#1
0
def main(self):
    """Creates a subwindow that displays a DICOM image's metadata. """
    try:
        logger.info("ViewMetaData.viewMetadata called")
        QApplication.setOverrideCursor(QCursor(QtCore.Qt.WaitCursor))

        if treeView.isAnImageSelected(self):
            imagePath = self.selectedImagePath
            imageName = self.selectedImageName
            dataset = readDICOM_Image.getDicomDataset(imagePath)
            displayMetaDataSubWindow(self, "Metadata for image {}".format(imageName), 
                                            dataset)
        elif treeView.isASeriesSelected(self):
            studyID = self.selectedStudy 
            seriesID = self.selectedSeries
            imageList = self.objXMLReader.getImagePathList(studyID, seriesID)
            firstImagePath = imageList[0]
            dataset = readDICOM_Image.getDicomDataset(firstImagePath)
            displayMetaDataSubWindow(self, "Metadata for series {}".format(seriesID), 
                                            dataset)

        QApplication.restoreOverrideCursor()
    except (IndexError, AttributeError):
                QApplication.restoreOverrideCursor()
                msgBox = QMessageBox()
                msgBox.setWindowTitle("View DICOM Metadata")
                msgBox.setText("Select either a series or an image")
                msgBox.exec()
    except Exception as e:
        print('Error in ViewMetaData.viewMetadata: ' + str(e))
        logger.error('Error in ViewMetaData.viewMetadata: ' + str(e))
def saveDicomNewSeries(derivedImagePathList, imagePathList, pixelArrayList, suffix, series_id=None, series_uid=None, series_name=None, parametric_map=None, colourmap=None, list_refs_path=None):
    """This method saves the pixelArrayList into DICOM files with metadata pointing to the same series"""
    # What if it's a map with less files than original? Think about iterating the first elements and sort path list by SliceLocation - see T2* algorithm
    # Think of a way to choose a select a new FilePath or Folder
    try:
        if os.path.exists(imagePathList[0]):
            # Series ID and UID
            if (series_id is None) and (series_uid is None):
                ids = generateUIDs(readDICOM_Image.getDicomDataset(imagePathList[0]))
                series_id = ids[0]
                series_uid = ids[1]
            elif (series_id is not None) and (series_uid is None):
                series_uid = generateUIDs(readDICOM_Image.getDicomDataset(imagePathList[0]), seriesNumber=series_id)[1]
            elif (series_id is None) and (series_uid is not None):
                series_id = int(str(readDICOM_Image.getDicomDataset(imagePathList[0]).SeriesNumber) + str(random.randint(0, 9999)))

            refs = None
            for index, newFilePath in enumerate(derivedImagePathList):
                # Extra references, besides the main one, which is imagePathList
                if list_refs_path is not None:
                    if len(np.shape(list_refs_path)) == 1:
                        refs = list_refs_path[index]
                    else:
                        refs = []
                        for individualRef in list_refs_path:
                            refs.append(individualRef[index])

                saveNewSingleDicomImage(newFilePath, imagePathList[index], pixelArrayList[index], suffix, series_id=series_id, series_uid=series_uid, series_name=series_name, image_number=index, parametric_map=parametric_map, 
                                      colourmap=colourmap, list_refs_path=refs)
            del series_id, series_uid, refs
            return
        else:
            return None
    except Exception as e:
        print('Error in function saveDICOM_Image.saveDicomNewSeries: ' + str(e))
def insertNewSeriesInXMLFile(self,
                             origImageList,
                             newImageList,
                             suffix,
                             newSeriesName=None):
    """Creates a new series to hold the series of New images"""
    try:
        logger.info("InterfaceDICOMXMLFile insertNewSeriesInXMLFile called")
        #Get current study & series IDs
        #studyID = self.selectedStudy
        #seriesID = self.selectedSeries
        # Get a new series ID by default
        (subjectID, studyID,
         seriesID) = treeView.getPathParentNode(self, origImageList[0])
        dataset = readDICOM_Image.getDicomDataset(newImageList[0])
        newSeriesID = getNewSeriesName(
            self, studyID, dataset, suffix,
            newSeriesName=newSeriesName)  # If developer sets seriesName
        self.objXMLReader.insertNewSeriesInXML(origImageList, newImageList,
                                               studyID, newSeriesID, seriesID,
                                               suffix)
        self.statusBar.showMessage('New series created: - ' + newSeriesID)
        return newSeriesID
    except Exception as e:
        print('Error in InterfaceDICOMXMLFile.insertNewSeriesInXMLFile: ' +
              str(e))
        logger.error(
            'Error in InterfaceDICOMXMLFile.insertNewSeriesInXMLFile: ' +
            str(e))
def renameSeriesinXMLFile(self, imageList, series_id=None, series_name=None):
    """Removes a whole series from the DICOM XML file"""
    try:
        logger.info("InterfaceDICOMXMLFile renameSeriesinXMLFile called")
        (subjectID, studyID,
         seriesID) = treeView.getPathParentNode(self, imageList[0])
        seriesNumber = str(
            readDICOM_Image.getDicomDataset(imageList[0]).SeriesNumber
        ) if series_id is None else str(series_id)
        newName = str(
            readDICOM_Image.getDicomDataset(imageList[0]).SeriesDescription
        ) if series_name is None else str(series_name)
        xmlSeriesName = seriesNumber + "_" + newName
        self.objXMLReader.renameSeriesinXMLFile(studyID, seriesID,
                                                xmlSeriesName)
    except Exception as e:
        print('Error in InterfaceDICOMXMLFile removeSeriesFromXMLFile: ' +
              str(e))
        logger.error(
            'Error in InterfaceDICOMXMLFile removeSeriesFromXMLFile: ' +
            str(e))
def returnPixelArray(imagePath, func):
    """Applies the algorithm in the function, func to
   an image and returns the resulting PixelArray"""
    try:
        if os.path.exists(imagePath):
            dataset = readDICOM_Image.getDicomDataset(imagePath)
            pixelArray = readDICOM_Image.returnPixelArray(imagePath)
            derivedImage = func(pixelArray, dataset)
            return derivedImage
        else:
            return None
    except Exception as e:
        print('Error in function #.returnPixelArray: ' + str(e))
def saveNewSingleDicomImage(newFilePath, imagePath, pixelArray, suffix, series_id=None, series_uid=None, series_name=None, image_number=None, parametric_map=None, colourmap=None, list_refs_path=None):
    """This method saves the new pixelArray into DICOM in the given newFilePath"""
    try:
        if os.path.exists(imagePath):
            dataset = readDICOM_Image.getDicomDataset(imagePath)
            if list_refs_path is not None:
                refs = []
                for individualRef in list_refs_path:
                    refs.append(readDICOM_Image.getDicomDataset(individualRef))
            else:
                refs = None
            newDataset = createNewSingleDicom(dataset, pixelArray, series_id=series_id, series_uid=series_uid, series_name=series_name, comment=suffix, parametric_map=parametric_map, colourmap=colourmap, list_refs=refs)
            if (image_number is not None) and (len(np.shape(pixelArray)) < 3):
                newDataset.InstanceNumber = image_number
                newDataset.ImageNumber = image_number
            saveDicomToFile(newDataset, output_path=newFilePath)
            del dataset, newDataset, refs, image_number
            return
        else:
            return None

    except Exception as e:
        print('Error in function saveDICOM_Image.saveNewSingleDicomImage: ' + str(e))
示例#7
0
def saveROI(self, regionName, graphicsView):
    try:
        # Save Current ROI
        logger.info("DisplayImageDrawROI.saveROI called")
        maskList = graphicsView.dictROIs.dictMasks[
            regionName]  # Will return a list of boolean masks
        maskList = [np.array(mask, dtype=np.int) for mask in maskList
                    ]  # Convert each 2D boolean to 0s and 1s
        suffix = str("_ROI_" + regionName)
        if len(maskList) > 1:
            inputPath = self.imageList
        else:
            inputPath = [self.selectedImagePath]
        # Saving Progress message
        messageWindow.displayMessageSubWindow(
            self,
            "<H4>Saving ROIs into a new DICOM Series ({} files)</H4>".format(
                len(inputPath)), "Export ROIs")
        messageWindow.setMsgWindowProgBarMaxValue(self, len(inputPath))
        ids = saveDICOM_Image.generateUIDs(
            readDICOM_Image.getDicomDataset(inputPath[0]))
        seriesID = ids[0]
        seriesUID = ids[1]
        #outputPath = []
        #for image in inputPath:
        for index, path in enumerate(inputPath):
            #outputPath.append(saveDICOM_Image.returnFilePath(image, suffix))
            messageWindow.setMsgWindowProgBarValue(self, index)
            outputPath = saveDICOM_Image.returnFilePath(path, suffix)
            saveDICOM_Image.saveNewSingleDicomImage(outputPath,
                                                    path,
                                                    maskList[index],
                                                    suffix,
                                                    series_id=seriesID,
                                                    series_uid=seriesUID,
                                                    parametric_map="SEG")
            treeSeriesID = interfaceDICOMXMLFile.insertNewImageInXMLFile(
                self, path, outputPath, suffix)
        #saveDICOM_Image.saveDicomNewSeries(outputPath, inputPath, maskList, suffix, parametric_map="SEG") # Consider Enhanced DICOM for parametric_map
        #seriesID = interfaceDICOMXMLFile.insertNewSeriesInXMLFile(self, inputPath, outputPath, suffix)
        messageWindow.setMsgWindowProgBarValue(self, len(inputPath))
        messageWindow.closeMessageSubWindow(self)
        treeView.refreshDICOMStudiesTreeView(self, newSeriesName=treeSeriesID)
        QMessageBox.information(self, "Export ROIs", "Image Saved")
    except Exception as e:
        print('Error in DisplayImageDrawROI.saveROI: ' + str(e))
        logger.error('Error in DisplayImageDrawROI.saveROI: ' + str(e))
def updateSingleDicomImage(objWeasel, spinBoxIntensity, spinBoxContrast, 
                imagePath='', seriesID='', studyID='', colourmap=None, lut=None):
    try:
        logger.info("In saveDICOM_Image.updateSingleDicomImage")
        messageWindow.displayMessageSubWindow(objWeasel,
            "<H4>Updating 1 DICOM file</H4>",
            "Updating DICOM images")
        messageWindow.setMsgWindowProgBarMaxValue(objWeasel,1)
        messageWindow.setMsgWindowProgBarValue(objWeasel,0)
        dataset = readDICOM_Image.getDicomDataset(imagePath)
        levels = [spinBoxIntensity.value(), spinBoxContrast.value()]
        updatedDataset = updateSingleDicom(dataset, colourmap=colourmap, levels=levels, lut=lut)
        saveDicomToFile(updatedDataset, output_path=imagePath)
        messageWindow.setMsgWindowProgBarValue(objWeasel,1)
        messageWindow.closeMessageSubWindow(objWeasel)
    except Exception as e:
        print('Error in saveDICOM_Image.updateSingleDicomImage: ' + str(e))
def overwriteDicomFileTag(imagePath, dicomTag, newValue):
    try:
        if isinstance(imagePath, list):
            datasetList = readDICOM_Image.getSeriesDicomDataset(imagePath)
            for index, dataset in enumerate(datasetList):
                if isinstance(dicomTag, str):
                    try: dataset.data_element(dicomTag).value = newValue
                    except: dataset.add_new(dicomTag, dictionary_VR(dicomTag), newValue)
                else:
                    try: dataset[hex(dicomTag)].value = newValue
                    except: dataset.add_new(hex(dicomTag), dictionary_VR(hex(dicomTag)), newValue)
                saveDicomToFile(dataset, output_path=imagePath[index])
        else:
            dataset = readDICOM_Image.getDicomDataset(imagePath)
            if isinstance(dicomTag, str):
                try: dataset.data_element(dicomTag).value = newValue
                except: dataset.add_new(dicomTag, dictionary_VR(dicomTag), newValue)
            else:
                try: dataset[hex(dicomTag)].value = newValue
                except: dataset.add_new(hex(dicomTag), dictionary_VR(hex(dicomTag)), newValue)
            saveDicomToFile(dataset, output_path=imagePath)
        return
    except Exception as e:
        print('Error in saveDICOM_Image.overwriteDicomFileTag: ' + str(e))
示例#10
0
def loadROI(self, cmbROIs, graphicsView):
    try:
        logger.info("DisplayImageDrawROI.loadROI called")
        # The following workflow is assumed:
        #   1. The user first loads a series of DICOM images
        #   2. Then the user loads the series of ROIs that are superimposed upon the images

        # Prompt Windows to select Series
        # paramDict = {"Series":"dropdownlist"}
        paramDict = {"Series": "listview"}
        helpMsg = "Select a Series with ROI"
        studyID = self.selectedStudy
        study = self.objXMLReader.getStudy(studyID)
        listSeries = [series.attrib['id']
                      for series in study]  # if 'ROI' in series.attrib['id']]
        inputDlg = inputDialog.ParameterInputDialog(paramDict,
                                                    title="Load ROI",
                                                    helpText=helpMsg,
                                                    lists=[listSeries])
        listParams = inputDlg.returnListParameterValues()
        if inputDlg.closeInputDialog() == False:
            # for series ID in listParams[0]: # more than 1 ROI may be selected
            seriesID = listParams[0][0]  # Temporary, only the first ROI
            imagePathList = self.objXMLReader.getImagePathList(
                studyID, seriesID)
            maskList = []
            # Consider DICOM Tag SegmentSequence[:].SegmentLabel as some 3rd software do
            if hasattr(readDICOM_Image.getDicomDataset(imagePathList[0]),
                       "ContentDescription"):
                region = readDICOM_Image.getSeriesTagValues(
                    imagePathList, "ContentDescription")[0][0]
            else:
                region = "new_region_number"

            # Affine re-adjustment
            # It takes longer to load with this, so we could do an if/else involving Affine
            for dicomFile in self.imageList:
                dataset_original = readDICOM_Image.getDicomDataset(dicomFile)
                tempArray = np.zeros(
                    np.shape(readDICOM_Image.getPixelArray(dataset_original)))
                for maskFile in imagePathList:
                    dataset = readDICOM_Image.getDicomDataset(maskFile)
                    maskArray = readDICOM_Image.getPixelArray(dataset)
                    maskArray[maskArray != 0] = 1
                    affineResults = readDICOM_Image.mapMaskToImage(
                        maskArray, dataset, dataset_original)
                    for coordinates in affineResults:
                        tempArray[coordinates] = 1
                    #tempArray = np.add(tempArray, np.transpose(affineResults))
                #np.where(tempArray > 1, tempArray, 1)
                maskList.append(tempArray)

            # First populate the ROI_Storage data structure in a loop
            for imageNumber in range(len(maskList)):
                graphicsView.dictROIs.addRegion(
                    region,
                    np.array(maskList[imageNumber]).astype(bool),
                    imageNumber + 1)

            # Second populate the dropdown list of region names
            cmbROIs.blockSignals(True)
            #remove previous contents of ROI dropdown list
            cmbROIs.clear()
            cmbROIs.addItems(graphicsView.dictROIs.getListOfRegions())
            cmbROIs.blockSignals(False)

            # Redisplay the current image to show the mask
            mask = graphicsView.dictROIs.getMask(region, 1)
            graphicsView.graphicsItem.reloadMask(mask)

    except Exception as e:
        print('Error in DisplayImageDrawROI.loadROI: ' + str(e))
        logger.error('Error in DisplayImageDrawROI.loadROI: ' + str(e))
 def insertNewImageInXML(self, imageName,
                newImageFileName, studyID, seriesID, suffix, newSeriesName=None):
     #First determine if a series with parentID=seriesID exists
     #and typeID=suffix
     try:
         dataset = readDICOM_Image.getDicomDataset(newImageFileName)
         if newSeriesName:
             newSeriesID = str(dataset.SeriesNumber) + "_" + newSeriesName
         else:
             newSeriesID = str(dataset.SeriesNumber) + "_" + dataset.SeriesDescription
         series = self.getSeriesOfSpecifiedType(
             studyID, seriesID, newSeriesID, suffix)
         #Get image label, date & time
         imageLabel = self.getImageLabel(studyID, seriesID, imageName)
         imageTime = self.getImageTime(studyID, seriesID)#, imageName)
         imageDate = self.getImageDate(studyID, seriesID)#, imageName)
         if series is None:
             #Need to create a new series to hold this new image
             #Get study branch
             currentStudy = self.getStudy(studyID)
             newAttributes = {'id':newSeriesID, 
                                 'parentID':seriesID, 
                                 'typeID':suffix}
                
             #Add new series to study to hold new images
             newSeries = ET.SubElement(currentStudy, 'series', newAttributes)
                 
             comment = ET.Comment('This series holds new images')
             newSeries.append(comment)
                 
             #print("image time {}, date {}".format(imageTime, imageDate))
             #Now add image element
             newImage = ET.SubElement(newSeries,'image')
             #Add child nodes of the image element
             labelNewImage = ET.SubElement(newImage, 'label')
             labelNewImage.text = imageLabel
             nameNewImage = ET.SubElement(newImage, 'name')
             nameNewImage.text = newImageFileName
             timeNewImage = ET.SubElement(newImage, 'time')
             timeNewImage.text = imageTime
             dateNewImage = ET.SubElement(newImage, 'date')
             dateNewImage.text = imageDate
             self.tree.write(self.fullFilePath)
             return newSeriesID
         else:
             #A series already exists to hold new images from
             #the current parent series
             newImage = ET.SubElement(series,'image')
             #Add child nodes of the image element
             labelNewImage = ET.SubElement(newImage, 'label')
             labelNewImage.text = imageLabel
             nameNewImage = ET.SubElement(newImage, 'name')
             nameNewImage.text = newImageFileName
             timeNewImage = ET.SubElement(newImage, 'time')
             timeNewImage.text = imageTime
             dateNewImage = ET.SubElement(newImage, 'date')
             dateNewImage.text = imageDate
             self.tree.write(self.fullFilePath)
             return series.attrib['id']
     except Exception as e:
         print('Error in WeaselXMLReader.insertNewImageInXML: ' + str(e)) 
         logger.error('Error in WeaselXMLReader.insertNewImageInXML: ' + str(e))
示例#12
0
def readLevelsFromDICOMImage(self, pixelArray):
    """Reads levels directly from the DICOM image
        
        Input Parmeters
        ***************
        self - an object reference to the WEASEL interface.
        pixelArray - pixel array to be displayed

        Output Parameters
        *****************
        centre - Image intensity
        width - Image contrast
        maximumValue - Maximum pixel value in the image
        minimumValue - Minimum pixel value in the image
        """
    try:
        logger.info("DisplayImageCommon.readLevelsFromDICOMImage called")
        #set default values
        centre = -1
        width = -1
        maximumValue = -1
        minimumValue = -1
        dataset = readDICOM_Image.getDicomDataset(self.selectedImagePath)
        if dataset and hasattr(dataset, 'WindowCenter') and hasattr(
                dataset, 'WindowWidth'):
            slope = float(getattr(dataset, 'RescaleSlope', 1))
            intercept = float(getattr(dataset, 'RescaleIntercept', 0))
            centre = dataset.WindowCenter  # * slope + intercept
            width = dataset.WindowWidth  # * slope
            maximumValue = centre + width / 2
            minimumValue = centre - width / 2
        elif dataset and hasattr(dataset, 'PerFrameFunctionalGroupsSequence'):
            # In Enhanced MRIs, this display will retrieve the centre and width values of the first slice
            slope = dataset.PerFrameFunctionalGroupsSequence[
                0].PixelValueTransformationSequence[0].RescaleSlope
            intercept = dataset.PerFrameFunctionalGroupsSequence[
                0].PixelValueTransformationSequence[0].RescaleIntercept
            centre = dataset.PerFrameFunctionalGroupsSequence[
                0].FrameVOILUTSequence[0].WindowCenter  # * slope + intercept
            width = dataset.PerFrameFunctionalGroupsSequence[
                0].FrameVOILUTSequence[0].WindowWidth  # * slope
            maximumValue = centre + width / 2
            minimumValue = centre - width / 2
        else:
            minimumValue = np.amin(pixelArray) if (
                np.median(pixelArray) - iqr(pixelArray, rng=(1, 99)) /
                2) < np.amin(pixelArray) else np.median(pixelArray) - iqr(
                    pixelArray, rng=(1, 99)) / 2
            maximumValue = np.amax(pixelArray) if (
                np.median(pixelArray) + iqr(pixelArray, rng=(1, 99)) /
                2) > np.amax(pixelArray) else np.median(pixelArray) + iqr(
                    pixelArray, rng=(1, 99)) / 2
            centre = minimumValue + (abs(maximumValue) - abs(minimumValue)) / 2
            width = maximumValue - abs(minimumValue)

        return centre, width, maximumValue, minimumValue
    except Exception as e:
        print('Error in DisplayImageCommon.readLevelsFromDICOMImage: ' +
              str(e))
        logger.error('Error in DisplayImageCommon.readLevelsFromDICOMImage: ' +
                     str(e))