Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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
Esempio n. 8
0
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
Esempio n. 9
0
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
Esempio n. 10
0
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
Esempio n. 11
0
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
Esempio n. 12
0
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
Esempio n. 14
0
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