def _make_cell_map(self): #### Get the cell map according to this #### # # Pre: Requires both a Nucleus and Membrane map # Post: Sets a 'cell_map' in the 'segmentation_images' segmentation_images = self.get_data('segmentation_images').set_index( 'segmentation_label') nucid = segmentation_images.loc['Nucleus', 'image_id'] memid = segmentation_images.loc['Membrane', 'image_id'] nuc = self.get_image(nucid) mem = self.get_image(memid) mids = map_image_ids(mem) coords = list(zip(mids['x'], mids['y'])) center = median_id_coordinates(nuc, coords) im = mem.copy() im2 = mem.copy() orig = pd.DataFrame(mem.copy()) for i, cell_index in enumerate(center.index): coord = (center.loc[cell_index]['x'], center.loc[cell_index]['y']) mask = flood(im2, (coord[1], coord[0]), connectivity=1, tolerance=0) if mask.sum().sum() >= 2000: continue im2[mask] = cell_index v = map_image_ids(im2, remove_zero=False) zeros = v.loc[v['id'] == 0] zeros = list(zip(zeros['x'], zeros['y'])) start = v.loc[v['id'] != 0] start = list(zip(start['x'], start['y'])) c1 = map_image_ids(im2).reset_index().rename( columns={'id': 'cell_index_1'}) c2 = map_image_ids(im2).reset_index().rename( columns={'id': 'cell_index_2'}) overlap = c1.merge(c2, on=['x', 'y']).query('cell_index_1!=cell_index_2') if overlap.shape[0] > 0: raise ValueError("need to handle overlap") #print("DONE FILLING IN") cell_map_id = uuid4().hex self._images[cell_map_id] = im2.copy() increment = self.get_data('segmentation_images').index.max() + 1 extra = pd.DataFrame( pd.Series( dict({ 'db_id': increment, 'segmentation_label': 'cell_map', 'image_id': cell_map_id }))).T extra = pd.concat( [self.get_data('segmentation_images'), extra.set_index('db_id')]) self.set_data('segmentation_images', extra)
def make_cell_image(self): """ Requires the 'cell_model' be set by **\*.set_cell_model(model)** Sets properties: - cell_image (numpy.array) - nucleus_image (numpy.array) - edge_image (numpy.array) - processed_image (numpy.array) Returns: - cell_image - edge_image - processed_image """ if self.cell_model is None: raise ValueError("cell_model is required to be set. see the method .set_cell_model(model)") nuc = np.zeros(self.shape).astype(np.uint32) # Initialize the image to a pixel at the centroid for index,row in self.cell_model.cells.iterrows(): #print((index,list(row.index))) nuc[row['y']][row['x']] = index nuc1 = nuc.copy() # work on the cell_image nuc2 = nuc.copy() # work on the nucleus_image sys.stderr.write("Making cell image\n") _total_count = self.cell_model.cells.shape[0] # Preserve a point list of the non-centroid points that we can watershed into. finish = map_image_ids(nuc1,remove_zero=False).query('id==0').apply(lambda x: (x['x'],x['y']),1) if finish.shape[0]==0: finish = [] for index,row in self.cell_model.cells.iterrows(): sys.stderr.write("Making cell "+str(index)+" of "+str(_total_count)+" \r") start = [(row['x'],row['y'])] # Shared starting point # Fill in the cell_image nuc1 = watershed_image(nuc1,list(start),list(finish),fill_value=row.name,steps=self.cell_steps,border=0) # Fill in the nucleus nuc2 = watershed_image(nuc2,list(start),list(finish),fill_value=row.name,steps=math.ceil(self.cell_steps/4),border=0) sys.stderr.write("\n") self.nucleus_image = nuc2 self.cell_image = nuc1 self.edge_image = image_edges(nuc1) # Work on the processed image starting from the cell_image start = map_image_ids(nuc1,remove_zero=False).query('id!=0').apply(lambda x: (x['x'],x['y']),1) finish = map_image_ids(nuc1,remove_zero=False).query('id==0').apply(lambda x: (x['x'],x['y']),1) if start.shape[0]==0: start = [] if finish.shape[0]==0: finish = [] temp = watershed_image(nuc1,list(start),list(finish),steps=self.boundary_steps,border=0) self.processed_image = temp.astype(np.bool).astype(np.uint8) return
def edge_map(self): """ Return a dataframe of cells by ID's of coordinates only on the edge of the cells """ if 'edge_map' not in list( self.get_data('segmentation_images')['segmentation_label']): return None cmid = self.get_data('segmentation_images').set_index( 'segmentation_label').loc['edge_map', 'image_id'] return map_image_ids(self.get_image(cmid)).\ rename(columns={'id':'cell_index'})
def cell_map(self): """ Return a dataframe of cell ID's and locations """ if 'cell_map' not in list( self.get_data('segmentation_images')['segmentation_label']): return None cmid = self.get_data('segmentation_images').set_index( 'segmentation_label').loc['cell_map', 'image_id'] return map_image_ids( self.get_image(cmid)).rename(columns={'id': 'cell_index'})
def get_coordinates(self): if self._coordinates is not None: return self._coordinates df = self.set_index(self.cdf.frame_columns+['shape']).stack().\ reset_index().rename(columns={'level_7':'image_type',0:'image'}).\ set_index(self.cdf.frame_columns+['shape','image_type']) imgs = [] for i, r in df.iterrows(): if self.verbose: sys.stderr.write("Extracting coordinates from " + str(list(i)) + "\n") left = pd.DataFrame([i], columns=df.index.names) left['_key'] = 1 img = map_image_ids(r['image']).groupby('id').apply( lambda x: list(zip(*x[['x', 'y']].apply(tuple).tolist()))) img = img.reset_index().rename(columns={ 'id': 'cell_index', 0: 'coords' }) img['_key'] = 1 img = left.merge(img, on='_key').drop(columns='_key') imgs.append(img) imgs = pd.concat(imgs) self._coordinates = imgs return imgs
def get_segmentation_map_images(self, type='edge', subset_logic=None, color=None, watershed_steps=0, blank=(0, 0, 0, 255)): # if subset logic is set only plot those cells # if color is set color all cells that color if self.verbose: sys.stderr.write("getting segmap " + str(type) + "\n") ems = self.get_segmentation_maps(type=type) if subset_logic is not None: subset = self.cdf.subset(subset_logic) ems = ems.merge(subset.loc[:, subset.frame_columns + ['cell_index']], on=subset.frame_columns + ['cell_index']) edf = ems.set_index(list(self.columns)) imgs = [] for i, r in self.iterrows(): imsize = r['shape'] img = pd.DataFrame(np.zeros(imsize)) if subset.shape[0] == 0: # case where there is nothing to do if self.verbose: sys.stderr.write("Empty image for this phenotype subset\n") imgs.append(list(r) + [img]) continue edfsub = edf.loc[tuple(r)] #if self.verbose: sys.stderr.write("make image and fill zeros\n") fullx = pd.DataFrame({'x': list(range(0, imsize[1]))}) fullx['_key'] = 1 fully = pd.DataFrame({'y': list(range(0, imsize[0]))}) fully['_key'] = 1 full = fullx.merge(fully, on='_key').merge(edfsub, on=['x', 'y'], how='left').fillna(0) img = np.array( full.pivot(columns='x', index='y', values='cell_index').astype(int)) #if self.verbose: sys.stderr.write("finished making image and fill zeros\n") if watershed_steps > 0: # get the zero and nonzero components mid = map_image_ids(img, remove_zero=False) midzero = list( zip(*mid.query('id==0').copy()[['x', 'y']].apply( tuple).tolist())) mid = list( zip(*mid.query('id!=0').copy()[['x', 'y']].apply( tuple).tolist())) img = watershed_image(np.array(img), mid, midzero, steps=watershed_steps) if color is not None: # we need to make a new image thats colored in fresh = np.zeros(list(imsize) + [len(color)]).astype(int) blank = tuple(list(blank)[0:len(color)]) fresh[:][:] = blank # get our coordinates coords = np.array( list( zip(*map_image_ids(img)[['y', 'x']].apply( tuple).tolist()))) fresh[tuple([*coords.T])] = color #for i2,r2 in map_image_ids(img).iterrows(): # fresh[r2['y']][r2['x']] = color img = fresh imgs.append(list(r) + [img]) imgs = pd.DataFrame(imgs, columns=list(self.columns) + ['image']) return imgs
def _make_cell_map_legacy(self): from pythologist_image_utilities import flood_fill #raise ValueError("legacy") segmentation_images = self.get_data('segmentation_images').set_index( 'segmentation_label') nucid = segmentation_images.loc['Nucleus', 'image_id'] nuc = self.get_image(nucid) nmap = map_image_ids(nuc) memid = segmentation_images.loc['Membrane', 'image_id'] mem = self.get_image(memid) mem = pd.DataFrame(mem).astype(float).applymap(lambda x: 9999999 if x > 0 else x) mem = np.array(mem) points = self.get_data('cells')[['x', 'y']] #points = points.loc[points.index.isin(nmap['id'])] # we may need this .. not sure output = np.zeros(mem.shape).astype(int) for cell_index, v in points.iterrows(): xi = v['x'] yi = v['y'] nums = flood_fill(mem, xi, yi, lambda x: x != 0, max_depth=1000, border_trim=1) if len(nums) >= 2000: continue for num in nums: if output[num[1]][num[0]] != 0: sys.stderr.write("Warning: skipping cell index overalap\n") break output[num[1]][num[0]] = cell_index # Now fill out one point on all non-zeros into the zeros with watershed v = map_image_ids(output, remove_zero=False) zeros = v.loc[v['id'] == 0] zeros = list(zip(zeros['x'], zeros['y'])) start = v.loc[v['id'] != 0] start = list(zip(start['x'], start['y'])) output = watershed_image(output, start, zeros, steps=1, border=1).astype(int) # Now we need to clean up the image # Try to identify cells that are overlapping the processed image if self.processed_image_id is not None: ci = map_image_ids(output, remove_zero=False) pi = map_image_ids(self.processed_image, remove_zero=False) mi = ci.merge(pi, on=['x', 'y']) bad = mi.loc[(mi['id_y'] == 0) & (mi['id_x'] != 0), 'id_x'].unique() # find the bad #if self.verbose: sys.stderr.write("Removing "+str(bad.shape)+" bad points") mi.loc[mi['id_x'].isin(bad), 'id_x'] = 0 # set the bad to zero output = np.array(mi.pivot(columns='x', index='y', values='id_x')) cell_map_id = uuid4().hex self._images[cell_map_id] = output.copy() increment = self.get_data('segmentation_images').index.max() + 1 extra = pd.DataFrame( pd.Series( dict({ 'db_id': increment, 'segmentation_label': 'cell_map', 'image_id': cell_map_id }))).T extra = pd.concat( [self.get_data('segmentation_images'), extra.set_index('db_id')]) self.set_data('segmentation_images', extra)