def getZoneByLocation(lat, lon, level): level += 2 h_size = calcHexSize(level) z_xy = loc2xy(lon, lat) lon_grid = z_xy.x lat_grid = z_xy.y unit_x = 6 * h_size unit_y = 6 * h_size * H_K h_pos_x = (lon_grid + lat_grid / H_K) / unit_x h_pos_y = (lat_grid - H_K * lon_grid) / unit_y h_x_0 = floor_int(h_pos_x) h_y_0 = floor_int(h_pos_y) h_x_q = h_pos_x - h_x_0 h_y_q = h_pos_y - h_y_0 h_x = round_int(h_pos_x) h_y = round_int(h_pos_y) if h_y_q > -h_x_q + 1: if (h_y_q < 2 * h_x_q) and (h_y_q > 0.5 * h_x_q): h_x = h_x_0 + 1 h_y = h_y_0 + 1 elif h_y_q < -h_x_q + 1: if (h_y_q > (2 * h_x_q) - 1) and (h_y_q < (0.5 * h_x_q) + 0.5): h_x = h_x_0 h_y = h_y_0 h_lat = (H_K * h_x * unit_x + h_y * unit_y) / 2 h_lon = (h_lat - h_y * unit_y) / H_K z_loc = xy2loc(h_lon, h_lat) z_loc_x = z_loc.lon z_loc_y = z_loc.lat if H_BASE - h_lon < h_size: z_loc_x = 180 h_xy = h_x h_x = h_y h_y = h_xy h_code = "" code3_x = [0] * (level + 1) code3_y = [0] * (level + 1) code3 = "" code9 = "" mod_x = h_x mod_y = h_y for i in range(level + 1): h_pow = math.pow(3, level - i) if mod_x >= ceil_int(h_pow/2): code3_x[i] = 2 mod_x -= h_pow elif mod_x <= -ceil_int(h_pow/2): code3_x[i] = 0 mod_x += h_pow else: code3_x[i] = 1 if mod_y >= ceil_int(h_pow/2): code3_y[i] =2 mod_y -= h_pow elif mod_y <= -ceil_int(h_pow/2): code3_y[i] =0 mod_y += h_pow else: code3_y[i] = 1 for i in range(len(code3_x)): code3 += "%s%s" % (code3_x[i], code3_y[i]) code9 += str(int(code3, 3)) h_code += code9 code9 = "" code3 = "" h_2 = h_code[3:] h_1 = h_code[0:3] h_a1 = floor_int(int(h_1) / 30) h_a2 = int(h_1) % 30 h_code = (H_KEY[h_a1] + H_KEY[h_a2]) + h_2 return Zone(z_loc_y, z_loc_x, h_x, h_y, h_code)
def find_bubble_edges(array, blob, max_extent=1.0, edge_mask=None, nsig_thresh=1, value_thresh=None, radius=None, return_mask=False, min_pixels=16, filter_size=4, verbose=False, min_radius_frac=0.0, try_local_bkg=True, **kwargs): ''' Expand/contract to match the contours in the data. Parameters ---------- array : 2D numpy.ndarray or spectral_cube.LowerDimensionalObject Data used to define the region boundaries. max_extent : float, optional Multiplied by the major radius to set how far should be searched when searching for the boundary. nsig_thresh : float, optional Number of times sigma above the mean to set the boundary intensity requirement. This is used whenever the local background is higher than the given `value_thresh`. value_thresh : float, optional When given, sets the minimum intensity for defining a bubble edge. The natural choice is a few times the noise level in the cube. radius : float, optional Give an optional radius to use instead of the major radius defined for the bubble. kwargs : passed to profile.profile_line. Returns ------- extent_coords : np.ndarray Array with the positions of edges. ''' if try_local_bkg: mean, std = intensity_props(array, blob) background_thresh = mean + nsig_thresh * std # Define a suitable background based on the intensity within the # elliptical region if value_thresh is None: value_thresh = background_thresh else: # If value_thresh is higher use it. Otherwise use the bkg. if value_thresh < background_thresh: value_thresh = background_thresh # Set the number of theta to be ~ the perimeter. y, x, major, minor, pa = blob[:5] y = int(np.round(y, decimals=0)) x = int(np.round(x, decimals=0)) # If the center is on the edge of the array, subtract one to # index correctly if y == array.shape[0]: y -= 1 if x == array.shape[1]: x -= 1 # Use the ellipse model to define a bounding box for the mask. bbox = Ellipse2D(True, 0.0, 0.0, major * max_extent, minor * max_extent, pa).bounding_box y_range = ceil_int(bbox[0][1] - bbox[0][0] + 1 + filter_size) x_range = ceil_int(bbox[1][1] - bbox[1][0] + 1 + filter_size) shell_thetas = [] yy, xx = np.mgrid[-int(y_range / 2): int(y_range / 2) + 1, -int(x_range / 2): int(x_range / 2) + 1] if edge_mask is not None: arr = edge_mask[max(0, y - int(y_range / 2)): y + int(y_range / 2) + 1, max(0, x - int(x_range / 2)): x + int(x_range / 2) + 1] else: arr = array[max(0, y - int(y_range / 2)):y + int(y_range / 2) + 1, max(0, x - int(x_range / 2)):x + int(x_range / 2) + 1] # Adjust meshes if they exceed the array shape x_min = -min(0, x - int(x_range / 2)) x_max = xx.shape[1] - max(0, x + int(x_range / 2) - array.shape[1] + 1) y_min = -min(0, y - int(y_range / 2)) y_max = yy.shape[0] - max(0, y + int(y_range / 2) - array.shape[0] + 1) offset = (max(0, int(y - (y_range / 2))), max(0, int(x - (x_range / 2)))) yy = yy[y_min:y_max, x_min:x_max] xx = xx[y_min:y_max, x_min:x_max] dist_arr = np.sqrt(yy**2 + xx**2) if edge_mask is not None: smooth_mask = arr else: smooth_mask = \ smooth_edges(arr <= value_thresh, filter_size, min_pixels) region_mask = \ Ellipse2D(True, 0.0, 0.0, major * max_extent, minor * max_extent, pa)(xx, yy).astype(bool) region_mask = nd.binary_dilation(region_mask, eight_conn, iterations=2) # The bubble center must fall within a valid region mid_pt = np.where(dist_arr == 0.0) if len(mid_pt[0]) == 0: middle_fail = True else: local_center = zip(*np.where(dist_arr == 0.0))[0] middle_fail = False # _make_bubble_mask(smooth_mask, local_center) # If the center is not contained within a bubble region, return # empties. bad_case = not smooth_mask.any() or smooth_mask.all() or \ (smooth_mask * region_mask).all() or middle_fail if bad_case: if return_mask: return np.array([]), 0.0, 0.0, value_thresh, smooth_mask return np.array([]), 0.0, 0.0, value_thresh orig_perim = find_contours(region_mask, 0, fully_connected='high')[0] # new_perim = find_contours(smooth_mask, 0, fully_connected='high') coords = [] extent_mask = np.zeros_like(region_mask) # for perim in new_perim: # perim = perim.astype(np.int) # good_pts = \ # np.array([pos for pos, pt in enumerate(perim) # if region_mask[pt[0], pt[1]]]) # if not good_pts.any(): # continue # # Now split into sections # from utils import consec_split # split_pts = consec_split(good_pts) # # Remove the duplicated end point if it was initially connected # if len(split_pts) > 1: # # Join these if the end pts initially matched # if split_pts[0][0] == split_pts[-1][-1]: # split_pts[0] = np.append(split_pts[0], # split_pts[-1][::-1]) # split_pts.pop(-1) # for split in split_pts: # coords.append(perim[split]) # extent_mask[perim[good_pts][:, 0], perim[good_pts][:, 1]] = True # Based on the curvature of the shell, only fit points whose # orientation matches the assumed centre. # incoord, outcoord = shell_orientation(coords, local_center, # verbose=False) # Now only keep the points that are not blocked from the centre pixel for pt in orig_perim: theta = np.arctan2(pt[0] - local_center[0], pt[1] - local_center[1]) num_pts = int(np.round(np.hypot(pt[0] - local_center[0], pt[1] - local_center[1]), decimals=0)) ys = np.round(np.linspace(local_center[0], pt[0], num_pts), decimals=0).astype(np.int) xs = np.round(np.linspace(local_center[1], pt[1], num_pts), decimals=0).astype(np.int) not_on_edge = np.logical_and(ys < smooth_mask.shape[0], xs < smooth_mask.shape[1]) ys = ys[not_on_edge] xs = xs[not_on_edge] dist = np.sqrt((ys - local_center[0])**2 + (xs - local_center[1])**2) prof = smooth_mask[ys, xs] prof = prof[dist >= min_radius_frac * minor] ys = ys[dist >= min_radius_frac * minor] xs = xs[dist >= min_radius_frac * minor] # Look for the first 0 and ignore all others past it zeros = np.where(prof == 0)[0] # If none, move on if not zeros.any(): continue edge = zeros[0] extent_mask[ys[edge], xs[edge]] = True coords.append((ys[edge], xs[edge])) shell_thetas.append(theta) # Calculate the fraction of the region associated with a shell shell_frac = len(shell_thetas) / float(len(orig_perim)) shell_thetas = np.array(shell_thetas) coords = np.array(coords) # Use the theta values to find the standard deviation i.e. how # dispersed the shell locations are. Assumes a circle, but we only # consider moderately elongated ellipses, so the statistics approx. # hold. theta_var = np.sqrt(circvar(shell_thetas * u.rad)).value extent_coords = \ np.vstack([pt + off for pt, off in zip(np.where(extent_mask), offset)]).T if verbose: print("Shell fraction : " + str(shell_frac)) print("Angular Std. : " + str(theta_var)) import matplotlib.pyplot as p true_region_mask = \ Ellipse2D(True, 0.0, 0.0, major, minor, pa)(xx, yy).astype(bool) ax = p.subplot(121) ax.imshow(arr, origin='lower', interpolation='nearest') ax.contour(smooth_mask, colors='b') ax.contour(region_mask, colors='r') ax.contour(true_region_mask, colors='g') if len(coords) > 0: p.plot(coords[:, 1], coords[:, 0], 'bD') p.plot(local_center[1], local_center[0], 'gD') ax2 = p.subplot(122) ax2.imshow(extent_mask, origin='lower', interpolation='nearest') p.draw() raw_input("?") p.clf() if return_mask: return extent_coords, shell_frac, theta_var, value_thresh, \ extent_mask return extent_coords, shell_frac, theta_var, value_thresh
def find_bubble_edges(array, blob, max_extent=1.0, edge_mask=None, nsig_thresh=1, value_thresh=None, radius=None, return_mask=False, min_pixels=16, filter_size=4, verbose=False, min_radius_frac=0.0, try_local_bkg=True, **kwargs): ''' Expand/contract to match the contours in the data. Parameters ---------- array : 2D numpy.ndarray or spectral_cube.LowerDimensionalObject Data used to define the region boundaries. max_extent : float, optional Multiplied by the major radius to set how far should be searched when searching for the boundary. nsig_thresh : float, optional Number of times sigma above the mean to set the boundary intensity requirement. This is used whenever the local background is higher than the given `value_thresh`. value_thresh : float, optional When given, sets the minimum intensity for defining a bubble edge. The natural choice is a few times the noise level in the cube. radius : float, optional Give an optional radius to use instead of the major radius defined for the bubble. kwargs : passed to profile.profile_line. Returns ------- extent_coords : np.ndarray Array with the positions of edges. ''' if try_local_bkg: mean, std = intensity_props(array, blob) background_thresh = mean + nsig_thresh * std # Define a suitable background based on the intensity within the # elliptical region if value_thresh is None: value_thresh = background_thresh else: # If value_thresh is higher use it. Otherwise use the bkg. if value_thresh < background_thresh: value_thresh = background_thresh # Set the number of theta to be ~ the perimeter. y, x, major, minor, pa = blob[:5] y = int(np.round(y, decimals=0)) x = int(np.round(x, decimals=0)) # If the center is on the edge of the array, subtract one to # index correctly if y == array.shape[0]: y -= 1 if x == array.shape[1]: x -= 1 # Use the ellipse model to define a bounding box for the mask. bbox = Ellipse2D(True, 0.0, 0.0, major * max_extent, minor * max_extent, pa).bounding_box y_range = ceil_int(bbox[0][1] - bbox[0][0] + 1 + filter_size) x_range = ceil_int(bbox[1][1] - bbox[1][0] + 1 + filter_size) shell_thetas = [] yy, xx = np.mgrid[-int(y_range / 2):int(y_range / 2) + 1, -int(x_range / 2):int(x_range / 2) + 1] if edge_mask is not None: arr = edge_mask[max(0, y - int(y_range / 2)):y + int(y_range / 2) + 1, max(0, x - int(x_range / 2)):x + int(x_range / 2) + 1] else: arr = array[max(0, y - int(y_range / 2)):y + int(y_range / 2) + 1, max(0, x - int(x_range / 2)):x + int(x_range / 2) + 1] # Adjust meshes if they exceed the array shape x_min = -min(0, x - int(x_range / 2)) x_max = xx.shape[1] - max(0, x + int(x_range / 2) - array.shape[1] + 1) y_min = -min(0, y - int(y_range / 2)) y_max = yy.shape[0] - max(0, y + int(y_range / 2) - array.shape[0] + 1) offset = (max(0, int(y - (y_range / 2))), max(0, int(x - (x_range / 2)))) yy = yy[y_min:y_max, x_min:x_max] xx = xx[y_min:y_max, x_min:x_max] dist_arr = np.sqrt(yy**2 + xx**2) if edge_mask is not None: smooth_mask = arr else: smooth_mask = \ smooth_edges(arr <= value_thresh, filter_size, min_pixels) region_mask = \ Ellipse2D(True, 0.0, 0.0, major * max_extent, minor * max_extent, pa)(xx, yy).astype(bool) region_mask = nd.binary_dilation(region_mask, eight_conn, iterations=2) # The bubble center must fall within a valid region mid_pt = np.where(dist_arr == 0.0) if len(mid_pt[0]) == 0: middle_fail = True else: local_center = zip(*np.where(dist_arr == 0.0))[0] middle_fail = False # _make_bubble_mask(smooth_mask, local_center) # If the center is not contained within a bubble region, return # empties. bad_case = not smooth_mask.any() or smooth_mask.all() or \ (smooth_mask * region_mask).all() or middle_fail if bad_case: if return_mask: return np.array([]), 0.0, 0.0, value_thresh, smooth_mask return np.array([]), 0.0, 0.0, value_thresh orig_perim = find_contours(region_mask, 0, fully_connected='high')[0] # new_perim = find_contours(smooth_mask, 0, fully_connected='high') coords = [] extent_mask = np.zeros_like(region_mask) # for perim in new_perim: # perim = perim.astype(np.int) # good_pts = \ # np.array([pos for pos, pt in enumerate(perim) # if region_mask[pt[0], pt[1]]]) # if not good_pts.any(): # continue # # Now split into sections # from utils import consec_split # split_pts = consec_split(good_pts) # # Remove the duplicated end point if it was initially connected # if len(split_pts) > 1: # # Join these if the end pts initially matched # if split_pts[0][0] == split_pts[-1][-1]: # split_pts[0] = np.append(split_pts[0], # split_pts[-1][::-1]) # split_pts.pop(-1) # for split in split_pts: # coords.append(perim[split]) # extent_mask[perim[good_pts][:, 0], perim[good_pts][:, 1]] = True # Based on the curvature of the shell, only fit points whose # orientation matches the assumed centre. # incoord, outcoord = shell_orientation(coords, local_center, # verbose=False) # Now only keep the points that are not blocked from the centre pixel for pt in orig_perim: theta = np.arctan2(pt[0] - local_center[0], pt[1] - local_center[1]) num_pts = int( np.round(np.hypot(pt[0] - local_center[0], pt[1] - local_center[1]), decimals=0)) ys = np.round(np.linspace(local_center[0], pt[0], num_pts), decimals=0).astype(np.int) xs = np.round(np.linspace(local_center[1], pt[1], num_pts), decimals=0).astype(np.int) not_on_edge = np.logical_and(ys < smooth_mask.shape[0], xs < smooth_mask.shape[1]) ys = ys[not_on_edge] xs = xs[not_on_edge] dist = np.sqrt((ys - local_center[0])**2 + (xs - local_center[1])**2) prof = smooth_mask[ys, xs] prof = prof[dist >= min_radius_frac * minor] ys = ys[dist >= min_radius_frac * minor] xs = xs[dist >= min_radius_frac * minor] # Look for the first 0 and ignore all others past it zeros = np.where(prof == 0)[0] # If none, move on if not zeros.any(): continue edge = zeros[0] extent_mask[ys[edge], xs[edge]] = True coords.append((ys[edge], xs[edge])) shell_thetas.append(theta) # Calculate the fraction of the region associated with a shell shell_frac = len(shell_thetas) / float(len(orig_perim)) shell_thetas = np.array(shell_thetas) coords = np.array(coords) # Use the theta values to find the standard deviation i.e. how # dispersed the shell locations are. Assumes a circle, but we only # consider moderately elongated ellipses, so the statistics approx. # hold. theta_var = np.sqrt(circvar(shell_thetas * u.rad)).value extent_coords = \ np.vstack([pt + off for pt, off in zip(np.where(extent_mask), offset)]).T if verbose: print("Shell fraction : " + str(shell_frac)) print("Angular Std. : " + str(theta_var)) import matplotlib.pyplot as p true_region_mask = \ Ellipse2D(True, 0.0, 0.0, major, minor, pa)(xx, yy).astype(bool) ax = p.subplot(121) ax.imshow(arr, origin='lower', interpolation='nearest') ax.contour(smooth_mask, colors='b') ax.contour(region_mask, colors='r') ax.contour(true_region_mask, colors='g') if len(coords) > 0: p.plot(coords[:, 1], coords[:, 0], 'bD') p.plot(local_center[1], local_center[0], 'gD') ax2 = p.subplot(122) ax2.imshow(extent_mask, origin='lower', interpolation='nearest') p.draw() raw_input("?") p.clf() if return_mask: return extent_coords, shell_frac, theta_var, value_thresh, \ extent_mask return extent_coords, shell_frac, theta_var, value_thresh