├── .gitignore ├── README.md ├── demo ├── align_compose.py ├── align_sequential.py ├── align_v3.py ├── compose_v3.py ├── compress_jpeg.py ├── compute_simple_global_registration.py ├── construct_intensity_volume.py ├── download_atlas.py ├── download_demo_data.py ├── download_pretrained_classifiers.py ├── example_specs │ ├── DEMO998_input_spec.ini │ ├── DEMO998_raw_input_spec.json │ ├── MD585_fixed_brain_spec_12N.json │ ├── MD585_fixed_brain_spec_3N_R_4N_R.json │ ├── MD585_input_spec.ini │ ├── MD585_raw_input_spec.json │ ├── MD585_visualization_global_alignment_spec.json │ ├── MD585_visualization_per_structure_alignment_spec.json │ ├── MD589_input_spec.ini │ ├── MD594_input_spec.ini │ ├── UCSD001_fixed_brain_spec_12N.json │ ├── UCSD001_fixed_brain_spec_3N_R_4N_R.json │ ├── UCSD001_fixed_brain_spec_5N_L.json │ ├── UCSD001_visualization_global_alignment_spec.json │ ├── UCSD001_visualization_per_structure_alignment_spec.json │ ├── demo_fixed_brain_spec_12N.json │ ├── demo_fixed_brain_spec_3N_R_4N_R.json │ ├── demo_moving_brain_spec_12N.json │ ├── demo_moving_brain_spec_3N_R_4N_R.json │ ├── demo_moving_brain_spec_5N_L.json │ ├── demo_visualization_global_alignment_spec.json │ ├── demo_visualization_per_structure_alignment_spec.json │ ├── lauren_experiments.csv │ ├── lauren_experiments0.csv │ ├── lauren_experiments_4.csv │ └── render_config_atlas.csv ├── extract_channel.py ├── generate_original_image_crop_csv.py ├── generate_prob_volumes.py ├── jp2_to_tiff.py ├── masking.py ├── normalize_intensity.py ├── normalize_intensity_adaptive.py ├── register_brains.py ├── rescale.py ├── todo │ ├── demo_render3d.py │ ├── download_demo_data_render3d.py │ ├── train_classifiers.py │ └── vis3d_utilities.py ├── visualize_registration.py └── warp_crop.py ├── doc ├── example_registration_visualization.jpg ├── mask_generation.md └── rough_global_transform.md ├── setup ├── config.sh └── requirements.txt └── src ├── gui ├── DataFeeder.py ├── README.md ├── brain_labeling_gui_v28.py ├── gui_utilities.py ├── mask_editing_tool_v4.py ├── mask_editing_utilities.py ├── newStructureNames.txt ├── preprocess_tool_v3.py ├── structure_names.txt ├── structure_tree.json ├── ui │ ├── AlignmentGui.ui │ ├── BrainLabelingGui_v15.ui │ ├── GalleryDialog.ui │ ├── MaskEditingGui4.ui │ ├── MaskEditingGui5.ui │ ├── MaskParametersGui.ui │ ├── PreprocessTool.ui │ ├── PreprocessTool_v2.ui │ ├── RectificationTool.ui │ ├── __init__.py │ ├── accept_new_landmark_dialog.py │ ├── accept_new_landmark_dialog.ui │ ├── ui_AlignmentGui.py │ ├── ui_BrainLabelingGui_v15.py │ ├── ui_GalleryDialog.py │ ├── ui_MaskEditingGui.py │ ├── ui_MaskEditingGui4.py │ ├── ui_MaskEditingGui5.py │ ├── ui_MaskEditingGui5.ui.py │ ├── ui_MaskParametersGui.py │ ├── ui_PreprocessGui.py │ ├── ui_PreprocessGui_v2.py │ └── ui_RectificationTool.py └── widgets │ ├── DrawableZoomableBrowsableGraphicsScene.py │ ├── DrawableZoomableBrowsableGraphicsScene_ForLabeling.py │ ├── DrawableZoomableBrowsableGraphicsScene_ForLabeling_v2.py │ ├── DrawableZoomableBrowsableGraphicsScene_ForMasking.py │ ├── DrawableZoomableBrowsableGraphicsScene_ForSnake.py │ ├── MultiplePixmapsGraphicsScene.py │ ├── SignalEmittingGraphicsPathItem.py │ ├── SignalEmittingGraphicsPathItemWithVertexCircles.py │ ├── SignalEmittingItems.py │ ├── ZoomableBrowsableGraphicsScene.py │ ├── ZoomableBrowsableGraphicsSceneWithReadonlyPolygon.py │ ├── __init__.py │ └── custom_widgets.py ├── learning ├── classifier_settings.csv ├── dataset_settings.csv └── detector_settings.csv ├── preprocess └── morphsnakes.py ├── registration └── registration_settings.csv └── utilities ├── __init__.py ├── aligner_v3.py ├── annotation_utilities.py ├── colormap.json ├── colormap.json~ ├── conversion.ipynb ├── conversion.py ├── data_manager.py ├── distributed_utilities.py ├── learning_utilities.py ├── lie.py ├── metadata.py ├── preprocess_utilities.py ├── qt_utilities.py ├── randomcolor.py ├── registration_utilities.py ├── sequential_dispatcher.py ├── utilities2015.py ├── vis3d_utilities.py └── visualization_utilities.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Exclude demo data 2 | demo/demo_data/ 3 | 4 | # Exclude virtualenv 5 | mousebrainatlas_virtualenv/ 6 | 7 | # Exclude vtk installation 8 | setup/vtk* 9 | 10 | *.pyc 11 | **ipynb_checkpoints 12 | -------------------------------------------------------------------------------- /demo/align_compose.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | parser = argparse.ArgumentParser( 5 | formatter_class=argparse.RawDescriptionHelpFormatter, 6 | description="""Align consecutive images. Possible bad alignment pairs are written into a separate file. 7 | Usage 1: align_compose.py in.ini --op from_none_to_aligned 8 | """ 9 | ) 10 | 11 | parser.add_argument("input_spec", type=str, help="input specifier. ini") 12 | parser.add_argument("--op", type=str, help="operation id") 13 | 14 | args = parser.parse_args() 15 | 16 | import os 17 | import sys 18 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 19 | from utilities2015 import execute_command 20 | 21 | execute_command('python align_v3.py %s --op %s' % (args.input_spec, args.op)) 22 | execute_command('python compose_v3.py %s --op %s' % (args.input_spec, args.op)) 23 | -------------------------------------------------------------------------------- /demo/align_sequential.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import json 6 | import re 7 | 8 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 9 | from metadata import * 10 | from utilities2015 import * 11 | 12 | import argparse 13 | 14 | parser = argparse.ArgumentParser( 15 | formatter_class=argparse.RawDescriptionHelpFormatter, 16 | description='Align consecutive images. Possible bad alignment pairs are written into a separate file.') 17 | 18 | parser.add_argument("output_dir", type=str, help="output dir. Files for each pairwise transform are stored in sub-folder _to_.") 19 | parser.add_argument("kwargs_str", type=str, help="json-encoded list of dict (keyworded inputs). Each dict entry has four keys: prev_fp (previous image file path), curr_fp (current image file path).") 20 | parser.add_argument("-p", "--param_fp", type=str, help="elastix parameter file path", default=None) 21 | parser.add_argument("-r", help="re-generate even if already exists", action='store_true') 22 | 23 | args = parser.parse_args() 24 | 25 | output_dir = args.output_dir 26 | kwargs_str = json.loads(args.kwargs_str) 27 | param_fp = args.param_fp 28 | regenerate = args.r 29 | 30 | if param_fp is None: 31 | param_fp = os.path.join(os.environ['REPO_DIR'], 'preprocess', 'parameters', "Parameters_Rigid_MutualInfo.txt") 32 | 33 | failed_pairs = [] 34 | 35 | for kwarg in kwargs_str: 36 | 37 | prev_img_name = kwarg['prev_img_name'] 38 | curr_img_name = kwarg['curr_img_name'] 39 | prev_fp = kwarg['prev_fp'] 40 | curr_fp = kwarg['curr_fp'] 41 | 42 | output_subdir = os.path.join(output_dir, curr_img_name + '_to_' + prev_img_name) 43 | 44 | if os.path.exists(output_subdir) and 'TransformParameters.0.txt' in os.listdir(output_subdir): 45 | sys.stderr.write('Result for aligning %s to %s already exists.\n' % (curr_img_name, prev_img_name)) 46 | if not regenerate: 47 | sys.stderr.write('Skip.\n' % (curr_img_name, prev_img_name)) 48 | continue 49 | 50 | execute_command('rm -rf \"%s\"' % output_subdir) 51 | create_if_not_exists(output_subdir) 52 | 53 | ret = execute_command('%(elastix_bin)s -f \"%(fixed_fp)s\" -m \"%(moving_fp)s\" -out \"%(output_subdir)s\" -p \"%(param_fp)s\"' % \ 54 | {'elastix_bin': ELASTIX_BIN, 55 | 'param_fp': param_fp, 56 | 'output_subdir': output_subdir, 57 | 'fixed_fp': prev_fp, 58 | 'moving_fp': curr_fp 59 | }) 60 | 61 | if ret == 1: 62 | failed_pairs.append((prev_img_name, curr_img_name)) 63 | else: 64 | with open(os.path.join(output_subdir, 'elastix.log'), 'r') as f: 65 | t = f.read() 66 | g = re.search("Final metric value = (.*?)\n", t) 67 | assert g is not None 68 | metric = float(g.groups()[0]) 69 | sys.stderr.write("Metric = %.2f\n" % metric) 70 | 71 | import subprocess 72 | hostname = subprocess.check_output("hostname", shell=True).strip() 73 | 74 | if len(failed_pairs) > 0: 75 | with open(os.path.join(output_dir, 'intra_stack_alignment_failed_pairs_%s.txt' % (hostname.split('.')[0])), 'w') as f: 76 | for pf, cf in failed_pairs: 77 | f.write(pf + ' ' + cf + '\n') 78 | 79 | -------------------------------------------------------------------------------- /demo/align_v3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | parser = argparse.ArgumentParser( 5 | formatter_class=argparse.RawDescriptionHelpFormatter, 6 | description="""Align consecutive images. Possible bad alignment pairs are written into a separate file. 7 | Usage 1: align.py in.ini --prep_id alignedPadded 8 | Usage 2: align.py in.ini --elastix_output_dir DEMO998_elastix_output/ --param_fp params.txt 9 | Usage 3: align.py in.ini --op from_none_to_aligned 10 | """ 11 | ) 12 | 13 | parser.add_argument("input_spec", type=str, help="input specifier. ini") 14 | parser.add_argument("--op", type=str, help="operation id") 15 | parser.add_argument("--prep_id", type=str, help="Prep id of the warp operation.") 16 | parser.add_argument("--elastix_output_dir", type=str, help="output dir. Files for each pairwise transform are stored in sub-folder _to_.") 17 | parser.add_argument("--param_fp", type=str, help="elastix parameter file path") 18 | #parser.add_argument("-r", help="re-generate even if already exists", action='store_true') 19 | 20 | args = parser.parse_args() 21 | 22 | import os 23 | import sys 24 | import json 25 | import re 26 | 27 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 28 | from utilities2015 import * 29 | from data_manager import * 30 | from metadata import * 31 | from distributed_utilities import * 32 | 33 | input_spec = load_ini(args.input_spec) 34 | print input_spec 35 | stack = input_spec['stack'] 36 | prep_id = input_spec['prep_id'] 37 | if prep_id == 'None': 38 | prep_id = None 39 | resol = input_spec['resol'] 40 | version = input_spec['version'] 41 | if version == 'None': 42 | version = None 43 | image_name_list = input_spec['image_name_list'] 44 | if image_name_list == 'all': 45 | image_name_list = map(lambda x: x[0], sorted(DataManager.load_sorted_filenames(stack=stack)[0].items(), key=lambda x: x[1])) 46 | #image_name_list = DataManager.load_sorted_filenames(stack=stack)[0].keys() 47 | 48 | if args.op is not None: 49 | #op = load_ini(os.path.join(DATA_ROOTDIR, 'operation_configs', args.op + '.ini')) 50 | op = load_ini(DataManager.get_operation_config_filename(op=args.op, stack=stack)) 51 | assert op['type'] == 'warp', "Op must be a warp" 52 | elastix_output_dir = op['elastix_output_dir'] 53 | params_fp = op['elastix_parameter_fp'] 54 | 55 | assert op['base_prep_id'] == input_spec['prep_id'], "Op has base prep %s, but input has prep %s." % (op['base_prep_id'], input_spec['prep_id']) 56 | 57 | else: 58 | assert args.elastix_output_dir is not None, "Must provide elastix_output_dir" 59 | assert args.param_fp is not None, "Must provide param_fp" 60 | elastix_output_dir = args.elastix_output_dir 61 | params_fp = args.param_fp 62 | 63 | 64 | run_distributed("python %(script)s \"%(output_dir)s\" \'%%(kwargs_str)s\' -p %(param_fp)s -r" % \ 65 | {'script': os.path.join(os.getcwd(), 'align_sequential.py'), 66 | 'output_dir': elastix_output_dir, 67 | 'param_fp': params_fp 68 | }, 69 | kwargs_list=[{'prev_img_name': image_name_list[i-1], 70 | 'curr_img_name': image_name_list[i], 71 | 'prev_fp': DataManager.get_image_filepath_v2(stack=stack, fn=image_name_list[i-1], prep_id=prep_id, resol=resol, version=version), 72 | 'curr_fp': DataManager.get_image_filepath_v2(stack=stack, fn=image_name_list[i], prep_id=prep_id, resol=resol, version=version) 73 | } 74 | for i in range(1, len(image_name_list))], 75 | argument_type='list', 76 | jobs_per_node=8, 77 | local_only=True) 78 | -------------------------------------------------------------------------------- /demo/compose_v3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | 5 | parser = argparse.ArgumentParser( 6 | formatter_class=argparse.RawDescriptionHelpFormatter, 7 | description="""Generate a csv file that stores a dict. Keys are image names and values are flattened (3,3)-matrices. 8 | Usage 1: compose.py --input_spec in.ini --op_id from_none_to_aligned 9 | Usage 2: compose.py --input_spec input_spec.ini --elastix_output_dir DEMO998_elastix_output --custom_output_dir DEMO998_custom_output --anchor_img_name "MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250" --out DEMO998_transformsTo_anchor.csv" 10 | """) 11 | 12 | # parser.add_argument("stack", type=str, help="stack") 13 | parser.add_argument("input_spec", type=str, help="Input specifier. ini.") 14 | parser.add_argument("--op", type=str, help="Op id of warp") 15 | parser.add_argument("--prep_id", type=str, help="Prep ID of the warp") 16 | parser.add_argument("--elastix_output_dir", type=str, help="Elastix-generated pairwise transform output dir") 17 | parser.add_argument("--custom_output_dir", type=str, help="User-corrected pairwise transform output dir") 18 | parser.add_argument("--anchor_img_name", type=str, help="Anchor image name") 19 | parser.add_argument("--out", type=str, help="csv, composed transforms for each image to anchor") 20 | 21 | args = parser.parse_args() 22 | 23 | import os 24 | import numpy as np 25 | import sys 26 | import cPickle as pickle 27 | import json 28 | 29 | sys.path.append(os.environ['REPO_DIR'] + '/utilities/') 30 | from metadata import * 31 | from preprocess_utilities import * 32 | from data_manager import DataManager 33 | 34 | input_spec = load_ini(args.input_spec) 35 | image_name_list = input_spec['image_name_list'] 36 | if image_name_list == 'all': 37 | #image_name_list = DataManager.load_sorted_filenames(stack=stack)[0].keys() 38 | image_name_list = map(lambda x: x[0], sorted(DataManager.load_sorted_filenames(stack=input_spec['stack'])[0].items(), key=lambda x: x[1])) 39 | 40 | #op = load_ini(os.path.join(DATA_ROOTDIR, 'CSHL_data_processed', input_spec['stack'], 'operation_configs', args.op + '.ini')) 41 | #op = load_ini(os.path.join(DATA_ROOTDIR, 'operation_configs', args.op + '.ini')) 42 | op = load_ini(DataManager.get_operation_config_filename(op=args.op, stack=input_spec['stack'])) 43 | assert op['type'] == 'warp', "Op type must be warp." 44 | assert op['base_prep_id'] == input_spec['prep_id'], "Op requires %s, but input has prep %s." % (op['base_prep_id'], input_spec['prep_id']) 45 | 46 | elastix_output_dir = op['elastix_output_dir'] 47 | custom_output_dir = op['custom_output_dir'] 48 | toanchor_transforms_fp = op['transforms_csv'] 49 | anchor_img_name = op['anchor_image_name'] 50 | base_prep_id = op['base_prep_id'] 51 | 52 | ################################################# 53 | 54 | anchor_idx = image_name_list.index(anchor_img_name) 55 | 56 | transformation_to_previous_sec = {} 57 | 58 | for i in range(1, len(image_name_list)): 59 | 60 | transformation_to_previous_sec[i] = DataManager.load_consecutive_section_transform(moving_fn=image_name_list[i], fixed_fn=image_name_list[i-1], elastix_output_dir=elastix_output_dir, custom_output_dir=custom_output_dir) 61 | 62 | transformation_to_anchor_sec = {} 63 | 64 | for moving_idx in range(len(image_name_list)): 65 | 66 | if moving_idx == anchor_idx: 67 | # transformation_to_anchor_sec[moving_idx] = np.eye(3) 68 | transformation_to_anchor_sec[image_name_list[moving_idx]] = np.eye(3) 69 | 70 | elif moving_idx < anchor_idx: 71 | T_composed = np.eye(3) 72 | for i in range(anchor_idx, moving_idx, -1): 73 | T_composed = np.dot(np.linalg.inv(transformation_to_previous_sec[i]), T_composed) 74 | # transformation_to_anchor_sec[moving_idx] = T_composed 75 | transformation_to_anchor_sec[image_name_list[moving_idx]] = T_composed 76 | 77 | else: 78 | T_composed = np.eye(3) 79 | for i in range(anchor_idx+1, moving_idx+1): 80 | T_composed = np.dot(transformation_to_previous_sec[i], T_composed) 81 | # transformation_to_anchor_sec[moving_idx] = T_composed 82 | transformation_to_anchor_sec[image_name_list[moving_idx]] = T_composed 83 | 84 | print moving_idx, image_name_list[moving_idx], transformation_to_anchor_sec[image_name_list[moving_idx]] 85 | 86 | ################################################# 87 | 88 | dict_to_csv(transformation_to_anchor_sec, toanchor_transforms_fp) 89 | -------------------------------------------------------------------------------- /demo/compress_jpeg.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import json 6 | 7 | from multiprocess import Pool 8 | 9 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 10 | from utilities2015 import * 11 | from data_manager import * 12 | from metadata import * 13 | from distributed_utilities import * 14 | 15 | import argparse 16 | 17 | parser = argparse.ArgumentParser( 18 | formatter_class=argparse.RawDescriptionHelpFormatter, 19 | description='Compress image as JPEG. The output version is the input version with "Jpeg" appended.') 20 | 21 | parser.add_argument("input_spec", type=str, help="Input specifier") 22 | parser.add_argument("--depth", type=int, help="Image depth", default=8) # imagemagick cannot generate 16-bit JPEG (?) 23 | parser.add_argument("--quality", type=int, help="JPEG quality", default=80) 24 | args = parser.parse_args() 25 | 26 | 27 | input_spec = load_ini(args.input_spec) 28 | 29 | stack = input_spec['stack'] 30 | prep_id = input_spec['prep_id'] 31 | if prep_id == 'None': 32 | prep_id = None 33 | resol = input_spec['resol'] 34 | version = input_spec['version'] 35 | if version == 'None': 36 | version = None 37 | 38 | image_name_list = input_spec['image_name_list'] 39 | if image_name_list == 'all': 40 | image_name_list = DataManager.load_sorted_filenames(stack=stack)[0].keys() 41 | 42 | depth = args.depth 43 | quality = args.quality 44 | 45 | for img_name in image_name_list: 46 | 47 | in_fp = DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, resol=resol, version=version, fn=img_name) 48 | out_fp = DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, resol=resol, version=version+'Jpeg', fn=img_name) 49 | 50 | create_parent_dir_if_not_exists(out_fp) 51 | #download_from_s3(input_fp) 52 | execute_command("convert \"%(input_fp)s\" -depth %(depth)d -format jpg -quality %(quality)d \"%(output_fp)s\"" % dict(input_fp=in_fp, output_fp=out_fp, depth=depth, quality=quality)) 53 | #upload_to_s3(output_fp) 54 | 55 | -------------------------------------------------------------------------------- /demo/construct_intensity_volume.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import time 6 | 7 | import matplotlib 8 | # Force matplotlib to not use any Xwindows backend. 9 | matplotlib.use('Agg') # https://stackoverflow.com/a/3054314 10 | import matplotlib.pyplot as plt 11 | import numpy as np 12 | 13 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 14 | from utilities2015 import * 15 | from registration_utilities import * 16 | from annotation_utilities import * 17 | from metadata import * 18 | from data_manager import * 19 | 20 | import argparse 21 | 22 | parser = argparse.ArgumentParser( 23 | formatter_class=argparse.RawDescriptionHelpFormatter, 24 | description='') 25 | 26 | parser.add_argument("brain_name", type=str, help="Brain name") 27 | parser.add_argument("--tb_version", type=str, help="Image version (Default: None)") 28 | parser.add_argument("--tb_resol", type=str, help="Image resolution (Default: %(default)s)", default='thumbnail') 29 | parser.add_argument("--output_resol", type=str, help="Output volume resolution (Default: %(default)s)", default='10.0um') 30 | 31 | args = parser.parse_args() 32 | 33 | stack = args.brain_name 34 | 35 | output_resolution = args.output_resol 36 | tb_version = args.tb_version 37 | tb_resol = args.tb_resol 38 | 39 | images = {} 40 | 41 | # for sec in metadata_cache['valid_sections_all'][stack]: 42 | for sec in metadata_cache['valid_sections'][stack]: 43 | 44 | img_rgb = DataManager.load_image_v2(stack, section=sec, 45 | resol=tb_resol, 46 | prep_id='alignedWithMargin', 47 | version=tb_version) 48 | img = img_as_ubyte(rgb2gray(img_rgb)) # Use greylevel 49 | 50 | mask = DataManager.load_image_v2(stack=stack, section=sec, 51 | prep_id='alignedWithMargin', 52 | resol=tb_resol, 53 | version='mask') 54 | img[~mask] = 0 55 | 56 | images[sec] = img 57 | 58 | # Specify isotropic resolution of the output volume. 59 | voxel_size_um = convert_resolution_string_to_um(resolution=output_resolution, stack=stack) 60 | 61 | input_image_resolution_um = convert_resolution_string_to_um(resolution=tb_resol, stack=stack) 62 | 63 | volume_outVolResol, volume_origin_wrt_wholebrainWithMargin_outVolResol = images_to_volume_v2(images=images, 64 | spacing_um=20., 65 | in_resol_um=input_image_resolution_um, 66 | out_resol_um=voxel_size_um) 67 | print volume_outVolResol.shape 68 | 69 | ############################################################## 70 | 71 | prep5_origin_wrt_prep1_tbResol = DataManager.load_cropbox_v2(stack=stack, only_2d=True, prep_id='alignedWithMargin') 72 | 73 | loaded_cropbox_resol = 'thumbnail' 74 | 75 | prep5_origin_wrt_prep1_outVolResol = prep5_origin_wrt_prep1_tbResol * \ 76 | convert_resolution_string_to_um(resolution=loaded_cropbox_resol, stack=stack) / voxel_size_um 77 | 78 | wholebrainWithMargin_origin_wrt_wholebrain_outVolResol = np.r_[np.round(prep5_origin_wrt_prep1_outVolResol).astype(np.int)[[0,2]], 0] 79 | # wholebrainWithMargin_origin_wrt_wholebrain = np.array([0,0,0]) 80 | 81 | volume_origin_wrt_wholebrain_outVolResol = volume_origin_wrt_wholebrainWithMargin_outVolResol + wholebrainWithMargin_origin_wrt_wholebrain_outVolResol 82 | 83 | ######################################## 84 | 85 | stack_spec = dict(name=stack, 86 | resolution=output_resolution, 87 | prep_id='wholebrainWithMargin', 88 | vol_type='intensity') 89 | 90 | save_data(volume_outVolResol, 91 | fp=DataManager.get_original_volume_filepath_v2(stack_spec=stack_spec, structure=None)) 92 | 93 | save_data(volume_origin_wrt_wholebrain_outVolResol, 94 | fp=DataManager.get_original_volume_origin_filepath_v3(stack_spec=stack_spec, structure=None)) 95 | -------------------------------------------------------------------------------- /demo/download_atlas.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys, os 4 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 5 | from utilities2015 import * 6 | from metadata import * 7 | from data_manager import * 8 | 9 | import argparse 10 | 11 | parser = argparse.ArgumentParser( 12 | formatter_class=argparse.RawDescriptionHelpFormatter, 13 | description='This script downloads input data for demo.') 14 | 15 | parser.add_argument("-d", "--demo_data_dir", type=str, help="Directory to store demo input data") 16 | parser.add_argument("-s", "--structure_list", type=str, help="Json-encoded list of structures (sided) (Default: all known structures)") 17 | args = parser.parse_args() 18 | 19 | import json 20 | if hasattr(args, 'structure_list') and args.structure_list is not None: 21 | structure_list = json.loads(args.structure_list) 22 | else: 23 | structure_list = all_known_structures_sided 24 | print(structure_list) 25 | 26 | if args.demo_data_dir is None: 27 | demo_data_dir = DATA_ROOTDIR 28 | else: 29 | demo_data_dir = args.demo_data_dir 30 | 31 | def download_to_demo(fp): 32 | s3_http_prefix = 'https://s3-us-west-1.amazonaws.com/v0.2-required-data/' 33 | url = s3_http_prefix + fp 34 | demo_fp = os.path.join(demo_data_dir, fp) 35 | execute_command('wget -N -P \"%s\" \"%s\"' % (os.path.dirname(demo_fp), url)) 36 | return demo_fp 37 | 38 | 39 | #for name_s in ['3N_R', '4N_R', '3N_R_surround_200um', '4N_R_surround_200um','12N', '12N_surround_200um']: 40 | for name_s in structure_list + [compose_label(name_s, surround_margin='200um') for name_s in structure_list]: 41 | 42 | fp = DataManager.get_score_volume_filepath_v3(stack_spec={'name':'atlasV7', 'resolution':'10.0um', 'vol_type':'score'}, structure=name_s) 43 | rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 44 | download_to_demo(rel_fp) 45 | 46 | fp = DataManager.get_score_volume_origin_filepath_v3(stack_spec={'name':'atlasV7', 'resolution':'10.0um', 'vol_type':'score'}, structure=name_s, wrt='canonicalAtlasSpace') 47 | rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 48 | download_to_demo(rel_fp) 49 | 50 | -------------------------------------------------------------------------------- /demo/download_demo_data.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys, os 4 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 5 | from utilities2015 import execute_command, create_if_not_exists 6 | from metadata import * 7 | from data_manager import relative_to_local 8 | 9 | import argparse 10 | 11 | parser = argparse.ArgumentParser( 12 | formatter_class=argparse.RawDescriptionHelpFormatter, 13 | description='This script downloads input data for demo.') 14 | 15 | parser.add_argument("-d", "--demo_data_dir", type=str, help="Directory to store demo input data") 16 | args = parser.parse_args() 17 | 18 | if args.demo_data_dir is None: 19 | demo_data_dir = DATA_ROOTDIR 20 | else: 21 | demo_data_dir = args.demo_data_dir 22 | 23 | def download_to_demo(fp): 24 | """ 25 | Args: 26 | fp (str): file path relative to data root. 27 | """ 28 | create_if_not_exists(demo_data_dir) 29 | s3_http_prefix = 'https://s3-us-west-1.amazonaws.com/v0.2-required-data/' 30 | url = s3_http_prefix + fp 31 | demo_fp = os.path.join(demo_data_dir, fp) 32 | execute_command('wget -N -P \"%s\" \"%s\"' % (os.path.dirname(demo_fp), url)) 33 | return demo_fp 34 | 35 | 36 | # Download raw JPEG2000 images 37 | for img_name in [ 38 | 'MD662&661-F68-2017.06.06-07.39.27_MD661_2_0203', 39 | 'MD662&661-F73-2017.06.06-09.53.20_MD661_1_0217', 40 | 'MD662&661-F79-2017.06.06-11.52.28_MD661_1_0235', 41 | 'MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250', 42 | 'MD662&661-F89-2017.06.06-16.49.49_MD661_1_0265', 43 | 'MD662&661-F94-2017.06.06-19.01.05_MD661_1_0280', 44 | 'MD662&661-F99-2017.06.06-21.14.03_MD661_1_0295', 45 | ]: 46 | 47 | download_to_demo(os.path.join('jp2_files', 'DEMO998', img_name + '_lossless.jp2')) 48 | #pass 49 | 50 | # Download mxnet model 51 | 52 | model_dir_name = 'inception-bn-blue' 53 | 54 | fp = os.path.join(MXNET_MODEL_ROOTDIR, model_dir_name, 'inception-bn-blue-0000.params') 55 | download_to_demo(relative_to_local(fp, local_root=DATA_ROOTDIR)) 56 | 57 | fp = os.path.join(MXNET_MODEL_ROOTDIR, model_dir_name, 'inception-bn-blue-symbol.json') 58 | download_to_demo(relative_to_local(fp, local_root=DATA_ROOTDIR)) 59 | 60 | fp = os.path.join(MXNET_MODEL_ROOTDIR, model_dir_name, 'mean_224.npy') 61 | download_to_demo(relative_to_local(fp, local_root=DATA_ROOTDIR)) 62 | 63 | # Download warp/crop operation configs. 64 | for fn in [ 65 | 'crop_orig_template', 66 | 'from_aligned_to_none', 67 | 'from_aligned_to_padded', 68 | 'from_none_to_aligned_template', 69 | 'from_none_to_padded', 70 | 'from_none_to_wholeslice', 71 | 'from_padded_to_brainstem_template', 72 | 'from_padded_to_wholeslice_template', 73 | 'from_padded_to_none', 74 | 'from_wholeslice_to_brainstem' 75 | ]: 76 | download_to_demo(os.path.join('operation_configs', fn + '.ini')) 77 | 78 | # Download brain meta data 79 | print("Download brain DEMO998 meta data") 80 | download_to_demo(os.path.join('brains_info', 'DEMO998.ini')) 81 | 82 | download_to_demo(os.path.join('CSHL_data_processed', 'DEMO998', 'DEMO998_sorted_filenames.txt')) 83 | download_to_demo(os.path.join('CSHL_data_processed', 'DEMO998', 'DEMO998_prep2_sectionLimits.ini')) 84 | 85 | # Elastix intra-stack registration parameters 86 | download_to_demo('elastix_parameters', 'Parameters_Rigid_MutualInfo_noNumberOfSpatialSamples_4000Iters.txt') 87 | 88 | # Rough global transform 89 | download_to_demo(os.path.join('CSHL_simple_global_registration', 'DEMO998_registered_atlas_structures_wrt_wholebrainXYcropped_xysecTwoCorners.json')) 90 | download_to_demo(os.path.join('CSHL_simple_global_registration', 'DEMO998_T_atlas_wrt_canonicalAtlasSpace_subject_wrt_wholebrain_atlasResol.txt')) 91 | -------------------------------------------------------------------------------- /demo/download_pretrained_classifiers.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys, os 4 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 5 | from utilities2015 import * 6 | from metadata import * 7 | from data_manager import * 8 | 9 | import argparse 10 | 11 | parser = argparse.ArgumentParser( 12 | formatter_class=argparse.RawDescriptionHelpFormatter, 13 | description='This script downloads input data for demo.') 14 | parser.add_argument("-s", "--structure_list", type=str, help="Json-encoded list of structures (sided) (Default: all known structures)") 15 | args = parser.parse_args() 16 | 17 | import json 18 | if hasattr(args, 'structure_list') and args.structure_list is not None: 19 | structure_list = json.loads(args.structure_list) 20 | else: 21 | structure_list = all_known_structures 22 | print(structure_list) 23 | 24 | 25 | #parser.add_argument("-d", "--demo_data_dir", type=str, help="Directory to store demo input data", default='demo_data') 26 | #args = parser.parse_args() 27 | 28 | # demo_data_dir = '/home/yuncong/Brain/demo_data/' 29 | 30 | demo_data_dir = DATA_ROOTDIR 31 | 32 | def download_to_demo(fp): 33 | #demo_data_dir = args.demo_data_dir 34 | s3_http_prefix = 'https://s3-us-west-1.amazonaws.com/v0.2-required-data/' 35 | url = s3_http_prefix + fp 36 | demo_fp = os.path.join(demo_data_dir, fp) 37 | execute_command('wget -N -P \"%s\" \"%s\"' % (os.path.dirname(demo_fp), url)) 38 | return demo_fp 39 | 40 | #for sec in range(220, 223): 41 | #for sec in []: 42 | # Download features 43 | # fp = DataManager.get_dnn_features_filepath_v2(stack=stack, sec=sec, prep_id=prep_id, win_id=win_id, 44 | # normalization_scheme=normalization_scheme, 45 | # model_name=model_name, what='features', timestamp=timestamp) 46 | # fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 47 | # download_to_demo(fp) 48 | 49 | # fp = DataManager.get_dnn_features_filepath_v2(stack=stack, sec=sec, prep_id=prep_id, win_id=win_id, 50 | # normalization_scheme=normalization_scheme, 51 | # model_name=model_name, what='locations', timestamp=timestamp) 52 | # rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 53 | # download_to_demo(rel_fp) 54 | 55 | 56 | # Download pre-trained logistic regression classifiers. 57 | classifier_id = 899 58 | #for name_u in ['3N', '4N', '12N']: 59 | #for name_u in all_known_structures: 60 | for name_u in structure_list: 61 | fp = DataManager.get_classifier_filepath(structure=name_u, classifier_id=classifier_id) 62 | rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 63 | download_to_demo(rel_fp) 64 | 65 | -------------------------------------------------------------------------------- /demo/example_specs/DEMO998_input_spec.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | image_name_list = MD662&661-F68-2017.06.06-07.39.27_MD661_2_0203 3 | MD662&661-F73-2017.06.06-09.53.20_MD661_1_0217 4 | MD662&661-F79-2017.06.06-11.52.28_MD661_1_0235 5 | MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250 6 | MD662&661-F89-2017.06.06-16.49.49_MD661_1_0265 7 | MD662&661-F94-2017.06.06-19.01.05_MD661_1_0280 8 | MD662&661-F99-2017.06.06-21.14.03_MD661_1_0295 9 | stack = DEMO998 10 | prep_id = alignedBrainstemCrop 11 | version = NtbNormalizedAdaptiveInvertedGamma 12 | resol = raw 13 | -------------------------------------------------------------------------------- /demo/example_specs/DEMO998_raw_input_spec.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"version": null, "resolution": "raw", "data_dirs": "/home/yuncong/demo_data/jp2_files/DEMO998/", "filepath_to_imageName_mapping": "/home/yuncong/demo_data/jp2_files/DEMO998/(.*)?_lossless.jp2", "imageName_to_filepath_mapping": "/home/yuncong/demo_data/jp2_files/DEMO998/%s_lossless.jp2"} 3 | ] 4 | -------------------------------------------------------------------------------- /demo/example_specs/MD585_fixed_brain_spec_12N.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"MD585", 3 | "vol_type": "score", 4 | "resolution":"10.0um", 5 | "detector_id":799, 6 | "structure":["12N"] 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo/example_specs/MD585_fixed_brain_spec_3N_R_4N_R.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"MD585", 3 | "vol_type": "score", 4 | "structure":["3N_R", "4N_R"], 5 | "resolution":"10.0um", 6 | "detector_id":799 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo/example_specs/MD585_input_spec.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | image_name_list = all 3 | stack = MD585 4 | prep_id = alignedBrainstemCrop 5 | version = gray 6 | resol = raw 7 | -------------------------------------------------------------------------------- /demo/example_specs/MD585_raw_input_spec.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"version": null, "resolution": "raw", "data_dirs": "/nfs/birdstore-brainbucket1/Active_Atlas_Data/CSHL_NanoZoomer/MD585_01Aug2015/", "filepath_to_imageName_mapping": "/nfs/birdstore-brainbucket1/Active_Atlas_Data/CSHL_NanoZoomer/MD585_01Aug2015/(.*?)_lossless.jp2", "imageName_to_filepath_mapping": "/nfs/birdstore-brainbucket1/Active_Atlas_Data/CSHL_NanoZoomer/MD585_01Aug2015/%s_lossless.jp2"} 3 | ] 4 | -------------------------------------------------------------------------------- /demo/example_specs/MD585_visualization_global_alignment_spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "stack_m": 3 | { 4 | "name":"atlasV7", 5 | "vol_type": "score", 6 | "resolution":"10.0um" 7 | }, 8 | "stack_f": 9 | { 10 | "name":"MD585", 11 | "vol_type": "score", 12 | "resolution":"10.0um", 13 | "detector_id":799 14 | }, 15 | "warp_setting": 0 16 | } 17 | 18 | -------------------------------------------------------------------------------- /demo/example_specs/MD585_visualization_per_structure_alignment_spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "3N_R": 3 | { 4 | "stack_m": 5 | { 6 | "name":"atlasV7", 7 | "vol_type": "score", 8 | "structure":["3N_R", "4N_R"], 9 | "resolution":"10.0um" 10 | }, 11 | "stack_f": 12 | { 13 | "name":"MD585", 14 | "vol_type": "score", 15 | "structure":["3N_R", "4N_R"], 16 | "resolution":"10.0um", 17 | "detector_id":799 18 | }, 19 | "warp_setting": 7 20 | }, 21 | "4N_R": 22 | { 23 | "stack_m": 24 | { 25 | "name":"atlasV7", 26 | "vol_type": "score", 27 | "structure":["3N_R", "4N_R"], 28 | "resolution":"10.0um" 29 | }, 30 | "stack_f": 31 | { 32 | "name":"MD585", 33 | "vol_type": "score", 34 | "structure":["3N_R", "4N_R"], 35 | "resolution":"10.0um", 36 | "detector_id":799 37 | }, 38 | "warp_setting": 7 39 | }, 40 | 41 | "12N": 42 | { 43 | "stack_m": 44 | { 45 | "name":"atlasV7", 46 | "vol_type": "score", 47 | "structure":["12N"], 48 | "resolution":"10.0um" 49 | }, 50 | "stack_f": 51 | { 52 | "name":"MD585", 53 | "vol_type": "score", 54 | "structure":["12N"], 55 | "resolution":"10.0um", 56 | "detector_id":799 57 | }, 58 | "warp_setting": 7 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /demo/example_specs/MD589_input_spec.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | image_name_list = all 3 | stack = MD589 4 | prep_id = alignedBrainstemCrop 5 | version = gray 6 | resol = raw 7 | -------------------------------------------------------------------------------- /demo/example_specs/MD594_input_spec.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | image_name_list = all 3 | stack = MD594 4 | prep_id = alignedBrainstemCrop 5 | version = gray 6 | resol = raw 7 | -------------------------------------------------------------------------------- /demo/example_specs/UCSD001_fixed_brain_spec_12N.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"UCSD001", 3 | "vol_type": "score", 4 | "resolution":"10.0um", 5 | "detector_id":799, 6 | "structure":["12N"] 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo/example_specs/UCSD001_fixed_brain_spec_3N_R_4N_R.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"UCSD001", 3 | "vol_type": "score", 4 | "structure":["3N_R", "4N_R"], 5 | "resolution":"10.0um", 6 | "detector_id":799 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo/example_specs/UCSD001_fixed_brain_spec_5N_L.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"UCSD001", 3 | "vol_type": "score", 4 | "resolution":"10.0um", 5 | "detector_id":799, 6 | "structure":["5N_L"] 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo/example_specs/UCSD001_visualization_global_alignment_spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "stack_m": 3 | { 4 | "name":"atlasV7", 5 | "vol_type": "score", 6 | "resolution":"10.0um" 7 | }, 8 | "stack_f": 9 | { 10 | "name":"UCSD001", 11 | "vol_type": "score", 12 | "resolution":"10.0um", 13 | "detector_id":799 14 | }, 15 | "warp_setting": 0 16 | } 17 | 18 | -------------------------------------------------------------------------------- /demo/example_specs/UCSD001_visualization_per_structure_alignment_spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "3N_R": 3 | { 4 | "stack_m": 5 | { 6 | "name":"atlasV7", 7 | "vol_type": "score", 8 | "structure":["3N_R", "4N_R"], 9 | "resolution":"10.0um" 10 | }, 11 | "stack_f": 12 | { 13 | "name":"UCSD001", 14 | "vol_type": "score", 15 | "structure":["3N_R", "4N_R"], 16 | "resolution":"10.0um", 17 | "detector_id":799 18 | }, 19 | "warp_setting": 7 20 | }, 21 | "4N_R": 22 | { 23 | "stack_m": 24 | { 25 | "name":"atlasV7", 26 | "vol_type": "score", 27 | "structure":["3N_R", "4N_R"], 28 | "resolution":"10.0um" 29 | }, 30 | "stack_f": 31 | { 32 | "name":"UCSD001", 33 | "vol_type": "score", 34 | "structure":["3N_R", "4N_R"], 35 | "resolution":"10.0um", 36 | "detector_id":799 37 | }, 38 | "warp_setting": 7 39 | }, 40 | 41 | "12N": 42 | { 43 | "stack_m": 44 | { 45 | "name":"atlasV7", 46 | "vol_type": "score", 47 | "structure":["12N"], 48 | "resolution":"10.0um" 49 | }, 50 | "stack_f": 51 | { 52 | "name":"UCSD001", 53 | "vol_type": "score", 54 | "structure":["12N"], 55 | "resolution":"10.0um", 56 | "detector_id":799 57 | }, 58 | "warp_setting": 7 59 | }, 60 | "5N_L": 61 | { 62 | "stack_m": 63 | { 64 | "name":"atlasV7", 65 | "vol_type": "score", 66 | "structure":["5N_L"], 67 | "resolution":"10.0um" 68 | }, 69 | "stack_f": 70 | { 71 | "name":"UCSD001", 72 | "vol_type": "score", 73 | "structure":["5N_L"], 74 | "resolution":"10.0um", 75 | "detector_id":799 76 | }, 77 | "warp_setting": 7 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /demo/example_specs/demo_fixed_brain_spec_12N.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"DEMO998", 3 | "vol_type": "score", 4 | "resolution":"10.0um", 5 | "detector_id":799, 6 | "structure":["12N"] 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo/example_specs/demo_fixed_brain_spec_3N_R_4N_R.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"DEMO998", 3 | "vol_type": "score", 4 | "structure":["3N_R", "4N_R"], 5 | "resolution":"10.0um", 6 | "detector_id":799 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo/example_specs/demo_moving_brain_spec_12N.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"atlasV7", 3 | "vol_type": "score", 4 | "structure": ["12N"], 5 | "resolution":"10.0um" 6 | } 7 | 8 | -------------------------------------------------------------------------------- /demo/example_specs/demo_moving_brain_spec_3N_R_4N_R.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"atlasV7", 3 | "vol_type": "score", 4 | "structure":["3N_R", "4N_R"], 5 | "resolution":"10.0um" 6 | } 7 | 8 | -------------------------------------------------------------------------------- /demo/example_specs/demo_moving_brain_spec_5N_L.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"atlasV7", 3 | "vol_type": "score", 4 | "structure": ["5N_L"], 5 | "resolution":"10.0um" 6 | } 7 | 8 | -------------------------------------------------------------------------------- /demo/example_specs/demo_visualization_global_alignment_spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "stack_m": 3 | { 4 | "name":"atlasV7", 5 | "vol_type": "score", 6 | "resolution":"10.0um" 7 | }, 8 | "stack_f": 9 | { 10 | "name":"DEMO998", 11 | "vol_type": "score", 12 | "resolution":"10.0um", 13 | "detector_id":799 14 | }, 15 | "warp_setting": 0 16 | } 17 | 18 | -------------------------------------------------------------------------------- /demo/example_specs/demo_visualization_per_structure_alignment_spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "3N_R": 3 | { 4 | "stack_m": 5 | { 6 | "name":"atlasV7", 7 | "vol_type": "score", 8 | "structure":["3N_R", "4N_R"], 9 | "resolution":"10.0um" 10 | }, 11 | "stack_f": 12 | { 13 | "name":"DEMO998", 14 | "vol_type": "score", 15 | "structure":["3N_R", "4N_R"], 16 | "resolution":"10.0um", 17 | "detector_id":799 18 | }, 19 | "warp_setting": 7 20 | }, 21 | "4N_R": 22 | { 23 | "stack_m": 24 | { 25 | "name":"atlasV7", 26 | "vol_type": "score", 27 | "structure":["3N_R", "4N_R"], 28 | "resolution":"10.0um" 29 | }, 30 | "stack_f": 31 | { 32 | "name":"DEMO998", 33 | "vol_type": "score", 34 | "structure":["3N_R", "4N_R"], 35 | "resolution":"10.0um", 36 | "detector_id":799 37 | }, 38 | "warp_setting": 7 39 | }, 40 | 41 | "12N": 42 | { 43 | "stack_m": 44 | { 45 | "name":"atlasV7", 46 | "vol_type": "score", 47 | "structure":["12N"], 48 | "resolution":"10.0um" 49 | }, 50 | "stack_f": 51 | { 52 | "name":"DEMO998", 53 | "vol_type": "score", 54 | "structure":["12N"], 55 | "resolution":"10.0um", 56 | "detector_id":799 57 | }, 58 | "warp_setting": 7 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /demo/example_specs/lauren_experiments.csv: -------------------------------------------------------------------------------- 1 | ,injection_site,marker_color 2 | LM31,PcRT,"(0.69803921568627447, 0.0, 1.0)" 3 | LM40new,DR,"(1.0, 0.0, 0.0)" 4 | LM46,Pno,"(0.0, 0.0, 1.0)" 5 | LM48,PcRT,"(0.69803921568627447, 0.0, 1.0)" 6 | LM54,DR,"(1.0, 0.0, 0.0)" 7 | LM84,Pno,"(0.0, 0.0, 1.0)" 8 | LM94_LM96_LM25,DR,"(1.0, 0.0, 0.0)" 9 | -------------------------------------------------------------------------------- /demo/example_specs/lauren_experiments0.csv: -------------------------------------------------------------------------------- 1 | ,injection_site,marker_color 2 | LM17,CSC,"(0.37647058823529411, 0.78823529411764703, 0.94901960784313721)" 3 | LM22,CSC,"(0.37647058823529411, 0.78823529411764703, 0.94901960784313721)" 4 | LM27,LSC,"(0, 1, 0)" 5 | LM30new,LSC,"(0, 1, 0)" 6 | LM31,PcRT,"(0.69803921568627447, 0.0, 1.0)" 7 | LM32,IC,"(0.70588235294117652, 0.93725490196078431, 0.33725490196078434)" 8 | LM37,MSC,"(1.0, 1.0, 0.0)" 9 | LM38,IC,"(0.70588235294117652, 0.93725490196078431, 0.33725490196078434)" 10 | LM40new,DR,"(1.0, 0.0, 0.0)" 11 | LM41,CSC,"(0.37647058823529411, 0.78823529411764703, 0.94901960784313721)" 12 | LM46,Pno,"(0.0, 0.0, 1.0)" 13 | LM48,PcRT,"(0.69803921568627447, 0.0, 1.0)" 14 | LM54,DR,"(1.0, 0.0, 0.0)" 15 | LM84,Pno,"(0.0, 0.0, 1.0)" 16 | LM86,LSC,"(0, 1, 0)" 17 | LM94_LM96_LM25,DR,"(1.0, 0.0, 0.0)" 18 | LM95,MSC,"(1.0, 1.0, 0.0)" 19 | LM51,PPN,"(.5,0,0)" 20 | LM107,VM,"(0,0.5,0)" 21 | LM106,PPN,"(0,0,0.5)" 22 | LM105,VM,"(0.25,0.25,0)" 23 | -------------------------------------------------------------------------------- /demo/example_specs/lauren_experiments_4.csv: -------------------------------------------------------------------------------- 1 | ,injection_site,marker_color 2 | LM51,,"(.5,0,0)" 3 | LM107,VM,"(0,0.5,0)" 4 | LM106,PPN,"(0,0,0.5)" 5 | LM105,VM,"(0.25,0.25,0)" 6 | 7 | -------------------------------------------------------------------------------- /demo/example_specs/render_config_atlas.csv: -------------------------------------------------------------------------------- 1 | name,color,level,opacity 2 | 10N_L,"(244, 200, 0)",0.5,0.03 3 | 10N_R,"(0, 0, 255)",0.5,0.03 4 | 12N,"(255, 142, 0)",0.5,0.03 5 | 3N_L,"(246, 118, 142)",0.5,0.03 6 | 3N_R,"(206, 162, 98)",0.5,0.03 7 | 4N_L,"(255, 128, 0)",0.5,0.03 8 | 4N_R,"(255, 128, 128)",0.5,0.03 9 | 5N_L,"(255, 128, 128)",0.5,0.03 10 | 5N_R,"(0, 255, 0)",0.5,0.03 11 | 6N_L,"(166, 189, 215)",0.5,0.03 12 | 6N_R,"(255, 104, 0)",0.5,0.03 13 | 7N_L,"(241, 58, 19)",0.5,0.03 14 | 7N_R,"(35, 44, 22)",0.5,0.03 15 | 7n_L,"(255, 255, 0)",0.5,0.03 16 | 7n_R,"(255, 0, 0)",0.5,0.03 17 | AP,"(83, 55, 122)",0.5,0.03 18 | Amb_L,"(0, 83, 138)",0.5,0.03 19 | Amb_R,"(244, 200, 0)",0.5,0.03 20 | DC_L,"(255, 179, 0)",0.5,0.03 21 | DC_R,"(193, 0, 32)",0.5,0.03 22 | IC,"(127, 24, 13)",0.5,0.03 23 | LC_L,"(0, 0, 255)",0.5,0.03 24 | LC_R,"(128, 0, 0)",0.5,0.03 25 | LRt_L,"(128, 62, 117)",0.5,0.03 26 | LRt_R,"(147, 170, 0)",0.5,0.03 27 | PBG_L,"(255, 0, 0)",0.5,0.03 28 | PBG_R,"(0, 83, 138)",0.5,0.03 29 | Pn_L,"(129, 112, 102)",0.5,0.03 30 | Pn_R,"(255, 179, 0)",0.5,0.03 31 | RMC_L,"(255, 0, 255)",0.5,0.03 32 | RMC_R,"(127, 24, 13)",0.5,0.03 33 | RtTg,"(89, 51, 21)",0.5,0.03 34 | SC,"(255, 0, 255)",0.5,0.03 35 | SNC_L,"(179, 40, 81)",0.5,0.03 36 | SNC_R,"(0, 125, 52)",0.5,0.03 37 | SNR_L,"(122, 122, 150)",0.04,0.15 38 | SNR_R,"(128, 128, 128)",0.5,0.03 39 | Sp5C_L,"(35, 44, 22)",0.5,0.03 40 | Sp5C_R,"(255, 255, 0)",0.5,0.03 41 | Sp5I_L,"(0, 255, 0)",0.5,0.03 42 | Sp5I_R,"(166, 189, 215)",0.5,0.03 43 | Sp5O_L,"(255, 104, 0)",0.5,0.03 44 | Sp5O_R,"(241, 58, 19)",0.5,0.03 45 | Tz_L,"(193, 0, 32)",0.5,0.03 46 | Tz_R,"(83, 55, 122)",0.5,0.03 47 | VCA_L,"(128, 0, 0)",0.5,0.03 48 | VCA_R,"(128, 62, 117)",0.5,0.03 49 | VCP_L,"(147, 170, 0)",0.5,0.03 50 | VCP_R,"(129, 112, 102)",0.5,0.03 51 | VLL_L,"(255, 142, 0)",0.5,0.03 52 | VLL_R,"(89, 51, 21)",0.5,0.03 53 | -------------------------------------------------------------------------------- /demo/extract_channel.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import time 6 | import argparse 7 | 8 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 9 | from utilities2015 import * 10 | from metadata import * 11 | from data_manager import * 12 | 13 | parser = argparse.ArgumentParser( 14 | formatter_class=argparse.RawDescriptionHelpFormatter, 15 | description='Rename thumbnail images according to our naming format with consecutive section numbers') 16 | 17 | parser.add_argument("input_spec", type=str, help="Path to input files specification as ini file") 18 | parser.add_argument("channel", type=int, help="Channel index, -1 to produce gray from RGB.") 19 | parser.add_argument("out_version", type=str, help="Output image version") 20 | parser.add_argument("-j", "--njobs", type=int, help="Number of parallel jobs", default=1) 21 | args = parser.parse_args() 22 | 23 | input_spec = load_ini(args.input_spec) 24 | 25 | stack = input_spec['stack'] 26 | prep_id = input_spec['prep_id'] 27 | if prep_id == 'None': 28 | prep_id = None 29 | resol = input_spec['resol'] 30 | version = input_spec['version'] 31 | if version == 'None': 32 | version = None 33 | image_name_list = input_spec['image_name_list'] 34 | if image_name_list == 'all': 35 | image_name_list = DataManager.load_sorted_filenames(stack=stack)[0].keys() 36 | 37 | create_if_not_exists(DataManager.get_image_dir_v2(stack=stack, prep_id=prep_id, resol=resol, version=args.out_version)) 38 | 39 | if args.channel == -1: 40 | run_distributed('convert \"%(in_fp)s\" -set colorspace Gray -separate -average \"%(out_fp)s\"', 41 | kwargs_list=[{'in_fp': DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, 42 | resol=resol, version=version, fn=img_name), 43 | 'out_fp': DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, 44 | resol=resol, version=args.out_version, fn=img_name)} 45 | for img_name in image_name_list], 46 | argument_type='single', 47 | jobs_per_node=args.njobs, 48 | local_only=True) 49 | else: 50 | run_distributed('convert \"%%(in_fp)s\" -channel %(channel)s -separate \"%%(out_fp)s\"' % {'channel': 'RGB'[args.channel]}, 51 | kwargs_list=[{'in_fp': DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, 52 | resol=resol, version=version, fn=img_name), 53 | 'out_fp': DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, 54 | resol=resol, version=args.out_version, fn=img_name)} 55 | for img_name in image_name_list], 56 | argument_type='single', 57 | jobs_per_node=args.njobs, 58 | local_only=True) 59 | 60 | -------------------------------------------------------------------------------- /demo/generate_original_image_crop_csv.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import os 5 | 6 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 7 | from utilities2015 import * 8 | from data_manager import * 9 | from metadata import * 10 | from distributed_utilities import * 11 | import pandas as pd 12 | 13 | import argparse 14 | 15 | parser = argparse.ArgumentParser( 16 | formatter_class=argparse.RawDescriptionHelpFormatter, 17 | description='Generate original_image_crop.csv') 18 | 19 | parser.add_argument("input_spec", type=str, help="Input image specification") 20 | args = parser.parse_args() 21 | 22 | input_spec = load_ini(args.input_spec) 23 | 24 | stack = input_spec['stack'] 25 | prep_id = input_spec['prep_id'] 26 | if prep_id == 'None': 27 | prep_id = None 28 | resol = input_spec['resol'] 29 | version = input_spec['version'] 30 | if version == 'None': 31 | version = None 32 | 33 | image_name_list = input_spec['image_name_list'] 34 | if image_name_list == 'all': 35 | image_name_list = DataManager.load_sorted_filenames(stack=stack)[0].keys() 36 | 37 | # x,y,w,h 38 | d = {img_name: \ 39 | (0,0) + DataManager.load_image_v2(stack=stack, prep_id=prep_id, resol=resol, version=version, fn=img_name).shape[::-1] 40 | for img_name in image_name_list} 41 | 42 | df = pd.DataFrame.from_dict({k: np.array(v).flatten() for k, v in d.iteritems()}, orient='index') 43 | df.to_csv(os.path.join(DATA_ROOTDIR, 'CSHL_data_processed', stack, stack + '_original_image_crop.csv'), header=False) 44 | -------------------------------------------------------------------------------- /demo/jp2_to_tiff.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import time 6 | import argparse 7 | 8 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 9 | from utilities2015 import * 10 | from metadata import * 11 | from data_manager import * 12 | 13 | parser = argparse.ArgumentParser( 14 | formatter_class=argparse.RawDescriptionHelpFormatter, 15 | description='Rename thumbnail images according to our naming format with consecutive section numbers') 16 | 17 | parser.add_argument("stack_name", type=str, help="stack name") 18 | parser.add_argument("spec", type=str, help="Path to input files specification as json file") 19 | args = parser.parse_args() 20 | 21 | stack = args.stack_name 22 | with open(args.spec, 'r') as f: 23 | input_spec = json.load(f) 24 | 25 | data_dirs = {} 26 | imageName_to_filepath_mapping = {} 27 | filepath_to_imageName_mapping = {} 28 | for spec_one_version in input_spec: 29 | vr = (spec_one_version['version'], spec_one_version['resolution']) 30 | data_dirs[vr] = spec_one_version['data_dirs'] 31 | filepath_to_imageName_mapping[vr] = spec_one_version['filepath_to_imageName_mapping'] 32 | imageName_to_filepath_mapping[vr] = spec_one_version['imageName_to_filepath_mapping'] 33 | 34 | image_names_all_data_dirs_flattened = set([]) 35 | image_names_all_data_dirs = {} 36 | for vr, data_dir in data_dirs.iteritems(): 37 | if data_dir is None: continue 38 | image_names = set([]) 39 | if vr in filepath_to_imageName_mapping: 40 | for fn in os.listdir(data_dir): 41 | g = re.search(filepath_to_imageName_mapping[vr], os.path.join(data_dir, fn)) 42 | if g is not None: 43 | img_name = g.groups()[0] 44 | image_names.add(img_name) 45 | image_names_all_data_dirs_flattened.add(img_name) 46 | image_names_all_data_dirs[vr] = image_names 47 | 48 | print "Found %d images.\n" % len(image_names_all_data_dirs_flattened) 49 | 50 | # Make sure the every image has all three channels. 51 | for vr, img_names in image_names_all_data_dirs.iteritems(): 52 | print vr, 'missing:' 53 | print image_names_all_data_dirs_flattened - img_names 54 | 55 | create_if_not_exists(DataManager.get_image_dir_v2(stack=stack, prep_id=None, resol='raw')) 56 | 57 | # The KDU program automatically uses all cores, so we just set jobs_per_node = 1. 58 | run_distributed('export LD_LIBRARY_PATH=%(kdu_dir)s:$LD_LIBRARY_PATH; %(kdu_bin)s -i \"%%(in_fp)s\" -o \"%%(out_fp)s\"' % \ 59 | {'kdu_bin': KDU_EXPAND_BIN, 'kdu_dir': os.path.dirname(KDU_EXPAND_BIN)}, 60 | kwargs_list={'in_fp': [imageName_to_filepath_mapping[(None, 'raw')] % img_name 61 | for img_name in list(image_names_all_data_dirs_flattened)], 62 | 'out_fp': [DataManager.get_image_filepath_v2(stack=stack, prep_id=None, 63 | resol='raw', version=None, fn=img_name) 64 | for img_name in list(image_names_all_data_dirs_flattened)]}, 65 | argument_type='single', 66 | jobs_per_node=1, 67 | local_only=True) 68 | -------------------------------------------------------------------------------- /demo/masking.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import time 6 | 7 | import numpy as np 8 | from multiprocess import Pool 9 | 10 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 11 | from utilities2015 import * 12 | from data_manager import * 13 | from preprocess_utilities import * 14 | 15 | ####################################################################################### 16 | 17 | import argparse 18 | 19 | parser = argparse.ArgumentParser( 20 | formatter_class=argparse.RawDescriptionHelpFormatter, 21 | description='Generate masks for aligned thumbnail images') 22 | parser.add_argument("input_spec", type=str, help="stack name") 23 | parser.add_argument("init_snake_contours_fp", type=str, help="initial snake contour file path") 24 | parser.add_argument("--min_size", type=int, help="minimum submask size", default=MIN_SUBMASK_SIZE) 25 | parser.add_argument("--default_channel", type=int, help="default RGB channel to do snake on; ignored if input images are single-channel", default=0) 26 | parser.add_argument("--shrink", type=float, help="shrink strength or lambda1 in morphsnake paper, default 1", default=1.) 27 | args = parser.parse_args() 28 | 29 | input_spec = load_ini(args.input_spec) 30 | stack = input_spec['stack'] 31 | prep_id = input_spec['prep_id'] 32 | if prep_id == 'None': 33 | prep_id = None 34 | resol = input_spec['resol'] 35 | version = input_spec['version'] 36 | if version == 'None': 37 | version = None 38 | 39 | image_name_list = input_spec['image_name_list'] 40 | if image_name_list == 'all': 41 | image_name_list = DataManager.load_sorted_filenames(stack=stack)[0].keys() 42 | 43 | 44 | min_size = args.min_size 45 | default_channel = args.default_channel 46 | lambda1 = args.shrink 47 | 48 | init_snake_contours_fp = args.init_snake_contours_fp 49 | download_from_s3(init_snake_contours_fp) 50 | init_snake_contour_vertices = load_pickle(init_snake_contours_fp) # {fn: vertices} 51 | 52 | ############################################## 53 | 54 | def generate_contours(img_name, init_cnt): 55 | 56 | img = DataManager.load_image_v2(stack=stack, fn=img_name, resol=resol, prep_id=prep_id, version=version) 57 | img = brightfieldize_image(img) 58 | if img.ndim == 3: 59 | img = contrast_stretch_image(img[..., default_channel]) 60 | else: 61 | img = contrast_stretch_image(img) 62 | submasks = snake(img, init_contours=[init_cnt], lambda1=lambda1, min_size=min_size) 63 | submasks = dict(enumerate(submasks)) 64 | 65 | if len(submasks) == 0: 66 | sys.stderr.write("No submask is found.") 67 | return 68 | 69 | # Create output dir. 70 | create_if_not_exists(DataManager.get_auto_submask_dir_filepath(stack=stack, fn=img_name)) 71 | 72 | # Save submasks 73 | for submask_ind, m in submasks.iteritems(): 74 | submask_fp = DataManager.get_auto_submask_filepath(stack=stack, fn=img_name, what='submask', submask_ind=submask_ind) 75 | imsave(submask_fp, np.uint8(m)*255) 76 | upload_to_s3(submask_fp) 77 | 78 | submask_decisions = {sm_i: True for sm_i in submasks.iterkeys()} 79 | 80 | # Save submask decisions 81 | decisions_fp = DataManager.get_auto_submask_filepath(stack=stack, fn=img_name, what='decisions') 82 | from pandas import Series 83 | Series(submask_decisions).to_csv(decisions_fp) 84 | upload_to_s3(decisions_fp) 85 | 86 | 87 | t = time.time() 88 | 89 | # pool = Pool(NUM_CORES/2) 90 | pool = Pool(NUM_CORES) 91 | pool.map(lambda img_name: generate_contours(img_name, init_snake_contour_vertices[img_name]), image_name_list) 92 | pool.close() 93 | pool.join() 94 | 95 | # for fn in filenames: 96 | # generate_contours(fn, init_snake_contour_vertices[fn]) 97 | 98 | sys.stderr.write('Generate contours: %.2f\n' % (time.time()-t)) 99 | -------------------------------------------------------------------------------- /demo/normalize_intensity.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import argparse 4 | 5 | parser = argparse.ArgumentParser( 6 | formatter_class=argparse.RawDescriptionHelpFormatter, 7 | description='Linearly normalize intensity to between 0 and 255') 8 | 9 | parser.add_argument("input_spec", type=str, help="Input specification") 10 | parser.add_argument("out_version", type=str, help="Output image version") 11 | args = parser.parse_args() 12 | 13 | import sys 14 | import os 15 | 16 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 17 | from utilities2015 import * 18 | from data_manager import * 19 | from metadata import * 20 | from distributed_utilities import * 21 | 22 | 23 | out_version = args.out_version 24 | 25 | input_spec = load_ini(args.input_spec) 26 | image_name_list = input_spec['image_name_list'] 27 | stack = input_spec['stack'] 28 | prep_id = input_spec['prep_id'] 29 | if prep_id == 'None': 30 | prep_id = None 31 | resol = input_spec['resol'] 32 | version = input_spec['version'] 33 | if version == 'None': 34 | version = None 35 | 36 | for img_name in image_name_list: 37 | 38 | t = time.time() 39 | 40 | in_fp = DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, resol=resol, version=version, fn=img_name) 41 | out_fp = DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, resol=resol, version=out_version, fn=img_name) 42 | create_parent_dir_if_not_exists(out_fp) 43 | 44 | cmd = """convert "%(in_fp)s" -normalize -depth 8 "%(out_fp)s" """ % {'in_fp': in_fp, 'out_fp': out_fp} 45 | execute_command(cmd) 46 | 47 | sys.stderr.write("Intensity normalize: %.2f seconds.\n" % (time.time() - t)) 48 | -------------------------------------------------------------------------------- /demo/rescale.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import os 5 | 6 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 7 | from utilities2015 import * 8 | from data_manager import * 9 | from metadata import * 10 | from distributed_utilities import * 11 | 12 | import argparse 13 | 14 | parser = argparse.ArgumentParser( 15 | formatter_class=argparse.RawDescriptionHelpFormatter, 16 | description='Rescale image') 17 | 18 | parser.add_argument("input_spec", type=str, help="Input image name") 19 | parser.add_argument('out_resol', type=str, help='') 20 | parser.add_argument("-f", "--rescale_factor", type=float, help="Rescale factor") 21 | parser.add_argument("-W", "--width", type=int, help="Width") 22 | parser.add_argument("-H", "--height", type=int, help="Height") 23 | args = parser.parse_args() 24 | 25 | input_spec = load_ini(args.input_spec) 26 | stack = input_spec['stack'] 27 | prep_id = input_spec['prep_id'] 28 | if prep_id == 'None': 29 | prep_id = None 30 | resol = input_spec['resol'] 31 | version = input_spec['version'] 32 | if version == 'None': 33 | version = None 34 | 35 | image_name_list = input_spec['image_name_list'] 36 | if image_name_list == 'all': 37 | image_name_list = DataManager.load_sorted_filenames(stack=stack)[0].keys() 38 | 39 | 40 | for img_name in image_name_list: 41 | 42 | t = time.time() 43 | 44 | in_fp = DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, resol=resol, version=version, fn=img_name) 45 | out_fp = DataManager.get_image_filepath_v2(stack=stack, prep_id=prep_id, resol=args.out_resol, version=version, fn=img_name) 46 | create_parent_dir_if_not_exists(out_fp) 47 | 48 | img = imread(in_fp) 49 | print in_fp 50 | print img.dtype 51 | 52 | img_tb = img[::int(1./args.rescale_factor), ::int(1./args.rescale_factor)] 53 | imsave(out_fp, img_tb) 54 | 55 | # Alternative: ImageMagick introduces an artificial noisy stripe in the output image. 56 | # cmd = 'convert %(in_fp)s -scale 3.125%% %(out_fp)s' % {'in_fp': in_fp, 'out_fp': out_fp} 57 | # execute_command(cmd) 58 | 59 | sys.stderr.write("Rescale: %.2f seconds.\n" % (time.time() - t)) # ~20s / image 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /demo/todo/demo_render3d.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import os 5 | from ast import literal_eval 6 | import time 7 | import argparse 8 | 9 | import numpy as np 10 | import bloscpack as bp 11 | import pandas as pd 12 | 13 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 14 | from utilities2015 import * 15 | from annotation_utilities import * 16 | from registration_utilities import * 17 | from vis3d_utilities import * 18 | from metadata import * 19 | from data_manager import * 20 | 21 | parser = argparse.ArgumentParser( 22 | formatter_class=argparse.RawDescriptionHelpFormatter, 23 | description='This script renders the atlas in 3D using VTK, with optional markers.') 24 | 25 | # parser.add_argument("--fixed_brain_spec", type=str, help="Fixed brain specification, json", default='demo_fixed_brain_spec_12N.json') 26 | # parser.add_argument("--moving_brain_spec", type=str, help="Moving brain specification, json", default='demo_moving_brain_spec_12N.json') 27 | # parser.add_argument("-r", "--registration_setting", type=int, help="Registration setting, int, defined in registration_settings.csv", default=7) 28 | # parser.add_argument("-g", "--use_simple_global", action='store_false', help="Set this flag to NOT initialize with simple global registration") 29 | # parser.add_argument("--out_dir", type=str, help="Output directory") 30 | parser.add_argument("--render_config_atlas", type=str, help="csv file specifying the color/opacity of each structure. Default: %(default)s", default='render_config_atlas.csv') 31 | parser.add_argument("--experiments_config", type=str, help="A csv file with each row specifying info for one experiment. Default: %(default)s", default='lauren_experiments.csv') 32 | 33 | args = parser.parse_args() 34 | 35 | # Set this to true if want to show a largest possible SNR_L with the lowest possible level. 36 | #use_big_snr_l = True 37 | use_big_snr_l = True 38 | 39 | render_config_atlas = pd.read_csv(args.render_config_atlas, index_col='name').to_dict() 40 | render_config_atlas['color'] = {s: eval(c) for s, c in render_config_atlas['color'].iteritems()} 41 | render_config_atlas['level'] = {s: float(l) for s, l in render_config_atlas['level'].iteritems()} 42 | 43 | # atlas_spec = load_json(args.fixed_brain_spec) 44 | # brain_m_spec = load_json(args.moving_brain_spec) 45 | # registration_setting = args.registration_setting 46 | # use_simple_global = args.use_simple_global 47 | 48 | experiments = pd.read_csv(args.experiments_config, index_col=0).T.to_dict() 49 | 50 | atlas_name = 'atlasV7' 51 | atlas_spec = dict(name=atlas_name, resolution='10.0um', vol_type='score') 52 | 53 | #################################### 54 | 55 | atlas_meshes_10um = DataManager.load_meshes_v2(atlas_spec, sided=True, return_polydata_only=False, 56 | include_surround=False, levels=render_config_atlas['level']) 57 | atlas_meshes_um = {s: mesh_to_polydata(vertices=v*10., faces=f) for s, (v, f) in atlas_meshes_10um.iteritems()} 58 | 59 | if use_big_snr_l: 60 | 61 | SNR_L_vol_10um, SNR_L_origin_10um_wrt_canonicalAtlasSpace =\ 62 | DataManager.load_original_volume_v2(stack_spec=atlas_spec, structure='SNR_L', bbox_wrt='canonicalAtlasSpace') 63 | 64 | #SNR_R_vol_10um, SNR_R_ori_10um_wrt_canonicalAtlasSpace =\ 65 | #DataManager.load_original_volume_v2(stack_spec=atlas_spec, structure='SNR_R', bbox_wrt='canonicalAtlasSpace') 66 | #SNR_L_nominal_location_1um_wrt_canonicalAtlasSpace = load_data(DataManager.get_structure_mean_positions_filepath(atlas_name=atlas_name, resolution='1um'))['SNR_L'] 67 | #SNR_L_nominal_location_10um_wrt_canonicalAtlasSpace = SNR_L_nominal_location_1um_wrt_canonicalAtlasSpace / 10. 68 | #SNR_L_vol_10um, SNR_L_origin_10um_wrt_canonicalAtlasSpace = \ 69 | #mirror_volume_v2(SNR_R_vol_10um, SNR_L_nominal_location_10um_wrt_canonicalAtlasSpace) 70 | 71 | level = 0.000001 72 | num_simplify_iter = 4 73 | 74 | SNR_L_mesh_level01_vertices_10um, SNR_L_mesh_level01_faces = \ 75 | volume_to_polydata(volume=(SNR_L_vol_10um, SNR_L_origin_10um_wrt_canonicalAtlasSpace), 76 | level=level, 77 | num_simplify_iter=num_simplify_iter, 78 | smooth=True, 79 | return_vertex_face_list=True) 80 | 81 | SNR_L_mesh_level01_um = mesh_to_polydata(vertices=SNR_L_mesh_level01_vertices_10um * 10., 82 | faces=SNR_L_mesh_level01_faces) 83 | 84 | atlas_meshes_um['SNR_L'] = SNR_L_mesh_level01_um 85 | 86 | atlas_structure_actors_um = {s: actor_mesh(m, 87 | color=np.array(render_config_atlas['color'][s])/255., 88 | opacity=render_config_atlas['opacity'][s], 89 | ) 90 | for s, m in atlas_meshes_um.iteritems()} 91 | 92 | shell_polydata_10um_wrt_canonicalAtlasSpace = DataManager.load_mesh_v2(brain_spec=dict(name=atlas_name, vol_type='score', resolution='10.0um'), 93 | structure='shell') 94 | 95 | shell_polydata_um_wrt_canonicalAtlasSpace = rescale_polydata(shell_polydata_10um_wrt_canonicalAtlasSpace, 10.) 96 | 97 | shell_actor_um_wrt_canonicalAtlasSpace = actor_mesh(shell_polydata_um_wrt_canonicalAtlasSpace, (1,1,1), opacity=.1, 98 | wireframe=False) 99 | 100 | marker_resolution = '10.0um' 101 | 102 | markers_rel2atlas_actors = {} 103 | aligned_markers_rel2atlas_um_all_brains = {} 104 | 105 | for brain_name, experiment_info in experiments.iteritems(): 106 | # Load Neurolucida format. 107 | 108 | markers = load_data(DataManager.get_lauren_markers_filepath(brain_name, structure='All', resolution=marker_resolution)) 109 | 110 | #sample_n = min(len(markers), max(len(markers)/5, 10)) # Choice: sample 20% of each experiment but at least 10 markers 111 | sample_n = min(len(markers), 200) # Choice: randomly sample 50 markers for each experiment 112 | #sample_n = len(markers) # Choice: show all markers 113 | print brain_name, 'showing', sample_n, '/', len(markers) 114 | markers = markers[np.random.choice(range(len(markers)), size=sample_n, replace=False)] 115 | 116 | brain_f_spec = dict(name=brain_name, vol_type='annotationAsScore', structure='SNR_L', resolution='10.0um') 117 | brain_m_spec = dict(name=atlas_name, resolution='10.0um', vol_type='score', structure='SNR_L') 118 | alignment_spec = dict(stack_m=brain_m_spec, stack_f=brain_f_spec, warp_setting=7) 119 | 120 | tf_atlas_to_subj = DataManager.load_alignment_results_v3(alignment_spec, what='parameters', out_form=(4,4)) 121 | 122 | markers_rel2subj = {marker_id: marker_xyz for marker_id, marker_xyz in enumerate(markers)} 123 | 124 | aligned_markers_rel2atlas = {marker_ind: transform_points(pts=p, transform=np.linalg.inv(tf_atlas_to_subj)) 125 | for marker_ind, p in markers_rel2subj.iteritems()} 126 | 127 | aligned_markers_rel2atlas_um = {marker_ind: p * convert_resolution_string_to_um(marker_resolution) 128 | for marker_ind, p in aligned_markers_rel2atlas.iteritems()} 129 | 130 | aligned_markers_rel2atlas_um_all_brains[brain_name] = aligned_markers_rel2atlas_um 131 | 132 | markers_rel2atlas_actors[brain_name] = [actor_sphere(position=(x,y,z), radius=20, 133 | color=literal_eval(experiment_info['marker_color']), 134 | opacity=.6 ) 135 | for marker_id, (x,y,z) in aligned_markers_rel2atlas_um.iteritems()] 136 | 137 | 138 | launch_vtk( 139 | [m for b, marker_actors in markers_rel2atlas_actors.iteritems() for m in marker_actors ] \ 140 | + atlas_structure_actors_um.values() \ 141 | + [shell_actor_um_wrt_canonicalAtlasSpace] \ 142 | #+ [actor_sphere(position=(0,0,0), radius=5, color=(1,1,1), opacity=1.)] 143 | , 144 | #init_angle='sagittal' 145 | init_angle='horizontal_topDown' 146 | #init_angle='coronal_posteriorToAnterior' 147 | 148 | 149 | ) 150 | -------------------------------------------------------------------------------- /demo/todo/download_demo_data_render3d.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys, os 4 | sys.path.append(os.path.join(os.environ['REPO_DIR'], 'utilities')) 5 | from utilities2015 import * 6 | from metadata import * 7 | from data_manager import * 8 | 9 | import argparse 10 | 11 | parser = argparse.ArgumentParser( 12 | formatter_class=argparse.RawDescriptionHelpFormatter, 13 | description='This script downloads input data for demo.') 14 | 15 | parser.add_argument("-d", "--demo_data_dir", type=str, help="Directory to store demo input data", default='demo_data') 16 | args = parser.parse_args() 17 | 18 | # demo_data_dir = '/home/yuncong/Brain/demo_data/' 19 | 20 | def download_to_demo(fp): 21 | demo_data_dir = args.demo_data_dir 22 | s3_http_prefix = 'https://s3-us-west-1.amazonaws.com/mousebrainatlas-data/' 23 | url = s3_http_prefix + fp 24 | demo_fp = os.path.join(demo_data_dir, fp) 25 | execute_command('wget -N -P \"%s\" \"%s\"' % (os.path.dirname(demo_fp), url)) 26 | return demo_fp 27 | 28 | ##### For 3D rendering demo ##### 29 | 30 | # Download atlasV7 meshes. 31 | atlas_name = 'atlasV7' 32 | atlas_spec = dict(name=atlas_name, resolution='10.0um', vol_type='score') 33 | 34 | for structure in all_known_structures_sided: 35 | for level in [.5]: 36 | fp = DataManager.get_mesh_filepath_v2(brain_spec=atlas_spec, structure=structure, level=level) 37 | rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 38 | download_to_demo(rel_fp) 39 | 40 | fp = DataManager.get_mesh_filepath_v2(brain_spec=atlas_spec, structure='shell') 41 | rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 42 | download_to_demo(rel_fp) 43 | 44 | # Download atlasV7 structures 45 | 46 | structure = 'SNR_L' 47 | 48 | fp = DataManager.get_original_volume_filepath_v2(stack_spec=atlas_spec, structure=structure) 49 | rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 50 | download_to_demo(rel_fp) 51 | 52 | fp = DataManager.get_original_volume_origin_filepath_v3(stack_spec=atlas_spec, structure=structure, wrt='canonicalAtlasSpace') 53 | rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 54 | download_to_demo(rel_fp) 55 | 56 | # Download Lauren's experiment's markers that are before aligning to atlas. 57 | 58 | marker_resolution = '10.0um' 59 | for brain_name in ['LM94_LM96_LM25', 'LM38', 'LM30new', 'LM27', 'LM37', 'LM22', 'LM32', 'LM17', 'LM48', 'LM31', 'LM95', 'LM41', 'LM84', 'LM40new', 'LM86', 'LM54', 'LM46', 'LM51', 'LM107', 'LM106', 'LM105']: 60 | fp = DataManager.get_lauren_markers_filepath(brain_name, structure='All', resolution=marker_resolution) 61 | rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 62 | download_to_demo(rel_fp) 63 | 64 | # Download Lauren's experiment brains' registration parameters 65 | 66 | brain_f_spec = dict(name=brain_name, vol_type='annotationAsScore', structure='SNR_L', resolution='10.0um') 67 | brain_m_spec = dict(name=atlas_name, resolution='10.0um', vol_type='score', structure='SNR_L') 68 | alignment_spec = dict(stack_m=brain_m_spec, stack_f=brain_f_spec, warp_setting=7) 69 | fp = DataManager.get_alignment_result_filepath_v3(alignment_spec=alignment_spec, what='parameters') 70 | rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 71 | download_to_demo(rel_fp) 72 | 73 | # ##### For registration demo. ##### 74 | # 75 | # fp = DataManager.get_sorted_filenames_filename(stack='DEMO999') 76 | # rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 77 | # sorted_filenames_fp_demo = download_to_demo(rel_fp) 78 | # 79 | # fp = DataManager.get_anchor_filename_filename(stack='DEMO999') 80 | # rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 81 | # anchor_fp_demo = download_to_demo(rel_fp) 82 | # 83 | # anchor_fn = DataManager.load_data(anchor_fp_demo, filetype='anchor') 84 | # 85 | # fp = DataManager.get_section_limits_filename_v2(stack='DEMO999', anchor_fn=anchor_fn) 86 | # rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 87 | # download_to_demo(rel_fp) 88 | # 89 | # fp = DataManager.get_cropbox_filename_v2(stack='DEMO999', prep_id=2, anchor_fn=anchor_fn) 90 | # rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 91 | # download_to_demo(rel_fp) 92 | # 93 | # download_to_demo(os.path.join('CSHL_simple_global_registration', 'DEMO999_T_atlas_wrt_canonicalAtlasSpace_subject_wrt_wholebrain_atlasResol.bp')) 94 | # 95 | # # Download subject detection maps 96 | # for name_s in ['3N_R', '4N_R', '12N']: 97 | # 98 | # fp = DataManager.get_score_volume_filepath_v3(stack_spec={'name':'DEMO999', 'detector_id':799, 'resolution':'10.0um', 'vol_type':'score'}, structure=name_s) 99 | # rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 100 | # download_to_demo(rel_fp) 101 | # 102 | # fp = DataManager.get_score_volume_origin_filepath_v3(stack_spec={'name':'DEMO999', 'detector_id':799, 'resolution':'10.0um', 'vol_type':'score'}, structure=name_s, wrt='wholebrain') 103 | # rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 104 | # download_to_demo(rel_fp) 105 | # 106 | # # Download atlas 107 | # for name_s in ['3N_R', '4N_R', '3N_R_surround_200um', '4N_R_surround_200um','12N', '12N_surround_200um']: 108 | # 109 | # fp = DataManager.get_score_volume_filepath_v3(stack_spec={'name':'atlasV7', 'resolution':'10.0um', 'vol_type':'score'}, structure=name_s) 110 | # rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 111 | # download_to_demo(rel_fp) 112 | # 113 | # fp = DataManager.get_score_volume_origin_filepath_v3(stack_spec={'name':'atlasV7', 'resolution':'10.0um', 'vol_type':'score'}, structure=name_s, wrt='canonicalAtlasSpace') 114 | # rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 115 | # download_to_demo(rel_fp) 116 | # 117 | # ##### For visualization demo. ##### 118 | # 119 | # # Download images 120 | # for sec in range(221, 238): 121 | # fp = DataManager.get_image_filepath_v2(stack='DEMO999', prep_id=2, resol='raw', version='NtbNormalizedAdaptiveInvertedGammaJpeg', section=sec, sorted_filenames_fp=sorted_filenames_fp_demo) 122 | # rel_fp = relative_to_local(fp, local_root=DATA_ROOTDIR) 123 | # download_to_demo(rel_fp) 124 | # 125 | # fp = DataManager.get_original_volume_filepath_v2(stack_spec={'name':'DEMO999', 'resolution':'10.0um', 'vol_type':'intensity', 'prep_id':'wholebrainWithMargin'}, structure=None) 126 | # rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 127 | # download_to_demo(rel_fp) 128 | # 129 | # fp = DataManager.get_original_volume_origin_filepath_v3(stack_spec={'name':'DEMO999', 'resolution':'10.0um', 'vol_type':'intensity', 'prep_id':'wholebrainWithMargin'}, structure=None) 130 | # rel_fp = relative_to_local(fp, local_root=ROOT_DIR) 131 | # download_to_demo(rel_fp) 132 | # 133 | # download_to_demo(os.path.join('CSHL_simple_global_registration', 'DEMO999_registered_atlas_structures_wrt_wholebrainXYcropped_xysecTwoCorners.json')) 134 | -------------------------------------------------------------------------------- /doc/example_registration_visualization.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ActiveBrainAtlas/MouseBrainAtlas/b6ca6afcfc88f6772b073b9ad2bf5d0b3bf840bd/doc/example_registration_visualization.jpg -------------------------------------------------------------------------------- /doc/mask_generation.md: -------------------------------------------------------------------------------- 1 | 2 | - On a machine with monitor, launch the maskingGUI. Run `DATA_ROOTDIR=/home/yuncong/brainstem/home/yuncong/demo_data ROOT_DIR=/home/yuncong/brainstem/home/yuncong/demo_data THUMBNAIL_DATA_ROOTDIR=/home/yuncong/brainstem/home/yuncong/demo_data python src/gui/mask_editing_tool_v4.py DEMO998 NtbNormalized`. Generate initial masks. 3 | 4 | ```bash 5 | ├── CSHL_data_processed 6 | │   └── DEMO998 7 | │   ├── DEMO998_prep1_thumbnail_anchorInitSnakeContours.pkl 8 | │   ├── DEMO998_prep1_thumbnail_initSnakeContours.pkl 9 | ``` 10 | 11 | - Modify `input_spec.ini` as (alignedPadded,NtbNormalized,thumbnail). `python masking.py example_specs/DEMO998_input_spec.ini /home/yuncong/demo_data/CSHL_data_processed/DEMO998/DEMO998_prep1_thumbnail_initSnakeContours.pkl` 12 | 13 | ```bash 14 | ├── CSHL_data_processed 15 | │   └── DEMO998 16 | │   ├── DEMO998_prep1_thumbnail_autoSubmasks 17 | │   │   ├── MD662&661-F81-2017.06.06-12.44.40_MD661_2_0242 18 | │   │   │   ├── MD662&661-F81-2017.06.06-12.44.40_MD661_2_0242_prep1_thumbnail_autoSubmask_0.png 19 | │   │   │   └── MD662&661-F81-2017.06.06-12.44.40_MD661_2_0242_prep1_thumbnail_autoSubmaskDecisions.csv 20 | │   │   ├── MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250 21 | │   │   │   ├── MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250_prep1_thumbnail_autoSubmask_0.png 22 | │   │   │   └── MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250_prep1_thumbnail_autoSubmaskDecisions.csv 23 | │   │   └── MD662&661-F86-2017.06.06-14.56.48_MD661_2_0257 24 | │   │   ├── MD662&661-F86-2017.06.06-14.56.48_MD661_2_0257_prep1_thumbnail_autoSubmask_0.png 25 | │   │   └── MD662&661-F86-2017.06.06-14.56.48_MD661_2_0257_prep1_thumbnail_autoSubmaskDecisions.csv 26 | ``` 27 | 28 | - Re-launch masking GUI to inspect, correct the automatically generated masks, then export as PNGs. 29 | 30 | ```bash 31 | ├── CSHL_data_processed 32 | │   └── DEMO998 33 | │   ├── DEMO998_prep1_thumbnail_mask 34 | │   │   ├── MD662&661-F81-2017.06.06-12.44.40_MD661_2_0242_prep1_thumbnail_mask.png 35 | │   │   ├── MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250_prep1_thumbnail_mask.png 36 | │   │   └── MD662&661-F86-2017.06.06-14.56.48_MD661_2_0257_prep1_thumbnail_mask.png 37 | ``` 38 | 39 | - Modify `input_spec.ini` as (None,NtbNormalized,thumbnail). Run `python generate_original_image_crop_csv.py example_specs/DEMO998_input_spec.ini`. 40 | 41 | ```bash 42 | ├── CSHL_data_processed 43 | │   └── DEMO998 44 | │   ├── DEMO998_original_image_crop.csv 45 | ``` 46 | - Copy operation config template. `cp $DATA_ROOTDIR/operation_configs/crop_orig_template.ini $DATA_ROOTDIR/CSHL_data_processed/DEMO998/DEMO998_operation_configs/crop_orig.ini`. Modify `crop_orig.ini`. 47 | - Modify `input_spec.ini` as (alignedPadded,mask,thumbnail). Run `python warp_crop.py --input_spec example_specs/DEMO998_input_spec.ini --op_id from_padded_to_none`. 48 | 49 | ```bash 50 | ├── CSHL_data_processed 51 | │   └── DEMO998 52 | │   ├── DEMO998_thumbnail_mask 53 | │   │   ├── MD662&661-F81-2017.06.06-12.44.40_MD661_2_0242_thumbnail_mask.png 54 | │   │   ├── MD662&661-F84-2017.06.06-14.03.51_MD661_1_0250_thumbnail_mask.png 55 | │   │   └── MD662&661-F86-2017.06.06-14.56.48_MD661_2_0257_thumbnail_mask.png 56 | -------------------------------------------------------------------------------- /doc/rough_global_transform.md: -------------------------------------------------------------------------------- 1 | Between "Create section limits" and "Download atlas" 2 | 3 | - **Create intensity volume**. Run `./construct_intensity_volume.py DEMO998 --tb_version NtbNormalizedAdaptiveInvertedGamma --tb_resol thumbnail` 4 | 5 | ```bash 6 | ├── CSHL_volumes 7 | │   └── DEMO998 8 | │   └── DEMO998_wholebrainWithMargin_10.0um_intensityVolume 9 | │   ├── DEMO998_wholebrainWithMargin_10.0um_intensityVolume.bp 10 | │   └── DEMO998_wholebrainWithMargin_10.0um_intensityVolume_origin_wrt_wholebrain.txt 11 | ``` 12 | 13 | - **Manual rough global registration**. Run `DATA_ROOTDIR=/home/yuncong/brainstem/home/yuncong/demo_data ROOT_DIR=/home/yuncong/brainstem/home/yuncong/demo_data THUMBNAIL_DATA_ROOTDIR=/home/yuncong/brainstem/home/yuncong/demo_data python src/gui/brain_labeling_gui_v28.py DEMO998 --img_version NtbNormalizedAdaptiveInvertedGammaJpeg`. Note down x and y coordinates of the center of 12N and of 3N. Also note down the z-coordinate of the midline. Coordinates show up when clicking on the high resolution panel while holding the space bar. 14 | 15 | - Create `$DATA_ROOTDIR/CSHL_simple_global_registration/DEMO998_manual_anchor_points.ini` with the above information. 16 | 17 | ```bash 18 | [DEFAULT] 19 | x_12N=561 20 | y_12N=204 21 | x_3N=372 22 | y_3N=167 23 | z_midline=6 24 | ``` 25 | 26 | Between "download atlas" and "Download pre-trained classifiers" 27 | 28 | - **Compute rough global registration matrix**. Run `python compute_simple_global_registration.py DEMO998 $DATA_ROOTDIR/CSHL_simple_global_registration/DEMO998_manual_anchor_points.ini`. 29 | 30 | ```bash 31 | ├── CSHL_simple_global_registration 32 | │ ├── DEMO998_registered_atlas_structures_wrt_wholebrainXYcropped_xysecTwoCorners.json 33 | │ └── DEMO998_T_atlas_wrt_canonicalAtlasSpace_subject_wrt_wholebrain_atlasResol.txt 34 | -------------------------------------------------------------------------------- /setup/config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # User can modify this part 4 | PROJECT_DIR=/home/yuncong/MouseBrainAtlas_dev_trial3 5 | virtualenv="mousebrainatlas_virtualenv" 6 | ################################################## 7 | 8 | red='\e[1;31m' 9 | purple='\e[1;35m' 10 | green='\e[1;32m' 11 | cyan='\e[1;36m' 12 | NC='\033[0m' # No Color 13 | 14 | export REPO_DIR=$PROJECT_DIR/src 15 | 16 | #export ROOT_DIR=$PROJECT_DIR/demo/demo_data/ 17 | #export DATA_ROOTDIR=$PROJECT_DIR/demo/demo_data/ 18 | #export THUMBNAIL_DATA_ROOTDIR=$PROJECT_DIR/demo/demo_data/ 19 | 20 | #export ROOT_DIR=/media/yuncong/BstemAtlasData/atlas_data 21 | #export DATA_ROOTDIR=/media/yuncong/BstemAtlasData/atlas_data 22 | #export THUMBNAIL_DATA_ROOTDIR=/media/yuncong/BstemAtlasData/atlas_data 23 | 24 | export ROOT_DIR=/home/yuncong/demo_data 25 | export DATA_ROOTDIR=/home/yuncong/demo_data 26 | export THUMBNAIL_DATA_ROOTDIR=/home/yuncong/demo_data 27 | 28 | #export ROOT_DIR=/home/yuncong/brainstem/media/yuncong/BstemAtlasData/atlas_data 29 | #export DATA_ROOTDIR=/home/yuncong/brainstem/media/yuncong/BstemAtlasData/atlas_data 30 | #export THUMBNAIL_DATA_ROOTDIR=/home/yuncong/brainstem/media/yuncong/BstemAtlasData/atlas_data 31 | 32 | #export ROOT_DIR=/media/yuncong/YuncongPublic/atlas_data 33 | #export DATA_ROOTDIR=/media/yuncong/YuncongPublic/atlas_data 34 | #export THUMBNAIL_DATA_ROOTDIR=/media/yuncong/YuncongPublic/atlas_data 35 | 36 | if [ ! -d $virtualenv ]; then 37 | echo "" 38 | echo -e "${green}Creating a virtualenv environment${NC}" 39 | #virtualenv --system-site-packages $virtualenv 40 | virtualenv -p python $PROJECT_DIR/$virtualenv 41 | fi 42 | 43 | echo "" 44 | echo -e "${green}Activating the virtualenv environment${NC}" 45 | source $PROJECT_DIR/$virtualenv/bin/activate 46 | 47 | echo "" 48 | echo -e "${green}[virtualenv] Installing Python packages${NC}" 49 | pip install -r $PROJECT_DIR/setup/requirements.txt 50 | -------------------------------------------------------------------------------- /setup/requirements.txt: -------------------------------------------------------------------------------- 1 | opencv-python==3.1.0.3 2 | scikit-image==0.14.2 3 | scikit-learn==0.19.1 4 | matplotlib==2.2.2 5 | pandas==0.23.0 6 | tables==3.4.2 7 | bloscpack==0.9.0 8 | multiprocess==0.70.4 9 | shapely==1.6.4 10 | randomcolor==0.4.4.5 11 | mxnet-cu90==1.0.0 12 | joblib==0.10.2 13 | qimage2ndarray==1.7 14 | -------------------------------------------------------------------------------- /src/gui/README.md: -------------------------------------------------------------------------------- 1 | # Labeling GUI 2 | 3 | To launch the labeling GUI, run: 4 | 5 | `~/Brain/gui/brain_labeling_gui_v27.py [stack_name] -v jpeg -p [prep_id]` 6 | 7 | `prep_id` is 2 for brainstem crop and 3 for thalamus crop. 8 | 9 | The left panel shows the full resolution images. The panels at the right are virtual coronal, horizontal and sagittal whole-brain slices, from top to bottom respectively. 10 | 11 | Left click and drag to pan. Scroll mouse wheel to zoom. 12 | 13 | **Create new polygon**: Right click -> Select "New polygon" -> left click to place new vertices; press Enter to close a polygon. 14 | 15 | **Set side**: Right click anywhere inside the polygon -> Select "Set side". 16 | 17 | **Insert vertex**: Right click anywhere inside the polygon -> Select "Insert vertex" -> left click at anywhere between two existing vertices, and a new vertex will be placed there. -> Keep clicking to insert more vertices. Press ESC to finish. 18 | 19 | **Delete vertex**: Right click anywhere inside the polygon -> Select "Delete vertex" -> left click and drag a box and all vertices inside the box will be deleted. -> Keep making boxes to delete more vertices. Press ESC to finish. 20 | 21 | **Save**: Click "Save contours" in the bottom row. The annotations on the full resolution panel will be saved into `~/CSHL_labelings_thalamus/[stack]/[stack]_annotation_contours_[timestamp].hdf`. Annotations for the coronal and horizontal panels are also saved. One can read and inspect the annotation files as shown in [this notebook](https://github.com/mistycheney/MouseBrainAtlas/blob/master/annotation/check_annotation_file_v3_for_thalamus.ipynb). 22 | 23 | **Load**: Click "Load contours" in the bottom row -> Select the latest `[stack]_annotation_contours_[timestamp]` according to the modified time. 24 | 25 | ## Key bindings 26 | - 1/2: go backward/forward along the stack in the full resolution panel. 27 | - 3/4, 5/6, 7/8: go forward/backward in the coronal, horizontal, sagittal whole-brain overview panel, respectively. 28 | - v: toggle whether vertices are shown. 29 | - c: toggle whether contours are shown. 30 | - l: toggle whether label are shown. 31 | - hold ctrl: 2d shift 32 | - hold alt: 2d rotate 33 | - t: switch to prob 3d shift mode. Then move polygon. 34 | - r: switch to prob 3d rotate mode. Then rotate the polygon. Rotation center is assumed to be the centroid of the 2d contour in current section. 35 | - alt + t: switch to global 3d shift mode. 36 | - alt + r: switch to global 3d rotation mode. 37 | - s: switch to show score map (need to have active polygon) / histology image 38 | -------------------------------------------------------------------------------- /src/gui/newStructureNames.txt: -------------------------------------------------------------------------------- 1 | UDF undefined nucleus 2 | UDFn undefined nerve 3 | BC Brachium Conjunctivum 4 | EmGr Eminentia Granularis 5 | VMu nucleus trigeminalis descendens, pars Muralis 6 | VIp nucleus trigeminalis descendens, pars Interpolaris 7 | PrVd nucleus trigeminalis principalis, pars dorsalis 8 | VIpp nucleus trigeminalis descendens interpolaris, pars posterior 9 | VOrp nucleus trigeminalis descendens Oralis, pars posterior 10 | PrVv nucleus trigeminalis principalis, pars ventralis 11 | VOra nucleus trigeminalis descendens Oralis pars anterior 12 | preV nucleus pretrigeminalis?? 13 | TrVdes Tractus trigemini descendens 14 | UDFtr Undefined Tract 15 | VOri nucleus trigeminalis descendens Oralis, pars intermedius 16 | Vcd nucleus trigemini descendens, pars caudalis/spinialis 17 | CereNuc Deep cerebellar nuclei 18 | 9N glossopharyngeal nucleus 19 | RtTgD reticulotegmental nucleus of the pons, dorsal part 20 | Nuc1 undefined nucleus 1 21 | Nuc2 undefined nucleus 2 22 | LM1 moderate sized dense area, at 4th ventricle floor and frontal to sp5 23 | LM1C LM1, caudal part 24 | LM1R LM1, rostral part 25 | 7N2 facial nucleus, anterior subpart 26 | bv1 Blood Vessel 1 27 | bv2 Blood Vessel 2 28 | bv3 Blood Vessel 3 29 | bv4 Blood Vessel 4 30 | bv5 Blood Vessel 5 31 | bv6 Blood Vessel 6 32 | bv7 Blood Vessel 7 33 | bv8 Blood Vessel 8 34 | bv9 Blood Vessel 9 35 | bv10 Blood Vessel 10 36 | bv11 Blood Vessel 11 37 | bv12 Blood Vessel 12 38 | LC2 Locus Coeruleus, long cell part 39 | Pn2 Pontine nuclei, sparse part 40 | 7n1 facial nerve, small 1 41 | 7n2 facial nerve, small 2 42 | 7n3 facial nerve, small 3 43 | DDGC Dorsal Deiters Gigantocellular Nucleus 44 | IC inferior colliculus 45 | SOC Superior Olivary Complex 46 | Cb Cerebellum 47 | -------------------------------------------------------------------------------- /src/gui/ui/AlignmentGui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AlignmentGui 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1390 10 | 972 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | Qt::Horizontal 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Previous 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | TextLabel 42 | 43 | 44 | 45 | 46 | 47 | 48 | TextLabel 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Add anchor pair 62 | 63 | 64 | 65 | 66 | 67 | 68 | Compute Transform 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Current 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | TextLabel 96 | 97 | 98 | 99 | 100 | 101 | 102 | TextLabel 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | Elastix parameters 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | align using Elastix 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | Current aligned to Previous 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | Upload transform to server 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/gui/ui/BrainLabelingGui_v15.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | BrainLabelingGui 4 | 5 | 6 | 7 | 0 8 | 0 9 | 2280 10 | 1113 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | Qt::Horizontal 22 | 23 | 24 | 25 | 26 | Qt::Vertical 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Username: 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 3D Reconstruct 50 | 51 | 52 | 53 | 54 | 55 | 56 | Nagivate To Structure 57 | 58 | 59 | 60 | 61 | 62 | 63 | Display Structures 64 | 65 | 66 | 67 | 68 | 69 | 70 | Infer Side 71 | 72 | 73 | 74 | 75 | 76 | 77 | Clear Side Assignment 78 | 79 | 80 | 81 | 82 | 83 | 84 | Display Options 85 | 86 | 87 | 88 | 89 | 90 | 91 | Save Handdrawn Structures 92 | 93 | 94 | 95 | 96 | 97 | 98 | Save Atlas Structures 99 | 100 | 101 | 102 | 103 | 104 | 105 | Save Contours 106 | 107 | 108 | 109 | 110 | 111 | 112 | Save Markers 113 | 114 | 115 | 116 | 117 | 118 | 119 | Load Structures 120 | 121 | 122 | 123 | 124 | 125 | 126 | Load Handdrawn Structures 127 | 128 | 129 | 130 | 131 | 132 | 133 | Load Warped Atlas 134 | 135 | 136 | 137 | 138 | 139 | 140 | Load Unwarped Atlas 141 | 142 | 143 | 144 | 145 | 146 | 147 | Load Contours 148 | 149 | 150 | 151 | 152 | 153 | 154 | Load Markers 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 0 166 | 0 167 | 2280 168 | 25 169 | 170 | 171 | 172 | 173 | 174 | 175 | toolBar 176 | 177 | 178 | TopToolBarArea 179 | 180 | 181 | false 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /src/gui/ui/GalleryDialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | gallery_dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1007 10 | 728 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 0 26 | 0 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Move before 37 | 38 | 39 | 40 | 41 | 42 | 43 | Move after 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/gui/ui/MaskEditingGui4.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MaskEditingGui 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1046 10 | 825 11 | 12 | 13 | 14 | Review Masks 15 | 16 | 17 | 18 | 19 | 20 | Automatic Masks 21 | 22 | 23 | 24 | 25 | 26 | 27 | Channel 28 | 29 | 30 | 31 | 32 | 33 | 34 | SLIC 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 500 43 | 500 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 500 53 | 500 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 500 63 | 500 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Channel 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | Update SLIC 86 | 87 | 88 | 89 | 90 | 91 | 92 | Initial Masks for Snake 93 | 94 | 95 | 96 | 97 | 98 | 99 | User Masks 100 | 101 | 102 | 103 | 104 | 105 | 106 | Merged Mask 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | Dissim Threshold 125 | 126 | 127 | 128 | 129 | 130 | 131 | Qt::Horizontal 132 | 133 | 134 | 135 | 136 | 137 | 138 | 0.5 139 | 140 | 141 | 142 | 143 | 144 | 145 | Update Init Masks 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | Shrink 157 | 158 | 159 | 160 | 161 | 162 | 163 | Qt::Horizontal 164 | 165 | 166 | 167 | 168 | 169 | 170 | TextLabel 171 | 172 | 173 | 174 | 175 | 176 | 177 | Update Snake Final Masks 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | Update Merged Mask 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | Qt::Horizontal 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | Automatically Generate All Masks 214 | 215 | 216 | 217 | 218 | 219 | 220 | Save All Decisions 221 | 222 | 223 | 224 | 225 | 226 | 227 | Upload 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /src/gui/ui/MaskEditingGui5.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MaskEditingGui 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1905 10 | 825 11 | 12 | 13 | 14 | Review Masks 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Automatically Generate Masks for All 23 | 24 | 25 | 26 | 27 | 28 | 29 | Load Anchor Contours 30 | 31 | 32 | 33 | 34 | 35 | 36 | Save Anchor Contours 37 | 38 | 39 | 40 | 41 | 42 | 43 | Load Init Contours for All Sections 44 | 45 | 46 | 47 | 48 | 49 | 50 | Save Initial Contours for All Sections 51 | 52 | 53 | 54 | 55 | 56 | 57 | Save Final Mask for Current Section 58 | 59 | 60 | 61 | 62 | 63 | 64 | Save Final Masks for All Sections 65 | 66 | 67 | 68 | 69 | 70 | 71 | Export Masks as PNG for All Sections 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Merged Mask 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 800 91 | 500 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Update Merged Mask 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Qt::Horizontal 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | Contrast Enhanced Image 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 800 130 | 500 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | Channel 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | Initial Submask Contour 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 800 165 | 500 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | TextLabel 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | Submasks 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 800 197 | 500 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | Shrink 208 | 209 | 210 | 211 | 212 | 213 | 214 | Qt::Horizontal 215 | 216 | 217 | 218 | 219 | 220 | 221 | TextLabel 222 | 223 | 224 | 225 | 226 | 227 | 228 | Min Size 229 | 230 | 231 | 232 | 233 | 234 | 235 | Qt::Horizontal 236 | 237 | 238 | 239 | 240 | 241 | 242 | TextLabel 243 | 244 | 245 | 246 | 247 | 248 | 249 | Do Snake 250 | 251 | 252 | 253 | 254 | 255 | 256 | Min Size 257 | 258 | 259 | 260 | 261 | 262 | 263 | Qt::Horizontal 264 | 265 | 266 | 267 | 268 | 269 | 270 | TextLabel 271 | 272 | 273 | 274 | 275 | 276 | 277 | Eliminate 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | -------------------------------------------------------------------------------- /src/gui/ui/MaskParametersGui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MaskParametersGui 4 | 5 | 6 | 7 | 0 8 | 0 9 | 446 10 | 300 11 | 12 | 13 | 14 | Mask Detection Parameters 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 10000 23 | 24 | 25 | 26 | 27 | 28 | 29 | Nissl 30 | 31 | 32 | 33 | 34 | 35 | 36 | Fluorescent 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Threshold on Border Distance to Determine Foreground 53 | 54 | 55 | true 56 | 57 | 58 | 59 | 60 | 61 | 62 | Use Which Percentile of Border Texture Distances 63 | 64 | 65 | true 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Minimum Size 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Confirm 85 | 86 | 87 | 88 | 89 | 90 | 91 | Quit 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/gui/ui/PreprocessTool_v2.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PreprocessGui 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1906 10 | 1088 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 0 29 | 0 30 | 31 | 32 | 33 | 34 | 600 35 | 500 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | TextLabel 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Filename 55 | 56 | 57 | 58 | 59 | 60 | 61 | Section Index 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Edit Transform 73 | 74 | 75 | 76 | 77 | 78 | 79 | Load Crop 80 | 81 | 82 | 83 | 84 | 85 | 86 | Save Crop 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Original 95 | 96 | 97 | 98 | 99 | Original Aligned 100 | 101 | 102 | 103 | 104 | Mask Contoured 105 | 106 | 107 | 108 | 109 | Brainstem Cropped 110 | 111 | 112 | 113 | 114 | Brainstem Cropped Masked 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | Update order 123 | 124 | 125 | 126 | 127 | 128 | 129 | Hide Invalid 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | Save Sorted Filenames 145 | 146 | 147 | 148 | 149 | 150 | 151 | Load Sorted Filenames 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 0 163 | 0 164 | 1906 165 | 25 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /src/gui/ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ActiveBrainAtlas/MouseBrainAtlas/b6ca6afcfc88f6772b073b9ad2bf5d0b3bf840bd/src/gui/ui/__init__.py -------------------------------------------------------------------------------- /src/gui/ui/accept_new_landmark_dialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui/accept_new_landmark_dialog.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_AcceptNewLandmarkDialog(object): 26 | def setupUi(self, AcceptNewLandmarkDialog): 27 | AcceptNewLandmarkDialog.setObjectName(_fromUtf8("AcceptNewLandmarkDialog")) 28 | AcceptNewLandmarkDialog.resize(460, 105) 29 | self.gridLayout = QtGui.QGridLayout(AcceptNewLandmarkDialog) 30 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 31 | self.buttonBox = QtGui.QDialogButtonBox(AcceptNewLandmarkDialog) 32 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 33 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.No|QtGui.QDialogButtonBox.Yes) 34 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 35 | self.gridLayout.addWidget(self.buttonBox, 2, 1, 1, 1) 36 | self.label = QtGui.QLabel(AcceptNewLandmarkDialog) 37 | font = QtGui.QFont() 38 | font.setPointSize(14) 39 | self.label.setFont(font) 40 | self.label.setObjectName(_fromUtf8("label")) 41 | self.gridLayout.addWidget(self.label, 1, 1, 1, 1) 42 | 43 | self.retranslateUi(AcceptNewLandmarkDialog) 44 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), AcceptNewLandmarkDialog.accept) 45 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), AcceptNewLandmarkDialog.reject) 46 | QtCore.QMetaObject.connectSlotsByName(AcceptNewLandmarkDialog) 47 | 48 | def retranslateUi(self, AcceptNewLandmarkDialog): 49 | AcceptNewLandmarkDialog.setWindowTitle(_translate("AcceptNewLandmarkDialog", "Accept new structure?", None)) 50 | self.label.setText(_translate("AcceptNewLandmarkDialog", "This set of regions have consistent texture. \n" 51 | "Accept as a new structure?", None)) 52 | 53 | 54 | if __name__ == "__main__": 55 | import sys 56 | app = QtGui.QApplication(sys.argv) 57 | AcceptNewLandmarkDialog = QtGui.QDialog() 58 | ui = Ui_AcceptNewLandmarkDialog() 59 | ui.setupUi(AcceptNewLandmarkDialog) 60 | AcceptNewLandmarkDialog.show() 61 | sys.exit(app.exec_()) 62 | 63 | -------------------------------------------------------------------------------- /src/gui/ui/accept_new_landmark_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AcceptNewLandmarkDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 460 10 | 105 11 | 12 | 13 | 14 | Accept new structure? 15 | 16 | 17 | 18 | 19 | 20 | Qt::Horizontal 21 | 22 | 23 | QDialogButtonBox::No|QDialogButtonBox::Yes 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 14 32 | 33 | 34 | 35 | This set of regions have consistent texture. 36 | Accept as a new structure? 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | buttonBox 46 | accepted() 47 | AcceptNewLandmarkDialog 48 | accept() 49 | 50 | 51 | 248 52 | 254 53 | 54 | 55 | 157 56 | 274 57 | 58 | 59 | 60 | 61 | buttonBox 62 | rejected() 63 | AcceptNewLandmarkDialog 64 | reject() 65 | 66 | 67 | 316 68 | 260 69 | 70 | 71 | 286 72 | 274 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/gui/ui/ui_AlignmentGui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'AlignmentGui.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_AlignmentGui(object): 26 | def setupUi(self, AlignmentGui): 27 | AlignmentGui.setObjectName(_fromUtf8("AlignmentGui")) 28 | AlignmentGui.resize(1390, 972) 29 | self.gridLayout = QtGui.QGridLayout(AlignmentGui) 30 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 31 | self.splitter = QtGui.QSplitter(AlignmentGui) 32 | self.splitter.setOrientation(QtCore.Qt.Horizontal) 33 | self.splitter.setObjectName(_fromUtf8("splitter")) 34 | self.layoutWidget = QtGui.QWidget(self.splitter) 35 | self.layoutWidget.setObjectName(_fromUtf8("layoutWidget")) 36 | self.verticalLayout_4 = QtGui.QVBoxLayout(self.layoutWidget) 37 | self.verticalLayout_4.setObjectName(_fromUtf8("verticalLayout_4")) 38 | self.verticalLayout_2 = QtGui.QVBoxLayout() 39 | self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) 40 | self.label_2 = QtGui.QLabel(self.layoutWidget) 41 | self.label_2.setObjectName(_fromUtf8("label_2")) 42 | self.verticalLayout_2.addWidget(self.label_2) 43 | self.prev_gview = QtGui.QGraphicsView(self.layoutWidget) 44 | self.prev_gview.setObjectName(_fromUtf8("prev_gview")) 45 | self.verticalLayout_2.addWidget(self.prev_gview) 46 | self.horizontalLayout_3 = QtGui.QHBoxLayout() 47 | self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3")) 48 | self.label_previous_filename = QtGui.QLabel(self.layoutWidget) 49 | self.label_previous_filename.setObjectName(_fromUtf8("label_previous_filename")) 50 | self.horizontalLayout_3.addWidget(self.label_previous_filename) 51 | self.label_previous_index = QtGui.QLabel(self.layoutWidget) 52 | self.label_previous_index.setObjectName(_fromUtf8("label_previous_index")) 53 | self.horizontalLayout_3.addWidget(self.label_previous_index) 54 | self.verticalLayout_2.addLayout(self.horizontalLayout_3) 55 | self.verticalLayout_4.addLayout(self.verticalLayout_2) 56 | self.horizontalLayout_4 = QtGui.QHBoxLayout() 57 | self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4")) 58 | self.button_anchor = QtGui.QPushButton(self.layoutWidget) 59 | self.button_anchor.setObjectName(_fromUtf8("button_anchor")) 60 | self.horizontalLayout_4.addWidget(self.button_anchor) 61 | self.button_compute = QtGui.QPushButton(self.layoutWidget) 62 | self.button_compute.setObjectName(_fromUtf8("button_compute")) 63 | self.horizontalLayout_4.addWidget(self.button_compute) 64 | self.verticalLayout_4.addLayout(self.horizontalLayout_4) 65 | self.layoutWidget1 = QtGui.QWidget(self.splitter) 66 | self.layoutWidget1.setObjectName(_fromUtf8("layoutWidget1")) 67 | self.verticalLayout_5 = QtGui.QVBoxLayout(self.layoutWidget1) 68 | self.verticalLayout_5.setObjectName(_fromUtf8("verticalLayout_5")) 69 | self.verticalLayout = QtGui.QVBoxLayout() 70 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 71 | self.label = QtGui.QLabel(self.layoutWidget1) 72 | self.label.setObjectName(_fromUtf8("label")) 73 | self.verticalLayout.addWidget(self.label) 74 | self.curr_gview = QtGui.QGraphicsView(self.layoutWidget1) 75 | self.curr_gview.setObjectName(_fromUtf8("curr_gview")) 76 | self.verticalLayout.addWidget(self.curr_gview) 77 | self.horizontalLayout_2 = QtGui.QHBoxLayout() 78 | self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) 79 | self.label_current_filename = QtGui.QLabel(self.layoutWidget1) 80 | self.label_current_filename.setObjectName(_fromUtf8("label_current_filename")) 81 | self.horizontalLayout_2.addWidget(self.label_current_filename) 82 | self.label_current_index = QtGui.QLabel(self.layoutWidget1) 83 | self.label_current_index.setObjectName(_fromUtf8("label_current_index")) 84 | self.horizontalLayout_2.addWidget(self.label_current_index) 85 | self.verticalLayout.addLayout(self.horizontalLayout_2) 86 | self.verticalLayout_5.addLayout(self.verticalLayout) 87 | self.horizontalLayout = QtGui.QHBoxLayout() 88 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 89 | self.label_4 = QtGui.QLabel(self.layoutWidget1) 90 | self.label_4.setObjectName(_fromUtf8("label_4")) 91 | self.horizontalLayout.addWidget(self.label_4) 92 | self.comboBox_parameters = QtGui.QComboBox(self.layoutWidget1) 93 | self.comboBox_parameters.setObjectName(_fromUtf8("comboBox_parameters")) 94 | self.horizontalLayout.addWidget(self.comboBox_parameters) 95 | self.button_align = QtGui.QPushButton(self.layoutWidget1) 96 | self.button_align.setObjectName(_fromUtf8("button_align")) 97 | self.horizontalLayout.addWidget(self.button_align) 98 | self.verticalLayout_5.addLayout(self.horizontalLayout) 99 | self.layoutWidget2 = QtGui.QWidget(self.splitter) 100 | self.layoutWidget2.setObjectName(_fromUtf8("layoutWidget2")) 101 | self.verticalLayout_6 = QtGui.QVBoxLayout(self.layoutWidget2) 102 | self.verticalLayout_6.setObjectName(_fromUtf8("verticalLayout_6")) 103 | self.verticalLayout_3 = QtGui.QVBoxLayout() 104 | self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3")) 105 | self.label_3 = QtGui.QLabel(self.layoutWidget2) 106 | self.label_3.setObjectName(_fromUtf8("label_3")) 107 | self.verticalLayout_3.addWidget(self.label_3) 108 | self.aligned_gview = QtGui.QGraphicsView(self.layoutWidget2) 109 | self.aligned_gview.setObjectName(_fromUtf8("aligned_gview")) 110 | self.verticalLayout_3.addWidget(self.aligned_gview) 111 | self.verticalLayout_6.addLayout(self.verticalLayout_3) 112 | self.button_upload_transform = QtGui.QPushButton(self.layoutWidget2) 113 | self.button_upload_transform.setObjectName(_fromUtf8("button_upload_transform")) 114 | self.verticalLayout_6.addWidget(self.button_upload_transform) 115 | self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) 116 | 117 | self.retranslateUi(AlignmentGui) 118 | QtCore.QMetaObject.connectSlotsByName(AlignmentGui) 119 | 120 | def retranslateUi(self, AlignmentGui): 121 | AlignmentGui.setWindowTitle(_translate("AlignmentGui", "Dialog", None)) 122 | self.label_2.setText(_translate("AlignmentGui", "Previous", None)) 123 | self.label_previous_filename.setText(_translate("AlignmentGui", "TextLabel", None)) 124 | self.label_previous_index.setText(_translate("AlignmentGui", "TextLabel", None)) 125 | self.button_anchor.setText(_translate("AlignmentGui", "Add anchor pair", None)) 126 | self.button_compute.setText(_translate("AlignmentGui", "Compute Transform", None)) 127 | self.label.setText(_translate("AlignmentGui", "Current", None)) 128 | self.label_current_filename.setText(_translate("AlignmentGui", "TextLabel", None)) 129 | self.label_current_index.setText(_translate("AlignmentGui", "TextLabel", None)) 130 | self.label_4.setText(_translate("AlignmentGui", "Elastix parameters", None)) 131 | self.button_align.setText(_translate("AlignmentGui", "align using Elastix", None)) 132 | self.label_3.setText(_translate("AlignmentGui", "Current aligned to Previous", None)) 133 | self.button_upload_transform.setText(_translate("AlignmentGui", "Upload transform to server", None)) 134 | 135 | 136 | if __name__ == "__main__": 137 | import sys 138 | app = QtGui.QApplication(sys.argv) 139 | AlignmentGui = QtGui.QDialog() 140 | ui = Ui_AlignmentGui() 141 | ui.setupUi(AlignmentGui) 142 | AlignmentGui.show() 143 | sys.exit(app.exec_()) 144 | 145 | -------------------------------------------------------------------------------- /src/gui/ui/ui_GalleryDialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'GalleryDialog.ui' 4 | # 5 | # Created: Sat Sep 3 19:53:13 2016 6 | # by: PyQt4 UI code generator 4.10.4 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_gallery_dialog(object): 27 | def setupUi(self, gallery_dialog): 28 | gallery_dialog.setObjectName(_fromUtf8("gallery_dialog")) 29 | gallery_dialog.resize(1007, 728) 30 | self.gridLayout = QtGui.QGridLayout(gallery_dialog) 31 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 32 | self.horizontalLayout_2 = QtGui.QHBoxLayout() 33 | self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) 34 | self.verticalLayout = QtGui.QVBoxLayout() 35 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 36 | self.gallery_widget = QtGui.QWidget(gallery_dialog) 37 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) 38 | sizePolicy.setHorizontalStretch(0) 39 | sizePolicy.setVerticalStretch(0) 40 | sizePolicy.setHeightForWidth(self.gallery_widget.sizePolicy().hasHeightForWidth()) 41 | self.gallery_widget.setSizePolicy(sizePolicy) 42 | self.gallery_widget.setObjectName(_fromUtf8("gallery_widget")) 43 | self.verticalLayout.addWidget(self.gallery_widget) 44 | self.horizontalLayout = QtGui.QHBoxLayout() 45 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 46 | self.button_moveBefore = QtGui.QPushButton(gallery_dialog) 47 | self.button_moveBefore.setObjectName(_fromUtf8("button_moveBefore")) 48 | self.horizontalLayout.addWidget(self.button_moveBefore) 49 | self.button_moveAfter = QtGui.QPushButton(gallery_dialog) 50 | self.button_moveAfter.setObjectName(_fromUtf8("button_moveAfter")) 51 | self.horizontalLayout.addWidget(self.button_moveAfter) 52 | self.verticalLayout.addLayout(self.horizontalLayout) 53 | self.horizontalLayout_2.addLayout(self.verticalLayout) 54 | self.sorted_gview = QtGui.QGraphicsView(gallery_dialog) 55 | self.sorted_gview.setObjectName(_fromUtf8("sorted_gview")) 56 | self.horizontalLayout_2.addWidget(self.sorted_gview) 57 | self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1) 58 | 59 | self.retranslateUi(gallery_dialog) 60 | QtCore.QMetaObject.connectSlotsByName(gallery_dialog) 61 | 62 | def retranslateUi(self, gallery_dialog): 63 | gallery_dialog.setWindowTitle(_translate("gallery_dialog", "Dialog", None)) 64 | self.button_moveBefore.setText(_translate("gallery_dialog", "Move before", None)) 65 | self.button_moveAfter.setText(_translate("gallery_dialog", "Move after", None)) 66 | 67 | 68 | if __name__ == "__main__": 69 | import sys 70 | app = QtGui.QApplication(sys.argv) 71 | gallery_dialog = QtGui.QDialog() 72 | ui = Ui_gallery_dialog() 73 | ui.setupUi(gallery_dialog) 74 | gallery_dialog.show() 75 | sys.exit(app.exec_()) 76 | 77 | -------------------------------------------------------------------------------- /src/gui/ui/ui_MaskEditingGui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'MaskEditingGui.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | -------------------------------------------------------------------------------- /src/gui/ui/ui_MaskEditingGui5.ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'MaskEditingGui5.ui.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | -------------------------------------------------------------------------------- /src/gui/ui/ui_MaskParametersGui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'MaskParametersGui.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_MaskParametersGui(object): 26 | def setupUi(self, MaskParametersGui): 27 | MaskParametersGui.setObjectName(_fromUtf8("MaskParametersGui")) 28 | MaskParametersGui.resize(446, 300) 29 | self.gridLayout_2 = QtGui.QGridLayout(MaskParametersGui) 30 | self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) 31 | self.gridLayout = QtGui.QGridLayout() 32 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 33 | self.spinBox_minSize = QtGui.QSpinBox(MaskParametersGui) 34 | self.spinBox_minSize.setMaximum(10000) 35 | self.spinBox_minSize.setObjectName(_fromUtf8("spinBox_minSize")) 36 | self.gridLayout.addWidget(self.spinBox_minSize, 3, 2, 1, 1) 37 | self.label_7 = QtGui.QLabel(MaskParametersGui) 38 | self.label_7.setObjectName(_fromUtf8("label_7")) 39 | self.gridLayout.addWidget(self.label_7, 0, 3, 1, 1) 40 | self.label_6 = QtGui.QLabel(MaskParametersGui) 41 | self.label_6.setObjectName(_fromUtf8("label_6")) 42 | self.gridLayout.addWidget(self.label_6, 0, 2, 1, 1) 43 | self.spinBox_trainDistPercentile_nissl = QtGui.QSpinBox(MaskParametersGui) 44 | self.spinBox_trainDistPercentile_nissl.setObjectName(_fromUtf8("spinBox_trainDistPercentile_nissl")) 45 | self.gridLayout.addWidget(self.spinBox_trainDistPercentile_nissl, 1, 3, 1, 1) 46 | self.spinBox_trainDistPercentile_fluoro = QtGui.QSpinBox(MaskParametersGui) 47 | self.spinBox_trainDistPercentile_fluoro.setObjectName(_fromUtf8("spinBox_trainDistPercentile_fluoro")) 48 | self.gridLayout.addWidget(self.spinBox_trainDistPercentile_fluoro, 1, 2, 1, 1) 49 | self.spinBox_chi2Threshold_nissl = QtGui.QDoubleSpinBox(MaskParametersGui) 50 | self.spinBox_chi2Threshold_nissl.setObjectName(_fromUtf8("spinBox_chi2Threshold_nissl")) 51 | self.gridLayout.addWidget(self.spinBox_chi2Threshold_nissl, 2, 3, 1, 1) 52 | self.label_2 = QtGui.QLabel(MaskParametersGui) 53 | self.label_2.setWordWrap(True) 54 | self.label_2.setObjectName(_fromUtf8("label_2")) 55 | self.gridLayout.addWidget(self.label_2, 2, 0, 1, 2) 56 | self.label = QtGui.QLabel(MaskParametersGui) 57 | self.label.setWordWrap(True) 58 | self.label.setObjectName(_fromUtf8("label")) 59 | self.gridLayout.addWidget(self.label, 1, 0, 1, 2) 60 | self.spinBox_chi2Threshold_fluoro = QtGui.QDoubleSpinBox(MaskParametersGui) 61 | self.spinBox_chi2Threshold_fluoro.setObjectName(_fromUtf8("spinBox_chi2Threshold_fluoro")) 62 | self.gridLayout.addWidget(self.spinBox_chi2Threshold_fluoro, 2, 2, 1, 1) 63 | self.label_3 = QtGui.QLabel(MaskParametersGui) 64 | self.label_3.setObjectName(_fromUtf8("label_3")) 65 | self.gridLayout.addWidget(self.label_3, 3, 0, 1, 1) 66 | self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 2) 67 | self.button_confirmMaskParameters = QtGui.QPushButton(MaskParametersGui) 68 | self.button_confirmMaskParameters.setObjectName(_fromUtf8("button_confirmMaskParameters")) 69 | self.gridLayout_2.addWidget(self.button_confirmMaskParameters, 1, 0, 1, 1) 70 | self.button_closeMaskParameters = QtGui.QPushButton(MaskParametersGui) 71 | self.button_closeMaskParameters.setObjectName(_fromUtf8("button_closeMaskParameters")) 72 | self.gridLayout_2.addWidget(self.button_closeMaskParameters, 1, 1, 1, 1) 73 | 74 | self.retranslateUi(MaskParametersGui) 75 | QtCore.QMetaObject.connectSlotsByName(MaskParametersGui) 76 | 77 | def retranslateUi(self, MaskParametersGui): 78 | MaskParametersGui.setWindowTitle(_translate("MaskParametersGui", "Mask Detection Parameters", None)) 79 | self.label_7.setText(_translate("MaskParametersGui", "Nissl", None)) 80 | self.label_6.setText(_translate("MaskParametersGui", "Fluorescent", None)) 81 | self.label_2.setText(_translate("MaskParametersGui", "Threshold on Border Distance to Determine Foreground", None)) 82 | self.label.setText(_translate("MaskParametersGui", "Use Which Percentile of Border Texture Distances", None)) 83 | self.label_3.setText(_translate("MaskParametersGui", "Minimum Size", None)) 84 | self.button_confirmMaskParameters.setText(_translate("MaskParametersGui", "Confirm", None)) 85 | self.button_closeMaskParameters.setText(_translate("MaskParametersGui", "Quit", None)) 86 | 87 | 88 | if __name__ == "__main__": 89 | import sys 90 | app = QtGui.QApplication(sys.argv) 91 | MaskParametersGui = QtGui.QDialog() 92 | ui = Ui_MaskParametersGui() 93 | ui.setupUi(MaskParametersGui) 94 | MaskParametersGui.show() 95 | sys.exit(app.exec_()) 96 | 97 | -------------------------------------------------------------------------------- /src/gui/ui/ui_PreprocessGui_v2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui/PreprocessTool_v2.ui' 4 | # 5 | # Created by: PyQt4 UI code generator 4.11.4 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt4 import QtCore, QtGui 10 | 11 | try: 12 | _fromUtf8 = QtCore.QString.fromUtf8 13 | except AttributeError: 14 | def _fromUtf8(s): 15 | return s 16 | 17 | try: 18 | _encoding = QtGui.QApplication.UnicodeUTF8 19 | def _translate(context, text, disambig): 20 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 21 | except AttributeError: 22 | def _translate(context, text, disambig): 23 | return QtGui.QApplication.translate(context, text, disambig) 24 | 25 | class Ui_PreprocessGui(object): 26 | def setupUi(self, PreprocessGui): 27 | PreprocessGui.setObjectName(_fromUtf8("PreprocessGui")) 28 | PreprocessGui.resize(1906, 1088) 29 | self.centralwidget = QtGui.QWidget(PreprocessGui) 30 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 31 | self.verticalLayout_3 = QtGui.QVBoxLayout(self.centralwidget) 32 | self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3")) 33 | self.horizontalLayout_9 = QtGui.QHBoxLayout() 34 | self.horizontalLayout_9.setObjectName(_fromUtf8("horizontalLayout_9")) 35 | self.verticalLayout = QtGui.QVBoxLayout() 36 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 37 | self.horizontalLayout_8 = QtGui.QHBoxLayout() 38 | self.horizontalLayout_8.setObjectName(_fromUtf8("horizontalLayout_8")) 39 | self.sorted_sections_gview = QtGui.QGraphicsView(self.centralwidget) 40 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) 41 | sizePolicy.setHorizontalStretch(0) 42 | sizePolicy.setVerticalStretch(0) 43 | sizePolicy.setHeightForWidth(self.sorted_sections_gview.sizePolicy().hasHeightForWidth()) 44 | self.sorted_sections_gview.setSizePolicy(sizePolicy) 45 | self.sorted_sections_gview.setMinimumSize(QtCore.QSize(600, 500)) 46 | self.sorted_sections_gview.setObjectName(_fromUtf8("sorted_sections_gview")) 47 | self.horizontalLayout_8.addWidget(self.sorted_sections_gview) 48 | self.label_sorted_sections_status = QtGui.QLabel(self.centralwidget) 49 | self.label_sorted_sections_status.setObjectName(_fromUtf8("label_sorted_sections_status")) 50 | self.horizontalLayout_8.addWidget(self.label_sorted_sections_status) 51 | self.verticalLayout.addLayout(self.horizontalLayout_8) 52 | self.horizontalLayout_6 = QtGui.QHBoxLayout() 53 | self.horizontalLayout_6.setObjectName(_fromUtf8("horizontalLayout_6")) 54 | self.label_sorted_sections_filename = QtGui.QLabel(self.centralwidget) 55 | self.label_sorted_sections_filename.setObjectName(_fromUtf8("label_sorted_sections_filename")) 56 | self.horizontalLayout_6.addWidget(self.label_sorted_sections_filename) 57 | self.label_sorted_sections_index = QtGui.QLabel(self.centralwidget) 58 | self.label_sorted_sections_index.setObjectName(_fromUtf8("label_sorted_sections_index")) 59 | self.horizontalLayout_6.addWidget(self.label_sorted_sections_index) 60 | self.verticalLayout.addLayout(self.horizontalLayout_6) 61 | self.gridLayout_2 = QtGui.QGridLayout() 62 | self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) 63 | self.button_edit_transform = QtGui.QPushButton(self.centralwidget) 64 | self.button_edit_transform.setObjectName(_fromUtf8("button_edit_transform")) 65 | self.gridLayout_2.addWidget(self.button_edit_transform, 3, 4, 1, 1) 66 | self.button_load_crop = QtGui.QPushButton(self.centralwidget) 67 | self.button_load_crop.setObjectName(_fromUtf8("button_load_crop")) 68 | self.gridLayout_2.addWidget(self.button_load_crop, 3, 1, 1, 1) 69 | self.button_save_crop = QtGui.QPushButton(self.centralwidget) 70 | self.button_save_crop.setObjectName(_fromUtf8("button_save_crop")) 71 | self.gridLayout_2.addWidget(self.button_save_crop, 3, 3, 1, 1) 72 | self.comboBox_show = QtGui.QComboBox(self.centralwidget) 73 | self.comboBox_show.setObjectName(_fromUtf8("comboBox_show")) 74 | self.comboBox_show.addItem(_fromUtf8("")) 75 | self.comboBox_show.addItem(_fromUtf8("")) 76 | self.comboBox_show.addItem(_fromUtf8("")) 77 | self.comboBox_show.addItem(_fromUtf8("")) 78 | self.comboBox_show.addItem(_fromUtf8("")) 79 | self.gridLayout_2.addWidget(self.comboBox_show, 2, 1, 1, 1) 80 | self.button_update_order = QtGui.QPushButton(self.centralwidget) 81 | self.button_update_order.setObjectName(_fromUtf8("button_update_order")) 82 | self.gridLayout_2.addWidget(self.button_update_order, 2, 4, 1, 1) 83 | self.button_toggle_show_hide_invalid = QtGui.QPushButton(self.centralwidget) 84 | self.button_toggle_show_hide_invalid.setObjectName(_fromUtf8("button_toggle_show_hide_invalid")) 85 | self.gridLayout_2.addWidget(self.button_toggle_show_hide_invalid, 2, 3, 1, 1) 86 | self.verticalLayout.addLayout(self.gridLayout_2) 87 | self.horizontalLayout_9.addLayout(self.verticalLayout) 88 | self.verticalLayout_3.addLayout(self.horizontalLayout_9) 89 | self.horizontalLayout_2 = QtGui.QHBoxLayout() 90 | self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) 91 | self.button_save_sorted_filenames = QtGui.QPushButton(self.centralwidget) 92 | self.button_save_sorted_filenames.setObjectName(_fromUtf8("button_save_sorted_filenames")) 93 | self.horizontalLayout_2.addWidget(self.button_save_sorted_filenames) 94 | self.button_load_sorted_filenames = QtGui.QPushButton(self.centralwidget) 95 | self.button_load_sorted_filenames.setObjectName(_fromUtf8("button_load_sorted_filenames")) 96 | self.horizontalLayout_2.addWidget(self.button_load_sorted_filenames) 97 | self.verticalLayout_3.addLayout(self.horizontalLayout_2) 98 | PreprocessGui.setCentralWidget(self.centralwidget) 99 | self.menubar = QtGui.QMenuBar(PreprocessGui) 100 | self.menubar.setGeometry(QtCore.QRect(0, 0, 1906, 25)) 101 | self.menubar.setObjectName(_fromUtf8("menubar")) 102 | PreprocessGui.setMenuBar(self.menubar) 103 | self.statusbar = QtGui.QStatusBar(PreprocessGui) 104 | self.statusbar.setObjectName(_fromUtf8("statusbar")) 105 | PreprocessGui.setStatusBar(self.statusbar) 106 | 107 | self.retranslateUi(PreprocessGui) 108 | QtCore.QMetaObject.connectSlotsByName(PreprocessGui) 109 | 110 | def retranslateUi(self, PreprocessGui): 111 | PreprocessGui.setWindowTitle(_translate("PreprocessGui", "MainWindow", None)) 112 | self.label_sorted_sections_status.setText(_translate("PreprocessGui", "TextLabel", None)) 113 | self.label_sorted_sections_filename.setText(_translate("PreprocessGui", "Filename", None)) 114 | self.label_sorted_sections_index.setText(_translate("PreprocessGui", "Section Index", None)) 115 | self.button_edit_transform.setText(_translate("PreprocessGui", "Edit Transform", None)) 116 | self.button_load_crop.setText(_translate("PreprocessGui", "Load Crop", None)) 117 | self.button_save_crop.setText(_translate("PreprocessGui", "Save Crop", None)) 118 | self.comboBox_show.setItemText(0, _translate("PreprocessGui", "Original", None)) 119 | self.comboBox_show.setItemText(1, _translate("PreprocessGui", "Original Aligned", None)) 120 | self.comboBox_show.setItemText(2, _translate("PreprocessGui", "Mask Contoured", None)) 121 | self.comboBox_show.setItemText(3, _translate("PreprocessGui", "Brainstem Cropped", None)) 122 | self.comboBox_show.setItemText(4, _translate("PreprocessGui", "Brainstem Cropped Masked", None)) 123 | self.button_update_order.setText(_translate("PreprocessGui", "Update order", None)) 124 | self.button_toggle_show_hide_invalid.setText(_translate("PreprocessGui", "Hide Invalid", None)) 125 | self.button_save_sorted_filenames.setText(_translate("PreprocessGui", "Save Sorted Filenames", None)) 126 | self.button_load_sorted_filenames.setText(_translate("PreprocessGui", "Load Sorted Filenames", None)) 127 | 128 | 129 | if __name__ == "__main__": 130 | import sys 131 | app = QtGui.QApplication(sys.argv) 132 | PreprocessGui = QtGui.QMainWindow() 133 | ui = Ui_PreprocessGui() 134 | ui.setupUi(PreprocessGui) 135 | PreprocessGui.show() 136 | sys.exit(app.exec_()) 137 | 138 | -------------------------------------------------------------------------------- /src/gui/widgets/DrawableZoomableBrowsableGraphicsScene_ForMasking.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | from collections import defaultdict 3 | 4 | from PyQt4.QtCore import * 5 | from PyQt4.QtGui import * 6 | 7 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 8 | from data_manager import DataManager 9 | from metadata import * 10 | from gui_utilities import * 11 | from registration_utilities import find_contour_points 12 | from annotation_utilities import contours_to_mask, resample_polygon 13 | 14 | from DrawableZoomableBrowsableGraphicsScene import DrawableZoomableBrowsableGraphicsScene 15 | 16 | class DrawableZoomableBrowsableGraphicsScene_ForMasking(DrawableZoomableBrowsableGraphicsScene): 17 | """ 18 | Extends base class by: 19 | - defining specific signal handlers 20 | - adding a dict called submask_decisions 21 | """ 22 | 23 | submask_decision_updated = pyqtSignal(int, int, bool) 24 | submask_updated = pyqtSignal(int, int) 25 | 26 | def __init__(self, id, gview=None, parent=None): 27 | super(DrawableZoomableBrowsableGraphicsScene_ForMasking, self).__init__(id=id, gview=gview, parent=parent) 28 | 29 | self.set_default_line_color('g') 30 | self.set_default_line_width(1) 31 | self.set_default_vertex_color('b') 32 | self.set_default_vertex_radius(2) 33 | 34 | self.polygon_completed.connect(self._submask_added) 35 | self.polygon_pressed.connect(self._submask_clicked) 36 | self.polygon_deleted.connect(self._submask_deleted) 37 | self.polygon_changed.connect(self._submask_changed) 38 | 39 | # self._submasks = {} 40 | self._submask_decisions = defaultdict(dict) 41 | 42 | @pyqtSlot(int, int) 43 | def _submask_changed(self, section, submask_index): 44 | self.submask_updated.emit(section, submask_index) 45 | 46 | @pyqtSlot(object) 47 | def vertex_deleted_callback(self, circle): 48 | # Override the same method in inherited class. 49 | # print "!!!! In DrawableZoomableBrowsableGraphicsScene_ForMasking !!!!" 50 | super(DrawableZoomableBrowsableGraphicsScene_ForMasking, self).vertex_deleted_callback(circle) 51 | 52 | def set_submasks_and_decisions(self, submasks, submask_decisions): 53 | for sec in submasks.iterkeys(): 54 | self.set_submasks_and_decisions_one_section(sec, submasks[sec], submask_decisions[sec]) 55 | 56 | def set_submasks_and_decisions_one_section(self, sec, submasks, submask_decisions): 57 | assert set(submasks.keys()) == set(submask_decisions.keys()) 58 | self.remove_all_submasks_and_decisions_one_section(section=sec) 59 | self._add_submasks_and_decisions_one_section(sec=sec, submasks=submasks, submask_decisions=submask_decisions) 60 | 61 | def _update_color_from_submask_decision(self, sec, submask_ind): 62 | index, _ = self.get_requested_index_and_section(sec=sec) 63 | if self._submask_decisions[sec][submask_ind]: 64 | pen = QPen(Qt.green) 65 | else: 66 | pen = QPen(Qt.red) 67 | self.drawings[index][submask_ind].setPen(pen) 68 | 69 | def set_submask_decision(self, sec, submask_ind, decision): 70 | self._submask_decisions[sec][submask_ind] = decision 71 | self._update_color_from_submask_decision(sec, submask_ind) 72 | self.submask_decision_updated.emit(sec, submask_ind, decision) 73 | 74 | def remove_all_submasks_and_decisions_one_section(self, section): 75 | # if sec in self.submasks: 76 | # del self.submasks[sec] 77 | self.delete_all_polygons_one_section(section=section) 78 | if section in self._submask_decisions: 79 | self._submask_decisions.pop(section) 80 | 81 | def _add_submasks_and_decisions_one_section(self, sec, submasks, submask_decisions): 82 | 83 | for submask_ind, decision in submask_decisions.iteritems(): 84 | m = submasks[submask_ind] 85 | cnts = find_contour_points(m, sample_every=1)[m.max()] 86 | if len(cnts) == 0: 87 | raise Exception('ERROR: section %d %d, submask %d - no contour' % (sec, submask_ind, len(cnts))) 88 | elif len(cnts) > 1: 89 | sys.stderr.write('WARNING: section %d, submask %d - %d contours\n' % (sec, submask_ind, len(cnts))) 90 | cnt = sorted(cnts, key=lambda c: len(c), reverse=True)[0] 91 | else: 92 | cnt = cnts[0] 93 | 94 | self._submask_decisions[sec][submask_ind] = decision 95 | 96 | if decision: 97 | color = 'g' 98 | else: 99 | color = 'r' 100 | 101 | # self.add_polygon(path=vertices_to_path(cnt), section=sec, linewidth=2, color=color) 102 | 103 | resampled_contour_vertices = resample_polygon(cnt, len_interval=20) 104 | self.add_polygon_with_circles(path=vertices_to_path(resampled_contour_vertices), 105 | section=sec, linewidth=2, linecolor=color, vertex_radius=4) 106 | 107 | def _submask_added(self, polygon): 108 | pass 109 | # if self.active_section not in self.submask_decisions: 110 | # self.submask_decisions[self.active_section] = [] 111 | # n = len(self.submask_decisions[self.active_section]) 112 | # existing_submask_indices = range(n) 113 | # if len(existing_submask_indices) == 0: 114 | # first_available_submask_ind = 0 115 | # else: 116 | # available_submask_indices = [i for i in range(np.max(existing_submask_indices) + 2) if i not in existing_submask_indices] 117 | # first_available_submask_ind = available_submask_indices[0] 118 | # new_submask_ind = first_available_submask_ind 119 | # 120 | # # Update submask decisions 121 | # if new_submask_ind <= n-1: 122 | # self.submask_decisions[self.active_section][new_submask_ind] = True 123 | # else: 124 | # self.submask_decisions[self.active_section].append(True) 125 | # 126 | # # Update submask list 127 | # new_submask_contours = vertices_from_polygon(polygon) 128 | # 129 | # bbox = self.pixmapItem.boundingRect() 130 | # image_shape = (int(bbox.height()), int(bbox.width())) 131 | # new_submask = contours_to_mask([new_submask_contours], image_shape) 132 | # if self.active_section not in self.submasks: 133 | # self.submasks[self.active_section] = [] 134 | # if new_submask_ind <= n-1: 135 | # self.submasks[self.active_section][new_submask_ind] = new_submask 136 | # else: 137 | # self.submasks[self.active_section].append(new_submask) 138 | # 139 | # sys.stderr.write('Submask %d added.\n' % new_submask_ind) 140 | 141 | def _submask_deleted(self, polygon, index, polygon_index): 142 | submask_ind = polygon_index 143 | sys.stderr.write('Submask %d removed.\n' % submask_ind) 144 | pass 145 | 146 | # del self.submask_decisions[self.active_section][submask_ind] 147 | # del self.submasks[self.active_section][submask_ind] 148 | 149 | # self.update_mask_gui_window_title() 150 | 151 | def _submask_clicked(self, polygon): 152 | submask_ind = self.drawings[self.active_i].index(polygon) 153 | sys.stderr.write('Submask %d clicked.\n' % submask_ind) 154 | print(self._submask_decisions[self.active_section]) 155 | curr_decision = self._submask_decisions[self.active_section][submask_ind] 156 | self.set_submask_decision(submask_ind=submask_ind, decision=not curr_decision, sec=self.active_section) 157 | 158 | # def update_submask_decision(self, submask_ind, decision, sec): 159 | 160 | # if submask_ind in self.submask_decisions[sec]: 161 | # curr_decision = self.submask_decisions[sec][submask_ind] 162 | # if curr_decision == decision: 163 | # return 164 | # 165 | # self.submask_decisions[sec][submask_ind] = decision 166 | # 167 | # if decision: 168 | # pen = QPen(Qt.green) 169 | # else: 170 | # pen = QPen(Qt.red) 171 | # pen.setWidth(self.default_line_width) 172 | # 173 | # curr_i, _ = self.get_requested_index_and_section(sec=sec) 174 | # self.drawings[curr_i][submask_ind].setPen(pen) 175 | 176 | # self.submask_decision_updated.emit(submask_ind) 177 | 178 | def accept_all_submasks(self): 179 | # for submask_ind in self.submasks[self.active_section].iterkeys(): 180 | for submask_ind in range(len(self.submasks[self.active_section])): 181 | self.update_submask_decision(submask_ind=submask_ind, decision=True, sec=self.active_section) 182 | 183 | def eventFilter(self, obj, event): 184 | if event.type() == QEvent.KeyPress: 185 | key = event.key() 186 | if key == Qt.Key_Space: 187 | self.accept_all_submasks() 188 | return True 189 | 190 | return super(DrawableZoomableBrowsableGraphicsScene_ForMasking, self).eventFilter(obj, event) 191 | -------------------------------------------------------------------------------- /src/gui/widgets/DrawableZoomableBrowsableGraphicsScene_ForSnake.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | 3 | from PyQt4.QtCore import * 4 | from PyQt4.QtGui import * 5 | 6 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 7 | from data_manager import DataManager 8 | from metadata import * 9 | from gui_utilities import * 10 | from registration_utilities import find_contour_points 11 | from annotation_utilities import contours_to_mask, get_interpolated_contours 12 | 13 | # from DrawableZoomableBrowsableGraphicsScene import DrawableZoomableBrowsableGraphicsScene 14 | from widgets.DrawableZoomableBrowsableGraphicsScene_ForMasking import DrawableZoomableBrowsableGraphicsScene_ForMasking 15 | 16 | class DrawableZoomableBrowsableGraphicsScene_ForSnake(DrawableZoomableBrowsableGraphicsScene_ForMasking): 17 | """ 18 | Extends base class by: 19 | - define a dict of special polygon called init_snake_contour 20 | - define a flag is_adding_snake_contour, so we know a polygon_completed signal is for 21 | """ 22 | 23 | # submask_decision_updated = pyqtSignal(int) 24 | submask_decision_updated = pyqtSignal(int, int, bool) 25 | 26 | def __init__(self, id, gview=None, parent=None): 27 | 28 | super(DrawableZoomableBrowsableGraphicsScene_ForSnake, self).__init__(id=id, gview=gview, parent=parent) 29 | 30 | # self.polygon_completed.connect(self._submask_added) 31 | # self.polygon_deleted.connect(self._submask_deleted) 32 | 33 | self.init_snake_contour_polygons = {} 34 | self.is_adding_snake_contour = False 35 | self.anchor_sections = set([]) 36 | 37 | def _submask_added(self, polygon): 38 | if self.is_adding_snake_contour: 39 | self.init_snake_contour_polygons[self.active_section] = polygon 40 | self.set_current_section_as_anchor() 41 | self.is_adding_snake_contour = False 42 | else: 43 | super(DrawableZoomableBrowsableGraphicsScene_ForSnake, self)._submask_added(polygon) 44 | 45 | def _submask_deleted(self, polygon, index, polygon_index): 46 | if self.is_adding_snake_contour: 47 | pass 48 | else: 49 | super(DrawableZoomableBrowsableGraphicsScene_ForSnake, self)._submask_deleted(polygon, index, polygon_index) 50 | 51 | def eventFilter(self, obj, event): 52 | if event.type() == QEvent.KeyPress: 53 | key = event.key() 54 | if key == Qt.Key_Space: 55 | self.accept_all_submasks() 56 | return True 57 | elif key == Qt.Key_Comma: 58 | self.copy_init_snake_contour_from_previous_section() 59 | return True 60 | elif key == Qt.Key_Period: 61 | self.copy_init_snake_contour_from_next_section() 62 | return True 63 | 64 | return super(DrawableZoomableBrowsableGraphicsScene_ForMasking, self).eventFilter(obj, event) 65 | 66 | def copy_init_snake_contour_from_previous_section(self): 67 | self.copy_init_snake_contour(from_index=self.active_i-1, to_index=self.active_i) 68 | 69 | def copy_init_snake_contour_from_next_section(self): 70 | self.copy_init_snake_contour(from_index=self.active_i+1, to_index=self.active_i) 71 | 72 | def unset_init_snake_contour(self, section=None, index=None): 73 | try: 74 | index, section = self.get_requested_index_and_section(sec=section, i=index) 75 | except: 76 | return 77 | # Remove from gscene's record 78 | if section in self.init_snake_contour_polygons: 79 | init_snake_contour_polygon_to_delete = self.init_snake_contour_polygons[section] 80 | self.delete_polygon(polygon=init_snake_contour_polygon_to_delete) 81 | self.init_snake_contour_polygons.pop(section, None) 82 | 83 | def set_init_snake_contour(self, vertices, section=None, index=None): 84 | try: 85 | index, section = self.get_requested_index_and_section(sec=section, i=index) 86 | except: 87 | return 88 | self.init_snake_contour_polygons[section] = \ 89 | self.add_polygon_with_circles(path=vertices_to_path(vertices), index=index, linewidth=1, linecolor='b', vertex_radius=5) 90 | 91 | def copy_init_snake_contour(self, to_section=None, to_index=None, from_section=None, from_index=None): 92 | try: 93 | from_index, from_section = self.get_requested_index_and_section(sec=from_section, i=from_index) 94 | except: 95 | return 96 | 97 | assert from_section in self.init_snake_contour_polygons and self.init_snake_contour_polygons[from_section] is not None 98 | vertices = vertices_from_polygon(self.init_snake_contour_polygons[from_section]) 99 | self.unset_init_snake_contour(section=to_section, index=to_index) 100 | self.set_init_snake_contour(vertices=vertices, section=to_section, index=to_index) 101 | 102 | def set_section_as_anchor(self, section): 103 | self.anchor_sections.add(section) 104 | print "Anchor sections:", sorted(list(self.anchor_sections)) 105 | 106 | def set_current_section_as_anchor(self): 107 | self.set_section_as_anchor(section=self.active_section) 108 | 109 | def show_context_menu(self, pos): 110 | myMenu = QMenu(self.gview) 111 | 112 | action_newPolygon = myMenu.addAction("New polygon") 113 | action_deletePolygon = myMenu.addAction("Delete polygon") 114 | action_insertVertex = myMenu.addAction("Insert vertex") 115 | action_deleteVertices = myMenu.addAction("Delete vertices") 116 | action_addInitSnakeContour = myMenu.addAction("Create initial snake contour") 117 | action_deleteInitSnakeContour = myMenu.addAction("Delete initial snake contour") 118 | myMenu.addSeparator() 119 | action_setAsAnchorContour = myMenu.addAction("Set this section as anchor contour") 120 | action_autoEstimateAllContours = myMenu.addAction("Automatically estimate all contours") 121 | 122 | selected_action = myMenu.exec_(self.gview.viewport().mapToGlobal(pos)) 123 | 124 | if selected_action == action_newPolygon: 125 | self.close_curr_polygon = False 126 | self.active_polygon = self.add_polygon(QPainterPath(), index=self.active_i, linewidth=10) 127 | self.active_polygon.set_closed(False) 128 | self.set_mode('add vertices consecutively') 129 | 130 | elif selected_action == action_deletePolygon: 131 | self.polygon_deleted.emit(self.active_polygon, self.active_i, self.drawings[self.active_i].index(self.active_polygon)) 132 | sys.stderr.write('%s: polygon_deleted signal emitted.\n' % (self.id)) 133 | self.drawings[self.active_i].remove(self.active_polygon) 134 | self.removeItem(self.active_polygon) 135 | 136 | elif selected_action == action_insertVertex: 137 | self.set_mode('add vertices randomly') 138 | 139 | elif selected_action == action_deleteVertices: 140 | self.set_mode('delete vertices') 141 | 142 | elif selected_action == action_addInitSnakeContour: 143 | self.is_adding_snake_contour = True 144 | self.close_curr_polygon = False 145 | self.active_polygon = self.add_polygon(QPainterPath(), index=self.active_i, linewidth=1, color=(255,0,255), vertex_radius=5) 146 | self.active_polygon.set_closed(False) 147 | self.set_mode('add vertices consecutively') 148 | 149 | elif selected_action == action_deleteInitSnakeContour: 150 | self.polygon_deleted.emit(self.active_polygon, self.active_i, self.drawings[self.active_i].index(self.active_polygon)) 151 | sys.stderr.write('%s: polygon_deleted signal emitted.\n' % (self.id)) 152 | self.drawings[self.active_i].remove(self.active_polygon) 153 | self.removeItem(self.active_polygon) 154 | 155 | elif selected_action == action_setAsAnchorContour: 156 | self.set_current_section_as_anchor() 157 | 158 | elif selected_action == action_autoEstimateAllContours: 159 | self.anchor_sections_sorted = sorted(list(self.anchor_sections)) 160 | for sec in range(self.data_feeder.sections[0], self.anchor_sections_sorted[0]): 161 | self.copy_init_snake_contour(from_section=self.anchor_sections_sorted[0], to_section=sec) 162 | for sec in range(self.anchor_sections_sorted[-1], self.data_feeder.sections[-1]+1): 163 | self.copy_init_snake_contour(from_section=self.anchor_sections_sorted[-1], to_section=sec) 164 | contours_grouped_by_pos = {anchor_sec: vertices_from_polygon(self.init_snake_contour_polygons[anchor_sec]) 165 | for anchor_sec in self.anchor_sections} 166 | 167 | contours_all_sections = get_interpolated_contours(contours_grouped_by_pos, len_interval=10) 168 | 169 | for sec, contours in contours_all_sections.iteritems(): 170 | self.unset_init_snake_contour(section=sec) 171 | self.set_init_snake_contour(vertices=contours, section=sec) 172 | -------------------------------------------------------------------------------- /src/gui/widgets/MultiplePixmapsGraphicsScene.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtCore import * 2 | from PyQt4.QtGui import * 3 | 4 | from custom_widgets import * 5 | from SignalEmittingItems import * 6 | 7 | from gui_utilities import * 8 | 9 | sys.path.append(os.environ['REPO_DIR'] + '/utilities') 10 | from data_manager import DataManager 11 | from metadata import * 12 | 13 | class MultiplePixmapsGraphicsScene(QGraphicsScene): 14 | """ 15 | Variant that supports overlaying multiple pixmaps and adjusting opacity of each. 16 | """ 17 | 18 | active_image_updated = pyqtSignal() 19 | 20 | def __init__(self, id, pixmap_labels, gview=None, parent=None): 21 | """ 22 | Args: 23 | pixmap_labels (list of str): keys that specify different image groups 24 | """ 25 | 26 | super(QGraphicsScene, self).__init__(parent=parent) 27 | 28 | self.pixmapItems = {l: QGraphicsPixmapItem() for l in pixmap_labels} 29 | self.data_feeders = {} 30 | 31 | for pm in self.pixmapItems.itervalues(): 32 | self.addItem(pm) 33 | 34 | self.gview = gview 35 | self.id = id 36 | 37 | self.active_sections = None 38 | self.active_indices = None 39 | 40 | self.installEventFilter(self) 41 | 42 | # self.showing_which = 'histology' 43 | 44 | self.gview.setMouseTracking(False) 45 | self.gview.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff ) 46 | self.gview.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff ) 47 | self.gview.setAlignment(Qt.AlignLeft | Qt.AlignTop) 48 | self.gview.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) # Important! default is AnchorViewCenter. 49 | # self.gview.setResizeAnchor(QGraphicsView.AnchorUnderMouse) 50 | self.gview.setContextMenuPolicy(Qt.CustomContextMenu) 51 | self.gview.setDragMode(QGraphicsView.ScrollHandDrag) 52 | # gview.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) 53 | 54 | if not hasattr(self, 'contextMenu_set') or (hasattr(self, 'contextMenu_set') and not self.contextMenu_set): 55 | self.gview.customContextMenuRequested.connect(self.show_context_menu) 56 | 57 | # self.gview.installEventFilter(self) 58 | self.gview.viewport().installEventFilter(self) 59 | 60 | 61 | def set_opacity(self, pixmap_label, opacity): 62 | self.pixmapItems[pixmap_label].setOpacity(opacity) 63 | 64 | def set_data_feeder(self, feeder, pixmap_label): 65 | if hasattr(self, 'data_feeders') and pixmap_label in self.data_feeders and self.data_feeders[pixmap_label] == feeder: 66 | return 67 | self.data_feeders[pixmap_label] = feeder 68 | if hasattr(feeder, 'se'): # Only implemented for image reader, not volume resection reader. 69 | self.connect(feeder.se, SIGNAL("image_loaded(int)"), self.image_loaded) 70 | 71 | @pyqtSlot(int) 72 | def image_loaded(self, int): 73 | self.active_image_updated.emit() 74 | 75 | def set_active_indices(self, indices, emit_changed_signal=True): 76 | 77 | if indices == self.active_indices: 78 | return 79 | 80 | # old_indices = self.active_indices 81 | 82 | print self.id, ': Set active index to', indices, ', emit_changed_signal', emit_changed_signal 83 | 84 | self.active_indices = indices 85 | self.active_sections = {label: self.data_feeders[label].sections[i] for label, i in self.active_indices.iteritems()} 86 | print self.id, ': Set active section to', self.active_sections 87 | 88 | try: 89 | self.update_image() 90 | except Exception as e: 91 | sys.stderr.write('Failed to update image: %s.\n' % e) 92 | for label in self.pixmapItems.keys(): 93 | self.pixmapItems[label].setVisible(False) 94 | 95 | if emit_changed_signal: 96 | self.active_image_updated.emit() 97 | 98 | def set_active_sections(self, sections, emit_changed_signal=True): 99 | """ 100 | Args: 101 | sections (str or int dict): {set_name: image label} . 102 | """ 103 | 104 | print self.id, ': Set active sections to', sections 105 | 106 | indices = {set_name: self.data_feeders[set_name].sections.index(sec) for set_name, sec in sections.iteritems()} 107 | self.set_active_indices(indices, emit_changed_signal=emit_changed_signal) 108 | 109 | def update_image(self): 110 | 111 | indices = self.active_indices 112 | # sections = self.active_sections 113 | # indices = {label: self.data_feeders[label].all_sections.index(sec) for label, sec in sections.iteritems()} 114 | 115 | for set_name, idx in indices.iteritems(): 116 | try: 117 | qimage = self.data_feeders[set_name].retrieve_i(i=idx) 118 | pixmap = QPixmap.fromImage(qimage) 119 | self.pixmapItems[set_name].setPixmap(pixmap) 120 | self.pixmapItems[set_name].setVisible(True) 121 | except: 122 | sys.stderr.write("%s: set_name=%s, index=%s fails to show. Skip.\n" % (self.id, set_name, idx)) 123 | # self.set_active_indices(indices) 124 | 125 | def show_next(self, cycle=False): 126 | indices = {} 127 | for pixmap_label, idx in self.active_indices.iteritems(): 128 | if cycle: 129 | indices[pixmap_label] = (idx + 1) % self.data_feeders[pixmap_label].n 130 | else: 131 | indices[pixmap_label] = min(idx + 1, self.data_feeders[pixmap_label].n - 1) 132 | self.set_active_indices(indices) 133 | 134 | def show_previous(self, cycle=False): 135 | indices = {} 136 | for pixmap_label, idx in self.active_indices.iteritems(): 137 | if cycle: 138 | indices[pixmap_label] = (idx - 1) % self.data_feeders[pixmap_label].n 139 | else: 140 | indices[pixmap_label] = max(idx - 1, 0) 141 | self.set_active_indices(indices) 142 | 143 | def show_context_menu(self, pos): 144 | pass 145 | 146 | def eventFilter(self, obj, event): 147 | # print obj.metaObject().className(), event.type() 148 | # http://doc.qt.io/qt-4.8/qevent.html#Type-enum 149 | 150 | if event.type() == QEvent.KeyPress: 151 | key = event.key() 152 | if key == Qt.Key_BracketRight: 153 | self.show_next(cycle=True) 154 | elif key == Qt.Key_BracketLeft: 155 | self.show_previous(cycle=True) 156 | return True 157 | 158 | elif event.type() == QEvent.Wheel: 159 | # eat wheel event from gview viewport. default behavior is to trigger down scroll 160 | 161 | out_factor = .9 162 | in_factor = 1. / out_factor 163 | 164 | if event.delta() < 0: # negative means towards user 165 | self.gview.scale(out_factor, out_factor) 166 | else: 167 | self.gview.scale(in_factor, in_factor) 168 | 169 | return True 170 | 171 | return False 172 | -------------------------------------------------------------------------------- /src/gui/widgets/SignalEmittingGraphicsPathItem.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from PyQt4.QtCore import * 4 | from PyQt4.QtGui import * 5 | 6 | from SignalEmittingItems import PolygonSignalEmitter 7 | 8 | class SignalEmittingGraphicsPathItem(QGraphicsPathItem): 9 | """ 10 | Extend base class by 11 | - adding a member dict called `properties` to store application-specific data. 12 | """ 13 | def __init__(self, path, parent=None, gscene=None): 14 | super(SignalEmittingGraphicsPathItem, self).__init__(path, parent=parent) 15 | self.setPath(path) 16 | self.signal_emitter = PolygonSignalEmitter(parent=self) 17 | self.gscene = gscene 18 | 19 | self.properties = {} 20 | 21 | def set_properties(self, property_name, property_value): 22 | # sys.stderr.write('Trying to set %s to %s\n' % (property_name, property_value)) 23 | if property_name in self.properties and self.properties[property_name] is not None: 24 | if isinstance(self.properties[property_name], list) or \ 25 | isinstance(self.properties[property_name], tuple) or \ 26 | isinstance(property_value, list) or \ 27 | isinstance(property_value, tuple): 28 | if tuple(self.properties[property_name]) == tuple(property_value): 29 | return 30 | elif len(self.properties[property_name]) == len(property_value) and \ 31 | all([property_value[i] == self.properties[property_name][i] for i in range(len(self.properties[property_name]))]): 32 | return 33 | 34 | # The second condition uses tuple because a multi-value list may either be represented by tuple or list 35 | # print property_name, property_value 36 | if property_name in self.properties: 37 | old_value = self.properties[property_name] 38 | else: 39 | old_value = None 40 | self.properties[property_name] = property_value 41 | self.signal_emitter.property_changed.emit(property_name, property_value, old_value) 42 | 43 | def mousePressEvent(self, event): 44 | QGraphicsPathItem.mousePressEvent(self, event) 45 | self.signal_emitter.press.emit(self) 46 | -------------------------------------------------------------------------------- /src/gui/widgets/SignalEmittingGraphicsPathItemWithVertexCircles.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtCore import * 2 | from PyQt4.QtGui import * 3 | 4 | from SignalEmittingGraphicsPathItem import SignalEmittingGraphicsPathItem 5 | from SignalEmittingItems import PolygonSignalEmitter, QGraphicsEllipseItemModified, QGraphicsEllipseItemModified3 6 | 7 | from gui_utilities import * 8 | 9 | class SignalEmittingGraphicsPathItemWithVertexCircles(SignalEmittingGraphicsPathItem): 10 | """ 11 | Extends base class by: 12 | - Define a list of `QGraphicsEllipseItemModified` called vertex_circles. 13 | """ 14 | 15 | def __init__(self, path, parent=None, gscene=None, vertex_radius=None): 16 | super(SignalEmittingGraphicsPathItemWithVertexCircles, self).__init__(path, parent=parent, gscene=gscene) 17 | 18 | self.vertex_circles = [] 19 | if vertex_radius is None: 20 | self.vertex_radius = 20 21 | else: 22 | self.vertex_radius = vertex_radius 23 | 24 | self.closed = False 25 | 26 | def add_circles_for_all_vertices(self, radius=None, color='b'): 27 | ''' 28 | Add vertex circles for all vertices in a polygon with existing path. 29 | 30 | Args: 31 | polygon (QGraphicsPathItemModified): the polygon 32 | ''' 33 | 34 | path = self.path() 35 | is_closed = polygon_is_closed(path=path) 36 | 37 | n = polygon_num_vertices(path=path, closed=is_closed) 38 | 39 | for i in range(n): 40 | self.add_circle_for_vertex(index=i, radius=radius, color=color) 41 | 42 | def add_circle_for_vertex(self, index, radius=None, color='b'): 43 | """ 44 | Add a circle for an existing vertex. 45 | 46 | Args: 47 | color (str or tuple): color of vertex circle 48 | """ 49 | 50 | path = self.path() 51 | if index == -1: 52 | is_closed = polygon_is_closed(path=path) 53 | n = polygon_num_vertices(path=path, closed=is_closed) 54 | elem = path.elementAt(n-1) 55 | else: 56 | elem = path.elementAt(index) 57 | 58 | if radius is None: 59 | radius = self.vertex_radius 60 | 61 | ellipse = QGraphicsEllipseItemModified(-radius, -radius, 2*radius, 2*radius, polygon=self, parent=self) # set polygon as parent, so that moving polygon moves the children vertices as well 62 | ellipse.setPos(elem.x, elem.y) 63 | 64 | if color == 'r': 65 | ellipse.setPen(Qt.red) 66 | ellipse.setBrush(Qt.red) 67 | elif color == 'g': 68 | ellipse.setPen(Qt.green) 69 | ellipse.setBrush(Qt.green) 70 | elif color == 'b': 71 | ellipse.setPen(Qt.blue) 72 | ellipse.setBrush(Qt.blue) 73 | elif color == 'w': 74 | ellipse.setPen(Qt.white) 75 | ellipse.setBrush(Qt.white) 76 | elif isinstance(color, tuple) or isinstance(color, list): 77 | ellipse.setPen(QColor(color[0], color[1], color[2])) 78 | ellipse.setBrush(QColor(color[0], color[1], color[2])) 79 | else: 80 | raise Exception('Input color is not recognized.') 81 | 82 | ellipse.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemClipsToShape | QGraphicsItem.ItemSendsGeometryChanges | QGraphicsItem.ItemSendsScenePositionChanges) 83 | ellipse.setZValue(99) 84 | 85 | if index == -1: 86 | self.vertex_circles.append(ellipse) 87 | else: 88 | self.vertex_circles.insert(index, ellipse) 89 | 90 | self.signal_emitter.vertex_added.emit(ellipse) 91 | ellipse.signal_emitter.press.connect(self.vertex_press) 92 | ellipse.signal_emitter.moved.connect(self.vertex_moved_callback) 93 | return ellipse 94 | 95 | def vertex_moved_callback(self, circ, new_x, new_y): 96 | if circ in self.vertex_circles: 97 | # When circle is just created, itemChange will be called, but it is not added to the list yet. 98 | vertex_index = self.vertex_circles.index(circ) 99 | new_path = self.path() 100 | if vertex_index == 0 and polygon_is_closed(path=new_path): # closed 101 | new_path.setElementPositionAt(0, new_x, new_y) 102 | new_path.setElementPositionAt(len(self.vertex_circles), new_x, new_y) 103 | else: 104 | new_path.setElementPositionAt(vertex_index, new_x, new_y) 105 | self.setPath(new_path) 106 | 107 | self.signal_emitter.polygon_changed.emit() 108 | else: 109 | raise Exception('vertex_moved signal is received from a non-member vertex.') 110 | 111 | def add_vertex(self, x, y, new_index=-1, color='b'): 112 | if new_index == -1: 113 | polygon_goto(self, x, y) 114 | else: 115 | new_path = insert_vertex(self.path(), x, y, new_index) 116 | self.setPath(new_path) 117 | 118 | self.add_circle_for_vertex(new_index, color=color) 119 | 120 | def delete_vertices(self, indices_to_remove, merge=False): 121 | if merge: 122 | new_path = delete_vertices_merge(self.path(), indices_to_remove) 123 | self.setPath(new_path) 124 | 125 | # Remove all circles and rebuild based on the updated path. 126 | for c in self.vertex_circles: 127 | self.gscene.removeItem(c) 128 | self.vertex_circles = [] 129 | self.add_circles_for_all_vertices() 130 | 131 | # for i in indices_to_remove: 132 | # self.gscene.removeItem(self.vertex_circles[i]) 133 | # self.vertex_circles = [c for i, c in enumerate(self.vertex_circles) if i not in indices_to_remove] # Doing so risks inconsistent vertex ordering with polygon's path. 134 | self.signal_emitter.polygon_changed.emit() 135 | else: 136 | paths_to_remove, paths_to_keep = split_path(polygon.path(), indices_to_remove) 137 | 138 | def set_closed(self, closed): 139 | self.closed = closed 140 | 141 | @pyqtSlot(object) 142 | def vertex_press(self, circle): 143 | 144 | # print '\nSignalEmittingGraphicsPathItemWithVertexCircles::vertex_press\n' 145 | 146 | # Emit a polygon pressed signal 147 | # This is necessary for one-node polygon, 148 | # for which the built-in mouseclickevent will not fire if user clicks on the single vertex 149 | self.signal_emitter.press.emit(self) 150 | 151 | # if self.vertex_circles.index(circle) == 0 and len(self.vertex_circles) > 2 and not self.closed: 152 | if self.vertex_circles.index(circle) == 0 and not self.closed: 153 | # (self.mode == 'add vertices randomly' or self.mode == 'add vertices consecutively'): 154 | # the last condition is to prevent setting the flag when one clicks vertex 0 in idle mode. 155 | # print 'close polygon' 156 | self.closed = True 157 | self.close() 158 | self.signal_emitter.polygon_completed.emit() 159 | 160 | def close(self): 161 | print 'close' 162 | path = self.path() 163 | path.closeSubpath() 164 | self.setPath(path) 165 | -------------------------------------------------------------------------------- /src/gui/widgets/ZoomableBrowsableGraphicsSceneWithReadonlyPolygon.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtCore import * 2 | from PyQt4.QtGui import * 3 | 4 | from SignalEmittingGraphicsPathItem import SignalEmittingGraphicsPathItem 5 | from ZoomableBrowsableGraphicsScene import ZoomableBrowsableGraphicsScene 6 | 7 | from collections import defaultdict 8 | 9 | class ZoomableBrowsableGraphicsSceneWithReadonlyPolygon(ZoomableBrowsableGraphicsScene): 10 | """ 11 | Read-only polygons. 12 | """ 13 | 14 | polygon_pressed = pyqtSignal(object) 15 | 16 | def __init__(self, id, gview=None, parent=None): 17 | super(ZoomableBrowsableGraphicsSceneWithReadonlyPolygon, self).__init__(id=id, gview=gview, parent=parent) 18 | 19 | self.drawings = defaultdict(list) 20 | self.drawings_mapping = {} 21 | 22 | def set_default_line_width(self, width): 23 | self.default_line_width = width 24 | 25 | def set_default_line_color(self, color): 26 | """ 27 | Args: 28 | color (str): "r", "g" or "b" 29 | """ 30 | self.default_line_color = color 31 | 32 | def remove_polygon(self, polygon): 33 | self.polygon_deleted.emit(polygon) 34 | sys.stderr.write('%s: polygon_deleted signal emitted.\n' % (self.id)) 35 | self.drawings[self.active_i].remove(polygon) 36 | self.removeItem(polygon) 37 | 38 | def remove_all_polygons(self, sec=None, i=None): 39 | index, _ = self.get_requested_index_and_section(sec=sec, i=i) 40 | for p in self.drawings[index]: 41 | self.remove_polygon(p) 42 | 43 | def add_polygon(self, path=QPainterPath(), color=None, linewidth=None, section=None, index=None, z_value=50): 44 | ''' 45 | Add a polygon to a specified section. 46 | 47 | Args: 48 | path (QPainterPath): path of the polygon 49 | pen (QPen): pen used to draw polygon 50 | 51 | Returns: 52 | QGraphicsPathItemModified: added polygon 53 | ''' 54 | 55 | if color is None: 56 | color = self.default_line_color 57 | 58 | if color == 'r': 59 | pen = QPen(Qt.red) 60 | elif color == 'g': 61 | pen = QPen(Qt.green) 62 | elif color == 'b': 63 | pen = QPen(Qt.blue) 64 | elif isinstance(color, tuple) or isinstance(color, list): 65 | pen = QPen(QColor(color[0], color[1], color[2])) 66 | else: 67 | raise Exception('color not recognized.') 68 | 69 | if linewidth is None: 70 | linewidth = self.default_line_width 71 | 72 | pen.setWidth(linewidth) 73 | 74 | index, _ = self.get_requested_index_and_section(i=index, sec=section) 75 | 76 | polygon = SignalEmittingGraphicsPathItem(path, gscene=self) 77 | 78 | polygon.setPen(pen) 79 | polygon.setZValue(z_value) 80 | polygon.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemClipsToShape | QGraphicsItem.ItemSendsGeometryChanges | QGraphicsItem.ItemSendsScenePositionChanges) 81 | polygon.setFlag(QGraphicsItem.ItemIsMovable, False) 82 | 83 | polygon.signal_emitter.press.connect(self._polygon_pressed) 84 | # polygon.signal_emitter.release.connect(self.polygon_release) 85 | 86 | self.drawings[index].append(polygon) 87 | self.drawings_mapping[polygon] = index 88 | 89 | # if adding polygon to current section 90 | if index == self.active_i: 91 | print 'polygon added.' 92 | self.addItem(polygon) 93 | 94 | return polygon 95 | 96 | @pyqtSlot(object) 97 | def _polygon_pressed(self, polygon): 98 | 99 | print 'polygon pressed' 100 | 101 | self.active_polygon = polygon 102 | print 'active polygon selected', self.active_polygon 103 | 104 | self.polygon_pressed.emit(polygon) 105 | 106 | def set_active_i(self, i, emit_changed_signal=True): 107 | 108 | for polygon in self.drawings[self.active_i]: 109 | self.removeItem(polygon) 110 | 111 | super(ZoomableBrowsableGraphicsSceneWithReadonlyPolygon, self).set_active_i(i, emit_changed_signal=emit_changed_signal) 112 | 113 | for polygon in self.drawings[i]: 114 | self.addItem(polygon) 115 | -------------------------------------------------------------------------------- /src/gui/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ActiveBrainAtlas/MouseBrainAtlas/b6ca6afcfc88f6772b073b9ad2bf5d0b3bf840bd/src/gui/widgets/__init__.py -------------------------------------------------------------------------------- /src/gui/widgets/custom_widgets.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # import sip 4 | # sip.setapi('QVariant', 2) # http://stackoverflow.com/questions/21217399/pyqt4-qtcore-qvariant-object-instead-of-a-string 5 | 6 | import sys 7 | import os 8 | import numpy as np 9 | 10 | from PyQt4.QtCore import * 11 | from PyQt4.QtGui import * 12 | 13 | # from matplotlib.backends import qt4_compat 14 | # use_pyside = qt4_compat.QT_API == qt4_compat.QT_API_PYSIDE 15 | # if use_pyside: 16 | # #print 'Using PySide' 17 | # from PySide.QtCore import * 18 | # from PySide.QtGui import * 19 | # else: 20 | # #print 'Using PyQt4' 21 | # from PyQt4.QtCore import * 22 | # from PyQt4.QtGui import * 23 | 24 | 25 | class CustomQCompleter(QCompleter): 26 | # adapted from http://stackoverflow.com/a/26440173 27 | def __init__(self, *args):#parent=None): 28 | super(CustomQCompleter, self).__init__(*args) 29 | self.local_completion_prefix = "" 30 | self.source_model = None 31 | self.filterProxyModel = QSortFilterProxyModel(self) 32 | self.usingOriginalModel = False 33 | 34 | def setModel(self, model): 35 | self.source_model = model 36 | self.filterProxyModel = QSortFilterProxyModel(self) 37 | self.filterProxyModel.setSourceModel(self.source_model) 38 | super(CustomQCompleter, self).setModel(self.filterProxyModel) 39 | self.usingOriginalModel = True 40 | 41 | def updateModel(self): 42 | if not self.usingOriginalModel: 43 | self.filterProxyModel.setSourceModel(self.source_model) 44 | 45 | pattern = QRegExp(self.local_completion_prefix, 46 | Qt.CaseInsensitive, 47 | QRegExp.FixedString) 48 | 49 | self.filterProxyModel.setFilterRegExp(pattern) 50 | 51 | def splitPath(self, path): 52 | self.local_completion_prefix = path 53 | self.updateModel() 54 | if self.filterProxyModel.rowCount() == 0: 55 | self.usingOriginalModel = False 56 | self.filterProxyModel.setSourceModel(QStringListModel([path])) 57 | return [path] 58 | 59 | return [] 60 | 61 | class AutoCompleteComboBox(QComboBox): 62 | # adapted from http://stackoverflow.com/a/26440173 63 | def __init__(self, labels, *args, **kwargs): 64 | super(AutoCompleteComboBox, self).__init__(*args, **kwargs) 65 | 66 | self.setEditable(True) 67 | self.setInsertPolicy(self.NoInsert) 68 | 69 | self.comp = CustomQCompleter(self) 70 | self.comp.setCompletionMode(QCompleter.PopupCompletion) 71 | self.setCompleter(self.comp)# 72 | self.setModel(labels) 73 | 74 | self.clearEditText() 75 | 76 | def setModel(self, strList): 77 | self.clear() 78 | self.insertItems(0, strList) 79 | self.comp.setModel(self.model()) 80 | 81 | def focusInEvent(self, event): 82 | # self.clearEditText() 83 | super(AutoCompleteComboBox, self).focusInEvent(event) 84 | 85 | def keyPressEvent(self, event): 86 | key = event.key() 87 | if key == Qt.Key_Return: 88 | 89 | # make sure that the completer does not set the 90 | # currentText of the combobox to "" when pressing enter 91 | text = self.currentText() 92 | self.setCompleter(None) 93 | self.setEditText(text) 94 | self.setCompleter(self.comp) 95 | 96 | return super(AutoCompleteComboBox, self).keyPressEvent(event) 97 | 98 | class AutoCompleteInputDialog(QDialog): 99 | 100 | def __init__(self, labels, *args, **kwargs): 101 | super(AutoCompleteInputDialog, self).__init__(*args, **kwargs) 102 | self.comboBox = AutoCompleteComboBox(parent=self, labels=labels) 103 | va = QVBoxLayout(self) 104 | va.addWidget(self.comboBox) 105 | box = QWidget(self) 106 | ha = QHBoxLayout(self) 107 | va.addWidget(box) 108 | box.setLayout(ha) 109 | self.OK = QPushButton("OK", self) 110 | self.OK.setDefault(True) 111 | # cancel = QPushButton("Cancel", self) 112 | ha.addWidget(self.OK) 113 | # ha.addWidget(cancel) 114 | 115 | def set_test_callback(self, callback): 116 | self.OK.clicked.connect(callback) 117 | # OK.clicked.connect(self.accept) 118 | # cancel.clicked.connect(self.reject) 119 | 120 | class ListSelection(QDialog): 121 | """ 122 | https://stackoverflow.com/questions/41310023/pyside-popup-showing-list-and-multiple-select 123 | """ 124 | def __init__(self, title, message, items, items_checked, parent=None): 125 | """ 126 | Args: 127 | checked (list of str) 128 | """ 129 | super(ListSelection, self).__init__(parent=parent) 130 | form = QFormLayout(self) 131 | form.addRow(QLabel(message)) 132 | self.listView = QListView(self) 133 | form.addRow(self.listView) 134 | model = QStandardItemModel(self.listView) 135 | self.setWindowTitle(title) 136 | for item in items: 137 | # create an item with a caption 138 | standardItem = QStandardItem(item) 139 | standardItem.setCheckable(True) 140 | if item in items_checked: 141 | standardItem.setCheckState(True) 142 | model.appendRow(standardItem) 143 | self.listView.setModel(model) 144 | 145 | buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) 146 | form.addRow(buttonBox) 147 | buttonBox.accepted.connect(self.accept) 148 | buttonBox.rejected.connect(self.reject) 149 | 150 | def itemsSelected(self): 151 | selected = [] 152 | model = self.listView.model() 153 | i = 0 154 | while model.item(i): 155 | if model.item(i).checkState(): 156 | selected.append(model.item(i).text()) 157 | i += 1 158 | return selected 159 | 160 | 161 | # class ListSelection(QDialog): 162 | # def __init__(self, item_ls, parent=None): 163 | # super(ListSelection, self).__init__(parent) 164 | # 165 | # self.setWindowTitle('Detect which landmarks ?') 166 | # 167 | # self.selected = set([]) 168 | # 169 | # self.listWidget = QListWidget() 170 | # for item in item_ls: 171 | # w_item = QListWidgetItem(item) 172 | # self.listWidget.addItem(w_item) 173 | # 174 | # w_item.setFlags(w_item.flags() | Qt.ItemIsUserCheckable) 175 | # w_item.setCheckState(False) 176 | # 177 | # self.listWidget.itemChanged.connect(self.OnSingleClick) 178 | # 179 | # layout = QGridLayout() 180 | # layout.addWidget(self.listWidget,0,0,1,3) 181 | # 182 | # self.but_ok = QPushButton("OK") 183 | # layout.addWidget(self.but_ok ,1,1) 184 | # self.but_ok.clicked.connect(self.OnOk) 185 | # 186 | # self.but_cancel = QPushButton("Cancel") 187 | # layout.addWidget(self.but_cancel ,1,2) 188 | # self.but_cancel.clicked.connect(self.OnCancel) 189 | # 190 | # self.setLayout(layout) 191 | # self.setGeometry(300, 200, 460, 350) 192 | # 193 | # def OnSingleClick(self, item): 194 | # if not item.checkState(): 195 | # # item.setCheckState(False) 196 | # self.selected = self.selected - {str(item.text())} 197 | # # print self.selected 198 | # else: 199 | # # item.setCheckState(True) 200 | # self.selected.add(str(item.text())) 201 | # 202 | # print self.selected 203 | # 204 | # def OnOk(self): 205 | # self.close() 206 | # 207 | # def OnCancel(self): 208 | # self.selected = set([]) 209 | # self.close() 210 | -------------------------------------------------------------------------------- /src/learning/classifier_settings.csv: -------------------------------------------------------------------------------- 1 | classifier_id,model,margin_um,train_set_id,neg_composition,sample_weighting,input_img_version,svm_id,comment,num_samples_per_class 2 | 30,lr,500,20/21,neg_has_all_surround,,cropped_gray,30, 3 | 31,lr,500,21/22,neg_has_all_surround,,cropped_gray,31, 4 | 32,lr,500,20/22,neg_has_all_surround,,cropped_gray,32, 5 | 33,gb1,500,20/21,neg_has_all_surround,,cropped_gray,33, 6 | 34,gb1,500,21/22,neg_has_all_surround,,cropped_gray,34, 7 | 35,gb1,500,20/22,neg_has_all_surround,,cropped_gray,35, 8 | 36,gb1,500,23/24,neg_has_all_surround,,cropped_gray,36, 9 | 37,lr,500,23/24,neg_has_all_surround,,cropped_gray,37, 10 | 38,lr,500,23/24/27/28,neg_has_surround_and_negative,,cropped_gray,38, 11 | 39,lr,200,30/31/27/28,neg_has_surround_and_negative,,cropped_gray,39, 12 | 40,lr,1000,33/34/27/28,neg_has_surround_and_negative,,cropped_gray,40, 13 | 41,lr,500,36/37/27/28,neg_has_surround_and_negative,,cropped_gray,41, 14 | 42,lr,500,39/40/27/28,neg_has_surround_and_negative,,cropped_gray,42, 15 | 50,lr,500,27/28/29/60/61/62,neg_has_surround_and_negative,,cropped_gray,50,using mirror variations of patches to train 16 | 70,inception-bn-blue-softmax,500,60/61,neg_has_all_surround,,cropped_gray,, 17 | 71,inception-bn-blue-softmax,500,60/61/62,neg_has_all_surround,,cropped_gray,, 18 | 72,lr,500,66/67/68,neg_has_surround_and_negative,,,72,using mirror variations of patches to train; use both surround and far as negative 19 | 73,lr,500,66/67/68,neg_has_all_surround,,,73,using mirror variations for training; use only surround as negative, 20 | 74,lr,500,72/73/74,neg_has_all_surround,,,74,using rotation and intensity variations for training; use only surround as negative 21 | 75,lr,500,72/73/74,neg_has_surround_and_negative,,,75,using rotation and intensity variations for training; use both surr and neg 22 | 76,lr,500,75/76/77,neg_has_surround_and_negative,,,76,using no rotation for training; use both surr and neg 23 | 77,lr,500,66/67/68,neg_has_all_surround,,,77,using mirror variations for training; use only surround as negative;100 samples,100 24 | 78,xgb2,500,66/67/68,neg_has_all_surround,,,78,using mirror variations for training; use only surround as negative;sklearn gradient boost,10000 25 | 79,lin_svc,500,66/67/68,neg_has_all_surround,,,79,using mirror variations for training; use only surround as negative;svm,10000 26 | 80,lr,500,23/24,neg_has_all_surround,,cropped_gray_linearNormalized500,37, 27 | 81,lr,500,23/24,neg_has_all_surround,,cropped_gray_linearNormalized1000,37, 28 | 82,lr,500,23/24,neg_has_all_surround,,cropped_gray_linearNormalized1500,37, 29 | 83,lr,500,23/24,neg_has_all_surround,,cropped_gray_linearNormalized2000,37, 30 | 84,lr,500,23/24,neg_has_all_surround,,cropped_gray_linearNormalized2500,37, 31 | 95,gb2,500,93,neg_has_all_surround,,cropped_gray,95, 32 | 96,gb2,500,95,neg_has_all_surround,,cropped_gray,96, 33 | 97,gb2,500,97,neg_has_all_surround,,cropped_gray,97, 34 | 98,gb2,500,99,neg_has_all_surround,,cropped_gray,98, 35 | 99,lr,500,99,neg_has_all_surround,,cropped_gray,99, 36 | 110,lr,500,66/67/68,neg_has_all_surround,,,110,using mirror variations for training; use only surround as negative;1000 samples,1000 37 | 111,lr,500,66/67/68,neg_has_all_surround,,,111,using mirror variations for training; use only surround as negative;10000 samples,10000 38 | 112,lr,500,66/67,neg_has_all_surround,,,112,using mirror variations for training; use only surround as negative;1000 samples,1000 39 | 113,lr,500,66/67,neg_has_all_surround,,,113,using mirror variations for training; use only surround as negative;10000 samples,10000 40 | 114,lr,500,78/79,neg_has_all_surround,,,114,using mirror variations for training; use only surround as negative;100000 samples,100000 41 | 115,xgb2,500,66/67,neg_has_all_surround,,,115,using mirror variations for training; use only surround as negative;sklearn gradient boost,10000 42 | 116,lin_svc,500,66/67,neg_has_all_surround,,,116,using mirror variations for training; use only surround as negative;svm,10000 43 | 120,lr,500,75/76/77,neg_has_all_surround,,,120,classifier based on greylevel intensity,1000 44 | 130,lr,500,110/111/112,neg_has_all_surround,,,130,twice as large patch,10000 45 | 131,lr,500,113/114,neg_has_all_surround,,,131,trained using MD585 and MD589;twice as large patch,10000 46 | 132,lr,500,113/115,neg_has_all_surround,,,132,trained using MD585 and MD594;twice as large patch,10000 47 | 133,lr,500,114/115,neg_has_all_surround,,,133,trained using MD589 and MD594;twice as large patch,10000 48 | 134,lr,500,113/114/115,neg_has_all_surround,,,134,trained using three stacks;twice as large patch;1000 samples,1000 49 | -------------------------------------------------------------------------------- /src/learning/dataset_settings.csv: -------------------------------------------------------------------------------- 1 | dataset_id,classes,network_model,stain,margins_um,num_sample_per_class,stacks,cell_features_used,comment,raw_image_dataset,win_id 2 | 20,,Inception-BN,nissl,200/500,1000,MD585 3 | 21,,Inception-BN,nissl,200/500,1000,MD589 4 | 22,,Inception-BN,nissl,200/500,1000,MD594 5 | 23,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD585 6 | 24,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD589 7 | 25,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD594 8 | 26,,inception-bn-blue,nissl,,1000,MD594/MD589/MD585,,far negatives for Pn 9 | 27,,inception-bn-blue,nissl,,1000,MD585,,far negatives for all structures 10 | 28,,inception-bn-blue,nissl,,1000,MD589,,far negatives for all structures 11 | 29,neg,inception-bn-blue,nissl,,1000,MD594,,far negatives for all structures 12 | 30,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,200,1000,MD585 13 | 31,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,200,1000,MD589 14 | 32,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,200,1000,MD594 15 | 33,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,1000,1000,MD585 16 | 34,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,1000,1000,MD589 17 | 35,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,1000,1000,MD594 18 | 36,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,200,MD585 19 | 37,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,200,MD589 20 | 38,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,200,MD594 21 | 39,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,3000,MD585 22 | 40,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,3000,MD589 23 | 41,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,3000,MD594 24 | 50,,inception-bn-blue,neurotrace_blue,500,1000,MD642 25 | 51,,inception-bn-blue,neurotrace_blue,500,1000,MD635 26 | 60,,,nissl,500,1000,MD585,,raw image patches 27 | 61,,,nissl,500,1000,MD589,,raw image patches 28 | 62,,,nissl,500,1000,MD594,,raw image patches 29 | 63,pos/surPos/surNoclass/neg,,nissl,500,1000,MD585,,raw image patches with rotation variations 30 | 64,pos/surPos/surNoclass/neg,,nissl,500,1000,MD589,,raw image patches with rotation variations 31 | 65,pos/surPos/surNoclass/neg,,nissl,500,1000,MD594,,raw image patches with rotation variations 32 | 66,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD585,,features of image patches with rotation variations,63 33 | 67,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD589,,features of image patches with rotation variations,64 34 | 68,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD594,,features of image patches with rotation variations,65 35 | 70,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD590,,auto generated from registration result 36 | 71,pos/surPos/surNoclass/neg,inception-bn-blue,neurotrace_blue,500,1000,MD635,,auto generated from registration result 37 | 72,pos/surPos/surNoclass/neg,,nissl,500,1000,MD585,,raw image patches and features with variations in both rotation and intensity,72 38 | 73,pos/surPos/surNoclass/neg,,nissl,500,1000,MD589,,raw image patches and features with variations in both rotation and intensity,73 39 | 74,pos/surPos/surNoclass/neg,,nissl,500,1000,MD594,,raw image patches and features with variations in both rotation and intensity,74 40 | 75,pos/surPos/surNoclass/neg,,nissl,500,1000,MD585,,raw image patches and features with no variation,75 41 | 76,pos/surPos/surNoclass/neg,,nissl,500,1000,MD589,,raw image patches and features with no variation,76 42 | 77,pos/surPos/surNoclass/neg,,nissl,500,1000,MD594,,raw image patches and features with no variation,77 43 | 78,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,10000,MD585,,features of image patches with rotation variations,78 44 | 79,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,10000,MD589,,features of image patches with rotation variations,79 45 | 80,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,10000,MD594,,features of image patches with rotation variations,80 46 | 90,,,nissl,500,1000,MD589,allSizeHist/huMomentsHist 47 | 92,,,nissl,500,1000,MD589,largeLargeLinkLenHist 48 | 93,,,nissl,500,1000,MD594,largeLargeLinkLenHist 49 | 94,,,nissl,500,1000,MD589,largeSizeHist 50 | 95,,,nissl,500,1000,MD594,largeSizeHist 51 | 96,,,nissl,500,1000,MD589,largeSizeHist/largeLargeLinkLenHist 52 | 97,,,nissl,500,1000,MD594,largeSizeHist/largeLargeLinkLenHist 53 | 98,,,nissl,500,1000,MD594,largeOrientationHist/largeSizeHist/largeLargeLinkLenHist/largeSmallLinkLenHist 54 | 99,,,nissl,500,1000,MD589,largeOrientationHist/largeSizeHist/largeLargeLinkLenHist/largeSmallLinkLenHist 55 | 110,pos/surPos/surNoclass/neg,,nissl,500,1000,MD585,,raw images but twice as large patches,110,6 56 | 111,pos/surPos/surNoclass/neg,,nissl,500,1000,MD589,,raw images but twice as large patches,111,6 57 | 112,pos/surPos/surNoclass/neg,,nissl,500,1000,MD594,,raw images but twice as large patches,112,6 58 | 113,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD585,,cnn features using twice as large patches,110,6 59 | 114,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD589,,cnn features using twice as large patches,111,6 60 | 115,pos/surPos/surNoclass/neg,inception-bn-blue,nissl,500,1000,MD594,,cnn features using twice as large patches,112,6 61 | -------------------------------------------------------------------------------- /src/learning/detector_settings.csv: -------------------------------------------------------------------------------- 1 | detector_id,input_version,windowing_id,feature_network,feature_classifier_id,comments 2 | 15,gray,5,inception-bn-blue,73 3 | 19,gray,7,inception-bn-blue,73 4 | 799,NtbNormalizedAdaptiveInvertedGamma,7,inception-bn-blue,899 5 | 998,normalized_-1_5,7,inception-bn-blue,998,trained using normalized MD589/MD594/MD585 with 500um margin for negatives 6 | 999,normalized_-1_5,7,inception-bn-blue,999,trained from auto-aligned MD661/MD662 before correction 7 | -------------------------------------------------------------------------------- /src/registration/registration_settings.csv: -------------------------------------------------------------------------------- 1 | warp_id,upstream_warp_id,transform_type,grad_computation_sample_number,grid_search_sample_number,std_tx_um,std_ty_um,std_tz_um,std_theta_xy_degree,surround_weight,regularization_weight,terminate_thresh_trans,terminate_thresh_rot,history_len,max_iter_num,learning_rate_trans,learning_rate_rot,comment 2 | 7,None,rigid,100000,1000,50,50,50,10,inverse,,0.01,0.01,100,5000,1,0.01,"structure registration with surround, no initial registration" 3 | 20,None,affine,10000,,2000,2000,2000,10,inverse,,,,200,,,,global reg no surr no grid search 4 | 17,20,rigid,,10000,,,,,,inverse,0,local reg with surr no grid search,1000, 5 | 6 | -------------------------------------------------------------------------------- /src/utilities/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ActiveBrainAtlas/MouseBrainAtlas/b6ca6afcfc88f6772b073b9ad2bf5d0b3bf840bd/src/utilities/__init__.py -------------------------------------------------------------------------------- /src/utilities/colormap.json: -------------------------------------------------------------------------------- 1 | { 2 | "blue": { 3 | "hue_range": [179, 257], 4 | "lower_bounds": [ 5 | [20, 100], 6 | [30, 86], 7 | [40, 80], 8 | [50, 74], 9 | [60, 60], 10 | [70, 52], 11 | [80, 44], 12 | [90, 39], 13 | [100, 35] 14 | ] 15 | }, 16 | "green": { 17 | "hue_range": [63, 178], 18 | "lower_bounds": [ 19 | [30, 100], 20 | [40, 90], 21 | [50, 85], 22 | [60, 81], 23 | [70, 74], 24 | [80, 64], 25 | [90, 50], 26 | [100, 40] 27 | ] 28 | }, 29 | "monochrome": { 30 | "hue_range": [0, 0], 31 | "lower_bounds": [ 32 | [0, 0], 33 | [100, 0] 34 | ] 35 | }, 36 | "orange": { 37 | "hue_range": [19, 46], 38 | "lower_bounds": [ 39 | [20, 100], 40 | [30, 93], 41 | [40, 88], 42 | [50, 86], 43 | [60, 85], 44 | [70, 70], 45 | [100, 70] 46 | ] 47 | }, 48 | "pink": { 49 | "hue_range": [283, 334], 50 | "lower_bounds": [ 51 | [20, 100], 52 | [30, 90], 53 | [40, 86], 54 | [60, 84], 55 | [80, 80], 56 | [90, 75], 57 | [100, 73] 58 | ] 59 | }, 60 | "purple": { 61 | "hue_range": [258, 282], 62 | "lower_bounds": [ 63 | [20, 100], 64 | [30, 87], 65 | [40, 79], 66 | [50, 70], 67 | [60, 65], 68 | [70, 59], 69 | [80, 52], 70 | [90, 45], 71 | [100, 42] 72 | ] 73 | }, 74 | "red": { 75 | "hue_range": [-26, 18], 76 | "lower_bounds": [ 77 | [20, 100], 78 | [30, 92], 79 | [40, 89], 80 | [50, 85], 81 | [60, 78], 82 | [70, 70], 83 | [80, 60], 84 | [90, 55], 85 | [100, 50] 86 | ] 87 | }, 88 | "yellow": { 89 | "hue_range": [47, 62], 90 | "lower_bounds": [ 91 | [25, 100], 92 | [40, 94], 93 | [50, 89], 94 | [60, 86], 95 | [70, 84], 96 | [80, 82], 97 | [90, 80], 98 | [100, 75] 99 | ] 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/utilities/colormap.json~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ActiveBrainAtlas/MouseBrainAtlas/b6ca6afcfc88f6772b073b9ad2bf5d0b3bf840bd/src/utilities/colormap.json~ -------------------------------------------------------------------------------- /src/utilities/lie.py: -------------------------------------------------------------------------------- 1 | """Functions related to Lie Group.""" 2 | 3 | import numpy as np 4 | 5 | def matrix_exp(w): 6 | """Return the exponential map for rotation 3-vector w.""" 7 | wx, wy, wz = w 8 | w_skew = np.array([[0, -wz, wy], [wz, 0, -wx], [-wy, wx, 0]]) 9 | 10 | theta = np.sqrt(np.sum(w**2)) 11 | 12 | exp_w = np.eye(3) + np.sin(theta)/theta*w_skew + (1-np.cos(theta))/theta**2*np.dot(w_skew, w_skew) 13 | return exp_w 14 | 15 | def matrix_exp_v(v): 16 | """ 17 | Compute the exponenial map for v = [t w]^T where v is the 6-vector of coordinates in the Lie algebra se(3), 18 | comprising of two separate 3-vectors: w, the vector that determine rotation, and t, which determines translation. 19 | 20 | Args: 21 | v ((6,)-ndarray): the vector composed of translation parameters and rotation parameters. 22 | 23 | Returns: 24 | (exp_w_skew, Vt). The manifold element is a 4-by-4 matrix (exp_w_skew & Vt \\ 0 1). 25 | 26 | """ 27 | t = v[:3] # translation components 28 | w = v[3:] # rotation components 29 | 30 | # epsilon = 1e-8 31 | epsilon = 0 32 | theta = np.sqrt(np.sum(w**2)) + epsilon # Is this way to resolve divide-by-zero problem correct? 33 | 34 | wx, wy, wz = w 35 | w_skew = np.array([[0, -wz, wy], [wz, 0, -wx], [-wy, wx, 0]]) 36 | exp_w = np.eye(3) + np.sin(theta)/theta*w_skew + (1-np.cos(theta))/(theta**2)*np.dot(w_skew, w_skew) 37 | 38 | V = np.eye(3) + (1-np.cos(theta))/(theta**2)*w_skew + (theta-np.sin(theta))/(theta**3)*np.dot(w_skew, w_skew) 39 | 40 | return exp_w, np.dot(V, t) 41 | -------------------------------------------------------------------------------- /src/utilities/qt_utilities.py: -------------------------------------------------------------------------------- 1 | from PyQt4.QtCore import * 2 | from PyQt4.QtGui import * 3 | 4 | import copy 5 | import numpy as np 6 | 7 | gray_color_table = [qRgb(i, i, i) for i in range(256)] 8 | 9 | def numpy_to_qimage(img): 10 | """ 11 | Convert numpy array to QImage. 12 | """ 13 | h, w = img.shape[:2] 14 | if img.ndim == 3: 15 | qimage = QImage(img.flatten(), w, h, 3*w, QImage.Format_RGB888) 16 | else: 17 | qimage = QImage(img.flatten(), w, h, w, QImage.Format_Indexed8) 18 | qimage.setColorTable(gray_color_table) 19 | 20 | return qimage 21 | 22 | # def qimage_to_numpy(qimage): 23 | # ''' 24 | # Converts QImage to a numpy array. 25 | # 26 | # Reference: https://stackoverflow.com/a/36646415 27 | # ''' 28 | # 29 | # qimage = qimage.convertToFormat(QImage.Format_RGB888) 30 | # 31 | # width = qimage.width() 32 | # height = qimage.height() 33 | # 34 | # ptr = qimage.constBits() 35 | # print len(np.array(ptr)), width, height 36 | # arr = np.array(ptr).reshape(height, width, 3) # Copies the data 37 | # return arr 38 | 39 | def qimage_to_numpy(img, share_memory=False): 40 | """ Creates a numpy array from a QImage. 41 | 42 | If share_memory is True, the numpy array and the QImage is shared. 43 | Be careful: make sure the numpy array is destroyed before the image, 44 | otherwise the array will point to unreserved memory!! 45 | """ 46 | assert isinstance(img, QImage), "img must be a QtGui.QImage object" 47 | assert img.format() == QImage.Format_RGB32, \ 48 | "img format must be QImage.Format.Format_RGB32, got: {}".format(img.format()) 49 | 50 | img_size = img.size() 51 | buffer = img.constBits() 52 | 53 | # Sanity check 54 | n_bits_buffer = len(buffer) * 8 55 | n_bits_image = img_size.width() * img_size.height() * img.depth() 56 | assert n_bits_buffer == n_bits_image, \ 57 | "size mismatch: {} != {}".format(n_bits_buffer, n_bits_image) 58 | 59 | assert img.depth() == 32, "unexpected image depth: {}".format(img.depth()) 60 | 61 | # Note the different width height parameter order! 62 | arr = np.ndarray(shape = (img_size.height(), img_size.width(), img.depth()//8), 63 | buffer = buffer, 64 | dtype = np.uint8) 65 | 66 | if share_memory: 67 | return arr 68 | else: 69 | return copy.deepcopy(arr) 70 | -------------------------------------------------------------------------------- /src/utilities/randomcolor.py: -------------------------------------------------------------------------------- 1 | #!/usr/env/bin python 2 | 3 | import os 4 | import colorsys 5 | import random 6 | import json 7 | import sys 8 | 9 | 10 | class RandomColor(object): 11 | 12 | def __init__(self, seed=None): 13 | # Load color dictionary and populate the color dictionary 14 | self.colormap = json.load(open(os.path.join(os.path.dirname(__file__), 'colormap.json'))) 15 | 16 | self.seed = seed if seed else random.randint(0, sys.maxsize) 17 | 18 | self.random = random.Random(self.seed) 19 | 20 | for color_name, color_attrs in self.colormap.items(): 21 | lower_bounds = color_attrs['lower_bounds'] 22 | s_min = lower_bounds[0][0] 23 | s_max = lower_bounds[len(lower_bounds) - 1][0] 24 | 25 | b_min = lower_bounds[len(lower_bounds) - 1][1] 26 | b_max = lower_bounds[0][1] 27 | 28 | self.colormap[color_name]['saturation_range'] = [s_min, s_max] 29 | self.colormap[color_name]['brightness_range'] = [b_min, b_max] 30 | 31 | def generate(self, hue=None, luminosity=None, count=1, format_='hex'): 32 | colors = [] 33 | for _ in range(count): 34 | # First we pick a hue (H) 35 | H = self.pick_hue(hue) 36 | 37 | # Then use H to determine saturation (S) 38 | S = self.pick_saturation(H, hue, luminosity) 39 | 40 | # Then use S and H to determine brightness (B). 41 | B = self.pick_brightness(H, S, luminosity) 42 | 43 | # Then we return the HSB color in the desired format 44 | colors.append(self.set_format([H, S, B], format_)) 45 | 46 | return colors 47 | 48 | def pick_hue(self, hue): 49 | hue_range = self.get_hue_range(hue) 50 | hue = self.random_within(hue_range) 51 | 52 | # Instead of storing red as two seperate ranges, 53 | # we group them, using negative numbers 54 | if (hue < 0): 55 | hue += 360 56 | 57 | return hue 58 | 59 | def pick_saturation(self, hue, hue_name, luminosity): 60 | 61 | if luminosity == 'random': 62 | return self.random_within([0, 100]) 63 | 64 | if hue_name == 'monochrome': 65 | return 0 66 | 67 | saturation_range = self.get_saturation_range(hue) 68 | 69 | s_min = saturation_range[0] 70 | s_max = saturation_range[1] 71 | 72 | if luminosity == 'bright': 73 | s_min = 55 74 | elif luminosity == 'dark': 75 | s_min = s_max - 10 76 | elif luminosity == 'light': 77 | s_max = 55 78 | 79 | return self.random_within([s_min, s_max]) 80 | 81 | def pick_brightness(self, H, S, luminosity): 82 | b_min = self.get_minimum_brightness(H, S) 83 | b_max = 100 84 | 85 | if luminosity == 'dark': 86 | b_max = b_min + 20 87 | elif luminosity == 'light': 88 | b_min = (b_max + b_min) / 2 89 | elif luminosity == 'random': 90 | b_min = 0 91 | b_max = 100 92 | 93 | return self.random_within([b_min, b_max]) 94 | 95 | def set_format(self, hsv, format_): 96 | if 'hsv' in format_: 97 | color = hsv 98 | elif 'rgb' in format_: 99 | color = self.hsv_to_rgb(hsv) 100 | elif 'hex' in format_: 101 | r, g, b = self.hsv_to_rgb(hsv) 102 | return '#%02x%02x%02x' % (r, g, b) 103 | else: 104 | return "unrecognized format" 105 | 106 | if "Array" in format_ or format_ == 'hex': 107 | return color 108 | else: 109 | prefix = format_[:3] 110 | color_values = [str(x) for x in color] 111 | return "%s(%s)" % (prefix, ', '.join(color_values)) 112 | 113 | def get_minimum_brightness(self, H, S): 114 | lower_bounds = self.get_color_info(H)['lower_bounds'] 115 | 116 | for i in range(len(lower_bounds) - 1): 117 | s1 = lower_bounds[i][0] 118 | v1 = lower_bounds[i][1] 119 | 120 | s2 = lower_bounds[i + 1][0] 121 | v2 = lower_bounds[i + 1][1] 122 | 123 | if s1 <= S <= s2: 124 | m = (v2 - v1) / (s2 - s1) 125 | b = v1 - m * s1 126 | 127 | return m * S + b 128 | 129 | return 0 130 | 131 | def get_hue_range(self, color_input): 132 | if color_input and color_input.isdigit(): 133 | number = int(color_input) 134 | 135 | if 0 < number < 360: 136 | return [number, number] 137 | 138 | elif color_input and color_input in self.colormap: 139 | color = self.colormap[color_input] 140 | if 'hue_range' in color: 141 | return color['hue_range'] 142 | 143 | else: 144 | return [0, 360] 145 | 146 | def get_saturation_range(self, hue): 147 | return self.get_color_info(hue)['saturation_range'] 148 | 149 | def get_color_info(self, hue): 150 | # Maps red colors to make picking hue easier 151 | if 334 <= hue <= 360: 152 | hue -= 360 153 | 154 | for color_name, color in self.colormap.items(): 155 | if color['hue_range'] and color['hue_range'][0] <= hue <= color['hue_range'][1]: 156 | return self.colormap[color_name] 157 | 158 | # this should probably raise an exception 159 | return 'Color not found' 160 | 161 | def random_within(self, r): 162 | return self.random.randint(int(r[0]), int(r[1])) 163 | 164 | @classmethod 165 | def hsv_to_rgb(cls, hsv): 166 | h, s, v = hsv 167 | h = 1 if h == 0 else h 168 | h = 359 if h == 360 else h 169 | 170 | h = float(h)/360 171 | s = float(s)/100 172 | v = float(v)/100 173 | 174 | rgb = colorsys.hsv_to_rgb(h, s, v) 175 | return [int(c * 255) for c in rgb] -------------------------------------------------------------------------------- /src/utilities/sequential_dispatcher.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import os 4 | import argparse 5 | import sys 6 | import json 7 | 8 | parser = argparse.ArgumentParser( 9 | formatter_class=argparse.RawDescriptionHelpFormatter, 10 | description='Generic command launcher. This is run on one node. It sequentially executes the given command with variable arguments.') 11 | 12 | parser.add_argument("command", type=str, help="command") 13 | parser.add_argument('kwargs_list_str', type=str, help="json-encoded string of list of arguments") 14 | args = parser.parse_args() 15 | 16 | kwargs_list = json.loads(args.kwargs_list_str) 17 | 18 | if isinstance(kwargs_list, dict): 19 | # {'a': [1,2,3], 'b': ['x','y','z']} 20 | kwargs_list = [dict(zip(kwargs_list.keys(), vals)) for vals in zip(kwargs_list.values())] 21 | else: 22 | # [{'a':1, 'b':'x'}, {'a':2, 'b':'y'}, {'a':3, 'b':'z'}] 23 | assert isinstance(kwargs_list, list) 24 | 25 | for kwargs in kwargs_list: 26 | os.system(args.command % kwargs) --------------------------------------------------------------------------------