Esempio n. 1
0
def loaddata(dicomdata):
    indata = pydicom_series.read_files(dicomdata,showProgress=True)[0]  


    pixelsize =  float(indata.info["0028","0030"].value[0])
    
    rows = indata.info["0028","0010"].value
    cols = indata.info["0028","0011"].value

    newshape = (rows,cols)
    print "shape of dataslices: ", newshape
    
    bitdepth = indata.info["0028","0100"].value #bits allocated
    if bitdepth == 16:
        bv = np.int16
    elif bitdepth == 8:
        bv = np.int8    
    elif bitdepth == 32:
        bv = np.int32
    elif bitdepth == 64:
        bv = np.int64
    
    
    datlist = []

    sequence = indata.__dict__['_datasets']
    
    for i in range(len(sequence)):
       tmpkeys = sequence[i].keys()      
       datlist.append(np.reshape(np.fromstring(sequence[i][dicom.tag.Tag("7fe0","0010")].value,dtype=bv),newshape))
       

    array = np.array(datlist)
    print "loaddata complete"
    
    return pixelsize, array, indata
def dataSlicing(dataPath, masks=None):
    #Gui init
    startTime = time.time()
    global app, win, imv1, imv2, imv3, hLine1, hLine2, hLine3, vLine1, vLine2, vLine3
    app = QtGui.QApplication([])
    win = QtGui.QMainWindow()
    win.setWindowTitle('DataSlicing')
    win.resize(600,800)
    cw = QtGui.QWidget()
    win.setCentralWidget(cw)
    l = QtGui.QGridLayout()
    cw.setLayout(l)
    imv1 = pg.ImageView()
    imv2 = pg.ImageView()
    imv3 = pg.ImageView()
    l.addWidget(imv1, 0, 0)
    l.addWidget(imv2, 1, 0)
    l.addWidget(imv3, 2, 0)
    win.show()  

    #Get 3D data
    vol = diSeries.read_files(dataPath)
    data = vol[0].get_pixel_array()

    img1RGBA = np.zeros((data.shape[0],data.shape[1],4),dtype=np.ubyte)
    img2RGBA = np.zeros((data.shape[0],data.shape[2],4),dtype=np.ubyte)
    img3RGBA = np.zeros((data.shape[1],data.shape[2],4),dtype=np.ubyte)
    
    #input mask is a np array with numbered regions, 0 specifies no colour
    if masks is not None:                
        alpha = int(255/float(len(masks)))        
        #every mask in the list gets its own lookup table to avoid problems
        #with reset numbering of regions in different masks and 
        # different number of regions in each of the masks
        masksCol = []
        for j in range(len(masks)):
            if data.shape != masks[j].shape:
                raise Exception('The dimensions of the mask%d and data do not match.',j)
            #command np.unique(someArray) returns list of unique values in array
            colCount = len(np.unique(masks[j]))
            lookupTable = np.zeros((colCount,4),dtype=np.ubyte)
            lookupTable[0] = [0,0,0,0]

            for i in range(1,colCount):
                lookupTable[i]=np.random.randint(1,256,size=3).tolist()+[alpha]
                
            masksCol.append(pg.applyLookupTable(masks[j],lookupTable))

        maskBack = masksCol.pop(0)
        mask = np.zeros(maskBack.shape,dtype=np.ubyte)
        for m in masksCol:
            
            mask[:,:,:,3]=((m[:,:,:,3].astype(float)/255)+(maskBack[:,:,:,3].astype(float)/255)*(1-(m[:,:,:,3].astype(float)/255)))*255
            #when the alpha is zero, RGBs should be zero too
            #dividing by large number in float will produce int zero values
            mask[mask==0]=1000
            mask[:,:,:,0]=(m[:,:,:,0]*(m[:,:,:,3].astype(float)/255)+maskBack[:,:,:,0]*(maskBack[:,:,:,3].astype(float)/255)*(1-(m[:,:,:,3].astype(float)/255)))/(mask[:,:,:,3].astype(float)/255)
            mask[:,:,:,1]=(m[:,:,:,1]*(m[:,:,:,3].astype(float)/255)+maskBack[:,:,:,1]*(maskBack[:,:,:,3].astype(float)/255)*(1-(m[:,:,:,3].astype(float)/255)))/(mask[:,:,:,3].astype(float)/255)
            mask[:,:,:,2]=(m[:,:,:,2]*(m[:,:,:,3].astype(float)/255)+maskBack[:,:,:,2]*(maskBack[:,:,:,3].astype(float)/255)*(1-(m[:,:,:,3].astype(float)/255)))/(mask[:,:,:,3].astype(float)/255)
            maskBack = mask
        
        maskBack[maskBack==0]=255
        maskCol = maskBack
    else:
        maskCol = None

    #creates crosshairs, positioned in the middle of the picture, limited by
    #dimensions of the picture
    hLine1 = pg.InfiniteLine(angle=0, movable=True, pos=img1RGBA.shape[1]/2, bounds=[0,img1RGBA.shape[1]-1])
    vLine1 = pg.InfiniteLine(angle=90, movable=True, pos=img1RGBA.shape[0]/2, bounds=[0,img1RGBA.shape[0]-1])

    hLine2 = pg.InfiniteLine(angle=0, movable=True, pos=img2RGBA.shape[1]/2, bounds=[0,img2RGBA.shape[1]-1])
    vLine2 = pg.InfiniteLine(angle=90, movable=True, pos=img2RGBA.shape[0]/2, bounds=[0,img2RGBA.shape[0]-1])

    hLine3 = pg.InfiniteLine(angle=0, movable=True, pos=img3RGBA.shape[1]/2, bounds=[0,img3RGBA.shape[1]-1])
    vLine3 = pg.InfiniteLine(angle=90, movable=True, pos=img3RGBA.shape[0]/2, bounds=[0,img3RGBA.shape[0]-1])

    imv1.addItem(vLine1)
    imv1.addItem(hLine1)
    imv2.addItem(vLine2)
    imv2.addItem(hLine2)
    imv3.addItem(vLine3)
    imv3.addItem(hLine3)
    
    #{v,h}Line{1,2,3}.value() gives only one value, since the angle of lines is
    #zero or right
    #left upper corner of the picture is [0,0] coordinate
    
    def updateV1(): 
    #updates image views that get affected by dragging in imv1 in vertical dimension
        global imv3, img3, img3RGBA, vLine1, vLine2
        vLine2.setValue(vLine1.value()) 
        img3 = data[vLine1.value(),:,:]
        img3RGBA = pg.makeRGBA(img3,levels=[np.amin(img3),np.amax(img3)])[0]
        if maskCol is not None:
            maskSlice = maskCol[vLine1.value(),:,:,:]
            img3RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img3RGBA[:,:,0:3]
            img3RGBA[:,:,3] = 255

        imv3.setImage(img3RGBA.astype(int))

    def updateH1():
    #updates image views that get affected by dragging in imv1 in horizontal
    #dimension
        global img2, img2RGBA, imv2, hLine1, vLine3
        vLine3.setValue(hLine1.value())
        img2 = data[:,hLine1.value(),:]
        img2RGBA = pg.makeRGBA(img2,levels=[np.amin(img2),np.amax(img2)])[0]
        if maskCol is not None:
            maskSlice = maskCol[:,hLine1.value(),:,:]
            img2RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img2RGBA[:,:,0:3]
            img2RGBA[:,:,3] = 255

        imv2.setImage(img2RGBA.astype(int))

    vLine1.sigDragged.connect(updateV1)
    hLine1.sigDragged.connect(updateH1)
        
    def updateV2():
        global imv3, img3, img3RGBA, vLine2, vLine1
        vLine1.setValue(vLine2.value())
        img3 = data[vLine2.value(),:,:]
        img3RGBA = pg.makeRGBA(img3,levels=[np.amin(img3),np.amax(img3)])[0]
        if maskCol is not None:
            maskSlice = maskCol[vLine2.value(),:,:,:]
            img3RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img3RGBA[:,:,0:3]
            img3RGBA[:,:,3] = 255;

        imv3.setImage(img3RGBA.astype(int))

    def updateH2():
        global imv1, img1, img1RGBA, hLine2, hLine3
        hLine3.setValue(hLine2.value())
        img1 = data[:,:,hLine2.value()]
        img1RGBA = pg.makeRGBA(img1,levels=[np.amin(img1),np.amax(img1)])[0]
        if maskCol is not None:
            maskSlice = maskCol[:,:,hLine2.value(),:]
            img1RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img1RGBA[:,:,0:3]
            img1RGBA[:,:,3] = 255

        imv1.setImage(img1RGBA.astype(int))

    vLine2.sigDragged.connect(updateV2)
    hLine2.sigDragged.connect(updateH2)

    def updateV3():
        global imv2, img2, img2RGBA, vLine3, hLine1
        hLine1.setValue(vLine3.value())
        img2 = data[:,vLine3.value(),:]
        img2RGBA = pg.makeRGBA(img2,levels=[np.amin(img2),np.amax(img2)])[0]
        if maskCol is not None:
            maskSlice = maskCol[:,vLine3.value(),:,:]
            img2RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img2RGBA[:,:,0:3]
            img2RGBA[:,:,3] = 255

        imv2.setImage(img2RGBA.astype(int))

    def updateH3():
        global imv1, img1, img1RGBA, hLine3, hLine2
        hLine2.setValue(hLine3.value())
        img1 = data[:,:,hLine3.value()]
        img1RGBA = pg.makeRGBA(img1,levels=[np.amin(img1),np.amax(img1)])[0]
        if maskCol is not None:
            maskSlice = maskCol[:,:,hLine3.value(),:]
            img1RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img1RGBA[:,:,0:3]
            img1RGBA[:,:,3]

        imv1.setImage(img1RGBA.astype(int))

    vLine3.sigDragged.connect(updateV3)
    hLine3.sigDragged.connect(updateH3)
    
    #sets initial images, when script starts
    updateV1()
    updateH1()
    updateH2()
    endTime = time.time()
    elapsed = endTime - startTime
    print "time elapsed: ", elapsed
Esempio n. 3
0
def prepareInput(instancedict,headers_only,logTag="[prepareInput] "):
    """
    Reads inputfile as an EnhancedDICOM object; if an EnhancedDICOM object is detected, prepareEnhancedInput is called.
    Checks if the input is as expected: number of slices etc.
    If not headers_only, scaling the pixel values according to RescaleIntercept and RescaleIntercept of each frame
    and transposing for pyqtgraph format.
    Raises ValueError if file cannot be opened as a DICOM object
    Returns raw dcmfile, scaled and transposed pixeldata (or None), type of DICOM object.
    """
    # compile a list of valid files to read
    instancedict = removeBogusDICOMfiles(instancedict)

    dcmInfile = None
    pixeldataIn = None

    # Repair Mapping for MR; not correct for all scanner
    keymapping = [
                     ("0040,9096,0040,9224","0028,1052"), # Real World Value Intercept -> Rescale Intercept
                     ("0040,9096,0040,9225","0028,1053"), # Real World Value Slope -> Rescale Slope
    ]

    # Check if input data is as expected: MR needs 3D data
    if len(instancedict) == 1:
        ModeEnhanced = False
        ModeEnhanced = testIfEnhancedDICOM(instancedict[0])
        if ModeEnhanced:
            return prepareEnhancedInput(instancedict[0],headers_only=headers_only) # scaled and transposed

        if dcmInfile is None:
            filename = instancedict[0]
            dcmInfile = _readSingleImage(filename,headers_only=headers_only)
            if dcmInfile is None:
                # Not a dicom file
                raise ValueError("{} ERROR! {} is not a valid non-Enhanced DICOM object".format(logTag, filename))

            modality = dcmInfile.Modality
            
            if not headers_only:
                # need scaling for single slice, already done for series in pydicom_series, but not for some MR files
                if modality == 'CT' or modality == 'MR':
                    if not "RescaleIntercept" in dcmInfile: # in wrong place define for some MR files
                        dcmInfile.RescaleIntercept = readDICOMtag(keymapping[0][0],dcmInfile,0)
                        dcmInfile.RescaleSlope = readDICOMtag(keymapping[1][0],dcmInfile,0)

                    pixeldataIn = np.int16(np.transpose(dcmInfile.pixel_array.astype(int),(1,0)))
                    slope = dcmInfile.RescaleSlope
                    intercept = dcmInfile.RescaleIntercept
                    pixeldataIn = intercept + slope*pixeldataIn
                elif modality == 'MG' and getDICOMMode(dcmInfile) == stModeBTO:
                    print '!WARNING! MG BTO dataset! DICOM info is NOT properly adjusted, no scaling applied yet!'
                    pixeldataIn = np.transpose(dcmInfile.pixel_array,(0,2,1))
                elif modality == 'MG' or modality == 'CR':
                    pixeldataIn = dcmInfile.pixel_array.transpose()
                elif modality == 'RF': # fixme! 2D and 3D
                    pixeldataIn = dcmInfile.pixel_array.transpose()
                elif modality == 'US':
                    rgbmode = (dcmInfile.SamplesPerPixel == 3)
                    if not rgbmode:
                        if len(np.shape(dcmInfile.pixel_array)) == 2:
                            pixeldataIn = dcmInfile.pixel_array.transpose()
                        elif len(np.shape(dcmInfile.pixel_array)):
                            pixeldataIn = np.transpose(dcmInfile.pixel_array,(0,2,1))
                            pixeldataIn = pixeldataIn[0]
                    else:
                        # AS: this fix is needed in pydicom < 1.0; maybe solved in later versions?
                        try:
                            nofframes = dcmInfile.NumberOfFrames
                        except AttributeError:
                            nofframes = 1
                        if dcmInfile.PlanarConfiguration==0:
                            pixel_array = dcmInfile.pixel_array.reshape(nofframes, dcmInfile.Rows, dcmInfile.Columns, dcmInfile.SamplesPerPixel)
                        else:
                            pixel_array = dcmInfile.pixel_array.reshape(dcmInfile.SamplesPerPixel, nofframes, dcmInfile.Rows, dcmInfile.Columns)
                        if len(np.shape(pixel_array)) == 3: #2d rgb
                            pixeldataIn = pixel_array[:,:,0].transpose()
                            pixeldataInR = (pixel_array[:,:,0]).transpose()
                            pixeldataInG = (pixel_array[:,:,1]).transpose()
                            pixeldataInB = (pixel_array[:,:,2]).transpose()
                        elif len(np.shape(pixel_array)) == 4: #3d rgb
                            pixeldataIn = (pixel_array[-1,:,:,0]).transpose()
                            pixeldataInR = (pixel_array[-1,:,:,0]).transpose()
                            pixeldataInG = (pixel_array[-1,:,:,1]).transpose()
                            pixeldataInB = (pixel_array[-1,:,:,2]).transpose()
                        # remove rgb info
                        for y in range(dcmInfile.Rows):
                            for x in range(dcmInfile.Columns):
                                r = pixeldataInR[x,y]
                                g = pixeldataInG[x,y]
                                b = pixeldataInB[x,y]
                                ma = max(r,g,b)
                                mi = min(r,g,b)
                                if ma != mi:
                                    pixeldataIn[x,y] = 0

    else:
        path = os.path.dirname(instancedict[0])
        for ip in instancedict:
            if os.path.dirname(ip) != path:
                raise ValueError("{} ERROR! multiple would-be dicom files scattered over multiple dirs!".format(logTag))

        try:
            dcmInfile = dcmseries.read_files(path, True, readPixelData=False)[0]
            if not headers_only: # NOTE: Rescaling is already done pydicom_series, but maybe not for stupid MR
                pixeldataIn = np.transpose(dcmInfile.get_pixel_array(),(0,2,1))

        except:
            raise ValueError("{} ERROR! {} is not a valid non-Enhanced DICOM series".format(logTag, path))

    return dcmInfile,pixeldataIn,getDICOMMode(dcmInfile)
Esempio n. 4
0
def prepareInput(instancedict,headers_only,logTag="[prepareInput] "):
    """
    Reads inputfile as an EnhancedDICOM object; if an EnhancedDICOM object is detected, prepareEnhancedInput is called.
    Checks if the input is as expected: number of slices etc.
    If not headers_only, scaling the pixel values according to RescaleIntercept and RescaleIntercept of each frame
    and transposing for pyqtgraph format.
    Raises ValueError if file cannot be opened as a DICOM object
    Returns raw dcmfile, scaled and transposed pixeldata (or None), type of DICOM object.
    """
    # compile a list of valid files to read
    instancedict = removeBogusDICOMfiles(instancedict)

    dcmInfile = None
    pixeldataIn = None

    # Repair Mapping for MR; not correct for all scanner
    keymapping = [
                     ("0040,9096,0040,9224","0028,1052"), # Real World Value Intercept -> Rescale Intercept
                     ("0040,9096,0040,9225","0028,1053"), # Real World Value Slope -> Rescale Slope
    ]

    # Check if input data is as expected: MR needs 3D data
    if len(instancedict) == 1:
        ModeEnhanced = False
        ModeEnhanced = testIfEnhancedDICOM(instancedict[0])
        if ModeEnhanced:
            return prepareEnhancedInput(instancedict[0],headers_only=headers_only) # scaled and transposed

        if dcmInfile is None:
            filename = instancedict[0]
            dcmInfile = _readSingleImage(filename,headers_only=headers_only)
            if dcmInfile is None:
                # Not a dicom file
                raise ValueError("{} ERROR! {} is not a valid non-Enhanced DICOM object".format(logTag, filename))

            modality = dcmInfile.Modality
            
            if not headers_only:
                # need scaling for single slice, already done for series in pydicom_series, but not for some MR files
                if modality == 'CT' or modality == 'MR':
                    if not "RescaleIntercept" in dcmInfile: # in wrong place define for some MR files
                        dcmInfile.RescaleIntercept = readDICOMtag(keymapping[0][0],dcmInfile,0)
                        dcmInfile.RescaleSlope = readDICOMtag(keymapping[1][0],dcmInfile,0)

                    pixeldataIn = np.int16(np.transpose(dcmInfile.pixel_array.astype(int),(1,0)))
                    slope = dcmInfile.RescaleSlope
                    intercept = dcmInfile.RescaleIntercept
                    pixeldataIn = intercept + slope*pixeldataIn
                elif modality == 'MG' and getDICOMMode(dcmInfile) == stModeBTO:
                    print('!WARNING! MG BTO dataset! DICOM info is NOT properly adjusted, no scaling applied yet!')
                    pixeldataIn = np.transpose(dcmInfile.pixel_array,(0,2,1))
                elif modality == 'MG' or modality == 'CR' or modality == 'DX':
                    pixeldataIn = dcmInfile.pixel_array.transpose()
                elif modality == 'RF': # fixme! 2D and 3D
                    pixeldataIn = dcmInfile.pixel_array.transpose()
                elif modality == 'US':
                    rgbmode = (dcmInfile.SamplesPerPixel == 3)
                    if not rgbmode:
                        if len(np.shape(dcmInfile.pixel_array)) == 2:
                            pixeldataIn = dcmInfile.pixel_array.transpose()
                        elif len(np.shape(dcmInfile.pixel_array)):
                            pixeldataIn = np.transpose(dcmInfile.pixel_array,(0,2,1))
                            pixeldataIn = pixeldataIn[0]
                    else:
                        # AS: this fix is needed in pydicom < 1.0; maybe solved in later versions?
                        try:
                            nofframes = dcmInfile.NumberOfFrames
                        except AttributeError:
                            nofframes = 1
                        if dcmInfile.PlanarConfiguration==0:
                            pixel_array = dcmInfile.pixel_array.reshape(nofframes, dcmInfile.Rows, dcmInfile.Columns, dcmInfile.SamplesPerPixel)
                        else:
                            pixel_array = dcmInfile.pixel_array.reshape(dcmInfile.SamplesPerPixel, nofframes, dcmInfile.Rows, dcmInfile.Columns)

                        # force using only the RED channel in RGB.
                        if US_RGB_USE_RED == True:
                            if len(np.shape(pixel_array)) == 3: #2d rgb
                                pixeldataIn = pixel_array[:,:,0].transpose()
                            elif len(np.shape(pixel_array)) == 4: #3d rgb
                                pixeldataIn = (pixel_array[-1,:,:,0]).transpose()
                        else:
                            # remove all data where there is a difference between R,G,B
                            if len(np.shape(pixel_array)) == 3: #2d rgb
                                pixeldataIn = pixel_array[:,:,0].transpose()
                                pixeldataInR = (pixel_array[:,:,0]).transpose()
                                pixeldataInG = (pixel_array[:,:,1]).transpose()
                                pixeldataInB = (pixel_array[:,:,2]).transpose()
                            elif len(np.shape(pixel_array)) == 4: #3d rgb
                                pixeldataIn = (pixel_array[-1,:,:,0]).transpose()
                                pixeldataInR = (pixel_array[-1,:,:,0]).transpose()
                                pixeldataInG = (pixel_array[-1,:,:,1]).transpose()
                                pixeldataInB = (pixel_array[-1,:,:,2]).transpose()
                            # remove rgb info
                            for y in range(dcmInfile.Rows):
                                for x in range(dcmInfile.Columns):
                                    r = pixeldataInR[x,y]
                                    g = pixeldataInG[x,y]
                                    b = pixeldataInB[x,y]
                                    ma = max(r,g,b)
                                    mi = min(r,g,b)
                                    if ma != mi:
                                        pixeldataIn[x,y] = 0

    else:
        path = os.path.dirname(instancedict[0])
        for ip in instancedict:
            if os.path.dirname(ip) != path:
                raise ValueError("{} ERROR! multiple would-be dicom files scattered over multiple dirs!".format(logTag))

        try:
            dcmInfile = dcmseries.read_files(path, True, readPixelData=False)[0]
            if not headers_only: # NOTE: Rescaling is already done pydicom_series, but maybe not for stupid MR
                pixeldataIn = np.transpose(dcmInfile.get_pixel_array(),(0,2,1))

        except Exception as e:
            raise ValueError("{} ERROR! {} is not a valid non-Enhanced DICOM series".format(logTag, path))

    return dcmInfile,pixeldataIn,getDICOMMode(dcmInfile)