def main(): ( output_data_path, post_processing_data_path, post_composition_data_path, reduced_model_data_path, ) = get_data_paths_from_args(inputs=3) rot_mat = np.array([[0, 0, -1], [-1, 0, 0], [0, 1, 0]]) model = np.load(reduced_model_data_path / "reduced_model.npz")["arr_0"] if not output_data_path.exists(): output_data_path.mkdir(parents=True, exist_ok=True) graph = nx.read_graphml(post_composition_data_path / "tree.graphml") gen_split_obj(output_data_path / "splits_no_post_processing.obj", graph, rot_mat=rot_mat, model_shape=model.shape) graph = nx.read_graphml(post_processing_data_path / "tree.graphml") gen_split_obj(output_data_path / "splits.obj", graph, rot_mat=rot_mat, model_shape=model.shape)
def get_input(): output_data_path, tree_input_path = get_data_paths_from_args() classification_config = parse_classification_config() trees: List[nx.Graph] = [] for tree_path in Path(tree_input_path).glob("*/tree.graphml"): trees.append(nx.read_graphml(tree_path)) return output_data_path, trees, classification_config
def main(): """ Executes procedures in right order """ output_data_path, input_data_path = get_data_paths_from_args() lobe_graph_dict = build_connection_matrix(input_data_path) plot_connection_status(output_data_path / "connection-status.png", lobe_graph_dict)
def get_input(): output_data_path, tree_input_path = get_data_paths_from_args(inputs=1) classification_config = parse_classification_config() trees: List[nx.Graph] = [] ignored_patients = get_ignored_patients() print(ignored_patients) for tree_path in Path(tree_input_path).glob("*/tree.graphml"): if tree_path.parent.name not in ignored_patients: trees.append(nx.read_graphml(tree_path)) return output_data_path, trees, classification_config
def get_input(): output_data_path, tree_input_path = get_data_paths_from_args() trees: List[List[nx.Graph]] = [] for tree_path in Path(tree_input_path).glob("*"): pair = [] for name in ["tree.graphml", "tree_gt.graphml"]: if (tree_path / name).exists(): pair.append(nx.read_graphml(tree_path / name)) trees.append(pair) classification_config = parse_classification_config() return output_data_path, trees, classification_config
def get_input(): output_data_path, tree_input_path, render_path = get_data_paths_from_args( inputs=2) classification_config = parse_classification_config() for cc_dict in classification_config.values(): if "clustering_endnode" not in cc_dict: cc_dict["clustering_endnode"] = False trees: List[nx.Graph] = [] ignored_patients = get_ignored_patients() for tree_path in Path(tree_input_path).glob("*/tree.graphml"): if tree_path.parent.name not in ignored_patients: trees.append(nx.read_graphml(tree_path)) return output_data_path, trees, classification_config, render_path
def main(): output_data_path, tree_input_data_path, reduced_model_data_path = get_data_paths_from_args( inputs=2) patient_id = tree_input_data_path.parts[-1] if tree_input_data_path.is_dir and output_data_path.is_dir: coord_file_path = tree_input_data_path / "final_coords.npz" edges_file_path = tree_input_data_path / "final_edges.npz" coord_attributes_file_path = tree_input_data_path / "coord_attributes.npz" edge_attributes_file_path = tree_input_data_path / "edge_attributes.npz" else: sys.exit( f"ERROR: either {tree_input_data_path} or {output_data_path} do not exist!" ) if not reduced_model_data_path.exists(): print(reduced_model_data_path) sys.exit("ERROR: stage-02 needed") reduced_model = np.load(reduced_model_data_path / "reduced_model.npz")["arr_0"] print(np.unique(reduced_model)) reduced_model[reduced_model >= 7] = 0 # Remove all voxels 7, 8 and 9 since these are veins/arteries and not useful in classification print(np.unique(reduced_model)) np_coord = np.load(coord_file_path)["arr_0"] np_edges = np.load(edges_file_path)["arr_0"] np_coord_attributes = np.load(coord_attributes_file_path, allow_pickle=True)["arr_0"] np_edges_attributes = np.load(edge_attributes_file_path, allow_pickle=True)["arr_0"] # create empty graphs graph = nx.Graph(patient=patient_id) # compose graphs dic_coords = create_nodes(graph, np_coord, np_coord_attributes, reduced_model) dic_edges = create_edges(graph, np_edges, dic_coords, np_edges_attributes) # set levels to the graph graph = set_level(graph) # level 2 does not belong to a lobe graph = set_attribute_to_node(graph, ("level", 2), ("lobe", 0)) show_stats(graph, patient_id) nx.write_graphml(graph, output_data_path / "tree.graphml")
def main(): output_data_path, reduced_model_data_path, tree_data_path = get_data_paths_from_args( inputs=2) model = np.zeros( np.load(reduced_model_data_path / "reduced_model.npz")["arr_0"].shape) tree = nx.read_graphml(tree_data_path / "tree.graphml") for parent_id, child_ids in nx.bfs_successors(tree, "0"): parent_node = tree.nodes[parent_id] parent_point = get_point(parent_node) for child_id in child_ids: child_point = get_point(tree.nodes[child_id]) fill_line(model, parent_point, child_point, max(2, parent_node["group_size"] / 2)) print(*zip(*np.unique(model, return_counts=True))) np.savez_compressed(output_data_path / "model.npz", model)
def main(): ( output_data_path, reduced_model_path, distance_mask_path, tree_path, ) = get_data_paths_from_args(inputs=3) model = np.load(reduced_model_path / "reduced_model.npz")["arr_0"] distance_mask = np.load(distance_mask_path / "distance_mask.npz")["arr_0"] tree = nx.read_graphml(tree_path / f"tree.graphml") def should_color_func( condition: Callable[[nx.Graph, int], bool]) -> Callable: return lambda s: s in get_first_matching_ids(tree, condition) print(get_first_matching_ids(tree, is_lobe)) print(get_first_matching_ids(tree, is_segment)) for func, filename in [ (lambda _: True, "bronchus_color_mask.npz"), (should_color_func(is_segment), "segments.npz"), (should_color_func(is_lobe), "lobes.npz"), ]: color_mask = np.full(model.shape, 0) nodes_visit_order, color_hex_codes = get_nodes_visit_order( tree, distance_mask, func) print(color_hex_codes) fill_color_with_priority_queue(nodes_visit_order, model, distance_mask, color_mask) print("Colors:") for color, occ in zip(*np.unique(color_mask, return_counts=True)): print(f"Color {color} appears {occ:,} times in color mask") np.savez_compressed(output_data_path / filename, color_mask=color_mask, color_codes=np.array(color_hex_codes))
import math import queue from typing import Tuple, Dict import numpy as np from skimage.morphology import skeletonize from airway.util.helper_functions import adjacent from airway.util.util import get_data_paths_from_args Coordinate = Tuple[int, int, int] output_data_path, input_data_path = get_data_paths_from_args() patient_data_file = input_data_path / "reduced_model.npz" distance_to_coords_file = output_data_path / "map_distance_to_coords" coord_to_distance_file = output_data_path / "map_coord_to_distance.txt" coord_to_previous_file = output_data_path / "map_coord_to_previous.txt" coord_to_next_count_file = output_data_path / "map_coord_to_next_count.txt" distance_mask_path = output_data_path / "distance_mask" def find_first_voxel(model): """Find first (highest) voxel in the lung""" for layer in range(len(model)): possible_coords = [] found = False for line in range(len(model[layer])): for voxel in range(len(model[layer][line])): if model[layer][line][voxel] == 1:
from airway.util.util import get_data_paths_from_args plt.rcParams.update({"font.size": 7}) # |>--><-><-><-><-><->-<| # |>- Parse arguments -<| # |>--><-><-><-><-><->-<| ( output_data_path, bronchus_shell_data_path, map_coord_to_dist_data_path, final_coords_data_path, pre_post_processing_data_path, post_post_processing_data_path, ) = get_data_paths_from_args(inputs=5) try: show_plot = sys.argv[7].lower() == "true" except IndexError: show_plot = True try: show_bronchus = sys.argv[8].lower() == "true" except IndexError: show_bronchus = False # |>-<-><-><-><-><-><->-<| # |>- Define color map -<| # |>-<-><-><-><-><-><->-<|
def main(): """Executes all methods given above in the correct order""" # |>-<-><-><-><-><-><-><-<| # |>- Process arguments -<| # |>-<-><-><-><-><-><-><-<| output_data_path, input_data_path = get_data_paths_from_args() # |>-<-><-><-><->-<| # |>- Load graph -<| # |>-<-><-><-><->-<| graph = load_graph(input_data_path / "tree.graphml") assert nx.is_tree(graph), "ERROR: Graph is not a tree!" # |>-><-><-><-><-><-<| # |>- Process tree -<| # |>-><-><-><-><-><-<| print(f"===== Node Removal =====") # Run each of these multiple times since they do something on each # iteration. Quit when nothing changes iteration = 0 while True: node_count = graph.number_of_nodes() print(f"=== Iteration {iteration} ===") remove_minor_edges(graph) straighten_edges(graph) merge_close_nodes(graph) remove_children_without_children(graph) iteration += 1 if node_count == graph.number_of_nodes(): break # |>--><-><-><-><-><-><-><-><-><-><-><-><-><--<| # |>- Reset attributes from the other script -<| # |>--><-><-><-><-><-><-><-><-><-><-><-><-><--<| assign_children_count(graph) graph = set_level(graph) graph = set_attribute_to_node(graph, ("level", 2), ("lobe", 0)) graph = set_attribute_to_node(graph, ("level", 3), ("lobe", 0)) assert nx.is_tree(graph), "ERROR: Graph is no longer a tree!" # |>-<-><-><-><-><-><-><-><->-<| # |>- Write pre-colored tree -<| # |>-<-><-><-><-><-><-><-><->-<| print(f"===== Recoloring =====") if not output_data_path.exists(): output_data_path.mkdir(parents=True, exist_ok=True) nx.write_graphml(graph, output_data_path / "pre-recoloring.graphml") # |>-<-><-><-><->-<| # |>- Recoloring -<| # |>-<-><-><-><->-<| for _ in range(5): recolor_if_all_adjacent_have_different_color(graph) recolor_if_successors_all_different_color(graph) recolor_entire_subtree_to_majority_at_level_4_or_5(graph) possibly_make_neutral_above_level_4(graph) add_new_parent_for_lobe(graph) # |>-<-><-><-><->-<| # |>- Write tree -<| # |>-<-><-><-><->-<| nx.write_graphml(graph, output_data_path / "tree.graphml")
this script now checks whenever a group splits in 2 (there is no path between them), whenever this happens it marks this as a split and saves it later on. After doing that it backtracks all nodes and creates all the edges. """ import queue import math from typing import Tuple, Set import numpy as np from airway.util.helper_functions import adjacent, find_radius_via_sphere from airway.util.util import get_data_paths_from_args output_data_path, input_data_path, reduced_model_data_path = get_data_paths_from_args(inputs=2) REDUCED_MODEL = reduced_model_data_path / "reduced_model.npz" DISTANCE_TO_COORDS_FILE = input_data_path / "map_distance_to_coords.npz" MAP_COORD_TO_PREVIOUS_FILE = input_data_path / "map_coord_to_previous.txt" MAP_COORD_TO_NEXT_COUNT_FILE = input_data_path / "map_coord_to_next_count.txt" FINAL_COORDS_FILE = output_data_path / "final_coords" FINAL_EDGES_FILE = output_data_path / "final_edges" EDGE_ATTRIBUTES_FILE = output_data_path / "edge_attributes" COORD_ATTRIBUTES_FILE = output_data_path / "coord_attributes" model = np.load(REDUCED_MODEL)["arr_0"] print(model.shape)
def main(): output_data_path, input_data_path, distance_mask_path, color_mask_path = get_data_paths_from_args( inputs=3) original_color_tuples = { index: color_hex_to_floats(color) for index, color in enumerate([ "ffffff", "bee6be", "fa87f5", "fa4646", "41d741", "6478fa", "e6ff50", "5870ff", "ff5c64" ]) } model = np.load(input_data_path / "reduced_model.npz")["arr_0"] print(f"Loaded model with shape {model.shape}") distance_mask = np.load(distance_mask_path / "distance_mask.npz")["arr_0"] print(f"Loaded color mask with shape {distance_mask.shape}") try: color_mask_npz = np.load(color_mask_path / "bronchus_color_mask.npz") bronchus_color_mask = color_mask_npz["color_mask"] bronchus_color_codes = color_mask_npz["color_codes"] print(bronchus_color_codes) print(f"Loaded color mask with shape {bronchus_color_mask.shape}") color_codes = {i: code for i, code in enumerate(bronchus_color_codes)} print(color_codes) except FileNotFoundError: print("WARNING: Color mask not found, using white for all voxels!") bronchus_color_mask = None color_codes = {0: (1, 1, 1)} if not output_data_path.exists(): output_data_path.mkdir(parents=True, exist_ok=True) rot_mat = np.array([[0, 0, -1], [-1, 0, 0], [0, 1, 0]]) print("Running skeletonize on model") # Remove lobe coordinates from model by clipping everything # between 0 and 2, then modulo everything by 2 to remove 2s skeleton = skeletonize(np.clip(model, 0, 2) % 2) generate_obj(output_data_path / "skeleton.obj", set(), skeleton, rot_mat=rot_mat) # generate_obj(output_data_path / "bav.obj", {1, 7, 8}, model) generate_obj( output_data_path / "bronchus.obj", {1}, model, color_mask=bronchus_color_mask, color_to_rgb_tuple=color_codes, rot_mat=rot_mat, ) generate_obj(output_data_path / "distance_mask.obj", {1}, model, color_mask=distance_mask, rot_mat=rot_mat) generate_obj(output_data_path / "veins.obj", {7}, model, color_to_rgb_tuple={0: (0, 0, 1)}, rot_mat=rot_mat) generate_obj(output_data_path / "arteries.obj", {8}, model, color_to_rgb_tuple={0: (1, 0, 0)}, rot_mat=rot_mat)