def choose_img_pair(frame, raw_dir, overlay_dir): ''' Pick two paired images from two directories (eg, each directory contains a different channel) to see effects of contrast adjustment steps; both images chosen are displayed Args: frame: index of image location in directory raw_dir: full path to first image-containing directory overlay_dir: full path to second image-containing directory Returns: Full paths to both images selected ''' #load raw and overlay images based on frame number raw_img_name = get_img_names(raw_dir)[frame] raw_img_path = os.path.join(raw_dir, raw_img_name) raw_img = imread(raw_img_path) overlay_img_name = get_img_names(overlay_dir)[frame] overlay_img_path = os.path.join(overlay_dir, overlay_img_name) overlay_img = imread(overlay_img_path) fig, ax = plt.subplots(figsize=(16, 12), nrows=2) plt.subplot(211) plt.imshow(raw_img, cmap=mpl.cm.gray) plt.subplot(212) plt.imshow(overlay_img, cmap=mpl.cm.gray) plt.show() return raw_img_path, overlay_img_path
def post_annotation_load_training_images_3d(training_dir, training_folders, channel_names, image_size, num_frames, data_format="channels_last"): ''' Load each image in the training_folders into a numpy array. Args: training_dir: full path to parent directory that contains subfolders for different movies training_folders: list of folders where each folder contains subfolders of channels and features channel_names: list of folders where each folder contains a different channel of raw data to load into npz image_size: size of each image as tuple (x, y) num_frames: number of frames of movie to load into npz; if None, will default to the number of images in annotation folder data_format: channels_first or channels_last Returns: 5D tensor of image data ''' is_channels_first = data_format == 'channels_first' # Unpack size tuples image_size_x, image_size_y = image_size num_batches = len(training_folders) if num_frames == None: num_frames = len(get_img_names(os.path.join(training_dir, tranining_folders[0], channel_names[0]))) # Initialize training data array if is_channels_first: X_shape = (num_batches, num_frames, len(channel_names), image_size_x, image_size_y) else: X_shape = (num_batches, num_frames, image_size_x, image_size_y, len(channel_names)) X = np.zeros(X_shape, dtype=K.floatx()) for b, movie_folder in enumerate(training_folders): for c, raw_folder in enumerate(channel_names): raw_list = get_img_names(os.path.join(training_dir, movie_folder, raw_folder)) for f, frame in enumerate(raw_list): image_file = os.path.join(training_dir, movie_folder, raw_folder, frame) image_data = np.asarray(get_image(image_file), dtype=K.floatx()) if is_channels_first: X[b, f, c, :, :] = image_data else: X[b, f, :, :, c] = image_data return X
def post_annotation_load_annotated_images_2d(training_dir, annotation_folders, image_size, data_format="channels_last"): ''' Load each annotated image in the training_direcs into a numpy array. Args: training_dir: full path to parent directory that contains subfolders for annotations annotation_folders: list of folders where each folder contains a different annotation feature to load into npz image_size: size of each image as tuple (x, y) data_format: channels_first or channels_last Returns: 4D tensor of label masks ''' is_channels_first = data_format == 'channels_first' # Unpack size tuple image_size_x, image_size_y = image_size # wrapping single annotation name in list for consistency if not isinstance(annotation_folders, list): annotation_folders = [annotation_folders] num_batches = len(get_img_names(os.path.join(training_dir, annotation_folders[0]))) # Initialize feature mask array if is_channels_first: y_shape = (num_batches, len(annotation_folders), image_size_x, image_size_y) else: y_shape = (num_batches, image_size_x, image_size_y, len(annotation_folders)) y = np.zeros(y_shape, dtype='int32') for l, annotation_folder in enumerate(annotation_folders): annotation_list = get_img_names(os.path.join(training_dir, annotation_folder)) for b, img in enumerate(annotation_list): image_data = get_image(os.path.join(training_dir, annotation_folder, img)) if is_channels_first: y[b, l, :, :] = image_data else: y[b, :, :, l] = image_data return y
def relabel_montages(annotations_folder): ''' Relabel all annotations in folder Args: annotations_folder: full path to directory containing images to be cleaned Returns: None ''' #from folder, sort nicely, put images into list img_list = get_img_names(annotations_folder) for img in img_list: #load image img_name = os.path.join(annotations_folder, img) montage = imread(img_name, pilmode='I', as_gray=True) #pass image to relabel_montage with warnings.catch_warnings(): warnings.simplefilter("ignore") relabeled_montage = relabel_montage(montage) #save image imwrite(img_name, relabeled_montage) return None
def clean_montages(annotations_folder): ''' Clean all annotations in folder Args: annotations_folder: full path to directory containing images to be cleaned Returns: None ''' #from folder, sort nicely, put images into list img_list = get_img_names(annotations_folder) for img in img_list: #load image img_name = os.path.join(annotations_folder, img) #pass image to clean_montage with warnings.catch_warnings(): warnings.simplefilter("ignore") clean_montage(img_name) #save image #imwrite(img_name, cleaned_montage) return None
def post_annotation_load_training_images_2d(training_dir, channel_names, image_size, data_format="channels_last"): ''' Load each image in the training_dir into a numpy array. Args: training_dir: full path to parent directory that contains subfolders for channels channel_names: list of folders where each folder contains a different channel of raw data to load into npz image_size: size of each image as tuple (x, y) data_format: channels_first or channels_last Returns: 4D tensor of image data ''' is_channels_first = data_format == 'channels_first' # Unpack size tuples image_size_x, image_size_y = image_size num_batches = len(get_img_names(os.path.join(training_dir, channel_names[0]))) # Initialize training data array if is_channels_first: X_shape = (num_batches, len(channel_names), image_size_x, image_size_y) else: X_shape = (num_batches, image_size_x, image_size_y, len(channel_names)) X = np.zeros(X_shape, dtype=K.floatx()) for c, raw_folder in enumerate(channel_names): raw_list = get_img_names(os.path.join(training_dir, raw_folder)) for b, img in enumerate(raw_list): image_file = os.path.join(training_dir, raw_folder, img) image_data = np.asarray(get_image(image_file), dtype=K.floatx()) if is_channels_first: X[b, c, :, :] = image_data else: X[b, :, :, c] = image_data return X
def post_annotation_make_training_data_3d(training_dir, training_folders, file_name_save, channel_names, annotation_folders, num_frames = None, reshape_size=None): ''' Read all images in training folders and save as npz file. Args: training_dir: full path to parent directory that contains subfolders for different movies training_folders: list of folders where each folder contains subfolders of channels and features file_name_save: full path and file name for .npz file to save training data in channel_names: list of folders where each folder contains a different channel of raw data to load into npz annotation_folders: list of folders where each folder contains a different annotation feature to load into npz num_frames: number of frames of movie to load into npz; if None, will default to the number of images in annotation folder reshape_size: if provided, will reshape images to the given size (both x and y dimensions will be reshape_size) Returns: None ''' # Load one file to get image sizes (assumes all images same size) test_img_dir = os.path.join(training_dir, random.choice(training_folders), random.choice(channel_names)) test_img_path = os.path.join(test_img_dir, random.choice(get_img_names(test_img_dir))) test_img = imread(test_img_path) image_size = test_img.shape X = post_annotation_load_training_images_3d(training_dir = training_dir, training_folders = training_folders, channel_names = channel_names, image_size=image_size, num_frames = num_frames) y = post_annotation_load_annotated_images_3d(training_dir = training_dir, training_folders = training_folders, annotation_folders = annotation_folders, image_size=image_size, num_frames = num_frames) if reshape_size is not None: X, y = reshape_matrix(X, y, reshape_size=reshape_size) # Save training data in npz format np.savez(file_name_save, X=X, y=y) return None
def convert_grayscale_all(annotations_folder): ''' Convert all images in folder to greyscale Args: annotations_folder: full path to directory containing images to be converted to greyscale Returns: None ''' #from folder, sort nicely, put images into list img_list = get_img_names(annotations_folder) for img in img_list: #load image img_name = os.path.join(annotations_folder, img) grayscale_montage(img_name) return None
def upload(s3, bucket_name, aws_folder, folder_to_upload, include_context): ''' Uses an AWS s3 session to upload images. Args: s3: boto3.Session client allows script to upload to the user's AWS acct folder_to_save: location in bucket where files will be put, used to make keys bucket_name: name of AWS s3 bucket, "figure-eight-deepcell" by default folder_to_upload: string, full path to folder where images to be uploaded are include_context: whether to return lists of previous and next images to be included in figure8 job (only for single 3D images) Returns: lists of image urls (to be used to create a CSV file) ''' #load the images from specified folder but not the json log file imgs_to_upload = get_img_names(folder_to_upload) #create list of montages that were uploaded to pass to csv maker uploaded_images = [] prev_images = [] next_images = [] #upload each image from that folder for img in imgs_to_upload: if include_context: #frame number of image frame = int(img.split("frame_")[1].split(".png")[0]) if frame == 0: #no previous image if it's the first frame in that position prev_image_path = 'None' else: prev_image = img.split("frame_")[0] + "frame_" + str( frame - 1).zfill(3) + ".png" prev_image_key = os.path.join(aws_folder, prev_image) prev_image_path = os.path.join( "https://s3.us-east-2.amazonaws.com", bucket_name, prev_image_key) prev_images.append(prev_image_path) #next image should have an identical name to current image, but frame is current image frame + 1 next_image = img.split("frame_")[0] + "frame_" + str( frame + 1).zfill(3) + ".png" next_image_key = os.path.join(aws_folder, next_image) next_image_path = os.path.join( "https://s3.us-east-2.amazonaws.com", bucket_name, next_image_key) #if the next_image is not in the images we're uploading, current image is the last in that position if not next_image in imgs_to_upload: next_image_path = 'None' next_images.append(next_image_path) #set full path to image img_path = os.path.join(folder_to_upload, img) #set destination path img_key = os.path.join(aws_folder, img) #upload s3.upload_file(img_path, bucket_name, img_key, Callback=ProgressPercentage(img_path), ExtraArgs={ 'ACL': 'public-read', 'Metadata': { 'source_path': img_path } }) print('\n') #add uploaded montage url to list uploaded_images.append( os.path.join("https://s3.us-east-2.amazonaws.com", bucket_name, img_key)) return uploaded_images, prev_images, next_images
def raw_movie_maker(base_dir, raw_dir, identifier): ''' Chops raw images into pieces to match the annotation pieces; not currently used in pipeline. Args: base_dir: full path to directory that contains folder for json logs; "movies" folder will be created in this directory raw_dir: full path to directory that contains raw images to be chopped identifier: string used to specify data set (same variable used throughout pipeline), used to load files and save images Returns: None ''' movies_dir = os.path.join(base_dir, "movies") if not os.path.isdir(movies_dir): os.makedirs(movies_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(movies_dir, mode) #find json data in folder log was saved to; "json_logs" by default json_folder = os.path.join(base_dir, "json_logs") #get data, store as tuples json_params_montage = read_json_params_montage(json_folder, identifier) montage_len = json_params_montage[0] num_x_segments_m = json_params_montage[ 1] #check to make sure these are getting chopped into same number of segments num_y_segments_m = json_params_montage[2] num_montages = json_params_montage[6] json_params_chopper = read_json_params_chopper(json_folder, identifier) overlap_perc = json_params_chopper[0] num_x_segments = json_params_chopper[1] num_y_segments = json_params_chopper[2] #sanity check if num_x_segments == num_x_segments_m and num_y_segments == num_y_segments_m: #make folders for raw for part in range(num_montages): part_folder = os.path.join( movies_dir, "part" + str(part)) #zero based indexing for part folders if not os.path.isdir(part_folder): os.makedirs(part_folder) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(part_folder, mode) for x_seg in range(num_x_segments): for y_seg in range(num_y_segments): #make folder for that position position_folder = os.path.join( part_folder, "x_{0:02d}_y_{1:02d}".format(x_seg, y_seg)) raw_subfolder = os.path.join(position_folder, "raw") if not os.path.isdir(raw_subfolder): os.makedirs(raw_subfolder) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(raw_subfolder, mode) #sorting of raw movies into appropriate parts folders happens here total_frames = num_montages * montage_len raw_img_list = get_img_names(raw_dir) #get_img_names sorts them #don't chop more raw frames than we have annotated frames for frame in range(total_frames): #frame numbers will start from zero in each part #if needed in future can put into one continuous movie with frame = relative_frame + (part_num * montage_len) current_part = frame // montage_len relative_frame = frame - (current_part * montage_len) img_file = raw_img_list[frame] img_path = os.path.join(raw_dir, img_file) save_dir = os.path.join(movies_dir, "part" + str(current_part)) #sorting of chopped pieces into different position folders happens in the chopper #chop with warnings.catch_warnings( ): #ignore "low contrast image" warning warnings.simplefilter("ignore") overlapping_img_chopper(img_path, save_dir, identifier, relative_frame, num_x_segments, num_y_segments, overlap_perc) #frames in each part should start at zero; if they need to be stitched back together, scripts should utilize the "montage_len" variable to calculate offset else: print( "Num_segments mismatch; double-check your files and logs to make sure you're trying to put the correct movies together." ) return None
def overlapping_crop_dir(raw_direc, identifier, num_x_segments, num_y_segments, overlap_perc, frame_offset, is_2D=False): ''' Uses overlapping_img_chopper on all images in a folder. Also saves json log of settings, to be used when stitching images back together. Args: raw_direc: full path to folder containing movie slices that will be chopped identifier: string used to specify data set (same variable used throughout pipeline), used to load and save files num_x_segments: integer number of columns the images will be chopped into num_y_segments: integer number of rows the images will be chopped into overlap_perc: percent of image on each edge that overlaps with other chopped images frame_offset: frame number chopper is starting from, used to calculate correct frame number for each image is_2D: whether to use 2D naming convention for loading images and saving chopped image pieces Returns: None ''' #directories base_dir = os.path.dirname(raw_direc) unprocessed_name = os.path.basename(raw_direc) save_folder = unprocessed_name + "_offset_{0:03d}_chopped_{1:02d}_{2:02d}".format( frame_offset, num_x_segments, num_y_segments) save_dir = os.path.join(base_dir, save_folder) if not os.path.isdir(save_dir): os.makedirs(save_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(save_dir, mode) log_dir = os.path.join(base_dir, "json_logs") if not os.path.isdir(log_dir): os.makedirs(log_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(log_dir, mode) # pick a file to calculate neccesary information from img_stack = get_img_names(raw_direc) #load test image test_img_name = os.path.join(raw_direc, img_stack[0]) file_ext = os.path.splitext(img_stack[0])[1] test_img_temp = get_image(test_img_name) test_img_size = test_img_temp.shape img_squeeze = False print("Current Image Size: ", test_img_size) while True: start_flag = str(input("Correct dimensionality? (y/n): ")) if start_flag != "y" and start_flag != "n": print("Please type y for 'yes' or n for 'no'") continue elif start_flag == "n": print("Making input 2D") test_img = np.squeeze(test_img_temp, axis=0) test_img_size = test_img.shape img_squeeze = True print("New Image Size: ", test_img.shape) break else: test_img = test_img_temp break # input correct end loop # determine number of pixels required to achieve correct overlap start_y = test_img_size[0] // num_y_segments overlapping_y_pix = int(start_y * (overlap_perc / 100)) new_y = int(start_y + 2 * overlapping_y_pix) start_x = test_img_size[1] // num_x_segments overlapping_x_pix = int(start_x * (overlap_perc / 100)) new_x = int(start_x + 2 * overlapping_x_pix) #for images that don't aren't divided evenly by num_segments, restitching can lead to losing a few pixels #avoid this by logging the actual start indices for the subimages y_start_indices = [] x_start_indices = [] for i in range(num_x_segments): x_start_index = int(i * start_x) x_start_indices.append(x_start_index) for j in range(num_y_segments): y_start_index = int(j * start_y) y_start_indices.append(y_start_index) print("Your new images will be ", new_x, " pixels by ", new_y, " pixels in size.") print("Processing...") files = os.listdir(raw_direc) files_sorted = sorted_nicely(files) for frame, file in enumerate(files_sorted): # load image file_path = os.path.join(raw_direc, file) if img_squeeze == False: img = get_image(file_path) else: img = np.squeeze(get_image(file_path), axis=0) #factor in whether we're starting from frame zero so that chopped files get correct frame number current_frame = frame + frame_offset #each frame of the movie will be chopped into x by y smaller frames and saved overlapping_img_chopper(img, save_dir, identifier, current_frame, num_x_segments, num_y_segments, overlap_perc, is_2D, file_ext) #log in json for post-annotation use log_data = {} log_data['date'] = str(datetime.datetime.now()) log_data['num_x_segments'] = num_x_segments log_data['num_y_segments'] = num_y_segments log_data['overlap_perc'] = overlap_perc log_data['identifier'] = identifier log_data['y_start_indices'] = y_start_indices log_data['x_start_indices'] = x_start_indices log_data['overlapping_x_pix'] = overlapping_x_pix log_data['overlapping_y_pix'] = overlapping_y_pix log_data['original_y'] = test_img_size[0] log_data['original_x'] = test_img_size[1] log_data['frame_offset'] = frame_offset log_data['num_images'] = len(files_sorted) #save log in JSON format #save with identifier; should be saved in "log" folder log_path = os.path.join(log_dir, identifier + "_overlapping_chopper_log.json") with open(log_path, "w") as write_file: json.dump(log_data, write_file) print("Cropped files saved to {}".format(save_dir)) return None
def overlapping_stitcher_folder(pieces_dir, save_dir, identifier, num_images, json_chopper_log, is_2D): ''' Unpacks variables from json_chopper_log (and calculates variables if needed) to run overlapping_stitcher_core to stitch multiple images from image pieces contained in same folder. Args: pieces_dir: full path to directory where image pieces are saved save_dir: full path to directory where stitched annotation should be saved identifier: string used to specify data set (same variable used throughout pipeline), used to load image pieces and save stitched image num_images: number of stitched images to create, usually the same number of fullsize raw images that were annotated json_chopper_log: dictionary loaded from json log file containing variables that were used by the overlapping_chopper in constructing raw image pieces for this dataset is_2D: whether 2D naming convention was used to name image pieces Returns: None ''' #directories if not os.path.isdir(save_dir): os.makedirs(save_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(save_dir, mode) pieces_list = get_img_names(pieces_dir) #load test image for parameters if needed test_img = imread(os.path.join(pieces_dir, pieces_list[0])) small_img_size = test_img.shape #load variables from json log overlap_perc = json_chopper_log['overlap_perc'] num_x_segments = json_chopper_log['num_x_segments'] num_y_segments = json_chopper_log['num_y_segments'] try: x_start_indices = json_chopper_log['x_start_indices'] y_start_indices = json_chopper_log['y_start_indices'] overlapping_x_pix = json_chopper_log['overlapping_x_pix'] overlapping_y_pix = json_chopper_log['overlapping_y_pix'] original_x = json_chopper_log['original_x'] original_y = json_chopper_log['original_y'] #preferable to load these variables #but if they aren't in the log (outdated log or other reason?), calculate them except: #trim dimensions are the size of each sub image, with the overlap removed trim_y = math.ceil(small_img_size[0] / (1 + (2 * overlap_perc / 100))) trim_x = math.ceil(small_img_size[1] / (1 + (2 * overlap_perc / 100))) x_start_indices = [] for i in range(num_x_segments): x_start_index = int(i * trim_x) x_start_indices.append(x_start_index) y_start_indices = [] for j in range(num_y_segments): y_start_index = int(j * trim_y) y_start_indices.append(y_start_index) overlapping_x_pix = (small_img_size[1] - trim_x) // 2 overlapping_y_pix = (small_img_size[0] - trim_y) // 2 #print('overlapping pix x, y', overlapping_x_pix, overlapping_y_pix) #not sure if overlapping_pix or pad is better calculation so leaving this in #pad_x = int((overlap_perc/100)*trim_x) #pad_y = int((overlap_perc/100)*trim_y) #print('pad x, y', pad_x, pad_y) original_y = trim_y * num_y_segments original_x = trim_x * num_x_segments #not all json logs with start indices have frame_offset info try: frame_offset = json_chopper_log['frame_offset'] except: frame_offset = 0 #construct image name format for all sub pieces of one image/frame #also passes what the stitched image should be named to the stitcher core for image in range(num_images): if is_2D: sub_img_format = "_img_{0:03d}".format(image + frame_offset) save_name = identifier + sub_img_format + "_annotation.png" sub_img_format = "{0}" + sub_img_format + "_x_{1:02d}_y_{2:02d}_annotation.png" else: sub_img_format = "_frame_{0:03d}".format(image + frame_offset) save_name = identifier + sub_img_format + "_annotation.png" sub_img_format = "{0}_x_{1:02d}_y_{2:02d}" + sub_img_format + "_annotation.png" print("Stitching image {0} of {1}".format(image + frame_offset + 1, num_images)) overlapping_stitcher_core(pieces_dir, save_dir, x_start_indices, y_start_indices, overlapping_x_pix, overlapping_y_pix, original_x, original_y, identifier, sub_img_format, save_name) return None
def montage_maker(montage_len, chopped_dir, save_dir, identifier, x_pos, y_pos, row_length, x_buffer, y_buffer): ''' Take a stack of images from a specific x and y position in a movie and create montages Args: montage_len: integer number of frames montage will contain chopped_dir: full path to folder containing cropped images that will be turned into montages save_dir: full path to folder where montages will be saved identifier: string used to specify data set (same variable used throughout pipeline); used to load image pieces and to save montages x_pos: x coordinate of slice from original movie, used to load image pieces and to save montage y_pos: y coordinate of slice from original movie, used to load image pieces and to save montage row_length: integer number of frames each row of the montage will hold x_buffer: how many pixels will separate each column of images y_buffer: how many pixels will separate each row of images Returns: The number of montages created from the given image stack ''' #from folder, sort nicely, put images into list img_stack = get_img_names(chopped_dir) #load test image test_img_name = os.path.join(chopped_dir, img_stack[0]) test_img = imread(test_img_name) #get file_ext from test_img file_ext = os.path.splitext(test_img_name)[1] #determine how many montages can be made from movie subimg_list = [img for img in img_stack if "x_{0:02d}_y_{1:02d}".format(x_pos, y_pos) in img] num_frames = len(subimg_list) num_montages = num_frames // montage_len print("You will be able to make " + str(num_montages) + " montages from this movie.") print("The last %d frame(s) will not be used in a montage. \n" % (num_frames % montage_len)) ###check with user to confirm discarding last few images from movie if not divisible ###include option to make montage with remainder images? n by default #read image size and calculate montage size x_dim = test_img.shape[-1] y_dim = test_img.shape[-2] number_of_rows = math.ceil(montage_len/row_length) final_x = (row_length * x_dim) + ((row_length + 1) * x_buffer) final_y = (number_of_rows * y_dim) + ((number_of_rows + 1) * y_buffer) #loop through num_montages to make more than one montage per input movie if possible for montage in range(num_montages): #make array to hold montage montage_img = np.zeros((final_y, final_x), dtype = np.uint16) #name the montage montage_name = identifier + "_x_" + str(x_pos).zfill(2) + "_y_" + str(y_pos).zfill(2) + "_montage_" + str(montage).zfill(2) + ".png" montage_name = os.path.join(save_dir, montage_name) #loop through rows to add images to montage for row in range(number_of_rows): #set pixel range for current row y_start = y_buffer + ((y_buffer + y_dim) * row) y_end = (y_buffer + y_dim) * (row + 1) #loop through columns to add images to montage for column in range(row_length): #read img #this works because the images were saved in 3D naming mode frame_num = (montage * montage_len) + (row * row_length) + column current_frame_name = "{0}_x_{1:02d}_y_{2:02d}_frame_{3:03d}{4}".format(identifier, x_pos, y_pos, frame_num, file_ext) current_slice = imread(os.path.join(chopped_dir, current_frame_name)) #set pixel range for current column x_start = x_buffer + ((x_buffer + x_dim) * column ) x_end = (x_buffer + x_dim) * (column + 1) #add image to montage montage_img[y_start:y_end,x_start:x_end] = current_slice #save montage with warnings.catch_warnings(): #ignore "low contrast image" warnings warnings.simplefilter("ignore") imsave(montage_name, montage_img) return num_montages
def post_annotation_load_annotated_images_3d(training_dir, training_folders, annotation_folders, image_size, num_frames, data_format="channels_last"): ''' Load each annotated image in the training_folders into a numpy array. Args: training_dir: full path to parent directory that contains subfolders for different movies training_folders: list of folders where each folder contains subfolders of channels and features annotation_folders: list of folders where each folder contains a different annotation feature to load into npz image_size: size of each image as tuple (x, y) num_frames: number of frames of movie to load into npz; if None, will default to the number of images in annotation folder data_format: channels_first or channels_last Returns: 5D tensor of label masks ''' is_channels_first = data_format == 'channels_first' # Unpack size tuple image_size_x, image_size_y = image_size # wrapping single annotation name in list for consistency if not isinstance(annotation_folders, list): annotation_folders = [annotation_folders] num_batches = len(training_folders) if num_frames == None: num_frames = len(get_img_names(os.path.join(training_dir, training_folders[0], channel_names[0]))) # Initialize feature mask array if is_channels_first: y_shape = (num_batches, num_frames, len(annotation_folders), image_size_x, image_size_y) else: y_shape = (num_batches, num_frames, image_size_x, image_size_y, len(annotation_folders)) y = np.zeros(y_shape, dtype='int32') for b, movie_folder in enumerate(training_folders): for l, annotation_folder in enumerate(annotation_folders): annotation_list = get_img_names(os.path.join(training_dir, movie_folder, annotation_folder)) for f, frame in enumerate(annotation_list): image_data = get_image(os.path.join(training_dir, movie_folder, annotation_folder, frame)) if is_channels_first: y[b, f, l, :, :] = image_data else: y[b, f, :, :, l] = image_data return y
def adjust_overlay(base_dir, raw_folder, overlay_folder, identifier, raw_settings, overlay_settings, combined_settings, is_2D): ''' Constrast adjust images from two folders, overlay images, and save adjusted images in new folder. Also creates a json log to record settings used. Args: base_dir: full path to parent directory that holds raw_folder; json logs folder will be created here raw_folder: name of first folder (not full path) containing images to be contrast adjusted overlay_folder: name of second folder (not full path) containing images to be contrast adjusted identifier: string, used to name processed images and json log raw_settings: dictionary of settings to use for contrast adjustment of first folder overlay_settings: dictionary of settings to use for contrast adjustment of second folder combined_settings: dictionary of settings to use to overlay two images is_2D: whether to save images with 2D naming convention Returns: None ''' #directory management save_folder = raw_folder + "_overlay_" + overlay_folder save_dir = os.path.join(base_dir, save_folder) if not os.path.isdir(save_dir): os.makedirs(save_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(save_dir, mode) log_dir = os.path.join(base_dir, "json_logs") if not os.path.isdir(log_dir): os.makedirs(log_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(log_dir, mode) raw_dir = os.path.join(base_dir, raw_folder) overlay_dir = os.path.join(base_dir, overlay_folder) #extract variables from settings dictionaries raw_sigma = raw_settings['blur'] raw_eq_adapthist = raw_settings['equalize_adapthist'] raw_eq_hist = raw_settings['equalize_hist'] raw_gamma = raw_settings['gamma_adjust'] raw_invert = raw_settings['invert_img'] raw_sobel_factor = raw_settings['sobel_factor'] raw_sobel_toggle = raw_settings['sobel_toggle'] raw_min = raw_settings['v_min'] raw_max = raw_settings['v_max'] overlay_sigma = overlay_settings['blur'] overlay_eq_adapthist = overlay_settings['equalize_adapthist'] overlay_eq_hist = overlay_settings['equalize_hist'] overlay_gamma = overlay_settings['gamma_adjust'] overlay_invert = overlay_settings['invert_img'] overlay_sobel_factor = overlay_settings['sobel_factor'] overlay_sobel_toggle = overlay_settings['sobel_toggle'] overlay_min = overlay_settings['v_min'] overlay_max = overlay_settings['v_max'] prop_raw = combined_settings['prop_raw'] v_min = combined_settings['v_min'] v_max = combined_settings['v_max'] #go image by image through dataset img_list = get_img_names(raw_dir) for frame in range(len(img_list)): #contrast adjust raw raw_img_name = get_img_names(raw_dir)[frame] raw_img_path = os.path.join(raw_dir, raw_img_name) raw_img = imread(raw_img_path) raw_adjusted = contrast(raw_img, raw_sigma, raw_eq_hist, raw_eq_adapthist, raw_gamma, raw_sobel_toggle, raw_sobel_factor, raw_invert, raw_min, raw_max) #contrast adjust overlay overlay_img_name = get_img_names(overlay_dir)[frame] overlay_img_path = os.path.join(overlay_dir, overlay_img_name) overlay_img = imread(overlay_img_path) overlay_adjusted = contrast(overlay_img, overlay_sigma, overlay_eq_hist, overlay_eq_adapthist, overlay_gamma, overlay_sobel_toggle, overlay_sobel_factor, overlay_invert, overlay_min, overlay_max) #combine images prop_overlay = 1.0 - prop_raw mod_img = overlay_adjusted * prop_overlay + raw_adjusted * prop_raw mod_img = sk.exposure.rescale_intensity(mod_img, in_range='image', out_range='uint8') mod_img = mod_img.astype(np.uint8) mod_img = sk.exposure.equalize_adapthist(mod_img, kernel_size=None, clip_limit=0.01, nbins=256) #equalize_adapthist outputs float64 image #rescale image to (0,255) before changing to uint8 dtype mod_img = sk.exposure.rescale_intensity(mod_img, in_range="image", out_range=np.uint8) mod_img = mod_img.astype(np.uint8) #rescale brightness to user-defined range mod_img = sk.exposure.rescale_intensity(mod_img, in_range=(v_min, v_max)) #name file if is_2D: adjusted_name = identifier + "_" + raw_folder + "_overlay_" + overlay_folder + "_img_" + str( frame).zfill(3) + ".png" else: adjusted_name = identifier + "_" + raw_folder + "_overlay_" + overlay_folder + "_frame_" + str( frame).zfill(3) + ".png" adjusted_img_path = os.path.join(save_dir, adjusted_name) #save image in new folder imwrite(adjusted_img_path, mod_img) print("Saved " + adjusted_name + "; image " + str(frame + 1) + " of " + str(len(img_list))) print("Adjusted images have been saved in folder: " + save_folder) #log in json for future reference log_data = {} log_data['date'] = str(datetime.datetime.now()) log_data['raw_settings'] = raw_settings log_data['overlay_settings'] = overlay_settings log_data['combined_settings'] = combined_settings log_data['identifier'] = identifier log_data['overlay'] = overlay_folder log_data['raw'] = raw_folder log_data['combined'] = True #save log in JSON format #save with identifier; should be saved in "log" folder log_path = os.path.join( log_dir, identifier + "_contrast_adjustment_overlay_log.json") with open(log_path, "w") as write_file: json.dump(log_data, write_file) print('A record of the settings used has been saved in folder: ' + log_dir) return None
def adjust_folder(base_dir, raw_folder, identifier, contrast_settings, is_2D): ''' Constrast adjust images in a given folder, save contrast adjusted images in new folder. Also creates a json log to record settings used. Args: base_dir: full path to parent directory that holds raw_folder; json logs folder will be created here raw_folder: name of folder (not full path) containing images to be contrast adjusted identifier: string, used to name processed images and json log contrast_settings: dictionary of settings to use for contrast adjustment is_2D: whether to save images with 2D naming convention Returns: None ''' #directory specification, creating dirs when needed raw_dir = os.path.join(base_dir, raw_folder) #where will we save the processed files process_folder = raw_folder + "_contrast_adjusted" process_dir = os.path.join(base_dir, process_folder) if not os.path.isdir(process_dir): os.makedirs(process_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(process_dir, mode) #where we will save a log of the settings log_dir = os.path.join(base_dir, "json_logs") if not os.path.isdir(log_dir): os.makedirs(log_dir) #add folder modification permissions to deal with files from file explorer mode = stat.S_IRWXO | stat.S_IRWXU | stat.S_IRWXG os.chmod(log_dir, mode) #extract variables from settings dictionary sigma = contrast_settings['blur'] hist = contrast_settings['equalize_hist'] adapthist = contrast_settings['equalize_adapthist'] gamma = contrast_settings['gamma_adjust'] sobel_option = contrast_settings['sobel_toggle'] sobel = contrast_settings['sobel_factor'] invert = contrast_settings['invert_img'] v_min = contrast_settings['v_min'] v_max = contrast_settings['v_max'] # Sorted list of image names from raw directory img_list = get_img_names(raw_dir) number_of_images = len(img_list) #Adjust contrast for j in range(number_of_images): img_path = os.path.join(raw_dir, img_list[j]) image = get_image(img_path) #np.float32 adjusted_image = contrast(image, sigma, hist, adapthist, gamma, sobel_option, sobel, invert, v_min, v_max) #Save processed image if is_2D: adjusted_name = os.path.join( process_dir, identifier + "_adjusted_img_" + str(j).zfill(3) + ".png") else: adjusted_name = os.path.join( process_dir, identifier + "_adjusted_frame_" + str(j).zfill(3) + ".png") imwrite(adjusted_name, adjusted_image) print("Saved " + adjusted_name + "; image " + str(j + 1) + " of " + str(number_of_images)) print('Adjusted images have been saved in folder: ' + process_dir) #log in json for future reference log_data = {} log_data['date'] = str(datetime.datetime.now()) log_data['raw_settings'] = contrast_settings log_data['raw'] = raw_folder log_data['identifier'] = identifier log_data['combined'] = False #save log in JSON format #save with identifier; should be saved in "log" folder log_path = os.path.join(log_dir, identifier + "_contrast_adjustment_log.json") with open(log_path, "w") as write_file: json.dump(log_data, write_file) print('A record of the settings used has been saved in folder: ' + log_dir) return None