Esempio n. 1
0
    def __init__(self, x, y, rad, st_memory=100, lt_ratio=10, hl=50):
        # We initialize with circle params for now because that's all we can trace on the image
        # st_memory = how many sequential frames we keep
        # lt_ratio = how many frames to skip before stashing a long-term estimate
        # (lt params are just as long as st_memory)
        # we want to use the st params to calculate the stdev for filtering points
        # and the lt params for setting constraints.
        # hl = half-life for the exponentially weighted moving average

        self.lt_ratio = lt_ratio
        self.hl = hl

        # we store the initial params to make sanity checks
        x, y, rad = float(x), float(y), float(rad)
        self.initial_params = (x, y, rad, rad, 0.)
        self.initial_model = measure.EllipseModel()
        self.initial_model.params = self.initial_params

        # lists of deque to store the parameter history
        self.st_params = [deque(maxlen=st_memory) for i in range(5)]
        self.lt_params = [deque(maxlen=st_memory) for i in range(5)]

        # store the longest axis - aka the pupil diameter
        self.pupil_diam = []

        # store the number of points & residuals we get from edge detection to estimate frame quality
        self.n_points = deque(maxlen=st_memory)
        self.resids = deque(maxlen=st_memory)
        self.obl = deque(maxlen=st_memory)

        # store the standard deviation used to include/exclude points
        # we initialize to 1/8 of the radius of the circle for no particular reason for the first n frames
        self.stdev = 10
        self.stdevs = []
        self.mults = []

        # Make our ellipse model, set, and stash initial parameters
        self.model = measure.EllipseModel()
        self.model.params = (x, y, rad, rad, 0)  # x, y, a, b, theta

        # Make a frame-by-frame ellipse model to perform computations to update lt ellipse
        self.st_model = measure.EllipseModel()
        self.st_model.params = (x, y, rad, rad, 0)  # x, y, a, b, theta

        # counter to keep track of frames
        self.frame_counter = count()
        self.n_frames = 0

        # keep track of the frames where the circle fit failed
        self.failed_frames = []

        self.rmult = []
        self.point_mult = []

        self.f_points = None
Esempio n. 2
0
def approximate_ellipse(contour):
    ellipse = measure.EllipseModel()
    ellipse_dict = {'XY': [], 'Xc': 0, 'Yc': 0, 'a': 0, 'b': 0, 'theta': 0, 'dev': 0}
    if ellipse.estimate(contour):
        ellipse_dict.update({'XY': ellipse.predict_xy(np.linspace(0, 2 * np.pi, 1000), params=ellipse.params)})
        ellipse_dict.update({'Xc': float(ellipse.params[1])})
        ellipse_dict.update({'Yc': float(ellipse.params[0])})
        ellipse_dict.update({'a': float(ellipse.params[2])})
        ellipse_dict.update({'b': float(ellipse.params[3])})
        ellipse_dict.update({'theta': float(ellipse.params[4])})
        # Вычисление ошибки
        residuals_array = ellipse.residuals(contour)
        calc_dev = float(np.sqrt(np.sum((residuals_array ** 2) / len(residuals_array))))
        ellipse_dict.update({'dev': calc_dev})
    else:
        print('Проблема с эллипсом')
    return ellipse_dict
Esempio n. 3
0
def fit_object_coords(points, fit_obj='circle'):
    """Fits objects in each region of the input image, returning the
    parameters of each object.

    Parameters
    ----------
    points : list
        List containing the coordinates to fit the object.
    fit_obj : string, optional (default : 'circle')
        Object to be fitted on the regions. Accepts the strings 'circle'
        and 'ellipse'.

    Returns
    -------
    obj.params : array
        The parameters for the object fitted. Each column represents one
        parameter of the fitted object. For fit_obj='circle', they are
        the coordinates for the center of the circle, and the radius
        (x_center, y_center, radius); for fit_obj='ellipse', they are
        the coordinates for the center of the ellipse, the major and
        minor axis and the orientation (x_center, y_center, minor_axis,
        major_axis, theta).
    """

    obj2model = {
        'circle': measure.CircleModel(),
        'ellipse': measure.EllipseModel()
    }

    try:
        obj = obj2model.get(fit_obj, measure.CircleModel())
        obj.estimate(np.array(points))
        return obj.params

    except TypeError:
        print('Not sufficient points for fitting an object. Sorry')
        return None
Esempio n. 4
0
    def filter_points(self, points):
        # first remove any distractions
        edges_xy = self.convert_edges_xy(points)
        resids = self.model.residuals(edges_xy)
        edges_xy = edges_xy[resids > np.max(self.model.params[2:4]) / 2., :]
        points[edges_xy[:, 1], edges_xy[:, 0]] = 0

        labeled_edges = morphology.label(points)
        uq_edges = np.unique(labeled_edges)[1:]

        # if we only have one, just get on with it
        if len(uq_edges) != 1:
            # fit ellipses for all of em

            m_params = self.model.params
            last_best_ellipse = None
            last_best_resid = np.inf
            for e in uq_edges:
                ellipse_model = measure.EllipseModel()
                edges_xy = self.convert_edges_xy(labeled_edges, e)
                ret = ellipse_model.estimate(edges_xy)
                if not ret:
                    continue

                # pull out some params
                major_ax = np.max(ellipse_model.params[2:4])
                minor_ax = np.min(ellipse_model.params[2:4])
                im_major = np.max(points.shape)
                im_minor = np.min(points.shape)

                # check that we're not all weird
                # shouldn't travel more than 1/8 the image in a single frame...
                dist = euclidean(ellipse_model.params[0:2], m_params[0:2])
                if dist > (im_major / 5):
                    continue

                # or be huge or tiny
                if major_ax > im_major * .75 or major_ax < im_minor / 20:
                    continue

                # or be really oblong
                if major_ax / minor_ax < .6:
                    continue

                # calc distance from initial and last
                mod_resids = np.mean(self.model.residuals(edges_xy)**2)
                init_resids = np.mean(
                    self.initial_model.residuals(edges_xy)**2)
                #print(mod_resids)
                #print(init_resids)
                mean_resid = np.mean((mod_resids, mod_resids, init_resids))

                if mean_resid < last_best_resid:
                    last_best_resid = mean_resid
                    last_best_ellipse = ellipse_model

            # keep only points that made good ellipses
            #labeled_edges = np.isin(labeled_edges, good_ellipses)
            # catch any points that were unconnected but are in our ellipse
            if not last_best_ellipse:
                return False, False, False

            edges_xy = self.convert_edges_xy(points)
            resids = last_best_ellipse.residuals(edges_xy)
            major_ax = np.max(last_best_ellipse.params[2:4])
            edges_xy = edges_xy[resids < (major_ax / 10.), :]

        else:
            edges_xy = self.convert_edges_xy(labeled_edges)

        # now keep only points within certain distance of model

        resids = self.model.residuals(edges_xy)

        # greater than 1sd+mean
        #resids_std = np.mean(resids)+np.std(resids)
        # or 1/10 image size
        #abs_max = np.max(self.model.params[2:4])/5
        #thresh=abs_max

        #print(resids_std)
        #print(abs_max)
        #thresh = np.min((resids_std, abs_max))

        #mask = resids < thresh

        return True, edges_xy, np.mean(resids**2)
Esempio n. 5
0
def testEllpise():
    points = [(560036.4495758876, 6362071.890493258),
              (560036.4495758876, 6362070.890493258),
              (560036.9495758876, 6362070.890493258),
              (560036.9495758876, 6362070.390493258),
              (560037.4495758876, 6362070.390493258),
              (560037.4495758876, 6362064.890493258),
              (560036.4495758876, 6362064.890493258),
              (560036.4495758876, 6362063.390493258),
              (560035.4495758876, 6362063.390493258),
              (560035.4495758876, 6362062.390493258),
              (560034.9495758876, 6362062.390493258),
              (560034.9495758876, 6362061.390493258),
              (560032.9495758876, 6362061.390493258),
              (560032.9495758876, 6362061.890493258),
              (560030.4495758876, 6362061.890493258),
              (560030.4495758876, 6362061.390493258),
              (560029.9495758876, 6362061.390493258),
              (560029.9495758876, 6362060.390493258),
              (560029.4495758876, 6362060.390493258),
              (560029.4495758876, 6362059.890493258),
              (560028.9495758876, 6362059.890493258),
              (560028.9495758876, 6362059.390493258),
              (560028.4495758876, 6362059.390493258),
              (560028.4495758876, 6362058.890493258),
              (560027.4495758876, 6362058.890493258),
              (560027.4495758876, 6362058.390493258),
              (560026.9495758876, 6362058.390493258),
              (560026.9495758876, 6362057.890493258),
              (560025.4495758876, 6362057.890493258),
              (560025.4495758876, 6362057.390493258),
              (560023.4495758876, 6362057.390493258),
              (560023.4495758876, 6362060.390493258),
              (560023.9495758876, 6362060.390493258),
              (560023.9495758876, 6362061.890493258),
              (560024.4495758876, 6362061.890493258),
              (560024.4495758876, 6362063.390493258),
              (560024.9495758876, 6362063.390493258),
              (560024.9495758876, 6362064.390493258),
              (560025.4495758876, 6362064.390493258),
              (560025.4495758876, 6362065.390493258),
              (560025.9495758876, 6362065.390493258),
              (560025.9495758876, 6362065.890493258),
              (560026.4495758876, 6362065.890493258),
              (560026.4495758876, 6362066.890493258),
              (560026.9495758876, 6362066.890493258),
              (560026.9495758876, 6362068.390493258),
              (560027.4495758876, 6362068.390493258),
              (560027.4495758876, 6362068.890493258),
              (560027.9495758876, 6362068.890493258),
              (560027.9495758876, 6362069.390493258),
              (560028.4495758876, 6362069.390493258),
              (560028.4495758876, 6362069.890493258),
              (560033.4495758876, 6362069.890493258),
              (560033.4495758876, 6362070.390493258),
              (560033.9495758876, 6362070.390493258),
              (560033.9495758876, 6362070.890493258),
              (560034.4495758876, 6362070.890493258),
              (560034.4495758876, 6362071.390493258),
              (560034.9495758876, 6362071.390493258),
              (560034.9495758876, 6362071.890493258),
              (560036.4495758876, 6362071.890493258)]

    import skimage.measure as ms
    im = np.zeros((512, 512))

    #for x in xrange(25, 150):
    #    for i in xrange(1, 10):
    #        im[x , x + i ] = 1
    im[50:60, 50:150] = 1
    plt.imshow(im), plt.show()
    #l, w, theta = fitOnImageEllipse(im)
    #print('l= {} w = {} theta = {}'.format(l, w, theta))

    y, x = im.nonzero()
    points = zip(x, y)
    elModel = ms.EllipseModel()
    elModel.estimate(np.array(points))
    print elModel.params

    fig, axs = plt.subplots(2, 1, sharex=True, sharey=True)
    a_points = np.array(points)
    x = a_points[:, 0]
    y = a_points[:, 1]
    axs[0].plot(x, y)
    center, phi, axes = find_ellipse(x, y)
    print "center = ", center
    print "angle of rotation = ", phi
    print "axes = ", axes

    axs[1].plot(x, y)
    axs[1].scatter(center[0], center[1], color='red', s=100)
    axs[1].set_xlim(x.min(), x.max())
    axs[1].set_ylim(y.min(), y.max())

    plt.show()
Esempio n. 6
0
def video_from_params(param_fn, ell_fn, which_vid=0):
    thetas = np.linspace(0, np.pi * 2, num=300, endpoint=False)

    # load params from .json file, vid filenames will be in there
    with open(param_fn, 'r') as param_f:
        params = json.load(param_f)

    # for now just do one video
    vid_fn = str(params['files'][which_vid])

    vid = cv2.VideoCapture(vid_fn)
    total_frames = int(vid.get(cv2.CAP_PROP_FRAME_COUNT))

    ell_df = pd.read_csv(ell_fn)

    vid_path, vid_name = os.path.split(vid_fn)
    vid_name = "Ellone_" + vid_name.rsplit('.', 1)[0] + ".mp4"
    vid_out_fn = vid_path + "/" + vid_name

    writer = io.FFmpegWriter(vid_out_fn, outputdict={'-vcodec': 'libx264'})

    emod = measure.EllipseModel()

    ell_frame = ell_df.groupby('n')

    for i in trange(total_frames):

        ret, frame = vid.read()
        if ret == False:
            break
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        frame = imops.crop(frame, params['roi'])
        frame = img_as_float(frame)

        try:
            ell_rows = ell_frame.get_group(i)

            for i, e in ell_rows.iterrows():
                e_points = emod.predict_xy(thetas,
                                           params=(e.x, e.y, e.a, e.b, e.t))
                e_points = e_points.astype(np.int)

                draw.set_color(frame, (e_points[:, 0], e_points[:, 1]),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0] + 1, e_points[:, 1]),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0] - 1, e_points[:, 1]),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0], e_points[:, 1] + 1),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0], e_points[:, 1] - 1),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0] + 1, e_points[:, 1] + 1),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0] + 1, e_points[:, 1] - 1),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0] - 1, e_points[:, 1] + 1),
                               (1, 0, 0))
                draw.set_color(frame, (e_points[:, 0] - 1, e_points[:, 1] - 1),
                               (1, 0, 0))

        except KeyError:
            # no ellipses this frame, just write frame
            pass

        writer.writeFrame(frame * 255)

    writer.close()
Esempio n. 7
0
def play_fit(vid, roi, params, fps=30):
    thetas = np.linspace(0, np.pi * 2, num=200, endpoint=False)

    # start vid at first frame in params
    if "n" in params.keys():

        first_frame = params.n.min()
    else:
        first_frame = params.index.min()

    ret = vid.set(cv2.CAP_PROP_POS_FRAMES, first_frame)

    frame_counter = count()

    emod = measure.EllipseModel()

    cv2.namedWindow('play', flags=cv2.WINDOW_NORMAL)
    for i in xrange(len(params)):
        k = cv2.waitKey(1) & 0xFF
        if k == ord('\r'):
            break

        ret, frame_orig = vid.read()
        if ret == False:
            break
        frame_orig = cv2.cvtColor(frame_orig, cv2.COLOR_BGR2RGB)

        n_frame = frame_counter.next()

        if 'n' in params.keys():
            ell_rows = params[params.n == n_frame]
            frame_orig = imops.crop(frame_orig, roi)
            frame_orig = img_as_float(frame_orig)
            for i, e in ell_rows.iterrows():
                e_points = emod.predict_xy(thetas,
                                           params=(e.x, e.y, e.a, e.b, e.t))
                e_points = e_points.astype(np.int)

                draw.set_color(frame_orig, (e_points[:, 0], e_points[:, 1]),
                               (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0] + 1, e_points[:, 1]), (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0] - 1, e_points[:, 1]), (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0], e_points[:, 1] + 1), (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0], e_points[:, 1] - 1), (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0] + 1, e_points[:, 1] + 1),
                               (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0] + 1, e_points[:, 1] - 1),
                               (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0] - 1, e_points[:, 1] + 1),
                               (1, 0, 0))
                draw.set_color(frame_orig,
                               (e_points[:, 0] - 1, e_points[:, 1] - 1),
                               (1, 0, 0))

        else:
            p = params.iloc[n_frame]
            e_points = emod.predict_xy(thetas,
                                       params=(p.x, p.y, p.a, p.b, p.t))
            e_points = e_points.astype(np.int)

            frame_orig = imops.crop(frame_orig, roi)
            frame_orig = img_as_float(frame_orig)

            draw.set_color(frame_orig, (e_points[:, 0], e_points[:, 1]),
                           (1, 0, 0))
            draw.set_color(frame_orig, (e_points[:, 0] + 1, e_points[:, 1]),
                           (1, 0, 0))
            draw.set_color(frame_orig, (e_points[:, 0] - 1, e_points[:, 1]),
                           (1, 0, 0))
            draw.set_color(frame_orig, (e_points[:, 0], e_points[:, 1] + 1),
                           (1, 0, 0))
            draw.set_color(frame_orig, (e_points[:, 0], e_points[:, 1] - 1),
                           (1, 0, 0))
            draw.set_color(frame_orig,
                           (e_points[:, 0] + 1, e_points[:, 1] + 1), (1, 0, 0))
            draw.set_color(frame_orig,
                           (e_points[:, 0] + 1, e_points[:, 1] - 1), (1, 0, 0))
            draw.set_color(frame_orig,
                           (e_points[:, 0] - 1, e_points[:, 1] + 1), (1, 0, 0))
            draw.set_color(frame_orig,
                           (e_points[:, 0] - 1, e_points[:, 1] - 1), (1, 0, 0))
        cv2.imshow('play', frame_orig)
        sleep(1. / fps)

        # frame_orig = frame_orig*255
        # frame_orig = frame_orig.astype(np.uint8)

        # writer.writeFrame(frame_orig)

    cv2.destroyAllWindows()