Exemplo n.º 1
0
    def DiscretizeImage(self, maxVal=1, minVal=0):

        '''
        This function takes an image and finds the median pixel value, then compares
        the value of each pixel to the median.  If a pixel is greater than or equal
        to the median, the pixel value is set to a user supplied value.  If the pixel
        value is less than the median, the pixel value is set to another user
        supplied value.

        :param maxVal: the high value use for pixels
        :param minVal: the low value to use for pixels
        :return:
        '''
        gui = shareGui.getGui()

        if len(self.channels) > 1:
            answer = gui.showMessage('Error', 'Discretization can only be preformed on grayscale images.\nThe current image has the following bands: '
                                     '\n{}\nPress \'Ok\' to continue segmentation without discretizing, or \'Cancel\' to abort.'.format(self.channels), 'warning')
            if answer == 0:
                pass
            if answer == 1:
                return False

        shareGui.getGui().updateLog('Discretizing image')

        temp = numpy.zeros(self.size)

        for i in range(self.size):
            temp[i] = self.data[i]

        sorted_values = sorted(self.data)
        pixel_values = self.pixels.GetPixelArray()

        if self.size % 2 == 1:
            median = sorted_values[((self.size + 1) / 2) - 1]
        else:
            median = float((sorted_values[(self.size + 1) / 2] + sorted_values[(self.size - 1) / 2]) / 2.0)

        for i in range (self.height):
            for j in range(self.width):
                stride = (self.width * i) + j
                if temp[stride] >= median:
                    temp[stride] = maxVal
                    pixel_values[stride] = maxVal
                else:
                    temp[stride] = minVal
                    pixel_values[stride] = minVal

        newFile= '{}{}_discretized.{}'.format(self.segmentDir, self.imageFile.split('.')[0], self.fileFormat)
        self.WriteNewImage(temp, newFile)
        gui.returnDiscretized(newFile)
        self.__init__(newFile)
        self.ReadImage()
        return True
Exemplo n.º 2
0
    def SmoothImage(self, iterations):

        for i in range(iterations):
            shareGui.getGui().updateLog('Smoothing iteration #%d' % self.iteration)
            newImage = self.dataImage.filter(ImageFilter.SMOOTH_MORE)
            self.iteration += 1

        self.dataImage = newImage
        self.data = self.dataImage.getdata()
        self.pixels = PixelArray(self.width, self.height, self.data)

        return
Exemplo n.º 3
0
    def displayPlots(self):

        figures = plt.get_fignums()
        histogramFignums = []

        for figure in figures:
            if figure % 2 == 0:
                histogramFignums.append(figure)

        histogramFigures = list(map(plt.figure, histogramFignums))

        shareGui.getGui().addPlots(histogramFigures, 1)
        return
Exemplo n.º 4
0
    def CreateMatrix(
        self, sigmaI, sigmaX
    ):  # Creates a process pool and distributes their work to all pixels, to calculate weight matrix

        gui = shareGui.getGui()
        cpus = mp.cpu_count()
        # At most, use all but one core for processes
        poolCount = int(cpus - (math.ceil(cpus * 0.1)))
        args = [(self, sigmaI, sigmaX, i) for i in range(self.numPixels)]
        gui.updateLog("Cpu's on machine: %d" % cpus)
        gui.updateLog("Cpu's to process weight matrix: %d" % poolCount)

        pool = mp.Pool(processes=poolCount)
        gui.updateLog("Mapping pool processes")
        tempData = pool.map(unwrap_CreateMatrix, args)
        pool.close()
        pool.join()

        for (
            pixelList
        ) in tempData:  # This puts the data of each pixel, returned from each seperate process, into self.data
            for pixel in pixelList:
                self.data[pixel[1]] = pixel[0]

        self.matrix = numpy.matrix(self.data.reshape(self.columns, self.rows), numpy.float64)
        gui.updateLog("Weight Matrix shape: {}".format(self.matrix.shape))
        return
Exemplo n.º 5
0
def getFinalSegments(branches, segmentDir):

    #Goes through all pixel data from the segmentation and specifies which files correspond to final-size segments

    gui = shareGui.getGui()

    dirs = next(os.walk(segmentDir))[1]
    allPixelPaths = []
    finalSegments = [] #each entry is a numpy array (segment) containing pixel indices
    finalData = [] #each entry is a numpy array (segment) containing pixel values
    finalPaths = [] #each entry is a path string to the pixel data of a final segment

    #Finding all pixel files
    for dir in dirs:
        if dir.find('pixels_') != -1:
            dir = '/{}'.format(dir)
            pixelPaths = next(os.walk('{}{}'.format(segmentDir, dir)))[2]
            pixelPaths.sort()
            for n in range(len(pixelPaths)):
                pixelPaths[n] = segmentDir + dir + '/' + pixelPaths[n]
            allPixelPaths.extend(pixelPaths)

    #checking to see which pixel files correspond to final-size segments
    for n in range(len(branches)):
        if(branches[n] == 0):
            finalPaths.append(allPixelPaths[n])
            finalSegments.append((numpy.load(allPixelPaths[n]))['locations'])
            finalData.append((numpy.load(allPixelPaths[n]))['pixels'])

    finalSegments = numpy.array(finalSegments)
    gui.updateLog('Algorithm finished with {} final-size segments'.format(len(finalSegments)))

    return finalSegments, finalData, finalPaths
Exemplo n.º 6
0
    def displayPlots(self):

        figures = plt.get_fignums()
        scatterFignums = []

        for figure in figures:
            if figure % 2 == 1:
                #on every iteration, the scatter plot is created first, and fignums starts at 1, so if
                #the current fig_num % 2 = 1, then that figure is a scatter plot
                scatterFignums.append(figure)

        #scatterFigures is a list of matplotlib figures/their emory locations
        scatterFigures = list(map(plt.figure, scatterFignums))

        #The 0 passed to gui.addPlots() indicates that the list being passed is a list of scatters
        shareGui.getGui().addPlots(scatterFigures, 0)
        return
Exemplo n.º 7
0
    def CreateMatrix(self, weights):

        for i in range(self.size):
            self.data[i] = weights[i].sum()

        gui = shareGui.getGui()
        temp = numpy.diag(self.data)
        self.matrix = numpy.matrix(temp, numpy.float)
        gui.updateLog("Diagonal Matrix shape: {}".format(self.matrix.shape))

        return
Exemplo n.º 8
0
def finish(segmentData, maxVar, maxInt):

    #finish up the segmentation, return are necessary final data

    branches, segmentDir, image, dimensions = segmentData[0], segmentData[1], segmentData[2], segmentData[3]
    gui = shareGui.getGui()

    finalSegments, finalData, finalPaths = getFinalSegments(branches, segmentDir)
    finalBackground = findBackground(finalData, maxVar, maxInt)
    finalMap = mapBorders(segmentDir, dimensions, finalSegments, finalBackground)
    cleanup(segmentDir, finalPaths)

    results = [finalSegments, finalBackground, finalMap]
    return results
Exemplo n.º 9
0
def toMAPS(segments, backgrounds, dimensions, segmentDir, imageName):

    #takes all the final data gathered from finalize.py and turns it into hdf5 files, in the format that MAPS expected for ROIs

    gui = shareGui.getGui()
    gui.updateLog('Exporting segment data to MAPS ROIs')
    imageSize = dimensions[0]*dimensions[1]
    pixelIds = numpy.arange(imageSize)
    scanNumber = imageName.split('_')[1].split('.')[0]

    fgSegments = segments[backgrounds==0] #take all indices from 'segments' where the corresponding index in 'backgrounds is 0
    bgSegments = segments[backgrounds==1]
    numFgFiles = int(math.ceil(float(len(fgSegments))/16.0)) #MAPS supports only 16 distinct ROI's in one dataset
    numBgFiles = int(math.ceil(float(len(bgSegments))/16.0)) #so this will find how mant datasets are needed to account for all segs
    fgRois = [numpy.zeros(imageSize, int) for _ in range(numFgFiles)] #list of arrays, each the size of the image to be filled with ints 1-16
    bgRois = [numpy.zeros(imageSize, int) for _ in range(numBgFiles)]
    segs = [fgSegments, bgSegments]
    rois = [fgRois, bgRois]

    for i in range(len(rois)):
        regionNum = 1
        fileNum = 0
        for j in range(len(segs[i])):
            if(regionNum > 16):
                regionNum = 1
                fileNum += 1
            region = segs[i][j]
            for index in region:
                rois[i][fileNum][index] = regionNum
            regionNum += 1

        f,b=0,0 #current foreground segment, current background segment
        for n in range(len(rois[i])):
            nextData = rois[i][n].reshape(dimensions) #next segment
            if i==0:
                file = h5py.File('{}/{}_roi_FG{}.h5'.format(segmentDir, scanNumber, f), 'w') #create a new hdf5 file (should be changed in the future, only one total is really needed
                file.create_dataset('MAPS_ROIS/fg_roi_{}'.format(n), data=nextData) #create a MAPS group, and add a dataset containing the next segment
                file.create_dataset('MAPS_ROIS/pixel_id', data=pixelIds)
                f+=1
            elif i==1:
                file = h5py.File('{}/{}_roi_BG{}.h5'.format(segmentDir, scanNumber, b), 'w')
                file.create_dataset('MAPS_ROIS/bg_roi_{}'.format(n), data=nextData)
                file.create_dataset('MAPS_ROIS/pixel_id', data=pixelIds)
                b+=1

    gui.updateLog('Saved ROIs to MAPS compatible HDF5 formats'.format(segmentDir))

    return
Exemplo n.º 10
0
def findBackground(finalData, maxVar, maxInt):

    #flags segments as background or foreground (this will need some work, is farily simple at the moment)

    gui = shareGui.getGui()
    gui.updateLog('Finding background segments background segments:')
    gui.updateLog('Using variance threshold of {}'.format(maxVar))
    gui.updateLog('Using intensity threshold of {}'.format(maxInt))

    background = numpy.zeros(len(finalData), dtype = int)

    #if the current segment has a variance and mean intensity below both of the threshold values, it is set to '1' in the background list,
    #indicating that the segment at that index is a background segment
    for n in range(len(finalData)):
        if(numpy.var(finalData[n]) < maxVar and numpy.mean(finalData[n]) < maxInt):
            background[n] = 1

    return background
Exemplo n.º 11
0
def workSegment(haltThreshold, weightMatrix, data, divideType, displayPlots, cutNumber, paths, imageNumber, image):

    #Performs the algorithm

    gui = shareGui.getGui()
    pixel_path, matrix_path = paths[0], paths[1]
    prev_pixel_path, prev_matrix_path = paths[2], paths[3]
    imageSize = data.GetImageSize()
    imageData = data.GetImageData()
    pixelLocations = numpy.arange(imageSize)

    #initial segmentation-----------------------
    if (cutNumber == 1):
        pixelLength = imageSize
        divideData = imageData

    #each subsequent segmentation---------------
    else:
        # Get the name of the file without the file extension.
        filename = os.path.splitext(image)[0]

        gui.updateLog("\nWorking on %s" % image)

        # Load the image pixels and pixel locations into arrays
        newPixelsArrays = numpy.load(prev_pixel_path + "/" + filename + ".npz")
        newPixels = newPixelsArrays['pixels']
        divideData = newPixels
        pixelLocations = newPixelsArrays['locations']
        pixelLength = len(newPixels)
        gui.updateLog("Reading array of size %d from file %s.npz" % (newPixels.shape[0], filename))

        #If the size of the loaded image is below the halting threshold, do not segment,
        # and return (ending this branch of the segmentation)
        if(len(newPixels) < haltThreshold):
            gui.updateLog('Skipping file %s: segment size is below specified halting threshold.' % image)
            #return value of '0' means the segmentation on this branch has ended
            return(0)

        # Load the matrix data and create a new WeightMatrix
        temp = numpy.matrix(numpy.load(prev_matrix_path + "/" + filename + ".npy"))
        weightMatrix = WM(temp.shape[0], temp.shape[1])
        weightMatrix.SetMatrix(temp)
        gui.updateLog("Reading matrix of size %dx%d from file %s.npy" % (temp.shape[0], temp.shape[1], filename))

    #Create a new diagonal matrix.
    gui.updateLog("Creating diagonal matrix")
    if (cutNumber > 1):
        diagonalMatrix = DM(len(newPixels), 1) #had to change .size to len() to count multi-dimensional array items properly
    else:
        diagonalMatrix = DM(data.width, data.height)
    diagonalMatrix.CreateMatrix(weightMatrix.GetMatrix())

    gui.updateLog('Solving for eigenvalues')
    secondVec = solveEigenVectors(diagonalMatrix.GetMatrix(), weightMatrix.GetMatrix())


    # Divide the image into two using the second smallest eigenvector.  There are three options for dividing the image.
    # 1) All pixels corresponding to values in the eignevector greater than zero will be in one image,
    #    while all pixels corresponding to values in the eigenvector less than zero will be in the
    #    other image.
    #
    # 2) As option 1, except that eigenvector values will be compared to the median value of the eignevector.
    #
    # 3) Several different dividing values are tried.  The resulting ratio (edges in segment one / edges removed) +
    #    (edges in segment two / edges removed) is minimized.
    if divideType == 0:
        dividingValue = 0
        numsteps = 1


    if divideType == 1:
        dividingValue = numpy.median(secondVec, axis=0)
        numsteps = 1

    if divideType == 2:
        numSteps = int(secondVec.size / pow(math.log10(secondVec.size), 2))
        stepSize = (numpy.amax(secondVec) - numpy.amin(secondVec)) / numSteps
        if numSteps < 2:
            numSteps = 1
            dividingValue = numpy.median(secondVec, axis=0)
        else:
            maxVal = numpy.amax(secondVec)
            minVal = numpy.amin(secondVec)
            stepSize = (maxVal - minVal) / numSteps
            dividingValue = maxVal

    gui.updateLog('Dividing image pixel values')
    segmentInfo = DivideImage(secondVec, divideData, imageSize, pixelLength, pixelLocations, dividingValue)
    segmentOne = segmentInfo['segOne']
    segmentTwo = segmentInfo['segTwo']
    posIndices = segmentInfo['posIndices']
    negIndices = segmentInfo['negIndices']

    # Calculate the weights of the edges that were removed from the image.
    # Reduce the weight matrix to two new matrices, one for each image segment.
    cutSize, matrixOne, matrixTwo = weightMatrix.ReduceMatrix(posIndices, negIndices)
    gui.updateLog("Size of cut = %f" % cutSize)


    if divideType == 2:
        prevCutSize = cutSize
        prevSegInfo = segmentInfo
        prevMatrixOne = matrixOne
        prevMatrixTwo = matrixTwo

        #continue until smallest cut is found
        for i in range(numSteps - 1):
            dividingValue = dividingValue - stepSize
            segmentInfo = DivideImage(secondVec, divideData, imageSize, pixelLength, pixelLocations, dividingValue)
            segmentOne = segmentInfo['segOne']
            segmentTwo = segmentInfo['segTwo']
            posIndices = segmentInfo['posIndices']
            negIndices = segmentInfo['negIndices']

            # Calculate the weights of the edges that were removed from the image.
            # Reduce the weight matrix to two new matrices, one for each image segment.
            #edgeSum, matrixOne, matrixTwo = weightMatrix.ReduceMatrix(posIndices, negIndices)
            cutSize, matrixOne, matrixTwo = weightMatrix.ReduceMatrix(posIndices, negIndices)

            if cutSize < prevCutSize:
                prevCutSize = cutSize
                prevMatrixOne = matrixOne
                prevMatrixTwo = matrixTwo
                prevSegInfo = segmentInfo

        cutSize = prevCutSize
        matrixOne = prevMatrixOne
        matrixTwo = prevMatrixTwo
        gui.updateLog("Size of choosen cut = %f" % cutSize)
        segmentInfo = prevSegInfo
        segmentOne = segmentInfo['segOne']
        segmentTwo = segmentInfo['segTwo']
        posIndices = segmentInfo['posIndices']
        negIndices = segmentInfo['negIndices']

    #Progress output to gui.
    gui.updateLog("Pixels in segment one = %d" % len(posIndices))
    gui.updateLog("Pixels in segment two = %d" % len(negIndices))
    gui.updateLog("Matrix one size = %dx%d" % (matrixOne.GetMatrix().shape[0], matrixOne.GetMatrix().shape[1]))
    gui.updateLog("Matrix two size = %dx%d" % (matrixTwo.GetMatrix().shape[0], matrixTwo.GetMatrix().shape[1]))

    # Create two arrays of pixels from the original image using
    # the indices returned from DivideImage.
    posPixels = numpy.take(divideData, posIndices, axis=0)
    negPixels = numpy.take(divideData, negIndices, axis=0)


    #Final output to image files
    #Segment One-----------------------------------------------
    filename = "/segment_%d_%d" % (cutNumber, imageNumber)
    # Save the pixel locations for each new pixel array.
    posLocations = numpy.take(pixelLocations, posIndices)
    gui.updateLog("Writing pixels file {}.npz".format(filename))
    posArrays = {'pixels':posPixels, 'locations':posLocations}
    numpy.savez(pixel_path + "/%s.npz" % filename, **posArrays)
    gui.updateLog("Writing matrix file {}.npy".format(filename))
    numpy.save(matrix_path + "/%s.npy" % filename, matrixOne.GetMatrix())

    imageNumber += 1

    #Segment Two-----------------------------------------------
    filename = "/segment_%d_%d" % (cutNumber, imageNumber)
    negLocations = numpy.take(pixelLocations, negIndices)
    gui.updateLog("Writing pixels file {}.npz".format(filename))
    negArrays = {'pixels':negPixels, 'locations':negLocations}
    numpy.savez(pixel_path + "/%s.npz" % filename, **negArrays)
    gui.updateLog("Writing matrix file {}.npy".format(filename))
    numpy.save(matrix_path + "/%s.npy" % filename, matrixTwo.GetMatrix())


    #Displays scatter plots and histograms in the results panel in the gui if selected (probably to be removed)
    if(displayPlots):
        scatPlt = ScatterPlot("Original Image", secondVec)
        histPlt = HistogramPlot("Original image", secondVec)
        if(cutNumber > 1):
            scatPlt.AddPlot(image, secondVec)
            histPlt.AddPlot(image, secondVec)

    #return value of '1' means the segmentation is still going on this branch (the current working segment will be segmented again)
    return(1)
Exemplo n.º 12
0
def start(imagePath, divideType, maxPixelDistance, smoothValue, displayPlots, haltThreshold, numImages):

    #initiates the segmentation; makes directories, loads image data, builds weight matrix, etc.

    '''
    :param divideType = Set the type of dividing to be done.
        0 - divide the image using the value of zero
        1 - divide the image using the median value of the eignevector
        2 - try vector.size / (log(vector.size))^2 evenly spaced dividing points
    :param maxPixelDistance = how close 2 pixels must be to have a nonzero weight between them
    :param smoothValue = iterations of smoothing (smoothing not called if smoothValue = 0)
    :param displayPlots = self explanatory boolean
    :param haltThreshold = this is the pixel size that will end the cutting of a segment
    :return segmentDir or None
    '''

    gui = shareGui.getGui()
    imageDir, imageFile = os.path.split(imagePath)
    imageName, extension = imageFile.split('.')
    #creates two directories titled as the current date > the original image name, to save all output
    segmentDir = '{}/{}_segmentation/{}'.format(imageDir, time.strftime("%m-%d-%Y"), imageName)
    dateDir = os.path.split(segmentDir)[0]
    suffix = 1

    #This while loop ensures no segmentations of a common image are overwritten
    while(os.path.isdir(segmentDir) == True):
        segmentDir = '{}/{}_segmentation/{}_{}'.format(imageDir, time.strftime("%m-%d-%Y"), imageName, suffix)
        suffix += 1

    #Creates the segmentation directory
    if not os.path.isdir(segmentDir):
        try:
            os.makedirs(segmentDir)
        except OSError:
            if not os.path.isdir(segmentDir):
                raise

    gui.updateLog('------------------------ Starting on image {} ------------------------\n'.format(imageFile))
    gui.updateLog('Creating segmentation directory at: %s' % segmentDir)
    gui.updateLog('Using image located at: %s' % imagePath)
    gui.updateLog('Using divide type of %d' % divideType)
    gui.updateLog('Using maximum pixel distance of %d' % maxPixelDistance)
    gui.updateLog('Using halting threshold of %d' % haltThreshold)

    #loads selected image into imagedata object, depending on whether the user
    # selected data is a numpy array file (user opened a hdf5), or a nromal image file
    if extension == 'npz':
        data = ImageArrayData(imagePath, segmentDir)
    else:
        data = ImageFileData(imagePath, segmentDir)
    gui.updateLog('\n--- Reading Image ---\n')
    data.ReadImage()

    if smoothValue > 0:
        data.SmoothImage(smoothValue)

    #Setup
    gui.advanceProgressBar(10/numImages)
    imageData = data.GetImageData()
    imageSize = data.GetImageSize()
    dimensions = data.GetImageDimensions()
    channels = data.GetChannels()
    fileFormat = data.GetFileFormat()
    # Create an array of pixel locations, location=sqrt(x^2 + y^2)
    locationValues = data.pixels.CreateLocationArray()
    sigmaI = numpy.var(imageData)
    sigmaX = numpy.var(locationValues)

    #Output image properties
    gui.updateLog("Image mode is %s" % data.GetImageMode())
    gui.updateLog("Data format is %s" % fileFormat)
    gui.updateLog("Data channels are: {}".format(channels))
    gui.updateLog("Number of image pixels = %d" % imageSize)
    gui.updateLog("Image width = %d, image height = %d" % dimensions)
    gui.updateLog("Intensity variance = %f" % sigmaI)
    gui.updateLog("Location variance = %f" % sigmaX)
    #All of these lines change the graphic of the gui's progress bar
    gui.advanceProgressBar(10/numImages)

    #create weight matrix
    gui.updateLog("\n--- Creating weight matrix ---\n")
    weightMatrix = WM(data.size, data.size)
    weightMatrix.SetPixelData(data.GetPixels(), maxPixelDistance)

    #time weight matrix build
    t0 = time.time()
    weightMatrix.CreateMatrix(sigmaI, sigmaX)
    t2 = '%.2f' % (time.time() - t0)
    gui.updateLog('Parallel building of weight matrix took {} seconds'.format(t2))
    gui.advanceProgressBar(30/numImages)

    #Starts segmentation
    gui.updateLog('\n--- Starting segmentation---\n')
    t0 = time.time()
    branches = SegmentImage(weightMatrix, data, segmentDir, divideType, displayPlots, haltThreshold, numImages)
    t2 = '%.2f' % (time.time() - t0)
    gui.updateLog('\n\n--- Segmentation completed (took {} seconds) ---\n\n'.format(t2))

    gui.setSegmentPath(segmentDir)
    gui.setRawData(list(imageData))
    #This is the ultimate return back to the gui, a list of data resultant from the segmentation, for the gui to then pass to finalize.py and finalize
    segmentData = [branches, segmentDir, data, dimensions]
    return(segmentData)