Source code for OCT_GUI.Algorithms.RefinementRPE.GraphCutSegmentation

""" 
GraphCutSegmentation: Multithreaded RPE refinement execution
----------------------------------------------------------------------
PRLEC Framework for OCT Processing and Visualization 
"""
# This framework evolved from a collaboration of:
# - Research Laboratory of Electronics, Massachusetts Institute of Technology, Cambdrige, MA, US
# - Pattern Recognition Lab, Friedrich-Alexander-Universitaet Erlangen-Nuernberg, Germany
# - Department of Biomedical Engineering, Peking University, Beijing, China
# - New England Eye Center, Tufts Medical Center, Boston, MA, US
# v1.0: Updated on Mar 20, 2019
# @author: Daniel Stromer - EMAIL:daniel.stromer@fau.de
# Copyright (C) 2018-2019 - Daniel Stromer
# PRLE is developed as an Open Source project under the GNU General Public License (GPL) v3.0.
import numpy as np
from igraph import *
import threading
import Algorithms.RefinementRPE.BuildRPEGraph as gm_rpe
from Algorithms.RefinementRPE.InpaintSegmentation import inpaint
shortestPath={}
y_offset_dict = {}

[docs]class thread_pipeline (threading.Thread): """ Threaded Graph-Cut pipeline for RPE Refinement Global Parameters ---------------- shortestPath: dict storing the latest shortest path as input for next iteration y_offset_dict: dict storing the latest y_offset as input for next iteration -> runtime minimization """ def __init__(self, threadID ,volume_slice, gradient_slice, prior_shortest_path, scaling, UPORDOWN, mode, dictParameters): """ Initializing Pipeline. Parameters ---------- threadID: scalar slice number volume_slice: numpy array 2D slice that will be processed gradient_slice: numpy array 2D preprocessed gradient slice prior_shortest_path: numpy array 2D shortest path of predecessor scaling: scalar scaling factor of image up or downscaling UPORDOWN: string direction of algorithm (up/down) - important for storing current shortest path and y offset mode: string 'RPE', or 'ILM' dictParameters: dictionary parameters from parameters.txt """ threading.Thread.__init__(self) self.threadID = threadID self.volume_slice = volume_slice self.gradient_slice = gradient_slice self.prior_shortest_path = prior_shortest_path self.UPORDOWN = UPORDOWN self.scaling = scaling self.mode = mode self.dictParameters = dictParameters
[docs] def run(self): """ Execute Algorithm """ self.runPipeline()
[docs] def join(self): """ Returns resulting segmentation slice and thread id """ threading.Thread.join(self) return self.segmentation, self.threadID
[docs] def runPipeline(self): """ Pipeline implementation """ #restore y_offset y_offset = y_offset_dict[-1] if('down' is self.UPORDOWN): y_offset = y_offset_dict[1] #Calculate Graph and shortest path graph, endnode, y_offset = gm_rpe.getRPEGraph(self.gradient_slice, self.prior_shortest_path, self.scaling, y_offset) shortest_path = np.asarray(graph.get_shortest_paths(v=0, to=endnode, weights = 'weight')) if(shortest_path.size == 0): shortest_path = self.prior_shortest_path #Inpaint segmentation self.segmentation = inpaint(self.volume_slice,shortest_path, y_offset,self.mode, self.dictParameters) #storage variables for next iteration if('down' is self.UPORDOWN): shortestPath[1] = shortest_path.flatten() y_offset_dict[1] = y_offset else: shortestPath[-1] = shortest_path.flatten() y_offset_dict[-1] = y_offset
[docs]def execute_graphcut(oct_volume, gradient_volume, scaling, mode, dictParameters): """ Execute Graph-Cut algorithm. Parameters ---------- oct_volume: numpy array 2D/3D list of original volume slices for inpainting the results gradient_volume: numpy array 2D/3D preprocessed gradient_volume scaling: scalar, optional scale factor for image down or upscaling mode = string mode ='RPE' segments RPE, 'ILM' the inner limiting membrane dictParameters: dictionary parameters from parameters.txt Return ------ result: numpy array 2D/3D resulting segmented volume with rpe inpainted as value 127 """ #result array result = np.zeros((len(oct_volume),oct_volume[0].shape[0], oct_volume[0].shape[1])).astype("uint8") index = 0 center_slice = int(len(gradient_volume)/2) #iterate over volume starting from central slice while center_slice-index >= 0 or center_slice+index < len(gradient_volume): #time emasure - message at every 20th processed slice #if(index % 10 == 0): # print(str(index),'/',str(int(len(gradient_volume)/2))) #process initial slice (central) if index == 0: #compute graph and shortest path initial_graph, endnode, y_offset = gm_rpe.getRPEGraph(gradient_volume[center_slice], None, scaling,None ) shortestPath[1] = np.asarray(initial_graph.get_shortest_paths(v=0, to=endnode, weights = 'weight')).flatten() shortestPath[-1] = shortestPath[1] if(shortestPath[1].size == 0): raise Exception('no path found') #store offset y_offset_dict[1] = y_offset y_offset_dict[-1] = y_offset #inpaint shortest path result[center_slice] = inpaint(oct_volume[center_slice],shortestPath[1], y_offset, mode, dictParameters) #unflatten slice index += 1 continue #run through volume threads = [] if (center_slice-index) >= 0: thread = thread_pipeline((center_slice-index),oct_volume[(center_slice-index)], gradient_volume[(center_slice-index)], shortestPath[1],scaling, 'down', mode, dictParameters) thread.start() threads.append(thread) if (center_slice+index) < len(gradient_volume): thread = thread_pipeline((center_slice+index),oct_volume[(center_slice+index)], gradient_volume[(center_slice+index)], shortestPath[-1],scaling, 'up', mode, dictParameters) thread.start() threads.append(thread) # get processed slices and wait until all processes are finished for t in threads: result_part, t_id = t.join() result[t_id] = result_part index = index + 1 # stop when finished if(center_slice+index >= len(gradient_volume) and center_slice+index < 0): break return result