Пример #1
0
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
Пример #2
0
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)
Пример #3
0
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