def get_pore(img, percentile=75,edge_object_margin=1): """Extracts largest, non-border, darkest region from subimage - in context presumed to be the pore. Works out the values are 0. :param img: input image (section of full intensity leaf image with just stomate in it) :type img: numpy.ndarray :param percentile: the percentile of the intensity histogram below which values will be taken to be dark. :type percentile: int :param edge_object_margin: the width of border in which objects must lie to be removed as border objects, default = 1 :return: binary numpy.ndaarray """ dark_level = np.percentile(img, percentile ) #imshow(img) cp = np.copy(img) cp[img > dark_level] = 0 cp[img <= dark_level] = 1 label_objects, nb_labels = ndimage.label(cp) removed = np.copy(label_objects) for o in edge_objects(label_objects, margin=edge_object_margin): removed[removed == o] = 0 new_label_objects, new_nb_labels = ndimage.label(removed) props = measure.regionprops(new_label_objects, intensity_image=img) if len(props) > 0: area = max([i.area for i in props]) biggest = [i for i, j in enumerate(props) if j.area == area] index_of_obj_to_keep = biggest[0] label_of_obj_to_keep = np.arange(1, new_nb_labels + 1)[index_of_obj_to_keep] new_label_objects[new_label_objects != label_of_obj_to_keep] = 0 final_label_objects, final_nb_labels = ndimage.label(new_label_objects) return(final_label_objects) else: #no pore return(None)
def test_prediction_activity(out_dir, calcium_data, logged_ssvm_path, which_gt='gt', feats_unary='feats_pm', feats_pairwise='feats_xcorr_green'): img_x, img_y = 512, 512 logger = pystruct_logger(logged_ssvm_path) ssvm = logger.load() print ssvm print "Build edge graph" edges = create_2d_edge_graph(img_x, img_y) for sub in calcium_data.subvolumes: print 'Preparing output directory for', sub.name out_folder = 'test_prediction_activity/%s/' % sub.name create_out_path(out_path=out_dir, except_on_exist=False) print 'Loading stuff for subvolume', sub.name gt = sub.get(which_gt).astype('uint8') unary_feats = sub.get(feats_unary) pairwise_feats = sub.get(feats_pairwise) x_single = (unary_feats, edges, pairwise_feats) y_single = gt.reshape(img_x * img_y) print "\tPredicting on subvolume" pred=ssvm.predict([x_single]) pred=pred[0].reshape(img_x, img_y) print '\tScoring subvolume prediction' score = ssvm.score([x_single], [y_single]) print 'Score on subvolume:', score print 'Getting connected components' cc_pred, cnt_obj_pred = ndimage.label(pred) cc_gt, cnt_obj_gt = ndimage.label(gt) print 'cc:', cnt_obj_pred print 'Saving vizzzz' for cc in xrange(1, cnt_obj_pred + 1): label_indices_xy = np.where(cc_pred == cc) tmp = np.zeros_like(gt) tmp[label_indices_xy] = 1 tmp = tmp.reshape(img_x * img_y) label_indices_rshp = np.where(tmp == 1) label_indices_xy = np.asarray(label_indices_xy) label_polygons_pppx = sub.mpl_get_polygon_patches(['active_very_certain', 'active_mod_certain', 'uncertain']) label_polygons_ppp = sub.mpl_get_polygon_patches(['active_very_certain', 'active_mod_certain']) label_polygons_pp = sub.mpl_get_polygon_patches(['active_very_certain']) label_polygons = [label_polygons_pp, label_polygons_ppp, label_polygons_pppx] roi = Roi(indices=label_indices_rshp, xy=label_indices_xy, subvolume=sub, janelia_id=cc, meta_info='Spike trains of predicted neurons for %s (score: %.02f)' % (sub.name, score)) fig = roi.plot_like_annotation_labeler(prediction_image=pred, label_polygons=label_polygons) plt.savefig(out_dir + '%d.png' % roi.id, dpi=600) plt.close() plt.imsave(out_dir + 'cc_pred.png', cc_pred) plt.imsave(out_dir + 'cc_gt.png', cc_gt) print '\n============================================\n' print 'Done.'
def multithreshold(img,ignore_zeros=True,firstThreshold=20,nrThresholds=5): ''' labeled,N = multithreshold(img, ignore_zeros = True) Performs multi thresholding (which is a form of oversegmentation). labeled is of the same size and type as img and contains different labels for the N detected objects (the return of this function is similar to that of scipy.ndimage.label()) @param img: The input image @param ignore_zeros: Don't take zero pixels into account ''' output=numpy.zeros_like(img) if ignore_zeros: pmin=nonzeromin(img) else: pmin=img.min() thresholds=pmin+firstThreshold+(img.max()-pmin-firstThreshold)//nrThresholds*numpy.arange(nrThresholds) Ts=[majority_filter(img>T) for T in thresholds] obj_count = 0 Ts.append(Ts[0]*0) labeled0,N0=ndimage.label(Ts[0]) for T1 in Ts[1:]: labeled1,N1=ndimage.label(T1) for obj in xrange(N0): binimg=(labeled0 == (obj+1)) objects1=(labeled1*binimg) if not objects1.any() or ndimage.label(objects1)[1] == 1: obj_count += 1 output[binimg]=obj_count labeled0=labeled1 N0=N1 return output,obj_count
def remove_small_objects(ar, min_size=64, connectivity=1, in_place=False): # Should use `issubdtype` for bool below, but there's a bug in numpy 1.7 if not (ar.dtype == bool or np.issubdtype(ar.dtype, np.integer)): raise TypeError("Only bool or integer image types are supported. " "Got %s." % ar.dtype) if in_place: out = ar else: out = ar.copy() if min_size == 0: # shortcut for efficiency return out if out.dtype == bool: selem = nd.generate_binary_structure(ar.ndim, connectivity) ccs = np.zeros_like(ar, dtype=np.int32) nd.label(ar, selem, output=ccs) else: ccs = out try: component_sizes = np.bincount(ccs.ravel()) except ValueError: raise ValueError("Negative value labels are not supported. Try " "relabeling the input with `scipy.ndimage.label` or " "`skimage.morphology.label`.") too_small = component_sizes < min_size too_small_mask = too_small[ccs] out[too_small_mask] = 0 return out
def erode_to_connected(img,d=3,shape=3,rel_size=0.5,min_size=15, single=False): """ erode to structure to specified relative size; safe version, which won't collapse to a single pixel with connectivity constraints """ orig_size = np.count_nonzero(img) new_size = orig_size _,comp = ndimage.label(img) if(orig_size <= 0 or comp > 1): return img prev_img = img.copy() count = 0 # run for d times, but terminate early if the size (relative or # absolute) is too small, or the image breaks into multiple pieces while new_size > rel_size * orig_size \ and new_size > min_size \ and comp < 2 \ and count < d: prev_img = img.copy() img = erode(img,shape) new_size = np.count_nonzero(img) _,comp = ndimage.label(img) count += 1 return prev_img
def remove_small_blobs(img, threshold=1, debug=True): ''' Find blobs/clusters of same label. Only keep blobs with more than threshold elements. This can be used for postprocessing. :param img: 3D Image :param threshold: :return: ''' # mask, number_of_blobs = ndimage.label(img, structure=np.ones((3, 3, 3))) #Also considers diagonal elements for determining if a element belongs to a blob mask, number_of_blobs = ndimage.label(img) print('Number of blobs before: ' + str(number_of_blobs)) counts = np.bincount(mask.flatten()) # number of pixels in each blob if debug: print(counts) remove = counts <= threshold remove_idx = np.nonzero(remove)[0] # somehow returns tupple with 1 value -> remove tupple, only keep value for idx in remove_idx: mask[mask == idx] = 0 # set blobs we remove to 0 mask[mask > 0] = 1 # set everything else to 1 if debug: mask_after, number_of_blobs_after = ndimage.label(mask) print('Number of blobs after: ' + str(number_of_blobs_after)) return mask
def threshold_and_clean_tomo_layer(reconstruction_fbp,recon_thresh, noise_obj_size,min_hole_size,edge_cleaning_iter=None): binary_recon=reconstruction_fbp>recon_thresh #hard codeed cleaning, grinding sausage... binary_recon=img.morphology.binary_erosion(binary_recon,iterations=1) binary_recon=img.morphology.binary_dilation(binary_recon,iterations=4) labeled_img,num_labels=img.label(binary_recon) print('Cleaning...') print('Removing Noise...') for ii in np.arange(1,num_labels): obj1=np.where(labeled_img==ii) if obj1[0].shape[0]<noise_obj_size: binary_recon[obj1[0],obj1[1]]=0 labeled_img,num_labels=img.label(binary_recon!=1) print('Closing Holes...') for ii in np.arange(1,num_labels): obj1=np.where(labeled_img==ii) if obj1[0].shape[0]>=1 and obj1[0].shape[0]<min_hole_size: binary_recon[obj1[0],obj1[1]]=1 if edge_cleaning_iter is not None: binary_recon=img.morphology.binary_erosion(binary_recon,iterations=edge_cleaning_iter) binary_recon=img.morphology.binary_dilation(binary_recon,iterations=edge_cleaning_iter) return binary_recon
def threshold_segment(dna, threshold_method="otsu", smooth=None, median_size=5, min_obj_size=2500): """ labeled = threshold_method(dna, threshold_method='otsu',median_size=5,min_obj_size=2500) Simple threshold-based segmentation Params ------ * dna: either a pyslic.Image or a DNA image * threshold_method: thresholding method to use. Can be either a function or string which denotes the name of a function in pyslic.imageprocessing.thresholding (default: otsu) * smooth: either None (no smoothing) or a sigma value for a gaussian blur (default: None) * median_size: median filter size (default: 5). Set to None to skip filtering. * min_obj_size: minimum object size (default: 2500) """ if type(dna) == Image: with loadedimage(dna): return threshold_segment(dna.get("dna"), threshold_method, smooth, median_size, min_obj_size) if smooth is not None: dna = ndimage.gaussian_filter(dna, smooth) T = threshold(dna, threshold_method) binimg = dna > T if median_size is not None: binimg = majority_filter(binimg, median_size) L, N = ndimage.label(binimg) if N == 0: return L sizes = numpy.array(ndimage.sum(binimg, L, numpy.arange(N + 1))) for oid in numpy.where(sizes < min_obj_size)[0]: L[L == oid] = 0 L, N = ndimage.label(L != 0) return L
def get_stomata(max_proj_image, min_obj_size=200, max_obj_size=1000): """Performs image segmentation from a max_proj_image. Disposes of objects in range min_obj_size to max_obj_size :param max_proj_image: the maximum projection image :type max_proj_image: numpy.ndarray, uint16 :param min_obj_size: minimum size of object to keep :type min_obj_size: int :param max_obj_size: maximum size of object to keep :type max_obj_size: int :returns: list of [ [coordinates of kept objects - list of slice objects], binary object image - numpy.ndarray, labelled object image - numpy.ndarray ] """ # pore_margin = 10 # max_obj_size = 1000 # min_obj_size = 200 # for prop, value in segment_options: # if prop == 'pore_margin': # pore_margin = value # if prop == 'max_obj_size': # max_obj_size = value # if prop == 'min_obj_size': # min_obj_size = value # # print(pore_margin) # print(max_obj_size) # print(min_obj_size) #rescale_min = 50 #rescale_max= 100 #rescaled = exposure.rescale_intensity(max_proj_image, in_range=(rescale_min,rescale_max)) rescaled = max_proj_image seed = np.copy(rescaled) seed[1:-1, 1:-1] = rescaled.max() #mask = rescaled #if gamma != None: # rescaled = exposure.adjust_gamma(max_proj_image, gamma) #filled = reconstruction(seed, mask, method='erosion') closed = dilation(rescaled) seed = np.copy(closed) seed[1:-1, 1:-1] = closed.max() mask = closed filled = reconstruction(seed, mask, method='erosion') label_objects, nb_labels = ndimage.label(filled) sizes = np.bincount(label_objects.ravel()) mask_sizes = sizes mask_sizes = (sizes > min_obj_size) & (sizes < max_obj_size) #mask_sizes = (sizes > 200) & (sizes < 1000) mask_sizes[0] = 0 big_objs = mask_sizes[label_objects] stomata, _ = ndimage.label(big_objs) obj_slices = ndimage.find_objects(stomata) return [obj_slices, big_objs, stomata]
def findPlantsCanny(stackVar, stackSum, showImages=True): edges = canny(stackVar) fill_stack = ndimage.binary_fill_holes(edges) label_objects, nb_labels = ndimage.label(fill_stack) sizes = np.bincount(label_objects.ravel()) mask_sizes = sizes > 25 for label in range(len(mask_sizes)): ''' Get rid of lines in addition to the straight size threshold. ''' pts = np.where(label_objects == label) xRange = (max(pts[0]) - min(pts[0])) yRange = (max(pts[1]) - min(pts[1])) areaCovered = float(len(pts[0])) / (xRange*yRange) if (areaCovered < .33) or (xRange < 3) or (yRange < 3): mask_sizes[label] = False mask_sizes[0] = 0 plants_cleaned = mask_sizes[label_objects] labeled_plants, numPlants = ndimage.label(plants_cleaned) center = findCenters(labeled_plants, stackSum) if showImages: fig, axs = plt.subplots(1,3, figsize=(14,4), sharey=True) axs[0].imshow(stackVar) axs[1].imshow(stackVar, cmap=plt.cm.jet, interpolation='nearest') #@UndefinedVariable axs[1].contour(plants_cleaned, [0.5], linewidths=1.2, colors='y') axs[2].imshow(labeled_plants, cmap=plt.cm.spectral, interpolation='nearest') #@UndefinedVariable axs[2].scatter(np.array(center.tolist())[:,1], np.array(center.tolist())[:,0], color='grey') for ax in axs: ax.axis('off') fig.subplots_adjust(wspace=.01) return labeled_plants, center
def create_paths(pathimage): # shortest path through black then purple then cyan arr = np.transpose(pygame.surfarray.array3d(pathimage), [1,0,2]) maxval = arr.max() black = (((arr == 0).sum(axis=2)) == 3) print "found %d black pixels"%(black.sum()) purple = ((arr[:,:,0] == maxval) & (arr[:,:,1] == 0) & (arr[:,:,2] == maxval)) print "found %d purple pixels"%(purple.sum()) cyan = ((arr[:,:,0] == 0) & (arr[:,:,1] == maxval) & (arr[:,:,2] == maxval)) print "found %d cyan pixels"%(cyan.sum()) white = (((arr == arr.max()).sum(axis=2)) == 3) print "found %d white pixels"%(white.sum()) mask = black | purple | cyan | white black_blobs, black_count = ndi.label(black) purple_blobs, purple_count = ndi.label(purple) cyan_blobs, cyan_count = ndi.label(cyan) print black_count, purple_count, cyan_count try: black_centers, purple_distances, cyan_distances = cPickle.load(open("distances.pickle")) except: black_centers = ndi.center_of_mass(np.ones(black_blobs.shape), black_blobs, range(1, black_count + 1)) purple_distances = [masked_distance(purple_blobs == (b + 1), mask) for b in range(purple_count)] cyan_distances = [masked_distance(cyan_blobs == (b + 1), mask) for b in range(cyan_count)] cPickle.dump((black_centers, purple_distances, cyan_distances), open("distances.pickle", "w")) return black_centers, [purple_distances, cyan_distances]
def skeleton(seg): skel, dist = skmorph.medial_axis(seg, return_distance=True) node, edge, leaf = (spim.label(g, np.ones((3, 3), bool))[0] for g in skel2graph(skel)) trim_edge = (edge != 0) & ~(skmorph.binary_dilation(node != 0, np.ones((3, 3), bool)) != 0) trim_edge = spim.label(trim_edge, np.ones((3, 3), bool))[0] leaf_edge_vals = skmorph.binary_dilation(leaf != 0, np.ones((3, 3), bool)) != 0 leaf_edge_vals = np.unique(trim_edge[leaf_edge_vals]) leaf_edge_vals = leaf_edge_vals[leaf_edge_vals > 0] leaf_edge = leaf != 0 trim_edge = ndshm.fromndarray(trim_edge) leaf_edge = ndshm.fromndarray(leaf_edge) Parallel()(delayed(set_msk)(leaf_edge, trim_edge, l) for l in leaf_edge_vals) trim_edge = np.copy(trim_edge) leaf_edge = np.copy(leaf_edge) leaf_edge[(skmorph.binary_dilation(leaf_edge, np.ones((3, 3), bool)) != 0) & (edge != 0)] = True leaf_edge = spim.label(leaf_edge, np.ones((3, 3), bool))[0] leaf_edge_node = skmorph.binary_dilation(leaf_edge != 0, np.ones((3, 3), bool)) != 0 leaf_edge_node = ((node != 0) & leaf_edge_node) | leaf_edge leaf_edge_node = spim.label(leaf_edge_node, np.ones((3, 3), bool))[0] cand_node = leaf_edge_node * (node != 0) cand_node = cand_node.nonzero() cand_node = np.transpose((leaf_edge_node[cand_node],) + cand_node + (2 * dist[cand_node],)) cand_leaf = leaf_edge_node * (leaf != 0) cand_leaf = cand_leaf.nonzero() cand_leaf = np.transpose((leaf_edge_node[cand_leaf],) + cand_leaf) if len(cand_node) > 0 and len(cand_leaf) > 0: cand_leaf = ndshm.fromndarray(cand_leaf) cand_node = ndshm.fromndarray(cand_node) pruned = Parallel()(delayed(prune_leaves)(cand_leaf, cand_node, j) for j in np.unique(cand_node[:, 0])) cand_leaf = np.copy(cand_leaf) cand_node = np.copy(cand_node) pruned_ind = [] for p in pruned: pruned_ind.extend(p) pruned_ind = tuple(np.transpose(pruned_ind)) pruned = ~skel pruned = ndshm.fromndarray(pruned) leaf_edge = ndshm.fromndarray(leaf_edge) Parallel()(delayed(set_msk)(pruned, leaf_edge, l) for l in np.unique(leaf_edge[pruned_ind])) pruned = np.copy(pruned) leaf_edge = np.copy(leaf_edge) pruned = ~pruned else: pruned = skel return pruned
def run(self, workspace): objects = workspace.object_set.get_objects(self.objects_name.value) assert isinstance(objects, cpo.Objects) labels = objects.segmented if self.relabel_option == OPTION_SPLIT: output_labels, count = scind.label(labels > 0, np.ones((3, 3), bool)) else: if self.unify_option == UNIFY_DISTANCE: mask = labels > 0 if self.distance_threshold.value > 0: # # Take the distance transform of the reverse of the mask # and figure out what points are less than 1/2 of the # distance from an object. # d = scind.distance_transform_edt(~mask) mask = d < self.distance_threshold.value / 2 + 1 output_labels, count = scind.label(mask, np.ones((3, 3), bool)) output_labels[labels == 0] = 0 if self.wants_image: output_labels = self.filter_using_image(workspace, mask) elif self.unify_option == UNIFY_PARENT: parent_objects = workspace.object_set.get_objects(self.parent_object.value) output_labels = parent_objects.segmented.copy() output_labels[labels == 0] = 0 output_objects = cpo.Objects() output_objects.segmented = output_labels if objects.has_small_removed_segmented: output_objects.small_removed_segmented = copy_labels(objects.small_removed_segmented, output_labels) if objects.has_unedited_segmented: output_objects.unedited_segmented = copy_labels(objects.unedited_segmented, output_labels) output_objects.parent_image = objects.parent_image workspace.object_set.add_objects(output_objects, self.output_objects_name.value) measurements = workspace.measurements add_object_count_measurements(measurements, self.output_objects_name.value, np.max(output_objects.segmented)) add_object_location_measurements(measurements, self.output_objects_name.value, output_objects.segmented) # # Relate the output objects to the input ones and record # the relationship. # children_per_parent, parents_of_children = objects.relate_children(output_objects) measurements.add_measurement( self.objects_name.value, FF_CHILDREN_COUNT % self.output_objects_name.value, children_per_parent ) measurements.add_measurement( self.output_objects_name.value, FF_PARENT % self.objects_name.value, parents_of_children ) if self.wants_outlines: outlines = cellprofiler.cpmath.outline.outline(output_labels) outline_image = cpi.Image(outlines.astype(bool)) workspace.image_set.add(self.outlines_name.value, outline_image) if workspace.frame is not None: workspace.display_data.orig_labels = objects.segmented workspace.display_data.output_labels = output_objects.segmented
def find_peaks(file): #read image data f=pyfits.open(file) img=f[0].data #set NaN pixels (empty pixels) to zero img[img != img]=0.0 img[img<0.]=0.0 if dim==4: img=img[0,0,:,:] #gets rid of 3 and 4 dimensions, since FIRST fits files have four axis but only first two have data T=ndimage.standard_deviation(img) sourcelabels,num_sources=ndimage.label(img>T) backgroundlabels,num_background=ndimage.label(img<T) # define an 8-connected neighbourhood neighborhood = generate_binary_structure(2,2) fimg=img*sourcelabels #apply the local maximum filter; all pixel of maximal value #in their neighbourhood are set to 1 local_max=maximum_filter(fimg,footprint=neighborhood)==fimg #In order to isolate the peaks we must remove the background from the mask. #we create the mask of the background background=img*backgroundlabels #we must erode the background in order to #successfully subtract it form local_max, otherwise a line will #appear along the background border (artifact of the local maximum filter) eroded_background=binary_erosion(background,structure=neighborhood,border_value=1) #we obtain the final mask, containing only peaks, #by removing the background from the local_max mask detected_peaks=local_max-eroded_background #contains some peaks not in source (background bright features), but code can remove these #now need to find positions of these maximum #label peaks peaklabels,num_peaks=ndimage.measurements.label(detected_peaks) #get peak positions slices = ndimage.find_objects(peaklabels) x, y = [], [] for dy,dx in slices: x_center = (dx.start + dx.stop - 1)/2 x.append(x_center) y_center = (dy.start + dy.stop - 1)/2 y.append(y_center) peak_positions=zip(x,y) #get peak values, in Jy/beam peak_fluxes=[] for coord in peak_positions: peak_fluxes.append(img[coord[1],coord[0]]) peaks=zip(peak_positions,peak_fluxes) #sort by peak_fluxes. Two brightest peaks will be the first two in the list peaks=sorted(peaks,key=lambda l: l[1]) peaks.reverse() return peaks,img,f
def test_connect_regions_with_grid(): lena = sp.lena() mask = lena > 50 graph = grid_to_graph(*lena.shape, **{"mask": mask}) assert_equal(ndimage.label(mask)[1], cs_graph_components(graph)[0]) mask = lena > 150 graph = grid_to_graph(*lena.shape, **{"mask": mask, "dtype": None}) assert_equal(ndimage.label(mask)[1], cs_graph_components(graph)[0])
def split_up_binary_regions(seq_block, opening_param = 3, mshape = ((0,1,0),(1,1,1),(0,1,0)), min_size = 20): # for each region: # dilate, relabel, create stack with eroded single regions # delete overlapping pixels, recombine, assigning unique labels zdim, xdim, ydim = seq_block.shape splitblock = np.zeros_like(seq_block) for sidx in range(zdim): num_labels = int(np.max(seq_block[sidx])) if num_labels <= 1: continue max_label = num_labels for lidx in range(num_labels): comp = extract_region(seq_block[sidx], lidx+1) if np.sum(comp) < min_size: continue component = ndi.binary_erosion(comp,structure = mshape,iterations = opening_param) component, numnewcomponents = ndi.label(component) if numnewcomponents == 1: # component is not split up by erosion #component[component>0] = 1 #component = ndi.binary_dilation(component,structure = mshape,iterations = opening_param) splitblock[sidx][comp > 0] = int(lidx+1) else: compstack = np.zeros((numnewcomponents,xdim,ydim)) for cidx in range(numnewcomponents): compstack[cidx] = ndi.binary_dilation(extract_region(component, cidx+1),structure = mshape,iterations = opening_param) compstack[cidx] = ndi.binary_dilation(compstack[cidx],structure = ((0,1,0),(1,1,1),(0,1,0)),iterations = 2) overlapmask = np.sum(compstack, axis = 0) comp[overlapmask > 1] = 0 comp, numnewcomponents2 = ndi.label(comp) #if numnewcomponents != numnewcomponents2: #print "Lost something on the way: C1 = " + str(numnewcomponents) + ", C2 = " + str(numnewcomponents2) for cidx in range(numnewcomponents2): component = extract_region(comp, cidx+1) if np.sum(component) < min_size: continue #compstack[cidx] = compstack[cidx] * overlapmask #if np.sum(compstack[cidx]) > 0: max_label = max_label + 1 #compstack[cidx] = compstack[cidx] * max_label splitblock[sidx] = splitblock[sidx] + component.astype(int) * int(max_label) #splitblock[sidx] = splitblock[sidx] + np.sum(compstack,axis = 0).astype(int) # relabel components to unique labels all_labels = np.sort(np.unique(splitblock[sidx])) dum = np.zeros_like(splitblock[sidx]) l_idx = 1 for label in all_labels: if label >0: dum[splitblock[sidx]==label] = l_idx l_idx = l_idx + 1 return splitblock
def isolatefilaments(skel_img, size_threshold, pad_size=5): ''' This function separates each filament, over a threshold of number of pixels, into its own array with the same dimensions as the inputed image. Parameters ---------- skel_img : numpy.ndarray the resultant skeletons from the Medial Axis Transform mask : numpy.ndarray the binary mask from adaptive thresholding size_threshold : int sets the pixel size on the size of objects Returns ------- skelton_arrays : list contains the individual arrays for each skeleton mask : numpy.ndarray Updated version of the mask where small objects have been eliminated num : int Number of filaments corners : list Contains the indices where each skeleton array was taken from the original ''' skeleton_arrays = []; pix_val = []; corners = [] labels,num = nd.label(skel_img,eight_con()) sums = nd.sum(skel_img,labels,range(num)) for n in range(num): if sums[n]<size_threshold: x,y = np.where(labels==n) for i in range(len(x)): skel_img[x[i],y[i]]=0 # Relabel after deleting short skeletons. labels,num = nd.label(skel_img,eight_con()) # Split each skeleton into its own array. for n in range(1,num+1): x,y = np.where(labels==n) # Make an array shaped to the skeletons size and padded on each edge shapes = (x.max()-x.min()+2*pad_size, y.max()-y.min()+2*pad_size) eachfil = np.zeros(shapes) for i in range(len(x)): eachfil[x[i]-x.min()+pad_size,y[i]-y.min()+pad_size] = 1 skeleton_arrays.append(eachfil) # Keep the coordinates from the original image lower = (x.min()-pad_size,y.min()-pad_size) upper = (x.max()+pad_size,y.max()+pad_size) corners.append([lower,upper]) return skeleton_arrays, num, corners
def test_connect_regions_with_grid(): lena = sp.misc.lena() mask = lena > 50 graph = grid_to_graph(*lena.shape, mask=mask) assert_equal(ndimage.label(mask)[1], cs_graph_components(graph)[0]) mask = lena > 150 graph = grid_to_graph(*lena.shape, mask=mask, dtype=None) assert_equal(ndimage.label(mask)[1], cs_graph_components(graph)[0])
def test_connect_regions_with_grid(): lena = sp.lena() mask = lena > 50 graph = grid_to_graph(*lena.shape, **{'mask' : mask}) nose.tools.assert_equal(ndimage.label(mask)[1], cs_graph_components(graph)[0]) mask = lena > 150 graph = grid_to_graph(*lena.shape, **{'mask' : mask, 'dtype' : None}) nose.tools.assert_equal(ndimage.label(mask)[1], cs_graph_components(graph)[0])
def plot_filled(y, ax=None, thresh=None, plot_thresh=True, color='k', lw=2, facecolor='0.8', two_tailed=False, thresh_color='k', autoset_ylim=True, label=None): ''' Plot a filled cluster. (This function should only be used through **spm1d.plot.plot_spmi**) ''' y = np.asarray(y, dtype=float) x = _getQ(None, y.size) ax = _gca(ax) if thresh==None: thresh = 0 x0,y0,ind0 = x.copy(), y.copy(), np.arange(y.size) ### threshold: if two_tailed: L,n = ndimage.label(np.abs(y)>thresh) else: L,n = ndimage.label(y>thresh) ### plot: ax.plot(x0, y0, color=color, lw=lw, label=label) ### create patches if needed: if n>0: polyg = [] for i in range(n): ind = ind0[L==i+1].tolist() x = x0[L==i+1].tolist() y = y0[L==i+1].tolist() csign = np.sign(y[0]) ### insert extra nodes for interpolation: x = [x[0]] + x + [x[-1]] y = [csign*thresh] + y + [csign*thresh] ### interpolate if necessary: if ind[0] != ind0[0]: dx = x0[ind[0]] - x0[ind[0]-1] dy = (csign*thresh - y0[ind[0]]) / (y0[ind[0]] - y0[ind[0]-1]) x[0] += dy*dx if ind[-1] != ind0[-1]: dx = x0[ind[-1]+1] - x0[ind[-1]] dy = (csign*thresh - y0[ind[-1]]) / (y0[ind[-1]+1] - y0[ind[-1]]) x[-1] += dy*dx polyg.append( Polygon(list(zip(x,y))) ) patches = PatchCollection(polyg, edgecolors=None) ax.add_collection(patches) pyplot.setp(patches, facecolor=facecolor, edgecolor=facecolor) #set axis limits: # pyplot.setp(ax, xlim=(x0.min(), x0.max()), ylim=(y0.min(), y0.max())) pyplot.setp(ax, xlim=(x0.min(), x0.max()) ) #plot threshold(s): if (thresh!=None) and plot_thresh: h = [ax.hlines(thresh, x0.min(), x0.max())] if two_tailed: h.append( ax.hlines(-thresh, x0.min(), x0.max()) ) pyplot.setp(h, color=thresh_color, lw=1, linestyle='--') if autoset_ylim: _set_ylim(ax)
def find_dead_ends_once(arr): """Called by find_dead_ends""" Nx, Ny = arr.shape # Surround whole grid with border of False values to avoid index errors arr = np.append(arr, np.full((Nx, 1), False, dtype=bool), axis=1) arr = np.append(arr, np.full((1, Ny + 1), False, dtype=np.bool), axis=0) arr = np.insert(arr, 0, False, axis=1) arr = np.insert(arr, 0, False, axis=0) # Kernels used in convolution to identify possible dead ends x_kernel = np.array([[1], [0], [1]]) y_kernel = np.array([[1, 0, 1]]) conv_x = convolve(arr, y_kernel, 'same') conv_y = convolve(arr, x_kernel, 'same') inds_x = np.logical_and(arr, conv_x == 0) inds_x_labels, nxlabels = label(inds_x) inds_y = np.logical_and(arr, conv_y == 0) inds_y_labels, nylabels = label(inds_y) # Find inds in first direction for i in np.r_[1:nxlabels+1]: args_i = np.argwhere(inds_x_labels == i) y_inds = args_i[[0, -1], 0] + np.r_[-1, 1] x_ind = args_i[0, 1] if np.all(arr[y_inds, x_ind]): # Not a dead end, water on both sides inds_x_labels[inds_x_labels == i] = 0 inds_x = inds_x_labels > 0 # Same for second direction for i in np.r_[1:nylabels+1]: args_i = np.argwhere(inds_y_labels == i) y_ind = args_i[0, 0] x_inds = args_i[[0, -1], 1] + np.r_[-1, 1] if np.all(arr[y_ind, x_inds]): # Not a dead end, water on both sides inds_y_labels[inds_y_labels == i] = 0 inds_y = inds_y_labels > 0 dead_end_inds = np.logical_or(inds_x, inds_y) # Account for border of False values added at start dead_end_inds = dead_end_inds[1:-1, 1:-1] return dead_end_inds
def feature_vector_from_rgb(image, sample_size=None): """Compute a feature vector from the composite images. The channels are assumed to be in the following order: - Red: MCF-7 - Green: cytoplasm GFP - Blue: DAPI/Hoechst Parameters ---------- im : array, shape (M, N, 3) The input image. sample_size : int, optional For features based on quantiles, sample this many objects rather than computing full distribution. This can considerably speed up computation with little cost to feature accuracy. Returns ------- fs : 1D array of float The features of the image. names : list of string The feature names. """ all_fs, all_names = [], [] ims = np.rollaxis(image[..., :3], -1, 0) # toss out alpha chan if present mcf, cells, nuclei = ims prefixes = ['mcf', 'cells', 'nuclei'] for im, prefix in zip(ims, prefixes): fs, names = features.intensity_object_features(im, sample_size=sample_size) names = [prefix + '-' + name for name in names] all_fs.append(fs) all_names.extend(names) nuclei_mean = nd.label(nuclei > np.mean(nuclei))[0] fs, names = features.nearest_neighbors(nuclei_mean) all_fs.append(fs) all_names.extend(['nuclei-' + name for name in names]) mcf_mean = nd.label(mcf)[0] fs, names = features.fraction_positive(nuclei_mean, mcf_mean, positive_name='mcf') all_fs.append(fs) all_names.extend(names) cells_t_otsu = cells > threshold_otsu(cells) cells_t_adapt = threshold_adaptive(cells, 51) fs, names = features.nuclei_per_cell_histogram(nuclei_mean, cells_t_otsu) all_fs.append(fs) all_names.extend(['otsu-' + name for name in names]) fs, names = features.nuclei_per_cell_histogram(nuclei_mean, cells_t_adapt) all_fs.append(fs) all_names.extend(['adapt-' + name for name in names]) return np.concatenate(all_fs), all_names
def _process_B(B): L,N = ndimage.label(~B) bg = 0 bg_size = (L==bg).sum() for i in xrange(1,N+1): i_size = (L == i).sum() if i_size > bg_size: bg_size = i_size bg = i if i_size < _min_obj_size: L[L==i] = 0 L[L==bg]=0 L,_ = ndimage.label(L!=0) return L
def test_connect_regions_with_grid(): try: face = sp.face(gray=True) except AttributeError: # Newer versions of scipy have face in misc from scipy import misc face = misc.face(gray=True) mask = face > 50 graph = grid_to_graph(*face.shape, mask=mask) assert_equal(ndimage.label(mask)[1], connected_components(graph)[0]) mask = face > 150 graph = grid_to_graph(*face.shape, mask=mask, dtype=None) assert_equal(ndimage.label(mask)[1], connected_components(graph)[0])
def findNeuronsFromStDev(self,applyFilter=False,sigmax=3,sigmay=3,tRange=None,sizeLimit=40,distanceLimit=6): stdFrame = np.zeros(np.shape(self.motionCorrectedMovie.mov[0])) h,w = np.shape(stdFrame) for r in range(h): for c in range(w): stdFrame[r][c] = np.std(self.motionCorrectedMovie.mov[:,r,c]) if applyFilter: stdFrame = gaussian_filter(stdFrame,[sigmax,sigmay]) if tRange == None: med = np.median(stdFrame) stdStd = np.std(stdFrame) tRange = [med + 5*stdStd, med + 4*stdStd, med + 3*stdStd, med + 2*stdStd, med + stdStd, med] conmat = np.ones((3,3)) #np.array([[0,1,0],[1,1,1],[0,1,0]]) ntot = 0 for threshold in tRange: stdFrameFree = stdFrame for m in self.neuronMasks: stdFrameFree = stdFrameFree * (1-(m>0)) mask = stdFrameFree*(stdFrameFree > threshold) mask, n = label(mask > 0, conmat) nRejected = 0 nPruned = 0 avgPixelsPruned = 0 for i in range(1,n+1): iROI = (mask == i) iSize = np.sum(iROI) stdROI = iROI * stdFrameFree [[rmax],[cmax]] = np.where(stdROI == np.max(stdROI)) r,c = np.where(iROI == 1) for j in range(len(r)): if ((r[j]-rmax)**2 + (c[j]-cmax)**2)**0.5 < distanceLimit: iROI[r[j],c[j]] = 0 mask = mask * (1-iROI) diff = np.sum(iROI) iSizePruned = iSize - diff if iSizePruned < sizeLimit: iROI = (mask == i) mask = mask * (1-iROI) nRejected = nRejected + 1 elif diff > 0: nPruned = nPruned + 1 avgPixelsPruned = avgPixelsPruned + diff avgPixelsPruned = avgPixelsPruned / float(nPruned) mask, nfinal = label(mask > 0, conmat) self.neuronMasks.append(mask) print '%i potential neurons found above threshold %f' % (n,threshold) print '%i rejected after pruning for having size < %i' % (nRejected,sizeLimit) print '%i kept neurons pruned, average %i pixels removed' % (nPruned,avgPixelsPruned) ntot = ntot + n - nRejected return ntot
def all_alive(board): black_groups, black_count = nd.label(board == 1) empty_adjacent_count = nd.filters.convolve((board == 0).astype(np.uint8), np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]), mode='constant') black_adjacent_max = nd.maximum(empty_adjacent_count, black_groups, np.arange(1, black_count)) if np.any(black_adjacent_max == 0): return False white_groups, white_count = nd.label(board == 2) white_adjacenet_max = nd.maximum(empty_adjacent_count, white_groups, np.arange(1, white_count)) if np.any(white_adjacenet_max == 0): return False return True
def find_albino_features(self, T, im): import scipy.ndimage as ndi binarized = zeros_like(T) binarized[T > self.albino_threshold] = True (labels, nlabels) = ndi.label(binarized) slices = ndi.find_objects(labels) intensities = [] transform_means = [] if len(slices) < 2: return (None, None) for s in slices: transform_means.append(mean(T[s])) intensities.append(mean(im[s])) sorted_transform_means = argsort(transform_means) candidate1 = sorted_transform_means[-1] candidate2 = sorted_transform_means[-2] c1_center = array(ndi.center_of_mass(im, labels, candidate1 + 1)) c2_center = array(ndi.center_of_mass(im, labels, candidate2 + 1)) if intensities[candidate1] > intensities[candidate2]: return (c2_center, c1_center) else: return (c1_center, c2_center)
def test_connect_regions(): lena = sp.lena() for thr in (50, 150): mask = lena > thr graph = img_to_graph(lena, mask) nose.tools.assert_equal(ndimage.label(mask)[1], cs_graph_components(graph)[0])
def quantify_fibers2(self, args, vis_pix, thresholded_copix, im_co, rgb_pix): #label feature with number (2) vis_pix_matrix = vis_pix.reshape(im_co.size[1],im_co.size[0]) all_array, num_features = si.label(vis_pix_matrix,structure=[[1,1,1],[1,1,1],[1,1,1]]) co_fiber_sizes = [] for fiber_slice in si.find_objects(all_array): fiber_pix = (thresholded_copix[fiber_slice].flatten()) > 0 fiber_types = collections.Counter(all_array[fiber_slice].flatten()) max_type = None if len(fiber_types) > 2: max_count = 0 for ft in fiber_types: if ft > 0 and fiber_types[ft] > max_count: max_type = ft max_count = fiber_types[ft] if float(np.sum(fiber_pix))/float(fiber_pix.size) > .3: #if > 30% of the pixels are colocalized call entire fiber slow slow_fiber_size = 0 for i in xrange(fiber_slice[0].start,fiber_slice[0].stop): for j in xrange(fiber_slice[1].start,fiber_slice[1].stop): if vis_pix_matrix[i][j] == 1: if max_type: if all_array[i][j] == max_type: vis_pix_matrix[i][j] = 2 rgb_pix[i*im_co.size[0] + j] = (255, 255, 0) slow_fiber_size += 1 else: vis_pix_matrix[i][j] = 2 rgb_pix[i*im_co.size[0] + j] = (255, 255, 0) slow_fiber_size += 1 co_fiber_sizes.append(slow_fiber_size) vis_pix = vis_pix_matrix.flatten() return np.array(co_fiber_sizes)
def mark_lalo_anomoly(lat, lon): """mask pixels with abnormal values (0, etc.) This is found on sentinelStack multiple swath lookup table file. """ # ignore pixels with zero value zero_mask = np.multiply(lat != 0., lon != 0.) # ignore anomaly non-zero values # by get the most common data range (d_min, d_max) based on histogram mask = np.array(zero_mask, np.bool_) for data in [lat, lon]: bin_value, bin_edge = np.histogram(data[mask], bins=10) # if there is anomaly, histogram won't be evenly distributed while np.max(bin_value) > np.sum(zero_mask) * 0.3: # find the continous bins where the largest bin is --> normal data range bin_value_thres = ut.median_abs_deviation_threshold(bin_value, cutoff=3) bin_label = ndimage.label(bin_value > bin_value_thres)[0] idx = np.where(bin_label == bin_label[np.argmax(bin_value)])[0] # convert to min/max data value bin_step = bin_edge[1] - bin_edge[0] d_min = bin_edge[idx[0]] - bin_step / 2. d_max = bin_edge[idx[-1]+1] + bin_step / 2. mask *= np.multiply(data >= d_min, data <= d_max) bin_value, bin_edge = np.histogram(data[mask], bins=10) lat[mask == 0] = 90. lon[mask == 0] = 0. return lat, lon, mask
draw_line_endpoints(img, linesEndpoints) lower = np.array(lower, dtype="uint8") # brojevi su svelije nijanse sive upper = np.array(upper, dtype="uint8") mask = cv2.inRange(img, lower, upper) # cv2.imshow("maska", mask) img0 = 1.0 * mask img0 = cv2.dilate( img0, kernel ) #ako je broj prekriven sumom, dilatacija ce popuniti te praznine na samoj cifri img0 = cv2.dilate(img0, kernel) #jedna dilatacija nije bila dovoljna #cv2.imshow("dilat", img0) labeled, nr_objects = ndimage.label(img0) objects = ndimage.find_objects(labeled) for i in range(nr_objects): loc = objects[i] (xc, yc) = (int((loc[1].stop + loc[1].start) / 2), int((loc[0].stop + loc[0].start) / 2)) (dxc, dyc) = (int(loc[1].stop - loc[1].start), int(loc[0].stop - loc[0].start)) if (dxc < 12 and dyc < 12): continue cv2.circle(img, (xc, yc), 16, (25, 25, 255), 1) elem = {'center': (xc, yc), 'size': (dxc, dyc), 't': t} lst = inRange(20, elem, elements)
def compute_metrics(pred_mask_binary, mask, metrics, img_name): '''Read an image and return post-processed prediction according to a model. Keyword arguments: pred_mask_binary -- predicted mask mask -- true mask metrics -- pandas dataframe to store image-wise metrics img_name -- name of the image to be processed Return: metrics -- pandas dataframe with image-wise metrics ''' # extract predicted objects and counts pred_label, pred_count = ndimage.label(pred_mask_binary) pred_objs = ndimage.find_objects(pred_label) # compute centers of predicted objects pred_centers = [] for ob in pred_objs: pred_centers.append(((int( (ob[0].stop - ob[0].start) / 2) + ob[0].start), (int( (ob[1].stop - ob[1].start) / 2) + ob[1].start))) # extract target objects and counts targ_label, targ_count = ndimage.label(mask) targ_objs = ndimage.find_objects(targ_label) # compute centers of target objects targ_center = [] for ob in targ_objs: targ_center.append(((int( (ob[0].stop - ob[0].start) / 2) + ob[0].start), (int( (ob[1].stop - ob[1].start) / 2) + ob[1].start))) # associate matching objects, true positives tp = 0 fp = 0 for pred_idx, pred_obj in enumerate(pred_objs): min_dist = 30 # 1.5-cells distance is the maximum accepted TP_flag = 0 for targ_idx, targ_obj in enumerate(targ_objs): dist = hypot(pred_centers[pred_idx][0] - targ_center[targ_idx][0], pred_centers[pred_idx][1] - targ_center[targ_idx][1]) if dist < min_dist: TP_flag = 1 min_dist = dist index = targ_idx if TP_flag == 1: tp += 1 TP_flag = 0 targ_center.pop(index) targ_objs.pop(index) # derive false negatives and false positives fn = targ_count - tp fp = pred_count - tp # update metrics dataframe metrics.loc[img_name] = [tp, fp, fn, targ_count, pred_count] return (metrics)
def old_make_single_chipmask(fibparms, meansep, masktype='stellar', exclude_top_and_bottom=False, nx=4112, ny=4096): """OLD ROUTINE, NOT CURRENTLY IN USE!!!""" # some housekeeping... while masktype.lower() not in [ "stellar", "sky2", "sky3", "lfc", "thxe", "background", "bg" ]: print('ERROR: chipmask "type" not recognized!!!') masktype = raw_input( 'Please enter "type" - valid options are ["object" / "sky2" / "sky3" / "LFC" / "ThXe" / "background" or "bg"]: ' ) # ny, nx = img.shape chipmask = np.zeros((ny, nx)) # now actually make the "chipmask" for pix in np.arange(nx): if (pix + 1) % 100 == 0: print('Pixel column ' + str(pix + 1) + '/4112') for order in sorted(fibparms.keys()): if masktype.lower() == 'stellar': # for the object-fibres chipmask, take the middle between the last object fibre and first sky fibre at each end (ie the "gaps") f_upper = 0.5 * (fibparms[order]['fibre_04']['mu_fit'] + fibparms[order]['fibre_06']['mu_fit']) f_lower = 0.5 * (fibparms[order]['fibre_24']['mu_fit'] + fibparms[order]['fibre_26']['mu_fit']) elif masktype.lower() == 'sky2': # for the 2 sky fibres near the ThXe, we use the "gap" as the upper bound, and as the lower bound the trace of the lowermost sky fibre # minus half the average fibre separation for this order and pixel location, ie halfway between the lowermost sky fibre and the ThXe fibre f_upper = 0.5 * (fibparms[order]['fibre_24']['mu_fit'] + fibparms[order]['fibre_26']['mu_fit']) f_lower = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower.coefficients[-1] -= 0.5 * meansep[order][pix] elif masktype.lower() == 'sky3': # for the 3 sky fibres near the LFC, we use the "gap" as the lower bound, and as the upper bound the trace of the uppermost sky fibre # plus half the average fibre separation for this order and pixel location, ie halfway between the uppermost sky fibre and the LFC fibre f_upper = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper.coefficients[-1] += 0.5 * meansep[order][pix] f_lower = 0.5 * (fibparms[order]['fibre_04']['mu_fit'] + fibparms[order]['fibre_06']['mu_fit']) elif masktype.lower() == 'lfc': # for the LFC fibre, we assume as the lower bound the trace of the uppermost sky fibre plus half the average fibre separation for this order and pixel location, # ie halfway between the uppermost sky fibre and the LFC fibre, and as the upper bound the trace of the uppermost sky fibre plus two times the average # fibre separation for this order and pixel location f_upper = 1 * fibparms[order]['fibre_02']['mu_fit'] f_upper.coefficients[-1] += 2. * meansep[order][pix] f_lower = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower.coefficients[-1] += 0.5 * meansep[order][pix] elif masktype.lower() == 'thxe': # for the ThXe fibre, we assume as the upper bound the trace of the lowermost sky fibre minus half the average fibre separation for this order and pixel location, # ie halfway between the lowermost sky fibre and the ThXe fibre, and as the lower bound the trace of the lowermost sky fibre minus two times the average # fibre separation for this order and pixel location f_upper = 1 * fibparms[order]['fibre_27']['mu_fit'] f_upper.coefficients[-1] -= 0.5 * meansep[order][pix] f_lower = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower.coefficients[-1] -= 2. * meansep[order][pix] elif masktype.lower() in ['background', 'bg']: # could either do sth like 1. - np.sum(chipmask_i), but can also just use the lower bound of ThXe and the upper bound of LFC f_upper = 1 * fibparms[order]['fibre_02']['mu_fit'] f_upper.coefficients[-1] += 2. * meansep[order][pix] f_lower = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower.coefficients[-1] -= 2. * meansep[order][pix] else: print( 'ERROR: Nightmare! That should never happen -- must be an error in the Matrix...' ) return ymin = f_lower(pix) ymax = f_upper(pix) # these are the pixels that fall completely in the range # NOTE THAT THE CO-ORDINATES ARE CENTRED ON THE PIXELS, HENCE THE 0.5s... full_range = np.arange( np.maximum(np.ceil(ymin + 0.5), 0), np.minimum(np.floor(ymax - 0.5) + 1, ny - 1)).astype(int) if len(full_range) > 0: chipmask[full_range, pix] = 1. # bottom edge pixel if ymin > -0.5 and ymin < ny - 1 + 0.5: qlow = np.ceil(ymin - 0.5) - ymin + 0.5 chipmask[np.floor(ymin + 0.5).astype(int), pix] = qlow # top edge pixel if ymax > -0.5 and ymax < ny - 1 + 0.5: qtop = ymax - np.floor(ymax - 0.5) - 0.5 chipmask[np.ceil(ymax - 0.5).astype(int), pix] = qtop # for the background we have to invert that mask and (optionally) exclude the top and bottom regions # which still include fainter orders etc (same as in "extract_background") if masktype.lower() == 'background': chipmask = 1. - chipmask if exclude_top_and_bottom: print( 'WARNING: this fix works for the current Veloce CCD layout only!!!' ) labelled_mask, nobj = label(chipmask) # WARNING: this fix works for the current Veloce CCD layout only!!! topleftnumber = labelled_mask[ny - 1, 0] # toprightnumber = labelled_mask[ny-1,nx-1] # bottomleftnumber = labelled_mask[0,0] bottomrightnumber = labelled_mask[0, nx - 1] chipmask[labelled_mask == topleftnumber] = False # chipmask[labelled_mask == toprightnumber] = False chipmask[labelled_mask == bottomrightnumber] = False return chipmask
cmap=cm) fig.savefig( os.path.join(fig_dir, 'distribution_embedding_genotype_tbins=%d.pdf' % tbins)) #watershed it from scipy import ndimage as ndi from skimage.morphology import watershed from skimage.feature import peak_local_max local_maxi = peak_local_max(Y_xy, indices=False, footprint=np.ones((7, 7))) local_maxi = peak_local_max(Y_xy, indices=False, footprint=np.ones((10, 10))) markers = ndi.label(local_maxi)[0] labels = watershed(-Y_xy, markers) #, mask=image) #classify points Y_idx = np.array(np.round( (Y - [xmin, ymin]) / [xmax - xmin, ymax - ymin] * (npts - 1)), dtype=int) Y_idx[Y_idx < 0] = 0 Y_idx[Y_idx > npts - 1] = npts - 1 Y_class = labels[Y_idx[:, 0], Y_idx[:, 1]] cmap = 'jet' cmap = 'nipy_spectral' cmap = 'hsv' cmap = 'gist_ncar'
def Kristen_render(name_pattern, group_id, mCherry, extranuclear_mCherry_pad, GFP_orig, mCherry_orig, output, save=False, directory_to_save_to='verification'): labels, _ = ndi.label(extranuclear_mCherry_pad) unique_segmented_cells_labels = np.unique(labels)[1:] mCherry_cutoff = np.zeros_like(mCherry) qualifying_cell_label = [] qualifying_regression_stats = [] for cell_label in unique_segmented_cells_labels: mCherry_2 = np.zeros_like(mCherry) my_mask = labels == cell_label average_apply_mask = np.mean(mCherry[my_mask]) intensity = np.sum(mCherry[my_mask]) binary_pad = np.zeros_like(mCherry) binary_pad[my_mask] = 1 pixel = np.sum(binary_pad[my_mask]) if (average_apply_mask > .05 or intensity > 300) and pixel > 4000: GFP_limited_to_cell_mask = cf._3d_stack_2d_filter(GFP_orig, my_mask) mCherry_limited_to_cell_mask = cf._3d_stack_2d_filter(mCherry_orig, my_mask) qualifying_3d_GFP = GFP_limited_to_cell_mask[mCherry_limited_to_cell_mask>50] average_3d_GFP = np.mean(qualifying_3d_GFP) median_3d_GFP = np.median(qualifying_3d_GFP) std_3d_GFP = np.std(qualifying_3d_GFP) sum_qualifying_GFP = np.sum(qualifying_3d_GFP) nonqualifying_3d_GFP = GFP_limited_to_cell_mask[mCherry_limited_to_cell_mask<=50] average_nonqualifying_3d_GFP = np.mean(nonqualifying_3d_GFP) median_nonqualifying_3d_GFP = np.median(nonqualifying_3d_GFP) std_nonqualifying_3d_GFP = np.std(nonqualifying_3d_GFP) sum_nonqualifying_GFP = np.sum(nonqualifying_3d_GFP) sum_total_GFP = sum_qualifying_GFP + sum_nonqualifying_GFP percent_qualifying_over_total_GFP = sum_qualifying_GFP/sum_total_GFP # report the percentage too or sums are sufficient? GFP_orig_qualifying = cf._3d_stack_2d_filter(GFP_orig, my_mask) mCherry_orig_qualifying = cf._3d_stack_2d_filter(mCherry_orig, my_mask) mCherry_1d = mCherry_orig_qualifying[mCherry_orig_qualifying > 50] GFP_1d = GFP_orig_qualifying[mCherry_orig_qualifying>50] regression_results = stats.linregress(GFP_1d, mCherry_1d) mCherry_2[my_mask] = mCherry[my_mask] mCherry_cutoff[my_mask] = mCherry[my_mask] qualifying_cell_label.append(cell_label) qualifying_regression_stats.append((regression_results[0], regression_results[2], regression_results[3])) name_pattern_split = name_pattern.split(' - ') transfection_label = name_pattern_split[0] cell_type = name_pattern_split[1] exp_time = name_pattern_split[2] image_number = name_pattern_split[4] with open(output, 'ab') as output_file: writer = csv_writer(output_file, delimiter='\t') writer.writerow([transfection_label, cell_type, exp_time, image_number, cell_label, sum_qualifying_GFP, sum_total_GFP, average_3d_GFP, median_3d_GFP, std_3d_GFP, average_nonqualifying_3d_GFP, median_nonqualifying_3d_GFP, std_nonqualifying_3d_GFP, regression_results[0], regression_results[2], regression_results[3]]) plt.figure(figsize=(26.0, 15.0)) plt.title('Kristen\'s Data') plt.suptitle(name_pattern) main_ax = plt.subplot(221) plt.subplot(221, sharex=main_ax, sharey=main_ax) plt.title('mCherry Binary') im = plt.imshow(extranuclear_mCherry_pad, interpolation='nearest', cmap = 'hot') plt.colorbar(im) plt.subplot(222, sharex=main_ax, sharey=main_ax) plt.title('mCherry') plt.imshow(mCherry, interpolation='nearest') plt.contour(extranuclear_mCherry_pad, [0.5], colors='k') plt.subplot(223) dplt.better2D_desisty_plot(GFP_1d, mCherry_1d) plt.title('mCherry Intensity as a Function of GFP Voxel') plt.xlabel('GFP Voxel') plt.ylabel('mCherry Intensity') plt.subplot(224, sharex=main_ax, sharey=main_ax) plt.title('mCherry-cutoff applied') plt.imshow(mCherry_2, interpolation='nearest') if not save: plt.show() else: name_puck = directory_to_save_to + '/' + 'Kristen-' + name_pattern+ '_cell' + str(cell_label)+ '.png' plt.savefig(name_puck) plt.close() plt.figure(figsize=(26.0, 15.0)) main_ax = plt.subplot(121) plt.subplot(121, sharex=main_ax, sharey=main_ax) plt.suptitle('mCherry Before and After Qualifying Cell Cutoff is Applied') plt.title('mCherry') im = plt.imshow(mCherry, interpolation='nearest') plt.colorbar(im) plt.subplot(122, sharex=main_ax, sharey=main_ax) plt.title('mCherry') plt.imshow(mCherry_cutoff, interpolation='nearest') if not save: plt.show() else: name_puck = directory_to_save_to + '/' + 'Kristen-' + name_pattern + 'cutoff_app' + '.png' plt.savefig(name_puck) plt.close() return qualifying_regression_stats
def generate_saliency(self, input, target): #self.model.zero_grad() output = self.model(input) #index: 0 layer: HP # index: 1 layer: Ship # index: 2 layer: Small Towers # index: 3 layer: Big Towers # index: 4 layer: Small Cities # index: 5 layer: Big Cities # index: 6 layer: Friend # index: 7 layer: Enemy #return (input.grad.clone()[0] * input) input2 = input.cpu().clone() image = np.zeros((40, 40)) input2 = input2.view(40, 40, 8) #logical or of the input images to get the original image #only do or over small big cities and towers to get proper coordinates of cities and towers #otherwise it will include enemy ship too if enemy channel is included which will cause object to #be merged with tower or city object for i in range(2,6): if i!= 0: image = np.logical_or(image, input2[:, :, i].numpy())*1 #get the number of objects in the image labeled_array, num_objects = label(image) indices = [] for i in range(num_objects): indices.append(np.argwhere(labeled_array == i+1)) #special stuff for ship channel ship_image = input2[:, :, 1].clone().numpy() ship_image[19][20] = 0 ship_image[20][20] = 0 ship_image[21][20] = 0 ship_array, ships = label(ship_image) ship_indices = [] for i in range(ships): ship_indices.append(np.argwhere(ship_array == i+1)) #self.generate_file(ship_array, 'mod_ship_array') hp_array, hp = label(input2[:, :, 0].numpy()) hp_indices = [] for i in range(hp): hp_indices.append(np.argwhere(hp_array == i+1)) values = torch.zeros(40*40*5) values = values.view(40, 40, 5) input2 = input.clone() input2 = input2.view(40, 40, 8) # index: 0 layer: HP # index: 1 layer: Ship # index: 2 layer: Small Towers # index: 3 layer: Big Towers # index: 4 layer: Small Cities # index: 5 layer: Big Cities # index: 6 layer: Friend # index: 7 layer: Enemy #output layers: #0 HP #1 agent #2 size #3 type # friend/enemy #here i refers to the output salient layers #print('num_objects', num_objects) for i in range(5): if i==0:# output HP for j in range(hp): for k in range(hp_indices[j].shape[0]): x = hp_indices[j][k][0] y = hp_indices[j][k][1] temp = 0.3*input2[:, :, 0][x][y] input2[:, :, 0][x][y] += temp perturbed_output = self.model(input2.view(1, 12800)) gradient = (perturbed_output - output)/temp input2 = input.clone() input2 = input2.view(40, 40, 8) for k in range(hp_indices[j].shape[0]): x = hp_indices[j][k][0] y = hp_indices[j][k][1] values[:, :, 0][x][y] = gradient[:, target] elif i==1:#output agent for j in range(ships): for k in range(ship_indices[j].shape[0]): x = ship_indices[j][k][0] y = ship_indices[j][k][1] if input2[:, :, 1][x][y] == 1: input2[:, :, 1][x][y] = 0 perturbed_output = self.model(input2.view(1, 12800)) gradient = (perturbed_output - output) input2 = input.clone() input2 = input2.view(40, 40, 8) for k in range(ship_indices[j].shape[0]): x = ship_indices[j][k][0] y = ship_indices[j][k][1] values[:, :, 1][x][y] = gradient[:, target] elif i==2: #output size #print('in i== 2') for l in range(2, 6): #print('layer: ',l) for j in range(num_objects): # print('object: ',j) s = 0 for k in range(indices[j].shape[0]): x = indices[j][k][0] y = indices[j][k][1] # print('x: '+str(x)+' y: '+str(y)) # print('Value of input: '+str(input2[:, :, i][x][y])) # print(input2[:, :, l][x][y]) if l == 2 or l==4: #small tower/city if input2[:, :, l][x][y] == 1: s = 1 input2[:, :, l][x][y] = 0 input2[:, :, l+1][x][y] = 1 else: #big tower/city if input2[:, :, l ][x][y] == 1: s = 1 input2[:, :, l][x][y] = 0 input2[:, :, l-1][x][y] = 1 perturbed_output = self.model(input2.view(1, 12800)) gradient = (perturbed_output - output) #print(saliency) input2 = input.clone() input2 = input2.view(40, 40, 8) if s==1: for k in range(indices[j].shape[0]): x = indices[j][k][0] y = indices[j][k][1] values[:, :, 2][x][y] = gradient[:, target] #print(saliency[0][target]) elif i==3: #output type for l in range(2, 6): for j in range(num_objects): s = 0 for k in range(indices[j].shape[0]): x = indices[j][k][0] y = indices[j][k][1] # print('x: '+str(x)+' y: '+str(y)) # print('Value of input: '+str(input2[:, :, i][x][y])) if l == 2 or l == 3: #small tower/city if input2[:, :, l][x][y] == 1: s = 1 input2[:, :, l][x][y] = 0 input2[:, :, l+2][x][y] = 1 else: #big tower/city if input2[:, :, l ][x][y] == 1: s = 1 input2[:, :, l][x][y] = 0 input2[:, :, l-2][x][y] = 1 perturbed_output = self.model(input2.view(1, 12800)) gradient = (perturbed_output - output) #print(saliency) input2 = input.clone() input2 = input2.view(40, 40, 8) if s==1: for k in range(indices[j].shape[0]): x = indices[j][k][0] y = indices[j][k][1] values[:, :, 3][x][y] = gradient[:, target] else:# output frenemy for l in range(6, 8): for j in range(num_objects): s = 0 for k in range(indices[j].shape[0]): x = indices[j][k][0] y = indices[j][k][1] if l == 6: if input2[:, :, l][x][y] == 1: s = 1 input2[:, :, l][x][y] = 0 input2[:, :, l+1][x][y] = 1 else: if input2[:, :, l][x][y] == 1: s = 1 input2[:, :, l][x][y] = 0 input2[:, :, l-1][x][y] = 1 perturbed_output = self.model(input2.view(1, 12800)) gradient = (perturbed_output - output) #print(s) input2 = input.clone() input2 = input2.view(40, 40, 8) if s==1: for k in range(indices[j].shape[0]): x = indices[j][k][0] y = indices[j][k][1] values[:, :, 4][x][y] = gradient[:, target] #for l in range(6): # torchvision.utils.save_image(saliency[:, :, l], "Image perturbed: "+str(i) + "/" + "object perturbed: "+str(j)+ "/" + str(l) + ".png", normalize=True) return (values.view(1, 40*40*5))
""" Display a labels layer above of an image layer using the add_labels and add_image APIs """ from skimage import data from scipy import ndimage as ndi from napari_animation import Animation import napari blobs = data.binary_blobs(length=128, volume_fraction=0.1, n_dim=3) viewer = napari.view_image(blobs.astype(float), name='blobs') labeled = ndi.label(blobs)[0] viewer.add_labels(labeled, name='blob ID') animation = Animation(viewer) viewer.update_console({'animation': animation}) animation.capture_keyframe() viewer.camera.zoom = 0.2 animation.capture_keyframe() viewer.camera.zoom = 10.0 viewer.camera.center = (0, 40.0, 10.0) animation.capture_keyframe() viewer.dims.current_step = (60, 0, 0) animation.capture_keyframe(steps=60) viewer.dims.current_step = (0, 0, 0) animation.capture_keyframe(steps=60) viewer.reset_view() animation.capture_keyframe()
def compute_metrics2D(bin_im, dist_trsf_im, AP_pos=None, vs=None): """ Given an isotropic 2D binary image `bin_im`, a distance transform image `dist_trsf_im` of `bin_im`, a 2D position and a voxel size `vs`, computes the length, the width, the aspect ratio, the solidity, the sphericity, the volume and the surface of the binary image. Notes: - `bin_im` has to be isotropic otherwise the distances won't be computed correctly - `bin_im` and `dist_trsf_im` must share the same shape Parameters ---------- bin_im : array_like A n*m*l binary array with one single connected component dist_trsf_im : array_like A distance transformation of the bin_im array AP_pos : ((float, float), (float, float)) optional x, y position of the anterior part of the Neural Tube vs : float optional (default 1.) The size of the isotropic voxel in order to get measurements in physical units Returns ------- length : float The length of the masked object in the binary image width_spl : scipy.interpolate.InterpolatedUnivariateSpline The interpolated width along the masked object in the binary image width_median : float Median of the width along the masked object in the binary image AR : float The aspect ratio of the masked object in the binary image `length/median(width)` solidity : float The solidity of the masked object in the binary image Ratio of pixels in the region to pixels of the convex hull image. surface : The surface of the masked object in the binary image Number of voxels in the region perimeter : The perimeter of the masked object in the binary image circularity : The circularity of the masked object in the binary image 4*pi*(`surface`/(`perimeter`**2)) """ # Extract the largest connected component label_im = nd.label(bin_im)[0] labels = np.unique(label_im) labels = labels[labels != 0] surfaces = nd.sum(np.ones_like(label_im), index=labels, labels=label_im) final_cc = labels[np.argmax(surfaces)] bin_im = (label_im == final_cc).astype(np.uint8) # Compute the surface, perimeter, circularity and solidity if vs is None: vs = 1. props = measure.regionprops(bin_im.astype(np.uint8))[0] surface = props.area * vs**2 perimeter = props.perimeter * vs circularity = 4 * np.pi * (surface / perimeter**2) solidity = props.solidity # Skeletonize the mask and retrieve the coordinates of the skeleton skel_im = morphology.skeletonize(bin_im).astype(np.uint8) pos_arr = np.argwhere(skel_im) pos = dict(zip(range(len(pos_arr)), pos_arr)) nodes = set(pos) neighb = {} to_treat = set([min(nodes)]) done = set() # Builds the tree of the skeleton # The nodes are the coordinates # Two nodes are linked iff they are 4-connected while 0 < len(to_treat): curr = to_treat.pop() done.add(curr) dist = np.abs(pos_arr[curr] - pos_arr) N = set(np.where(np.max(dist, axis=1) == 1)[0]) for ni in N: neighb.setdefault(curr, []).append(ni) to_treat.update(N.difference(done)) # Finds the leaves of the tree extremities = [k for k, v in neighb.items() if len(v) == 1] D_out = {} # For each leaf, finds the most distant leaf # Using Dijkstra algorithm with Pool() as pool: mapping = [(nodes, neighb, e) for e in extremities] out = pool.map(Dijkstra, mapping) pool.terminate() pool.close() D_out = dict(zip(extremities, out)) # Finds the pair (e1, e2) of most distant leaves e1 = max(D_out, key=lambda x: D_out.get(x)[1]) e2 = D_out[e1][0] prev = D_out[e1][2] curr = e2 # Retrieve and smooth the longest path of the skeleton tree skel_im[skel_im != 0] = 1 path = [] while curr in prev: path += [pos[curr]] curr = prev[curr] X, Y = zip(*path) X_smoothed = np.round(nd.filters.gaussian_filter1d(X, sigma=2)).astype( np.uint16) Y_smoothed = np.round(nd.filters.gaussian_filter1d(Y, sigma=2)).astype( np.uint16) for x, y in zip(X_smoothed, Y_smoothed): skel_im[tuple([x, y])] = 2 # Build the graph containing the longest path of the skeleton tree pos_arr = np.argwhere(skel_im == 2) pos = dict(zip(range(len(pos_arr)), pos_arr)) nodes = set(pos) neighb = {} to_treat = set([min(nodes)]) done = set() while 0 < len(to_treat): curr = to_treat.pop() done.add(curr) dist = np.abs(pos_arr[curr] - pos_arr) N = set(np.where(np.max(dist, axis=1) == 1)[0]) for ni in N: neighb.setdefault(curr, []).append(ni) to_treat.update(N.difference(done)) # Retrieve the x, y, z coordinates of the longest path first = list(neighb.keys())[0] last, b, prev = Dijkstra((nodes, neighb, first)) last, b, prev = Dijkstra((nodes, neighb, last)) current = last ordered_pos = [pos[current]] while prev.get(current, -1) != -1: current = prev[current] ordered_pos += [pos[current]] # Gets the closest points of the skeleton to # the manually informed posterior and anterior positions if AP_pos is not None: A_pos, P_pos = AP_pos A_pos = np.array(A_pos) P_pos = np.array(P_pos) dist_to_A = np.linalg.norm(ordered_pos - A_pos, axis=1) A_pos = np.argmin(dist_to_A) dist_to_P = np.linalg.norm(ordered_pos - P_pos, axis=1) P_pos = np.argmin(dist_to_P) # Crop and reorder (if necessary) the skeleton if A_pos < P_pos: ordered_pos = ordered_pos[A_pos:P_pos + 1] ordered_pos = ordered_pos[::-1] P_pos, A_pos = A_pos, P_pos else: ordered_pos = ordered_pos[P_pos:A_pos + 1] # Computes, smooth and interpolate the width along the longest path dist_trsf_im *= vs x, y = zip(*ordered_pos) width = dist_trsf_im[(x, y)].flatten() width = nd.filters.gaussian_filter1d(width.astype(np.float), sigma=4) X = np.linspace(0, 1, len(width)) width_spl = InterpolatedUnivariateSpline(X, width) # Computes the length of the longest path in physical units (given by vs) tmp = np.array(list(zip(x, y))) * vs length = np.sum(np.linalg.norm(tmp[:-1] - tmp[1:], axis=1)) # Computes the Aspect Ration as the length over the median width AR = length / np.median(width) return (length, width_spl, np.median(width), AR, solidity, surface, perimeter, circularity)
def Fragmenter(): tmpOb = Config.Load( frgSpec, pth.expanduser( '~/korenbergNAS/3D_database/Working/configuration_files/SidescapeRelateBlockface/M{0}/section_{1}/section_{1}_frag0.yaml' .format(secOb.mkyNum, secOb.secNum))) dictBuild = {} #Load in the whole image so that the fragment can cropped out ssiSrc, bfiSrc, ssiMsk, bfiMsk = Loader(tmpOb, ca.MEM_HOST) #Because some of the functions only woth with gray images bfiGry = ca.Image3D(bfiSrc.grid(), bfiSrc.memType()) ca.Copy(bfiGry, bfiSrc, 1) lblSsi, _ = ndimage.label(np.squeeze(ssiMsk.asnp()) > 0) lblBfi, _ = ndimage.label(np.squeeze(bfiMsk.asnp()) > 0) seedPt = np.squeeze(pp.LandmarkPicker([lblBfi, lblSsi])) subMskBfi = common.ImFromNPArr(lblBfi == lblBfi[seedPt[0, 0], seedPt[0, 1]].astype('int8'), sp=bfiSrc.spacing(), orig=bfiSrc.origin()) subMskSsi = common.ImFromNPArr(lblSsi == lblSsi[seedPt[1, 0], seedPt[1, 1]].astype('int8'), sp=ssiSrc.spacing(), orig=ssiSrc.origin()) bfiGry *= subMskBfi bfiSrc *= subMskBfi ssiSrc *= subMskSsi #Pick points that are the bounding box of the desired subvolume corners = np.array( pp.LandmarkPicker( [np.squeeze(bfiGry.asnp()), np.squeeze(ssiSrc.asnp())])) bfiCds = corners[:, 0] ssiCds = corners[:, 1] #Extract the region from the source images bfiRgn = cc.SubVol(bfiSrc, xrng=[bfiCds[0, 0], bfiCds[1, 0]], yrng=[bfiCds[0, 1], bfiCds[1, 1]]) ssiRgn = cc.SubVol(ssiSrc, xrng=[ssiCds[0, 0], ssiCds[1, 0]], yrng=[ssiCds[0, 1], ssiCds[1, 1]]) #Extract the region from the mask images rgnMskSsi = cc.SubVol(subMskSsi, xrng=[ssiCds[0, 0], ssiCds[1, 0]], yrng=[ssiCds[0, 1], ssiCds[1, 1]]) rgnMskBfi = cc.SubVol(subMskBfi, xrng=[bfiCds[0, 0], bfiCds[1, 0]], yrng=[bfiCds[0, 1], bfiCds[1, 1]]) dictBuild['rgnBfi'] = np.divide( bfiCds, np.array(bfiSrc.size().tolist()[0:2], 'float')).tolist() dictBuild['rgnSsi'] = np.divide( ssiCds, np.array(ssiSrc.size().tolist()[0:2], 'float')).tolist() #Check the output directory for the source files of the fragment if not pth.exists( pth.expanduser(secOb.ssiSrcPath + 'frag{0}'.format(frgNum))): os.mkdir(pth.expanduser(secOb.ssiSrcPath + 'frag{0}'.format(frgNum))) if not pth.exists( pth.expanduser(secOb.bfiSrcPath + 'frag{0}'.format(frgNum))): os.mkdir(pth.expanduser(secOb.bfiSrcPath + 'frag{0}'.format(frgNum))) #Check the output directory for the mask files of the fragment if not pth.exists( pth.expanduser(secOb.ssiMskPath + 'frag{0}'.format(frgNum))): os.mkdir(pth.expanduser(secOb.ssiMskPath + 'frag{0}'.format(frgNum))) if not pth.exists( pth.expanduser(secOb.bfiMskPath + 'frag{0}'.format(frgNum))): os.mkdir(pth.expanduser(secOb.bfiMskPath + 'frag{0}'.format(frgNum))) dictBuild[ 'ssiSrcName'] = 'frag{0}/M{1}_01_ssi_section_{2}_frag1.tif'.format( frgNum, secOb.mkyNum, secOb.secNum) dictBuild[ 'bfiSrcName'] = 'frag{0}/M{1}_01_bfi_section_{2}_frag1.mha'.format( frgNum, secOb.mkyNum, secOb.secNum) dictBuild[ 'ssiMskName'] = 'frag{0}/M{1}_01_ssi_section_{2}_frag1_mask.tif'.format( frgNum, secOb.mkyNum, secOb.secNum) dictBuild[ 'bfiMskName'] = 'frag{0}/M{1}_01_bfi_section_{2}_frag1_mask.tif'.format( frgNum, secOb.mkyNum, secOb.secNum) #Write out the masked and cropped images so that they can be loaded from the YAML file #The BFI region needs to be saved as color and mha format so that the grid information is carried over. common.SaveITKImage( ssiRgn, pth.expanduser(secOb.ssiSrcPath + dictBuild['ssiSrcName'])) cc.WriteColorMHA( bfiRgn, pth.expanduser(secOb.bfiSrcPath + dictBuild['bfiSrcName'])) common.SaveITKImage( rgnMskSsi, pth.expanduser(secOb.ssiMskPath + dictBuild['ssiMskName'])) common.SaveITKImage( rgnMskBfi, pth.expanduser(secOb.bfiMskPath + dictBuild['bfiMskName'])) frgOb = Config.MkConfig(dictBuild, frgSpec) updateFragOb(frgOb) return None
# We can solve this by applying some smoothing to the image data. # Here we apply a 2D Gaussian smoothing function to the data. data2 = ndimage.gaussian_filter(aiamap.data * ~mask, 14) ############################################################################## # The issue with the filtering is that it create pixels where the values are # small (<100), so when we go on later to label this array, # we get one large region which encompasses the entire array. # If you want to see, just remove this line. data2[data2 < 100] = 0 ############################################################################## # Now we will make a second SunPy map with this smoothed data. aiamap2 = sunpy.map.Map(data2, aiamap.meta) ############################################################################## # The function `scipy.ndimage.label` counts the number of contiguous regions # in an image. labels, n = ndimage.label(aiamap2.data) ############################################################################## # Finally, we plot the smoothed bright image data, along with the estimate of # the number of distinct regions. We can see that approximately 6 distinct hot # regions are present above the 10% of the maximum level. plt.figure() ax = plt.subplot(projection=aiamap) aiamap.plot() plt.contour(labels) plt.figtext(0.3, 0.2, f'Number of regions = {n}', color='white') plt.show()
def make_single_chipmask(fibparms, meansep, masktype='stellar', exclude_top_and_bottom=True, nx=4112, ny=4096, use_lfc=False, debug_level=0, timit=False): if timit: start_time = time.time() # some housekeeping... while masktype.lower() not in [ "stellar", "sky2", "sky3", "lfc", "thxe", "background", "bg" ]: print('ERROR: chipmask "type" not recognized!!!') masktype = raw_input( 'Please enter "type" - valid options are ["object" / "sky2" / "sky3" / "LFC" / "ThXe" / "background" or "bg"]: ' ) # ny, nx = img.shape chipmask = np.zeros((ny, nx)) xx = np.arange(nx) yy = np.arange(ny) XX, YY = np.meshgrid(xx, yy) # now identify regions of the chip for order in sorted(fibparms.keys()): if debug_level >= 1: print('Checking ' + order) if masktype.lower() == 'stellar': # for the object-fibres chipmask, take the middle between the last object fibre and first sky fibre at each end (ie the "gaps") f_upper = 0.5 * (fibparms[order]['fibre_04']['mu_fit'] + fibparms[order]['fibre_06']['mu_fit']) f_lower = 0.5 * (fibparms[order]['fibre_24']['mu_fit'] + fibparms[order]['fibre_26']['mu_fit']) elif masktype.lower() == 'sky2': # for the 2 sky fibres near the ThXe, we use the "gap" as the upper bound, and as the lower bound either (i) the midpoint between the lowest sky2 fibre and # the simThXe fibre, or (ii) the trace of the lowermost sky fibre minus half the average fibre separation for this order and pixel location f_upper = 0.5 * (fibparms[order]['fibre_24']['mu_fit'] + fibparms[order]['fibre_26']['mu_fit']) try: f_lower = 0.5 * (fibparms[order]['fibre_27']['mu_fit'] + fibparms[order]['fibre_28']['mu_fit']) except: f_lower = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower -= 0.5 * meansep[order] elif masktype.lower() == 'sky3': # for the 3 sky fibres near the LFC, we use the "gap" as the lower bound, and as the upper bound either (i) the midpoint between the uppermost sky3 fibre and # the LFC fibre, or (ii) the trace of the uppermost sky fibre plus half the average fibre separation for this order and pixel location if use_lfc: try: f_upper = 0.5 * (fibparms[order]['fibre_02']['mu_fit'] + fibparms[order]['fibre_01']['mu_fit']) except: f_upper = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 0.5 * meansep[order] else: f_upper = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 0.5 * meansep[order] f_lower = 0.5 * (fibparms[order]['fibre_04']['mu_fit'] + fibparms[order]['fibre_06']['mu_fit']) elif masktype.lower() == 'lfc': # for the LFC fibre, we assume as the lower bound either (i) the midpoint between the uppermost sky3 fibre and the LFC fibre, or (ii) the trace of the uppermost # sky fibre plus half the average fibre separation for this order and pixel location; as the upper bound either (i) the trace of the LFC fibre plus half the average # fibre separation for this order and pixel location, or (ii) the trace of the uppermost sky3 fibre plus one and a half times the average fibre separation for this # order and pixel location if use_lfc: try: f_upper = 1 * fibparms[order]['fibre_01'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 0.5 * meansep[order] f_lower = 0.5 * (fibparms[order]['fibre_01']['mu_fit'] + fibparms[order]['fibre_02']['mu_fit']) except: f_upper = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 1.5 * meansep[order] f_lower = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower += 0.5 * meansep[order] else: f_upper = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 1.5 * meansep[order] f_lower = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower += 0.5 * meansep[order] elif masktype.lower() == 'thxe': # for the simThXe fibre, we assume as the lower bound either (i) the trace of the simThXe fibre minus half the average fibre separation for this order and pixel # location, or (ii) the trace of the lowermost sky2 fibre minus one and a half times the average fibre separation for this order and pixel location; as the upper # bound either (i) the midpoint between the lowermost sky2 fibre and the simThXe fibre, or (ii) the trace of the lowermost sky2 fibre minus one a half times the # average fibre separation for this order and pixel location try: f_upper = 0.5 * (fibparms[order]['fibre_27']['mu_fit'] + fibparms[order]['fibre_28']['mu_fit']) f_lower = 1 * fibparms[order]['fibre_28'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower -= 0.5 * meansep[order] except: f_upper = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper -= 0.5 * meansep[order] f_lower = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower -= 1.5 * meansep[order] elif masktype.lower() in ['background', 'bg']: # could either do sth like 1. - np.sum(chipmask_i), but we can also just use the lower bound of ThXe and the upper bound of LFC # identify what is NOT background, and later "invert" that if use_lfc: try: f_upper = 1 * fibparms[order]['fibre_01'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 1. * meansep[ order] # use whole meansep here to avoid contamination from the calib sources a bit more f_lower = 1 * fibparms[order]['fibre_28'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower -= 1. * meansep[ order] # use whole meansep here to avoid contamination from the calib sources a bit more except: f_upper = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 2. * meansep[ order] # use 2 here to avoid contamination from the calib sources a bit more f_lower = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower -= 2. * meansep[ order] # use 2 here to avoid contamination from the calib sources a bit more else: f_upper = 1 * fibparms[order]['fibre_02'][ 'mu_fit'] # the multiplication with one acts like a copy f_upper += 2. * meansep[ order] # use 2 here to avoid contamination from the calib sources a bit more try: f_lower = 1 * fibparms[order]['fibre_28'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower -= 1. * meansep[order] except: f_lower = 1 * fibparms[order]['fibre_27'][ 'mu_fit'] # the multiplication with one acts like a copy f_lower -= 2. * meansep[ order] # use 2 here to avoid contamination from the calib sources a bit more # get indices of the pixels that fall into the respective regions order_stripe = (YY < f_upper) & (YY > f_lower) chipmask = np.logical_or(chipmask, order_stripe) # for the background we have to invert that mask and (optionally) exclude the top and bottom regions # which still include fainter orders etc (same as in "extract_background") if masktype.lower() in ['bg', 'background']: chipmask = np.invert(chipmask) if exclude_top_and_bottom: if debug_level >= 1: print( 'WARNING: this fix works for the current Veloce CCD layout only!!!' ) labelled_mask, nobj = label(chipmask) # WARNING: this fix works for the current Veloce CCD layout only!!! topleftnumber = labelled_mask[ny - 1, 0] # toprightnumber = labelled_mask[ny-1,nx-1] # bottomleftnumber = labelled_mask[0,0] bottomrightnumber = labelled_mask[0, nx - 1] chipmask[labelled_mask == topleftnumber] = False # chipmask[labelled_mask == toprightnumber] = False chipmask[labelled_mask == bottomrightnumber] = False return chipmask
def ndimage_alg(self, img, opts): """Island detection using scipy.ndimage Use scipy.ndimage.label to detect islands of emission in the image. Island is defined as group of tightly connected (8-connectivity for 2D images) pixels with emission. The following cuts are applied: - pixel is considered to have emission if it is 'thresh_isl' times higher than RMS. - Island should have at least 'minsize' active pixels - There should be at lease 1 pixel in the island which is 'thresh_pix' times higher than noise (peak clip). Parameters: image, mask: arrays with image data and mask mean, rms: arrays with mean & rms maps thresh_isl: threshold for 'active pixels' thresh_pix: threshold for peak minsize: minimal acceptable island size Function returns a list of Island objects. """ ### islands detection mylog = mylogger.logging.getLogger("PyBDSM." + img.log + "Islands") image = img.ch0_arr mask = img.mask_arr rms = img.rms_arr mean = img.mean_arr thresh_isl = opts.thresh_isl thresh_pix = img.thresh_pix clipped_mean = img.clipped_mean saverank = opts.savefits_rankim # act_pixels is true if significant emission if img.masked: act_pixels = ~(mask.copy()) act_pixels[~mask] = (image[~mask] - mean[~mask]) / thresh_isl >= rms[~mask] else: act_pixels = (image - mean) / thresh_isl >= rms # dimension of image rank = len(image.shape) # generates matrix for connectivity, in this case, 8-conn connectivity = nd.generate_binary_structure(rank, rank) # labels = matrix with value = (initial) island number labels, count = nd.label(act_pixels, connectivity) # slices has limits of bounding box of each such island slices = nd.find_objects(labels) img.island_labels = labels ### apply cuts on island size and peak value pyrank = N.zeros(image.shape, dtype=N.int32) res = [] islid = 0 for idx, s in enumerate(slices): idx += 1 # nd.labels indices are counted from 1 # number of pixels inside bounding box which are in island isl_size = (labels[s] == idx).sum() isl_peak = nd.maximum(image[s], labels[s], idx) isl_maxposn = tuple(N.array(N.unravel_index(N.nanargmax(image[s]), image[s].shape))+\ N.array((s[0].start, s[1].start))) if (isl_size >= img.minpix_isl ) and (isl_peak - mean[isl_maxposn]) / thresh_pix > rms[isl_maxposn]: isl = Island(image, mask, mean, rms, labels, s, idx, img.pixel_beamarea()) res.append(isl) pyrank[tuple( isl.bbox)] += N.invert(isl.mask_active) * idx // idx return res
# 4. label the junctions and extract information #prepares to write in excel excelpath = parent_dir + "/Outlines.xlsx" Workbook().save(filename=excelpath) book = load_workbook(excelpath) writer = pd.ExcelWriter(excelpath, engine='openpyxl') writer.book = book s = [[1, 1, 1], [1, 1, 1], [1, 1, 1]] #structure parameter print("detecting Outlines...") for file in sorted(glob.glob(image_j2_dir)): #loops over cut Outlines read = io.imread(file) #labels the junctions mask = read == 1 label_mask, num_labels = ndimage.label(mask, structure=s) # imwrite(parent_dir+"/Outlines_cut/Outlines_id_"+file[-7:-4]+".tif", np.uint16(label_mask)) # junctionlabels = color.label2rgb(label_mask, bg_label=0) # plt.imshow(junctionlabels) #gets info from junctions props = regionprops_table( label_mask, properties=['label', 'area', 'coords', "centroid"]) df1 = pd.DataFrame(props) df1.to_excel(writer, sheet_name="Outline_t" + file[-7:-4]) # centroids2=data2["centroids"].tolist() print("saved Outlines.xlsx") writer.save() writer.close() #-----------------------------------------------------------------------------
def label(mask): labeled, nr_true = ndimage.label(mask) return labeled
def main(): parser = argparse.ArgumentParser() parser.add_argument('--path_run', help='path to the prediction folder.') parser.add_argument('--s_min', default=50, type=int, help='min spine size') parser.add_argument('--s_max', default=45000, type=int, help='max spine size') parsed_args = parser.parse_args(sys.argv[1:]) path_run = parsed_args.path_run # get prediction folder s_min = parsed_args.s_min # get min size s_max = parsed_args.s_max # get max size path_pred = os.path.join(path_run, "prediction") # initialization header = ['FP', 'FN', 'TP', 'Sens.', 'Precision'] FP_global = list() FN_global = list() TP_global = list() SENS_global = list() PREC_global = list() FP_d = list() FN_d = list() TP_d = list() SENS_d = list() PREC_d = list() threshold_global = list() validation_cases = list() for index in range(0, 10, 1): # threshold scan coinc_thr = index / 10 # from 0 to 1 in 0.1 steps FP_thr = np.array([]) FN_thr = np.array([]) TP_thr = np.array([]) dir = listdir(path_pred) for case_folder in dir: # for each case path, val_case = os.path.split(case_folder) # load gt and prediction files truth_file = os.path.join(path_pred, case_folder, "truth.nii.gz") truth_image = nib.load(truth_file) truth = truth_image.get_data() prediction_file = os.path.join(path_pred, case_folder, "prediction.nii.gz") prediction_image = nib.load(prediction_file) prediction = prediction_image.get_data() ''' DENDRITE ''' if index == 0: # run just the first time print("dendrite case: " + case_folder) # get dendrite coords fot GT and prediction den_pred = np.where(prediction == [150]) den_gt = np.where(truth == [150]) # transpose den_pred_t = np.transpose(np.asarray(den_pred)) den_gt_t = np.transpose(np.asarray(den_gt)) tp_d = 0 # init # count number of coincident coords for element in den_pred_t: find = np.where((den_gt_t == element).all(axis=1)) if find[0].size == 1: tp_d = tp_d + 1 # calculate evaluation metrics fp_d = den_pred_t.shape[0] - tp_d fn_d = den_gt_t.shape[0] - tp_d # append dendrite metrics FP_d.append(fp_d) FN_d.append(fn_d) TP_d.append(tp_d) SENS_d.append(tp_d / (tp_d + fn_d)) PREC_d.append(tp_d / (tp_d + fp_d)) validation_cases.append(val_case) ''' SPINE ''' # init tp_case = 0 fn_case = 0 used_list = list() # already detected spines # delete dendrite from GT and prediction prediction[den_pred[0], den_pred[1], den_pred[2]] = 0 truth[den_gt[0], den_gt[1], den_gt[2]] = 0 # get gt and prediction labels label_prediction, num_labels_prediction = label(prediction) label_truth, num_labels_truth = label(truth) # get gt and predictions spines props_pred = regionprops(label_prediction) # get prediction blobs props_truth = regionprops(label_truth) # preprocess prediction spines for spinePred in range(num_labels_prediction): # for each spine size = props_pred[spinePred].area # get size if size <= s_min or size >= s_max: # if not in between thresholds prediction[ props_pred[spinePred].coords[:, 0], props_pred[spinePred].coords[:, 1], props_pred[spinePred].coords[:, 2]] = 0 # delete spine # get new prediction labels and spines label_prediction, num_labels_prediction = label(prediction) props_pred = regionprops(label_prediction) for spineGT in range( num_labels_truth): # for each spine in gt (spineGT) # print progression prog = (spineGT / num_labels_truth) * 100 print("case: " + case_folder + " - Progreso gt to pred: " + str(round(prog, 1)) + "%") # init coincide_list_GT = list() coincide_list_Pred = list() coordsGT = props_truth[spineGT].coords # get spineGT coords for spinePred in range( num_labels_prediction ): # for each spine in prediction (spinePred) # init counter_sp_coord = 0 coordsPred = props_pred[ spinePred].coords # get spinePred coords for pos in coordsGT: # for each pixel in SpineGT find = np.where((coordsPred == pos).all( axis=1)) # look if it is in spinePred if find[0].size == 1: # if it is, count 1 counter_sp_coord += 1 # calculate % of pixels found, respect gt and pred size percentageGT = counter_sp_coord / props_truth[spineGT].area percentagePred = counter_sp_coord / props_pred[ spinePred].area # save % coincide_list_GT.append(percentageGT) coincide_list_Pred.append(percentagePred) # delete % from positions of already detected spines for ind in used_list: coincide_list_GT[ind] = 0 coincide_list_Pred[ind] = 0 # get maximum mean score coincide_list_mean = [ (x + y) / 2 for x, y in zip(coincide_list_GT, coincide_list_Pred) ] # scores mean max_coinc = max(coincide_list_mean) # max mean score max_index = coincide_list_mean.index( max_coinc) # max mean score index # check if spine is detected if max_coinc > coinc_thr: # if max_coinc is > than coinc_thr tp_case = tp_case + 1 # tp + 1 used_list.append(max_index) # spine detected else: fn_case = fn_case + 1 # if not, fn + 1 fp_case = num_labels_prediction - tp_case # get fp as the difference between detected spines and tp # save case metrics FP_thr = np.append(FP_thr, fp_case) FN_thr = np.append(FN_thr, fn_case) TP_thr = np.append(TP_thr, tp_case) # save dendrite results on csv dendrite_csv = ({ header[0]: FP_d, header[1]: FN_d, header[2]: TP_d, header[3]: SENS_d, header[4]: PREC_d }) df = pd.DataFrame.from_records(dendrite_csv, index=validation_cases) df.to_csv(path_run + "/dendrite_scores.csv") # calculate and save threshold metrics FP_sum = np.sum(FP_thr) FN_sum = np.sum(FN_thr) TP_sum = np.sum(TP_thr) SENS_thr = TP_sum / (TP_sum + FN_sum) PREC_thr = TP_sum / (TP_sum + FP_sum) FP_global.append(FP_sum) FN_global.append(FN_sum) TP_global.append(TP_sum) SENS_global.append(SENS_thr) PREC_global.append(PREC_thr) threshold_global.append(coinc_thr) # save spine results on csv spine_csv = ({ header[0]: FP_global, header[1]: FN_global, header[2]: TP_global, header[3]: SENS_global, header[4]: PREC_global }) df = pd.DataFrame.from_records(spine_csv, index=threshold_global) df.to_csv(path_run + "/spine_scores.csv")
def process_signal(audio_plot, audio_signal, parameters, time_stamps): # partition the audio history into blocks of type: # 1. noise, where the volume is greater than noise_threshold # 2. silence, where the volume is less than noise_threshold noise = audio_signal > parameters['noise_threshold'] silent = audio_signal < parameters['noise_threshold'] # join "noise blocks" that are closer together than min_quiet_time crying_blocks = [] if np.any(noise): silent_labels, _ = ndimage.label(silent) silent_ranges = ndimage.find_objects(silent_labels) for silent_block in silent_ranges: start = silent_block[0].start stop = silent_block[0].stop # don't join silence blocks at the beginning or end if start == 0: continue interval_length = time_stamps[stop - 1] - time_stamps[start] if interval_length < parameters['min_quiet_time']: noise[start:stop] = True # find noise blocks start times and duration crying_labels, num_crying_blocks = ndimage.label(noise) crying_ranges = ndimage.find_objects(crying_labels) for cry in crying_ranges: start = time_stamps[cry[0].start] stop = time_stamps[cry[0].stop - 1] duration = stop - start # ignore isolated noises (i.e. with a duration less than min_noise_time) if duration < parameters['min_noise_time']: continue # save some info about the noise block crying_blocks.append({ 'start': start, 'start_str': datetime.fromtimestamp(start).strftime("%I:%M:%S %p").lstrip( '0'), 'stop': stop, 'duration': format_time_difference(start, stop) }) # determine how long have we been in the current state time_current = time.time() time_crying = "" time_quiet = "" str_crying = "Drone noise for " str_quiet = "Drone quiet for " if len(crying_blocks) == 0: time_quiet = str_quiet + format_time_difference( time_stamps[0], time_current) else: if time_current - crying_blocks[-1]['stop'] < parameters[ 'min_quiet_time']: time_crying = str_crying + format_time_difference( crying_blocks[-1]['start'], time_current) else: time_quiet = str_quiet + format_time_difference( crying_blocks[-1]['stop'], time_current) results = { 'audio_plot': audio_plot, 'crying_blocks': crying_blocks, 'time_crying': time_crying, 'time_quiet': time_quiet } return results
def fill(self, coord, new_label, refresh=True): """Replace an existing label with a new label, either just at the connected component if the `contiguous` flag is `True` or everywhere if it is `False`, working either just in the current slice if the `n_dimensional` flag is `False` or on the entire data if it is `True`. Parameters ---------- coord : sequence of float Position of mouse cursor in image coordinates. new_label : int Value of the new label to be filled in. refresh : bool Whether to refresh view slice or not. Set to False to batch paint calls. """ int_coord = tuple(np.round(coord).astype(int)) # If requested fill location is outside data shape then return if np.any(np.less(int_coord, 0)) or np.any( np.greater_equal(int_coord, self.data.shape) ): return # If requested new label doesn't change old label then return old_label = self.data[int_coord] if old_label == new_label or ( self.preserve_labels and old_label != self._background_label ): return if refresh is True: self._save_history() if self.n_dimensional or self.ndim == 2: # work with entire image labels = self.data slice_coord = tuple(int_coord) else: # work with just the sliced image labels = self._data_raw slice_coord = tuple(int_coord[d] for d in self.dims.displayed) matches = labels == old_label if self.contiguous: # if contiguous replace only selected connected component labeled_matches, num_features = ndi.label(matches) if num_features != 1: match_label = labeled_matches[slice_coord] matches = np.logical_and( matches, labeled_matches == match_label ) # Replace target pixels with new_label labels[matches] = new_label if not (self.n_dimensional or self.ndim == 2): # if working with just the slice, update the rest of the raw data self.data[tuple(self._slice_indices)] = labels if refresh is True: self.refresh()
def DivideInNeighborhoods(data, number_of_spots, scale, sensitivity_limit=100): """ Given an image that includes N spots, divides it in N subimages with each of them to include one spot. Briefly, it filters the image, finds the N “brightest” spots and crops the region around them generating the subimages. This process is repeated until image division is feasible. data (model.DataArray): 2D array containing the intensity of each pixel number_of_spots (int,int): The number of CL spots scale (float): Distance between spots in optical grid (in pixels) sensitivity_limit (int): Limit of sensitivity returns subimages (List of DataArrays): One subimage per spot subimage_coordinates (List of tuples): The coordinates of the center of each subimage with respect to the overall image """ # Denoise filtered_image = ndimage.median_filter(data, 3) # Bold spots # Third parameter must be a length in pixels somewhat larger than a typical # spot filtered_image = _BandPassFilter(filtered_image, 1, 20) image = model.DataArray(filtered_image, data.metadata) avg_intensity = numpy.average(image) spot_factor = 10 step = 1 sensitivity = 4 # After filtering based on optical scale there is no need to adjust # filter window size filter_window_size = 8 # Increase sensitivity until expected number of spots is detected while sensitivity <= sensitivity_limit: subimage_coordinates = [] subimages = [] i_max, j_max = unravel_index(image.argmax(), image.shape) i_min, j_min = unravel_index(image.argmin(), image.shape) max_diff = image[i_max, j_max] - image[i_min, j_min] data_max = filters.maximum_filter(image, filter_window_size) data_min = filters.minimum_filter(image, filter_window_size) # Determine threshold i = sensitivity threshold = max_diff / i # Filter the parts of the image with variance in intensity greater # than the threshold maxima = (image == data_max) diff = ((data_max - data_min) > threshold) maxima[diff == 0] = 0 labeled, num_objects = ndimage.label(maxima) slices = ndimage.find_objects(labeled) (x_center_last, y_center_last) = (-10, -10) # Go through these parts and crop the subimages based on the neighborhood_size # value for dy, dx in slices: x_center = (dx.start + dx.stop - 1) / 2 y_center = (dy.start + dy.stop - 1) / 2 # Make sure we don't detect spots on the top of each other tab = tuple( map(operator.sub, (x_center_last, y_center_last), (x_center, y_center))) subimage = image[int(dy.start - 2.5):int(dy.stop + 2.5), int(dx.start - 2.5):int(dx.stop + 2.5)] if subimage.shape[0] == 0 or subimage.shape[1] == 0: continue if (subimage > spot_factor * avg_intensity).sum() < 6: continue # if spots detected too close keep the brightest one if (len(subimages) > 0) and (math.hypot(tab[0], tab[1]) < (scale / 2)): if numpy.sum(subimage) > numpy.sum( subimages[len(subimages) - 1]): subimages.pop() subimage_coordinates.pop() subimage_coordinates.append((x_center, y_center)) subimages.append(subimage) else: subimage_coordinates.append((x_center, y_center)) subimages.append(subimage) (x_center_last, y_center_last) = (x_center, y_center) # Take care of outliers expected_spots = numpy.prod(number_of_spots) clean_subimages, clean_subimage_coordinates = FilterOutliers( image, subimages, subimage_coordinates, expected_spots) if len(clean_subimages) >= numpy.prod(number_of_spots): break if sensitivity > 4: step = 4 sensitivity += step return clean_subimages, clean_subimage_coordinates
def join_bins(bin_edges, probabilities, min_prob=0.05): """Join bins until at least the minimum probability is contained. By joining adjacent bins, find the configuration with the maximum number of bins that each contain at least a certain probability. Parameters ---------- bin_edges : iterable of 2-tuple Upper and lower bounds associated with each bin. probabilities : array-like Probabilities in each bin. The contiguous ranges where bin joining must be attempted will automatically be determined. min_prob : float The minimum probability (inclusive) per (final) bin. Returns ------- bin_edges : list of 2-tuple List containing the new bin edges. probabilities : array Probabilities corresponding to the above bins. Raises ------ ValueError : If the number of bin edges does not match the number of probabilities. ValueError : If the sum of all `probabilities` does not exceed `min_prob`. """ if len(bin_edges) != len(probabilities): raise ValueError("Length of bin_edges and probabilities must match.") probabilities = np.asarray(probabilities) if np.sum(probabilities) <= min_prob: raise ValueError("Sum of probabilities must exceed min_prob.") max_i = probabilities.shape[0] - 1 def _join(start_i, end_i): """Return new bin edges and probabilities after a join. Parameters ---------- start_i : int Beginning of the join. end_i : int End of the join. Returns ------- bin_edges : list of 2-tuple List containing the new bin edges. probabilities : array Probabilities corresponding to the above bins. """ new_bin_edges = [] new_probabilities = [] # Remove all but the first index within the join window. for i in filterfalse( lambda x: x in range(start_i + 1, end_i + 1), range(max_i + 1), ): if i == start_i: new_bin_edges.append((bin_edges[start_i][0], bin_edges[end_i][1],)) new_probabilities.append(np.sum(probabilities[start_i : end_i + 1])) else: new_bin_edges.append(bin_edges[i]) new_probabilities.append(probabilities[i]) return join_bins( bin_edges=new_bin_edges, probabilities=new_probabilities, min_prob=min_prob, ) # Identify regions with low probabilities. join_mask = probabilities < min_prob if not np.any(join_mask): # Joining is complete. return (bin_edges, probabilities) # Find the contiguous clusters. labelled, n_clusters = label(join_mask) variations = [] # Carry out contiguous bin joining around all clusters. for cluster_i in range(1, n_clusters + 1): cluster_indices = np.where(labelled == cluster_i)[0] cluster_bounds = (cluster_indices[0], cluster_indices[-1]) # Also consider the adjacent bins, since this may be needed # in some cases. join_bounds = tuple( np.clip(np.array([cluster_bounds[0] - 1, cluster_bounds[1] + 1]), 0, max_i) ) for start_i in range(*join_bounds): # Optimisation: prevent 'orphan' bins on the left. if join_bounds[0] == 0 and start_i != 0: continue for end_i in range(start_i + 1, join_bounds[1] + 1): # Optimisation: prevent 'orphan' bins on the right. if join_bounds[1] == max_i and end_i != max_i: continue # If the sum of probabilities between `start_i` and `end_i` # exceeds the minimum threshold, join the bins. if np.sum(probabilities[start_i : end_i + 1]) >= min_prob: variations.append(_join(start_i, end_i)) # Return the 'best' variation - the set of bins with the lowest variability, # measured using the standard deviation of the probabilities. Only sets with # the largest number of bins will be considered here. lengths = [len(variation[0]) for variation in variations] max_length = max(lengths) long_variations = [ variation for variation in variations if len(variation[0]) == max_length ] variation_stds = [np.std(variation[1]) for variation in long_variations] min_index = np.argsort(variation_stds)[0] return long_variations[min_index]
def _detect_sources(data, thresholds, npixels, filter_kernel=None, connectivity=8, mask=None, deblend_skip=False): """ Detect sources above a specified threshold value in an image and return a `~photutils.segmentation.SegmentationImage` object. Detected sources must have ``npixels`` connected pixels that are each greater than the ``threshold`` value. If the filtering option is used, then the ``threshold`` is applied to the filtered image. The input ``mask`` can be used to mask pixels in the input data. Masked pixels will not be included in any source. This function does not deblend overlapping sources. First use this function to detect sources followed by :func:`~photutils.segmentation.deblend_sources` to deblend sources. Parameters ---------- data : array_like The 2D array of the image. thresholds : array-like of floats or arrays The data value or pixel-wise data values to be used for the detection thresholds. A 2D ``threshold`` must have the same shape as ``data``. See `~photutils.segmentation.detect_threshold` for one way to create a ``threshold`` image. npixels : int The number of connected pixels, each greater than ``threshold``, that an object must have to be detected. ``npixels`` must be a positive integer. filter_kernel : array-like (2D) or `~astropy.convolution.Kernel2D`, optional The 2D array of the kernel used to filter the image before thresholding. Filtering the image will smooth the noise and maximize detectability of objects with a shape similar to the kernel. connectivity : {4, 8}, optional The type of pixel connectivity used in determining how pixels are grouped into a detected source. The options are 4 or 8 (default). 4-connected pixels touch along their edges. 8-connected pixels touch along their edges or corners. For reference, SourceExtractor uses 8-connected pixels. mask : array_like of bool, optional A boolean mask, with the same shape as the input ``data``, where `True` values indicate masked pixels. Masked pixels will not be included in any source. deblend_skip : bool, optional If `True` do not include the segmentation image in the output list for any threshold level where the number of detected sources is less than 2. This is useful for source deblending and improves its performance. Returns ------- segment_image : list of `~photutils.segmentation.SegmentationImage` A list of 2D segmentation images, with the same shape as ``data``, where sources are marked by different positive integer values. A value of zero is reserved for the background. If no sources are found for a given threshold, then the output list will contain `None` for that threshold. Also see the ``deblend_skip`` keyword. """ from scipy import ndimage if (npixels <= 0) or (int(npixels) != npixels): raise ValueError('npixels must be a positive integer, got ' f'"{npixels}"') if mask is not None: if mask.shape != data.shape: raise ValueError('mask must have the same shape as the input ' 'image.') if filter_kernel is not None: data = _filter_data(data, filter_kernel, mode='constant', fill_value=0.0, check_normalization=True) selem = _make_binary_structure(data.ndim, connectivity) segms = [] for threshold in thresholds: # ignore RuntimeWarning caused by > comparison when data contains NaNs with warnings.catch_warnings(): warnings.simplefilter('ignore', category=RuntimeWarning) data2 = data > threshold if mask is not None: data2 &= ~mask # return if threshold was too high to detect any sources if np.count_nonzero(data2) == 0: warnings.warn('No sources were found.', NoDetectionsWarning) if deblend_skip: continue else: segms.append(None) continue segm_img, _ = ndimage.label(data2, structure=selem) # remove objects with less than npixels # NOTE: for typical data, making the cutout images is ~10x faster # than using segm_img directly segm_slices = ndimage.find_objects(segm_img) for i, slices in enumerate(segm_slices): cutout = segm_img[slices] segment_mask = (cutout == (i + 1)) if np.count_nonzero(segment_mask) < npixels: cutout[segment_mask] = 0 if np.count_nonzero(segm_img) == 0: warnings.warn('No sources were found.', NoDetectionsWarning) if deblend_skip: continue else: segms.append(None) continue segm = object.__new__(SegmentationImage) segm._data = segm_img if deblend_skip and segm.nlabels == 1: continue else: segm.relabel_consecutive() segms.append(segm) return segms
def segment_glomeruli3d(input_dir, output_dir, slice_names): """ Original implementation from Anna's script :param input_dir: :param output_dir: :param slice_names: :param voxel_xy: :param voxel_z: :return: """ if not os.path.exists(output_dir): os.makedirs(output_dir) num = 0 mask = io.imread(input_dir + "/" + slice_names[0]) l0 = np.zeros_like(mask) labels = [] limsize = int(float(glomeruli_maxrad)) nfiles = [output_dir + "/" + x for x in slice_names] # label for i in range(len(slice_names)): mask = io.imread(input_dir + "/" + slice_names[i]) l, n = ndimage.label(mask) labels.append(np.zeros_like(l)) for j in range(n): # FOR EACH label ind = np.where(l == j + 1) # Indices Of the current label ls = np.unique(l0[ind]) ls = ls[np.where( ls > 0 )] # Get the connections current_label -> last_layer_label if len(ls) == 0: num += 1 labels[-1][ind] = num if len(ls) == 1: labels[-1][ind] = ls[0] if len(ls) > 1: labels[-1][ind] = ls[0] # Assign to target (first encountered) for k in range(1, len(ls)): # FOREACH all other connections for s in range(len( labels)): # Go through all layers and remove them labels[s] = np.where(labels[s] == ls[k], ls[0], labels[s]) l0 = labels[-1] # if number of layers exceeds limit, save the first layer if len(labels) > limsize: mask = labels.pop(0) fname = nfiles.pop(0) tifffile.imsave(fname, img_as_int(mask), compress=5) # save remaining layers for i in range(len(labels)): mask = labels.pop(0) fname = nfiles.pop(0) tifffile.imsave(fname, img_as_int(mask), compress=5)
async def setup_learner(): await download_file(export_file_url, path / export_file_name) try: img_new = cv2.imread(str(path), cv2.IMREAD_COLOR) img_new = cv2.fastNlMeansDenoisingColored(img_new, None, 10, 10, 7, 21) img_sv = img_new img_test = img_sv img = img_new r = img.copy() r[:, :, 0] = 0 r[:, :, 1] = 0 img = r img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) test_r = img im_gray = cv2.cvtColor(r, cv2.COLOR_BGR2GRAY) im_blur = cv2.GaussianBlur(im_gray, (5, 5), 0) kernel_sharpening = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]]) im_sharp = cv2.filter2D(im_blur, -1, kernel_sharpening) img = im_sharp th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) img = im_sharp ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC) kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(thresh3, cv2.MORPH_OPEN, kernel, iterations=2) ret, th = cv2.threshold(thresh3, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) kernel = np.ones((3, 3), np.uint8) opening = cv2.morphologyEx(th, cv2.MORPH_OPEN, kernel, iterations=2) sure_bg = cv2.dilate(th, kernel, iterations=3) dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) ret, sure_fg = cv2.threshold(dist_transform, 0.005 * dist_transform.max(), 255, 0) sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown == 255] = 0 markers = cv2.watershed(img_sv, markers) img_sv[markers == -1] = [0, 255, 0] img_sv[markers == 1] = [0, 0, 0] from skimage.filters import threshold_otsu thresh_val = threshold_otsu(opening) mask = np.where(opening > thresh_val, 1, 0) if np.sum(mask == 0) < np.sum(mask == 1): mask = np.where(mask, 0, 1) from scipy import ndimage labels, nlabels = ndimage.label(mask) all_cords = {} for label_ind, label_coords in enumerate(ndimage.find_objects(labels)): cell = im_gray[label_coords] all_cords[label_ind] = label_coords if np.product(cell.shape) < 10: mask = np.where(labels == label_ind + 1, 0, mask) labels, nlabels = ndimage.label(mask) i = 0 res = {} for ii, obj_indices in enumerate( ndimage.find_objects(labels)[0:nlabels]): cell = img_sv[obj_indices] res[i] = cell i = i + 1 i = 0 features = {} for i in res: gcolor = res[i] h, w, _ = gcolor.shape ggray = np.array([[gcolor[i, j, 2] for j in range(w)] for i in range(h)], dtype=np.uint8) area = np.sum( np.sum([[1.0 for j in range(w) if ggray[i, j]] for i in range(h)])) mean_area = area / (h * w) r, b, g = np.sum( [gcolor[i, j] for j in range(w) for i in range(h)], axis=0) / (area * 256) _, _, eigen_value = pca(ggray) eccentricity = eigen_value[0] / eigen_value[1] l = [ mean_area, r, b, g, eigen_value[0], eigen_value[1], eccentricity ] features[i] = np.array(l) i = i + 1 out = {} #learn = load_learner(path, export_file_name) #Change Working directory of pkl file model = keras.models.load_model('../input/weight/weights.pkl') out = {} for i in features: out[i] = model.predict(np.array([features[i]])) good = not_good = 0 for i in out: s = res[i] if np.argmax(out[i][0]) == 0: good += 1 x1 = all_cords[i][0].start y1 = all_cords[i][1].start x2 = all_cords[i][1].stop y2 = all_cords[i][0].stop cv2.rectangle(img_test, (x2, x1), (y1, y2), (255, 0, 0), 8) else: x1 = all_cords[i][0].start y1 = all_cords[i][1].start x2 = all_cords[i][1].stop y2 = all_cords[i][0].stop not_good += 1 cv2.rectangle(img_test, (x2, x1), (y1, y2), (0, 0, 255), 3) p = (good / (good + not_good) * 100) print("Number of good grain :", good) print("Number of impure grains or impurity:", not_good) print("Percentage Purity is:", p) return p except RuntimeError as e: if len(e.args) > 0 and 'CPU-only machine' in e.args[0]: print(e) message = "\n\nThis model was trained with an old version of fastai and will not work in a CPU environment.\n\nPlease update the fastai library in your training environment and export your model again.\n\nSee instructions for 'Returning to work' at https://course.fast.ai." raise RuntimeError(message) else: raise
def test_bundle_of_tubes(self): im = ps.generators.bundle_of_tubes(shape=[101, 101, 1], spacing=10) labels, N = spim.label(input=im) assert N == 100
def test_lattice_spheres_triangular(self): im = ps.generators.lattice_spheres(shape=[101, 101], radius=5, lattice='triangular') labels, N = spim.label(input=~im) assert N == 85
def regionprops(label_image, properties=['Area', 'Centroid'], intensity_image=None): """Measure properties of labelled image regions. Parameters ---------- label_image : (N, M) ndarray Labelled input image. properties : {'all', list} Shape measurements to be determined for each labelled image region. Default is `['Area', 'Centroid']`. The following properties can be determined: * Area : int Number of pixels of region. * BoundingBox : tuple Bounding box `(min_row, min_col, max_row, max_col)` * CentralMoments : (3, 3) ndarray Central moments (translation invariant) up to 3rd order. mu_ji = sum{ array(x, y) * (x - x_c)^j * (y - y_c)^i } where the sum is over the `x`, `y` coordinates of the region, and `x_c` and `y_c` are the coordinates of the region's centroid. * Centroid : array Centroid coordinate tuple `(row, col)`. * ConvexArea : int Number of pixels of convex hull image. * ConvexImage : (H, J) ndarray Binary convex hull image which has the same size as bounding box. * Coordinates : (N, 2) ndarray Coordinate list `(row, col)` of the region. * Eccentricity : float Eccentricity of the ellipse that has the same second-moments as the region. The eccentricity is the ratio of the distance between its minor and major axis length. The value is between 0 and 1. * EquivDiameter : float The diameter of a circle with the same area as the region. * EulerNumber : int Euler number of region. Computed as number of objects (= 1) subtracted by number of holes (8-connectivity). * Extent : float Ratio of pixels in the region to pixels in the total bounding box. Computed as `Area / (rows*cols)` * FilledArea : int Number of pixels of filled region. * FilledImage : (H, J) ndarray Binary region image with filled holes which has the same size as bounding box. * HuMoments : tuple Hu moments (translation, scale and rotation invariant). * Image : (H, J) ndarray Sliced binary region image which has the same size as bounding box. * MajorAxisLength : float The length of the major axis of the ellipse that has the same normalized second central moments as the region. * MaxIntensity: float Value with the greatest intensity in the region. * MeanIntensity: float Value with the mean intensity in the region. * MinIntensity: float Value with the least intensity in the region. * MinorAxisLength : float The length of the minor axis of the ellipse that has the same normalized second central moments as the region. * Moments : (3, 3) ndarray Spatial moments up to 3rd order. m_ji = sum{ array(x, y) * x^j * y^i } where the sum is over the `x`, `y` coordinates of the region. * NormalizedMoments : (3, 3) ndarray Normalized moments (translation and scale invariant) up to 3rd order. nu_ji = mu_ji / m_00^[(i+j)/2 + 1] where `m_00` is the zeroth spatial moment. * Orientation : float Angle between the X-axis and the major axis of the ellipse that has the same second-moments as the region. Ranging from `-pi/2` to `pi/2` in counter-clockwise direction. * Perimeter : float Perimeter of object which approximates the contour as a line through the centers of border pixels using a 4-connectivity. * Solidity : float Ratio of pixels in the region to pixels of the convex hull image. * WeightedCentralMoments : (3, 3) ndarray Central moments (translation invariant) of intensity image up to 3rd order. wmu_ji = sum{ array(x, y) * (x - x_c)^j * (y - y_c)^i } where the sum is over the `x`, `y` coordinates of the region, and `x_c` and `y_c` are the coordinates of the region's centroid. * WeightedCentroid : array Centroid coordinate tuple `(row, col)` weighted with intensity image. * WeightedHuMoments : tuple Hu moments (translation, scale and rotation invariant) of intensity image. * WeightedMoments : (3, 3) ndarray Spatial moments of intensity image up to 3rd order. wm_ji = sum{ array(x, y) * x^j * y^i } where the sum is over the `x`, `y` coordinates of the region. * WeightedNormalizedMoments : (3, 3) ndarray Normalized moments (translation and scale invariant) of intensity image up to 3rd order. wnu_ji = wmu_ji / wm_00^[(i+j)/2 + 1] where `wm_00` is the zeroth spatial moment (intensity-weighted area). intensity_image : (N, M) ndarray, optional Intensity image with same size as labelled image. Default is None. Returns ------- properties : list of dicts List containing a property dict for each region. The property dicts contain all the specified properties plus a 'Label' field. References ---------- .. [1] Wilhelm Burger, Mark Burge. Principles of Digital Image Processing: Core Algorithms. Springer-Verlag, London, 2009. .. [2] B. Jähne. Digital Image Processing. Springer-Verlag, Berlin-Heidelberg, 6. edition, 2005. .. [3] T. H. Reiss. Recognizing Planar Objects Using Invariant Image Features, from Lecture notes in computer science, p. 676. Springer, Berlin, 1993. .. [4] http://en.wikipedia.org/wiki/Image_moment Examples -------- >>> from skimage.data import coins >>> from skimage.morphology import label >>> img = coins() > 110 >>> label_img = label(img) >>> props = regionprops(label_img) >>> props[0]['Centroid'] # centroid of first labelled object """ if not np.issubdtype(label_image.dtype, 'int'): raise TypeError('labelled image must be of integer dtype') # determine all properties if nothing specified if properties == 'all': properties = PROPS props = [] objects = ndimage.find_objects(label_image) for i, sl in enumerate(objects): label = i + 1 # create property dict for current label obj_props = {} props.append(obj_props) obj_props['Label'] = label array = (label_image[sl] == label).astype('double') # upper left corner of object bbox r0 = sl[0].start c0 = sl[1].start m = _moments.central_moments(array, 0, 0, 3) # centroid cr = m[0, 1] / m[0, 0] cc = m[1, 0] / m[0, 0] mu = _moments.central_moments(array, cr, cc, 3) # elements of the inertia tensor [a b; b c] a = mu[2, 0] / mu[0, 0] b = mu[1, 1] / mu[0, 0] c = mu[0, 2] / mu[0, 0] # eigen values of inertia tensor l1 = (a + c) / 2 + sqrt(4 * b**2 + (a - c)**2) / 2 l2 = (a + c) / 2 - sqrt(4 * b**2 + (a - c)**2) / 2 # cached results which are used by several properties _filled_image = None _convex_image = None _nu = None if 'Area' in properties: obj_props['Area'] = m[0, 0] if 'BoundingBox' in properties: obj_props['BoundingBox'] = (r0, c0, sl[0].stop, sl[1].stop) if 'Centroid' in properties: obj_props['Centroid'] = cr + r0, cc + c0 if 'CentralMoments' in properties: obj_props['CentralMoments'] = mu if 'ConvexArea' in properties: if _convex_image is None: _convex_image = convex_hull_image(array) obj_props['ConvexArea'] = np.sum(_convex_image) if 'ConvexImage' in properties: if _convex_image is None: _convex_image = convex_hull_image(array) obj_props['ConvexImage'] = _convex_image if 'Coordinates' in properties: rr, cc = np.nonzero(array) obj_props['Coordinates'] = np.vstack((rr + r0, cc + c0)).T if 'Eccentricity' in properties: if l1 == 0: obj_props['Eccentricity'] = 0 else: obj_props['Eccentricity'] = sqrt(1 - l2 / l1) if 'EquivDiameter' in properties: obj_props['EquivDiameter'] = sqrt(4 * m[0, 0] / PI) if 'EulerNumber' in properties: if _filled_image is None: _filled_image = ndimage.binary_fill_holes(array, STREL_8) euler_array = _filled_image != array _, num = ndimage.label(euler_array, STREL_8) obj_props['EulerNumber'] = -num if 'Extent' in properties: obj_props['Extent'] = m[0, 0] / (array.shape[0] * array.shape[1]) if 'HuMoments' in properties: if _nu is None: _nu = _moments.normalized_moments(mu, 3) obj_props['HuMoments'] = _moments.hu_moments(_nu) if 'Image' in properties: obj_props['Image'] = array if 'FilledArea' in properties: if _filled_image is None: _filled_image = ndimage.binary_fill_holes(array, STREL_8) obj_props['FilledArea'] = np.sum(_filled_image) if 'FilledImage' in properties: if _filled_image is None: _filled_image = ndimage.binary_fill_holes(array, STREL_8) obj_props['FilledImage'] = _filled_image if 'MajorAxisLength' in properties: obj_props['MajorAxisLength'] = 4 * sqrt(l1) if 'MinorAxisLength' in properties: obj_props['MinorAxisLength'] = 4 * sqrt(l2) if 'Moments' in properties: obj_props['Moments'] = m if 'NormalizedMoments' in properties: if _nu is None: _nu = _moments.normalized_moments(mu, 3) obj_props['NormalizedMoments'] = _nu if 'Orientation' in properties: if a - c == 0: if b > 0: obj_props['Orientation'] = -PI / 4. else: obj_props['Orientation'] = PI / 4. else: obj_props['Orientation'] = -0.5 * atan2(2 * b, (a - c)) if 'Perimeter' in properties: obj_props['Perimeter'] = perimeter(array, 4) if 'Solidity' in properties: if _convex_image is None: _convex_image = convex_hull_image(array) obj_props['Solidity'] = m[0, 0] / np.sum(_convex_image) if intensity_image is not None: weighted_array = array * intensity_image[sl] wm = _moments.central_moments(weighted_array, 0, 0, 3) # weighted centroid wcr = wm[0, 1] / wm[0, 0] wcc = wm[1, 0] / wm[0, 0] wmu = _moments.central_moments(weighted_array, wcr, wcc, 3) # cached results which are used by several properties _wnu = None _vals = None if 'MaxIntensity' in properties: if _vals is None: _vals = weighted_array[array.astype('bool')] obj_props['MaxIntensity'] = np.max(_vals) if 'MeanIntensity' in properties: if _vals is None: _vals = weighted_array[array.astype('bool')] obj_props['MeanIntensity'] = np.mean(_vals) if 'MinIntensity' in properties: if _vals is None: _vals = weighted_array[array.astype('bool')] obj_props['MinIntensity'] = np.min(_vals) if 'WeightedCentralMoments' in properties: obj_props['WeightedCentralMoments'] = wmu if 'WeightedCentroid' in properties: obj_props['WeightedCentroid'] = wcr + r0, wcc + c0 if 'WeightedHuMoments' in properties: if _wnu is None: _wnu = _moments.normalized_moments(wmu, 3) obj_props['WeightedHuMoments'] = _moments.hu_moments(_wnu) if 'WeightedMoments' in properties: obj_props['WeightedMoments'] = wm if 'WeightedNormalizedMoments' in properties: if _wnu is None: _wnu = _moments.normalized_moments(wmu, 3) obj_props['WeightedNormalizedMoments'] = _wnu return props
# convert the mean shift image to grayscale, then apply # Otsu's thresholding gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] thresh = cv2.copyMakeBorder(thresh, 1, 1, 1, 1, cv2.BORDER_CONSTANT, 0) #cv2.imshow("Thresh", thresh) # compute the exact Euclidean distance from every binary # pixel to the nearest zero pixel, then find peaks in this # distance map D = ndimage.distance_transform_edt(thresh) localMax = peak_local_max(D, indices=False, min_distance=20, labels=thresh) # perform a connected component analysis on the local peaks, # using 8-connectivity, then appy the Watershed algorithm markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0] labels = watershed(-D, markers, mask=thresh) print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1)) circles = np.empty((0, 3), int) # loop over the unique labels returned by the Watershed # algorithm for label in np.unique(labels): # if the label is zero, we are examining the 'background' # so simply ignore it if label == 0: continue # otherwise, allocate memory for the label region and draw # it on the mask
def extract_particles(self, segmentation): """ Saves particle centers into output .star file, after dismissing regions that are too big to contain a particle. Args: segmentation: Segmentation of the micrograph into noise and particle projections. """ segmentation = segmentation[self.query_size // 2 - 1:-self.query_size // 2, self.query_size // 2 - 1:-self.query_size // 2] labeled_segments, _ = ndimage.label(segmentation, np.ones((3, 3))) values, repeats = np.unique(labeled_segments, return_counts=True) values_to_remove = np.where(repeats > self.max_size ** 2) values = np.take(values, values_to_remove) values = np.reshape(values, (1, 1, np.prod(values.shape)), 'F') labeled_segments = np.reshape(labeled_segments, (labeled_segments.shape[0], labeled_segments.shape[1], 1), 'F') matrix1 = np.repeat(labeled_segments, values.shape[2], 2) matrix2 = np.repeat(values, matrix1.shape[0], 0) matrix2 = np.repeat(matrix2, matrix1.shape[1], 1) matrix3 = np.equal(matrix1, matrix2) matrix4 = np.sum(matrix3, 2) segmentation[np.where(matrix4 == 1)] = 0 labeled_segments, _ = ndimage.label(segmentation, np.ones((3, 3))) max_val = np.amax(np.reshape(labeled_segments, (np.prod(labeled_segments.shape)))) center = center_of_mass(segmentation, labeled_segments, np.arange(1, max_val)) center = np.rint(center) img = np.zeros((segmentation.shape[0], segmentation.shape[1])) img[center[:, 0].astype(int), center[:, 1].astype(int)] = 1 y, x = np.ogrid[-self.moa:self.moa+1, -self.moa:self.moa+1] element = x*x+y*y <= self.moa * self.moa img = binary_dilation(img, structure=element) labeled_img, _ = ndimage.label(img, np.ones((3, 3))) values, repeats = np.unique(labeled_img, return_counts=True) y = np.where(repeats == np.count_nonzero(element)) y = np.array(y) y = y.astype(int) y = np.reshape(y, (np.prod(y.shape)), 'F') y -= 1 center = center[y, :] center = center + (self.query_size // 2 - 1) * np.ones(center.shape) center = center + (self.query_size // 2 - 1) * np.ones(center.shape) center = center + np.ones(center.shape) center = config.apple.mrc_shrink_factor * center # swap columns to align with Relion center = center[:, [1, 0]] # first column is x; second column is y - offset by margins that were discarded from the image center[:, 0] += config.apple.mrc_margin_left center[:, 1] += config.apple.mrc_margin_top if self.output_directory is not None: basename = os.path.basename(self.filename) name_str, ext = os.path.splitext(basename) applepick_path = os.path.join(self.output_directory, "{}_applepick.star".format(name_str)) with open(applepick_path, "w") as f: np.savetxt(f, ["data_root\n\nloop_\n_rlnCoordinateX #1\n_rlnCoordinateY #2"], fmt='%s') np.savetxt(f, center, fmt='%d %d') return center
def pull_spots(self, plane_data, grain_params, imgser_dict, tth_tol=0.25, eta_tol=1., ome_tol=1., npdiv=2, threshold=10, eta_ranges=[ (-np.pi, np.pi), ], ome_period=(-np.pi, np.pi), dirname='results', filename=None, output_format='text', save_spot_list=False, quiet=True, check_only=False, interp='nearest'): """ Exctract reflection info from a rotation series encoded as an OmegaImageseries object """ # grain parameters rMat_c = makeRotMatOfExpMap(grain_params[:3]) tVec_c = grain_params[3:6] # grab omega ranges from first imageseries # # WARNING: all imageseries AND all wedges within are assumed to have # the same omega values; put in a check that they are all the same??? oims0 = imgser_dict[imgser_dict.keys()[0]] ome_ranges = [ np.radians([i['ostart'], i['ostop']]) for i in oims0.omegawedges.wedges ] # delta omega in DEGREES grabbed from first imageseries in the dict delta_ome = oims0.omega[0, 1] - oims0.omega[0, 0] # make omega grid for frame expansion around reference frame # in DEGREES ndiv_ome, ome_del = make_tolerance_grid( delta_ome, ome_tol, 1, adjust_window=True, ) # generate structuring element for connected component labeling if ndiv_ome == 1: label_struct = ndimage.generate_binary_structure(2, 2) else: label_struct = ndimage.generate_binary_structure(3, 3) # simulate rotation series sim_results = self.simulate_rotation_series(plane_data, [ grain_params, ], eta_ranges=eta_ranges, ome_ranges=ome_ranges, ome_period=ome_period) # patch vertex generator (global for instrument) tol_vec = 0.5 * np.radians([ -tth_tol, -eta_tol, -tth_tol, eta_tol, tth_tol, eta_tol, tth_tol, -eta_tol ]) # prepare output if requested if filename is not None and output_format.lower() == 'hdf5': this_filename = os.path.join(dirname, filename) writer = io.GrainDataWriter_h5(os.path.join(dirname, filename), self.write_config(), grain_params) # ===================================================================== # LOOP OVER PANELS # ===================================================================== iRefl = 0 compl = [] output = dict.fromkeys(self.detectors) for detector_id in self.detectors: # initialize text-based output writer if filename is not None and output_format.lower() == 'text': output_dir = os.path.join(dirname, detector_id) if not os.path.exists(output_dir): os.makedirs(output_dir) this_filename = os.path.join(output_dir, filename) writer = io.PatchDataWriter(this_filename) # grab panel panel = self.detectors[detector_id] instr_cfg = panel.config_dict(self.chi, self.tvec) native_area = panel.pixel_area # pixel ref area # pull out the OmegaImageSeries for this panel from input dict ome_imgser = imgser_dict[detector_id] # extract simulation results sim_results_p = sim_results[detector_id] hkl_ids = sim_results_p[0][0] hkls_p = sim_results_p[1][0] ang_centers = sim_results_p[2][0] xy_centers = sim_results_p[3][0] ang_pixel_size = sim_results_p[4][0] # now verify that full patch falls on detector... # ???: strictly necessary? # # patch vertex array from sim nangs = len(ang_centers) patch_vertices = (np.tile(ang_centers[:, :2], (1, 4)) + np.tile(tol_vec, (nangs, 1))).reshape( 4 * nangs, 2) ome_dupl = np.tile(ang_centers[:, 2], (4, 1)).T.reshape(len(patch_vertices), 1) # find vertices that all fall on the panel det_xy, _ = xrdutil._project_on_detector_plane( np.hstack([patch_vertices, ome_dupl]), panel.rmat, rMat_c, self.chi, panel.tvec, tVec_c, self.tvec, panel.distortion) _, on_panel = panel.clip_to_panel(det_xy, buffer_edges=True) # all vertices must be on... patch_is_on = np.all(on_panel.reshape(nangs, 4), axis=1) patch_xys = det_xy.reshape(nangs, 4, 2)[patch_is_on] # re-filter... hkl_ids = hkl_ids[patch_is_on] hkls_p = hkls_p[patch_is_on, :] ang_centers = ang_centers[patch_is_on, :] xy_centers = xy_centers[patch_is_on, :] ang_pixel_size = ang_pixel_size[patch_is_on, :] # TODO: add polygon testing right here! # done <JVB 06/21/16> if check_only: patch_output = [] for i_pt, angs in enumerate(ang_centers): # the evaluation omegas; # expand about the central value using tol vector ome_eval = np.degrees(angs[2]) + ome_del # ...vectorize the omega_to_frame function to avoid loop? frame_indices = [ ome_imgser.omega_to_frame(ome)[0] for ome in ome_eval ] if -1 in frame_indices: if not quiet: msg = """ window for (%d%d%d) falls outside omega range """ % tuple(hkls_p[i_pt, :]) print(msg) continue else: these_vertices = patch_xys[i_pt] ijs = panel.cartToPixel(these_vertices) ii, jj = polygon(ijs[:, 0], ijs[:, 1]) contains_signal = False for i_frame in frame_indices: contains_signal = contains_signal or np.any( ome_imgser[i_frame][ii, jj] > threshold) compl.append(contains_signal) patch_output.append((ii, jj, frame_indices)) else: # make the tth,eta patches for interpolation patches = xrdutil.make_reflection_patches( instr_cfg, ang_centers[:, :2], ang_pixel_size, omega=ang_centers[:, 2], tth_tol=tth_tol, eta_tol=eta_tol, rMat_c=rMat_c, tVec_c=tVec_c, distortion=panel.distortion, npdiv=npdiv, quiet=True, beamVec=self.beam_vector) # GRAND LOOP over reflections for this panel patch_output = [] for i_pt, patch in enumerate(patches): # strip relevant objects out of current patch vtx_angs, vtx_xy, conn, areas, xy_eval, ijs = patch prows, pcols = areas.shape nrm_fac = areas / float(native_area) nrm_fac = nrm_fac / np.min(nrm_fac) # grab hkl info hkl = hkls_p[i_pt, :] hkl_id = hkl_ids[i_pt] # edge arrays tth_edges = vtx_angs[0][0, :] delta_tth = tth_edges[1] - tth_edges[0] eta_edges = vtx_angs[1][:, 0] delta_eta = eta_edges[1] - eta_edges[0] # need to reshape eval pts for interpolation xy_eval = np.vstack( [xy_eval[0].flatten(), xy_eval[1].flatten()]).T # the evaluation omegas; # expand about the central value using tol vector ome_eval = np.degrees(ang_centers[i_pt, 2]) + ome_del # ???: vectorize the omega_to_frame function to avoid loop? frame_indices = [ ome_imgser.omega_to_frame(ome)[0] for ome in ome_eval ] if -1 in frame_indices: if not quiet: msg = """ window for (%d%d%d) falls outside omega range """ % tuple(hkl) print(msg) continue else: # initialize spot data parameters # !!! maybe change these to nan to not f**k up writer peak_id = -999 sum_int = None max_int = None meas_angs = None meas_xy = None # quick check for intensity contains_signal = False patch_data_raw = [] for i_frame in frame_indices: tmp = ome_imgser[i_frame][ijs[0], ijs[1]] contains_signal = contains_signal or np.any( tmp > threshold) patch_data_raw.append(tmp) pass patch_data_raw = np.stack(patch_data_raw, axis=0) compl.append(contains_signal) if contains_signal: # initialize patch data array for intensities if interp.lower() == 'bilinear': patch_data = np.zeros( (len(frame_indices), prows, pcols)) for i, i_frame in enumerate(frame_indices): patch_data[i] = \ panel.interpolate_bilinear( xy_eval, ome_imgser[i_frame], pad_with_nans=False ).reshape(prows, pcols) # * nrm_fac elif interp.lower() == 'nearest': patch_data = patch_data_raw # * nrm_fac else: msg = "interpolation option " + \ "'%s' not understood" raise (RuntimeError, msg % interp) # now have interpolated patch data... labels, num_peaks = ndimage.label( patch_data > threshold, structure=label_struct) slabels = np.arange(1, num_peaks + 1) if num_peaks > 0: peak_id = iRefl coms = np.array( ndimage.center_of_mass(patch_data, labels=labels, index=slabels)) if num_peaks > 1: center = np.r_[patch_data.shape] * 0.5 center_t = np.tile(center, (num_peaks, 1)) com_diff = coms - center_t closest_peak_idx = np.argmin( np.sum(com_diff**2, axis=1)) else: closest_peak_idx = 0 pass # end multipeak conditional coms = coms[closest_peak_idx] # meas_omes = \ # ome_edges[0] + (0.5 + coms[0])*delta_ome meas_omes = \ ome_eval[0] + coms[0]*delta_ome meas_angs = np.hstack([ tth_edges[0] + (0.5 + coms[2]) * delta_tth, eta_edges[0] + (0.5 + coms[1]) * delta_eta, mapAngle(np.radians(meas_omes), ome_period) ]) # intensities # - summed is 'integrated' over interpolated # data # - max is max of raw input data sum_int = np.sum(patch_data[ labels == slabels[closest_peak_idx]]) max_int = np.max(patch_data_raw[ labels == slabels[closest_peak_idx]]) # ???: Should this only use labeled pixels? # Those are segmented from interpolated data, # not raw; likely ok in most cases. # need MEASURED xy coords gvec_c = anglesToGVec(meas_angs, chi=self.chi, rMat_c=rMat_c, bHat_l=self.beam_vector) rMat_s = makeOscillRotMat( [self.chi, meas_angs[2]]) meas_xy = gvecToDetectorXY( gvec_c, panel.rmat, rMat_s, rMat_c, panel.tvec, self.tvec, tVec_c, beamVec=self.beam_vector) if panel.distortion is not None: # FIXME: distortion handling meas_xy = panel.distortion[0]( np.atleast_2d(meas_xy), panel.distortion[1], invert=True).flatten() pass # FIXME: why is this suddenly necessary??? meas_xy = meas_xy.squeeze() pass # end num_peaks > 0 else: patch_data = patch_data_raw pass # end contains_signal # write output if filename is not None: if output_format.lower() == 'text': writer.dump_patch(peak_id, hkl_id, hkl, sum_int, max_int, ang_centers[i_pt], meas_angs, xy_centers[i_pt], meas_xy) elif output_format.lower() == 'hdf5': xyc_arr = xy_eval.reshape(prows, pcols, 2).transpose( 2, 0, 1) writer.dump_patch( detector_id, iRefl, peak_id, hkl_id, hkl, tth_edges, eta_edges, np.radians(ome_eval), xyc_arr, ijs, frame_indices, patch_data, ang_centers[i_pt], xy_centers[i_pt], meas_angs, meas_xy) pass # end conditional on write output pass # end conditional on check only patch_output.append([ peak_id, hkl_id, hkl, sum_int, max_int, ang_centers[i_pt], meas_angs, meas_xy, ]) iRefl += 1 pass # end patch conditional pass # end patch loop output[detector_id] = patch_output if filename is not None and output_format.lower() == 'text': writer.close() pass # end detector loop if filename is not None and output_format.lower() == 'hdf5': writer.close() return compl, output
def peak_finding(self, im, transformed, roi=False, roi_pos=None, background_correction=None): start = time.time() img = np.copy(im) if background_correction is None and self.background_correction: img = self.subtract_background(img) self.log(self.threshold) self.log(self.pixel_upper_threshold) self.log(self.pixel_lower_threshold) self.log(self.flood_steps) self.log(img.shape) self.log(img.max()) img[img < self.threshold] = 0 labels, num_objects = ndi.label(img) label_size = np.bincount(labels.ravel()) # single photons and no noise mask_sp = np.where((label_size >= self.pixel_lower_threshold) & (label_size < self.pixel_upper_threshold), True, False) if sum(mask_sp) == 0: coor_sp = [] else: label_mask_sp = mask_sp[labels.ravel()].reshape(labels.shape) labels_sp = label_mask_sp * labels labels_sp, n_s = ndi.label(labels_sp) coor_sp = ndi.center_of_mass(img, labels_sp, range(1, labels_sp.max() + 1)) # multiple photons mask_mp = np.where((label_size >= self.pixel_upper_threshold) & (label_size < np.max(label_size)), True, False) if sum(mask_mp) > 0: label_mask_mp = mask_mp[labels.ravel()].reshape(labels.shape) labels_mp = label_mask_mp * labels labels_mp, n_m = ndi.label(labels_mp) for i in range(1, sum(mask_mp) + 1): objects = ndi.find_objects(labels_mp == i) if len(objects) == 0: self.print('No beads found!') return None slice_x, slice_y = objects[0] roi_i = np.copy(img[slice_x, slice_y]) max_i = np.max(roi_i) step = (0.95 * max_i - self.threshold) / self.flood_steps multiple = False coor_tmp = np.array( ndi.center_of_mass(roi_i, ndi.label(roi_i)[0])) for k in range(1, self.flood_steps + 1): new_threshold = self.threshold + k * step roi_i[roi_i < new_threshold] = 0 labels_roi, n_i = ndi.label(roi_i) if n_i > 1: roi_label_size = np.bincount(labels_roi.ravel()) if np.max(roi_label_size[1:] ) <= self.pixel_upper_threshold: if len(roi_label_size) == 3 and roi_label_size.min( ) < self.roi_min_size: break else: multiple = True coordinates_roi = np.array( ndi.center_of_mass(roi_i, labels_roi, range(1, n_i + 1))) [ coor_sp.append(coordinates_roi[j] + np.array((slice_x.start, slice_y.start))) for j in range(len(coordinates_roi)) ] break if not multiple: coor_sp.append(coor_tmp + np.array((slice_x.start, slice_y.start))) coor = np.array(coor_sp) if len(coor) == 0: return None if roi: try: return np.round(coor)[0] except IndexError: return None else: #peaks_2d = np.round(coor) peaks_2d = coor if roi_pos is not None and peaks_2d is not None: peaks_2d += roi_pos if self.aligning: if transformed: self.tf_peaks_align_ref = np.copy(peaks_2d) else: self.peaks_align_ref = np.copy(peaks_2d) else: if transformed: self.tf_peaks = peaks_2d if self.orig_tf_peaks is None: self.orig_tf_peaks = np.copy(self.tf_peaks) else: self.peaks = np.copy(peaks_2d) end = time.time() self.log('duration: ', end - start) self.print('Number of peaks found: ', peaks_2d.shape[0])
def extract_background_pid(img, P_id, slit_height=25, return_mask=False, exclude_top_and_bottom=True, timit=False): """ This function marks all relevant pixels for extraction. Extracts the background (ie the inter-order regions = everything outside the order stripes) from the original 2D spectrum to a sparse matrix containing only relevant pixels. INPUT: 'img' : 2D echelle spectrum [np.array] 'P_id' : dictionary of the form of {order: np.poly1d} (as returned by make_P_id / identify_stripes) 'slit_height' : half the total slit height in pixels 'return_mask' : boolean - do you want to return the mask of the background locations as well? 'exclude_top_and_bottom' : boolean - do you want to exclude the top and bottom bits (where there are usually incomplete orders) 'timit' : for timing tests... OUTPUT: 'mat.tocsc()' : scipy.sparse_matrix containing the locations and values of the inter-order regions 'bg_mask' : boolean array containing the location of what is considered background (ie the inter-order space) """ if timit: start_time = time.time() # logging.info('Extracting background...') print('Extracting background...') ny, nx = img.shape xx = np.arange(nx, dtype='f8') yy = np.arange(ny, dtype='f8') x_grid, y_grid = np.meshgrid(xx, yy, copy=False) bg_mask = np.ones((ny, nx), dtype=bool) for o, p in sorted(P_id.items()): # order trace y = np.poly1d(p)(xx) # distance from order trace distance = y_grid - y.repeat(ny).reshape((nx, ny)).T indices = abs(distance) > slit_height # include in global mask bg_mask *= indices final_bg_mask = bg_mask.copy() # in case we want to exclude the top and bottom parts where incomplete orders are located if exclude_top_and_bottom: print( 'WARNING: this fix works for the current Veloce CCD layout only!!!' ) labelled_mask, nobj = label(bg_mask) # WARNING: this fix works for the current Veloce CCD layout only!!! topleftnumber = labelled_mask[ny - 1, 0] toprightnumber = labelled_mask[ny - 1, nx - 1] # bottomleftnumber = labelled_mask[0,0] bottomrightnumber = labelled_mask[0, nx - 1] final_bg_mask[labelled_mask == topleftnumber] = False final_bg_mask[labelled_mask == toprightnumber] = False final_bg_mask[labelled_mask == bottomrightnumber] = False mat = sparse.coo_matrix((np.squeeze(np.array(img[final_bg_mask])), (y_grid[final_bg_mask], x_grid[final_bg_mask])), shape=(ny, nx)) # return mat.tocsr() if timit: print('Elapsed time: ', time.time() - start_time, ' seconds') if not return_mask: return mat.tocsc() else: return mat.tocsc(), final_bg_mask