def setUp(self): # Test images cropped around the droplet region self.empty_img = open_grey_scale_image('tests/test_images/empty_droplets.JPG')[250:2350, 0:4288] self.some_crystals_img = open_grey_scale_image('tests/test_images/some_crystals.JPG')[250:2350, 0:4288] self.all_crystals_img = open_grey_scale_image('tests/test_images/all_crystals.JPG')[250:2350, 0:4288] # Target number of droplets self.num_droplets = 149 self.delta = self.num_droplets // 0.7 # 15% variation in segmentation results is allowed
def segment_cells_to_file2p5(image_filename, save_overlay=False): if os.path.isdir(image_filename): img_list = [ os.path.join(image_filename, f) for f in os.listdir(image_filename) if f.endswith('.jpg') ] elif os.path.isfile(image_filename): img_list = [image_filename] for image_file in tqdm(img_list): # Open image image = open_grey_scale_image(image_file) # Segment image (labeled, num_regions) = segment2p5(image) # Save the overlay image if requested if save_overlay: image_overlay = label2rgb(labeled, bg_label=0) filename = image_file.split('.')[0] + '_segmented.jpg' with warnings.catch_warnings(): warnings.simplefilter("ignore") io.imsave(filename, image_overlay) # Extract individual cells cell_images, _, area_list2p5 = extract_indiv_cells2p5(image, labeled) # Output folder has the same name as the image by default out_directory = image_file.split('.')[0] if not os.path.exists(out_directory): os.mkdir(out_directory) logging.info("Saving segmented cells to %s", out_directory) # Save all the images in the output directory for (i, img) in enumerate(cell_images): name2p5 = os.path.join( out_directory, os.path.basename(image_file).split('.')[0] + '_cell_' + str(i) + '.jpg') with warnings.catch_warnings(): warnings.simplefilter("ignore") io.imsave(name2p5, img, check_contrast=False) cellarea2p5 = { name2p5[j]: area_list2p5[j] for j in range(len(name2p5)) } with open( os.path.join( out_directory, os.path.basename(image_file).split('.')[0] + '.pkl'), 'wb') as f: f.write(pickle.dumps(cellarea2p5))
def process_image(image_path, model, save_overlay=False): ''' Process a single image to obtain the number of detached and attached cells Parameters ---------- imgage_path: string Path to the image to process model: tensorflow model Instance of a tensorflow model trained to discriminate round and flat cells save_overlay: bool, optional Save an image with green / red overlays for detached / attached cells to `image_path / overlay` Returns ------- (date_take: datetime, num_cells: int, num_attached: int, num_detached: int) Date from the EXIF data, number of cells, number of attached cells, number of detached cells ''' # Open image #date_taken = get_date_taken(image_path) image = open_grey_scale_image(image_path) # Segment image (labeled, _) = segment(image) # Extract individual droplets cell_images, regProps = extract_indiv_cells(image, labeled) # Predict labels from model if cell_images and len(cell_images) > 0: X = np.asarray(cell_images) Y = model.predict_classes(X).flatten().tolist() num_cells = len(Y) num_attached = Y.count(0) num_detached = num_cells - num_attached else: logging.warning("No cells found in image %s", image_path) num_cells = 0 num_attached = 0 num_detached = 0 # Save overlay if applicable if save_overlay: path = os.path.join(os.path.dirname(image_path), 'overlay', os.path.basename(image_path)) save_overlay_image(path, image, regProps, Y) return (num_cells, num_attached, num_detached)
def process_image_folder(directory, show_plot=False, save_overlay=False, show_segmentation=False): # List images in directory supported_extensions = [ 'jpg', 'png', 'gif', 'jpeg ', 'eps', 'bmp', 'tiff', 'bmp', 'icns', 'ico', 'spi', ] image_list = [ os.path.join(directory, image_path) for image_path in os.listdir(directory) if os.path.splitext(image_path)[1][1:].lower() in supported_extensions ] # Define the model path model_name = "cnn-simple-model.json" # If show segmentation flag is asserted, display the segmentation of an image if show_segmentation: idx_80 = int(len(image_list) * 0.8) image_80 = open_grey_scale_image(image_list[idx_80]) logging.info("Segmentation check requested. Segmenting image %s", image_list[idx_80]) labeled, _ = segment(image_80) from skimage.color import label2rgb overlay_image = label2rgb(labeled, image=image_80, bg_label=1) import matplotlib matplotlib.use('Qt4Agg', force=True) import matplotlib.pyplot as plt fig = plt.figure() fig.set_tight_layout(True) plt.ion() plt.imshow(overlay_image) plt.show(block=False) plt.pause(0.1) result = input("Continue? (y/n)\n") while result != 'y': if result == 'n': plt.close() logging.warning( "Segmentation rejected. Stopping the application") return else: result = input("Please press 'y' for yes or 'n' for no\n") plt.close() # Compute the number of batches necessary num_images = len(image_list) logging.info("Number of images: %d", num_images) num_cpu = os.cpu_count() if num_images < num_cpu: logging.info("Processing on a single thread.") flat_data = process_image_batch(image_list, model_name, 0, logging.root.level, save_overlay) else: logging.info("Processing in parallel") batch_size = max([1, num_images // (num_cpu - 1)]) logging.info("Batch size: %d", batch_size) num_batches = int(math.ceil(num_images // batch_size)) logging.info("Number of batches: %d", num_batches) # Process all images from directory in parallel data = Parallel(n_jobs=-2)(delayed(process_image_batch)( image_list[i * batch_size:min([(i + 1) * batch_size, num_images])], model_name, i, logging.root.level, save_overlay) for i in range(num_batches)) flat_data = [item for sublist in data for item in sublist] # Make a dataframe from the data and save it to disk df = pd.DataFrame(sorted(flat_data, key=lambda x: x[0]), columns=[ "DateTime", "Num cells", "Num attached", "Num detached", "Image Name" ]) df['RelTime'] = (df['DateTime'] - df['DateTime'][0]).dt.total_seconds() df.to_csv(os.path.join(directory, "cellData.csv")) logging.info("Saved data to disk.") # Plot the data for imediate visualization if show_plot: plot_cell_data(df, directory)
def test_open_asserts_error_if_file_not_found(self): with self.assertRaises(OSError): open_grey_scale_image('some/nonexistent/path.JPG')
def setUp(self): self.empty_img = open_grey_scale_image( 'tests/test_images/empty_droplets.JPG')
def test_open_non_image_raises_error(self): with self.assertRaises(OSError): open_grey_scale_image('LICENSE')