def fit_region(coords, initial_props=None, try_fit_ellipse=True, use_ransac=False, min_in_mask=0.8, mask=None, max_resid=None, ransac_trials=50, beam_pix=4, max_rad=1.75, max_eccent=3., image_shape=None, conv_hull=None, verbose=False): ''' Fit a circle or ellipse to the given coordinates. ''' coords = np.array(coords).copy() ymean = coords[:, 0].mean() xmean = coords[:, 1].mean() # Fitting works better when the points are near the origin coords[:, 0] -= int(ymean) coords[:, 1] -= int(xmean) new_props = np.empty((5, )) if len(coords) < 3: raise ValueError("Must have at least 3 points to fit.") if len(coords) > 5 and try_fit_ellipse: with catch_warnings(): filterwarnings("ignore", r"Number of calls to function") filterwarnings("ignore", r"gtol=0.000000 is too small") if use_ransac: model, inliers = \ ransac(coords[:, ::-1], EllipseModel, 5, beam_pix, max_trials=ransac_trials) else: model = EllipseModel() model.estimate(coords[:, ::-1]) dof = len(coords) - 5 # Calculate the model residual resid = model.residuals(coords[:, ::-1]).sum() / dof pars = model.params.copy() pars[0] += int(xmean) pars[1] += int(ymean) eccent = pars[2] / float(pars[3]) # Sometimes a < b?? If so, manually correct. if eccent < 1: eccent = 1. / eccent pars[2], pars[3] = pars[3], pars[2] pars[4] = wrap_to_pi(pars[4] + 0.5 * np.pi) fail_conds = eccent > max_eccent if beam_pix is not None and not fail_conds: fail_conds = fail_conds or \ pars[3] < beam_pix if max_resid is not None and not fail_conds: fail_conds = fail_conds or \ resid > max_resid if initial_props is not None and not fail_conds: fail_conds = fail_conds or \ pars[2] > max_rad * initial_props[2] or \ not in_ellipse(initial_props[:2][::-1], pars) if image_shape is not None and not fail_conds: fail_conds = fail_conds or \ not in_array(pars[:2], image_shape[::-1]) # We require the entire region be inside the array. This # shouldn't be a big issue for galaxies, but should be revisited # when testing on galactic emission or incomplete maps. fail_conds = fail_conds or not \ ellipse_in_array(pars, image_shape[::-1]) if mask is not None and not fail_conds: # Make sure most of the region falls within the hole mask fail_conds = fail_conds or \ fraction_in_mask(pars, mask) < min_in_mask # Now make sure the region is within a region with signal. # We define this based on the convex hull. It seems # appropriate to just use min_in_mask, since most of it needs to # be within the region. if conv_hull is not None and not fail_conds: fail_conds = fail_conds or \ fraction_in_mask(pars, conv_hull) < min_in_mask # The center of the fit should fall within the convex hull mask y, x = floor_int(pars[1]), floor_int(pars[0]) fail_conds = fail_conds or not conv_hull[y, x] if fail_conds: ellip_fail = True else: new_props[0] = pars[1] new_props[1] = pars[0] new_props[2] = pars[2] new_props[3] = pars[3] new_props[4] = pars[4] ellip_fail = False else: ellip_fail = True # If ellipse fitting is not allowed, or it failed, fit a circle if ellip_fail: with catch_warnings(): filterwarnings("ignore", r"Number of calls to function") filterwarnings("ignore", r"gtol=0.000000 is too small") if use_ransac: model, inliers = \ ransac(coords[:, ::-1], CircleModel, 3, beam_pix, max_trials=ransac_trials) else: model = CircleModel() model.estimate(coords[:, ::-1]) dof = len(coords) - 3 # Calculate the model residual resid = model.residuals(coords[:, ::-1]).sum() / dof pars = model.params.copy() pars[0] += int(xmean) pars[1] += int(ymean) fail_conds = False if beam_pix is not None and not fail_conds: fail_conds = fail_conds or \ pars[2] < beam_pix if max_resid is not None and not fail_conds: fail_conds = fail_conds or \ resid > max_resid if initial_props is not None and not fail_conds: fail_conds = fail_conds or \ pars[2] > max_rad * initial_props[2] or \ not in_circle(initial_props[:2][::-1], pars) if image_shape is not None and not fail_conds: fail_conds = fail_conds or \ not in_array(pars[:2], image_shape[::-1]) # We require the entire region be inside the array. This # shouldn't be a big issue for galaxies, but should be revisited # when testing on galactic emission or incomplete maps. fail_conds = fail_conds or not \ circle_in_array(pars, image_shape[::-1]) if mask is not None and not fail_conds: fail_conds = fail_conds or \ fraction_in_mask(pars, mask) < min_in_mask if conv_hull is not None and not fail_conds: # Needs to be in convex hull. See ellipse rejections fail_conds = fail_conds or \ fraction_in_mask(pars, conv_hull) < min_in_mask # The center of the fit should fall within the convex hull mask y, x = floor_int(pars[1]), floor_int(pars[0]) fail_conds = fail_conds or not conv_hull[y, x] if fail_conds: if verbose: Warning("All fitting failed.") return None, None new_props[0] = pars[1] new_props[1] = pars[0] new_props[2] = pars[2] new_props[3] = pars[2] new_props[4] = 0.0 props = new_props return props, resid
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 fit_region(coords, initial_props=None, try_fit_ellipse=True, use_ransac=False, min_in_mask=0.8, mask=None, max_resid=None, ransac_trials=50, beam_pix=4, max_rad=1.75, max_eccent=3., image_shape=None, conv_hull=None, verbose=False): ''' Fit a circle or ellipse to the given coordinates. ''' coords = np.array(coords).copy() ymean = coords[:, 0].mean() xmean = coords[:, 1].mean() # Fitting works better when the points are near the origin coords[:, 0] -= int(ymean) coords[:, 1] -= int(xmean) new_props = np.empty((5,)) if len(coords) < 3: raise ValueError("Must have at least 3 points to fit.") if len(coords) > 5 and try_fit_ellipse: with catch_warnings(): filterwarnings("ignore", r"Number of calls to function") filterwarnings("ignore", r"gtol=0.000000 is too small") if use_ransac: model, inliers = \ ransac(coords[:, ::-1], EllipseModel, 5, beam_pix, max_trials=ransac_trials) else: model = EllipseModel() model.estimate(coords[:, ::-1]) dof = len(coords) - 5 # Calculate the model residual resid = model.residuals(coords[:, ::-1]).sum() / dof pars = model.params.copy() pars[0] += int(xmean) pars[1] += int(ymean) eccent = pars[2] / float(pars[3]) # Sometimes a < b?? If so, manually correct. if eccent < 1: eccent = 1. / eccent pars[2], pars[3] = pars[3], pars[2] pars[4] = wrap_to_pi(pars[4] + 0.5 * np.pi) fail_conds = eccent > max_eccent if beam_pix is not None and not fail_conds: fail_conds = fail_conds or \ pars[3] < beam_pix if max_resid is not None and not fail_conds: fail_conds = fail_conds or \ resid > max_resid if initial_props is not None and not fail_conds: fail_conds = fail_conds or \ pars[2] > max_rad * initial_props[2] or \ not in_ellipse(initial_props[:2][::-1], pars) if image_shape is not None and not fail_conds: fail_conds = fail_conds or \ not in_array(pars[:2], image_shape[::-1]) # We require the entire region be inside the array. This # shouldn't be a big issue for galaxies, but should be revisited # when testing on galactic emission or incomplete maps. fail_conds = fail_conds or not \ ellipse_in_array(pars, image_shape[::-1]) if mask is not None and not fail_conds: # Make sure most of the region falls within the hole mask fail_conds = fail_conds or \ fraction_in_mask(pars, mask) < min_in_mask # Now make sure the region is within a region with signal. # We define this based on the convex hull. It seems # appropriate to just use min_in_mask, since most of it needs to # be within the region. if conv_hull is not None and not fail_conds: fail_conds = fail_conds or \ fraction_in_mask(pars, conv_hull) < min_in_mask # The center of the fit should fall within the convex hull mask y, x = floor_int(pars[1]), floor_int(pars[0]) fail_conds = fail_conds or not conv_hull[y, x] if fail_conds: ellip_fail = True else: new_props[0] = pars[1] new_props[1] = pars[0] new_props[2] = pars[2] new_props[3] = pars[3] new_props[4] = pars[4] ellip_fail = False else: ellip_fail = True # If ellipse fitting is not allowed, or it failed, fit a circle if ellip_fail: with catch_warnings(): filterwarnings("ignore", r"Number of calls to function") filterwarnings("ignore", r"gtol=0.000000 is too small") if use_ransac: model, inliers = \ ransac(coords[:, ::-1], CircleModel, 3, beam_pix, max_trials=ransac_trials) else: model = CircleModel() model.estimate(coords[:, ::-1]) dof = len(coords) - 3 # Calculate the model residual resid = model.residuals(coords[:, ::-1]).sum() / dof pars = model.params.copy() pars[0] += int(xmean) pars[1] += int(ymean) fail_conds = False if beam_pix is not None and not fail_conds: fail_conds = fail_conds or \ pars[2] < beam_pix if max_resid is not None and not fail_conds: fail_conds = fail_conds or \ resid > max_resid if initial_props is not None and not fail_conds: fail_conds = fail_conds or \ pars[2] > max_rad * initial_props[2] or \ not in_circle(initial_props[:2][::-1], pars) if image_shape is not None and not fail_conds: fail_conds = fail_conds or \ not in_array(pars[:2], image_shape[::-1]) # We require the entire region be inside the array. This # shouldn't be a big issue for galaxies, but should be revisited # when testing on galactic emission or incomplete maps. fail_conds = fail_conds or not \ circle_in_array(pars, image_shape[::-1]) if mask is not None and not fail_conds: fail_conds = fail_conds or \ fraction_in_mask(pars, mask) < min_in_mask if conv_hull is not None and not fail_conds: # Needs to be in convex hull. See ellipse rejections fail_conds = fail_conds or \ fraction_in_mask(pars, conv_hull) < min_in_mask # The center of the fit should fall within the convex hull mask y, x = floor_int(pars[1]), floor_int(pars[0]) fail_conds = fail_conds or not conv_hull[y, x] if fail_conds: if verbose: Warning("All fitting failed.") return None, None new_props[0] = pars[1] new_props[1] = pars[0] new_props[2] = pars[2] new_props[3] = pars[2] new_props[4] = 0.0 props = new_props return props, resid