예제 #1
0
def _compile_multi_frame(col, mkr_list, attr_list, root_frame_list, frame_list,
                         auto_attr_blocks, block_iter_num, only_root_frames,
                         root_iter_num, anim_iter_num, global_solve,
                         root_frame_strategy, triangulate_bundles,
                         use_euler_filter, precomputed_data, withtest,
                         verbose):
    """
    Generate Actions to solve multiple-frames.

    :param mkr_list:
        Markers to be solved with.
    :type mkr_list: [Marker, ..]

    :param attr_list:
        Attributes to be solved.
    :type attr_list: [Attribute, ..]

    :param root_frame_list:
        Frames to solve static and animated attributes.
    :type root_frame_list: [[Frame, ..], ..]

    :param frame_list:
        Frames to solve animated attributes.
    :type frame_list: [Frame, ..]

    :param auto_attr_blocks:
        Split attributes into stages (based on categories) to be
        solved together.
    :type auto_attr_blocks: bool

    :param block_iter_num:
        How many iterations to perform for attribute categories.
    :type block_iter_num: int

    :param only_root_frames:
        Only solve the root frames.
    :param only_root_frames: bool

    :param root_iter_num:
        Number of iterations for root frame solves.
    :type root_iter_num: int

    :param anim_iter_num:
        Number of iterations for animated attribute solves.
    :type anim_iter_num: int

    :param global_solve:
        Should all frames be solved together, both animated and static
        attributes?
    :type global_solve: bool

    :param root_frame_strategy:
        The strategy ordering of root frames and how to solve them.
        Value must be one in ROOT_FRAME_STRATEGY_VALUE_LIST
    :type root_frame_strategy:

    :param triangulate_bundles:
        If True, unlocked bundles will be triangulated before being
        further refined by the solver processes.
    :type triangulate_bundles: bool

    :param use_euler_filter:
        Perform a Euler Filter after solving? A Euler filter will make
        sure no two keyframes rotate by more than 180 degrees, which
        will remove "Euler Flipping".
    :type use_euler_filter: bool

    :param withtest:
        Should validation tests be generated?
    :type withtest: bool

    :param verbose:
        Print out more detail than usual.
    :type verbose: bool

    :return:
        Yields a generator of two Actions. First Action is for solving,
        the second Action is for validation of inputs.
    :rtype: (Action, Action)
    """
    root_frame_list_num = [x.get_number() for x in root_frame_list]
    frame_list_num = [x.get_number() for x in frame_list]
    non_root_frame_list_num = set(frame_list_num) - set(root_frame_list_num)
    non_root_frame_list = [frame.Frame(x) for x in non_root_frame_list_num]

    all_frame_list_num = list(set(frame_list_num + root_frame_list_num))
    all_frame_list_num = list(sorted(all_frame_list_num))
    all_frame_list = [frame.Frame(x) for x in all_frame_list_num]
    start_frame = all_frame_list[0]
    end_frame = all_frame_list[-1]

    # Triangulate the (open) bundles here. We triangulate all
    #  valid bundles after the root frames have solved.
    #
    # NOTE: Bundle triangulation can only happen if the camera
    # is not nodal.
    if triangulate_bundles is True:
        sol = solvertriangulate.SolverTriangulate()
        # sol.root_frame_list = root_frame_list_num
        cache = api_compile.create_compile_solver_cache()
        generator = api_compile.compile_solver_with_cache(
            sol, col, mkr_list, attr_list, withtest, cache)
        for action, vaction in generator:
            yield action, vaction

    # Solver root frames, breaking attributes into little blocks
    # to solve.
    root_mkr_list, non_root_mkr_list = _filter_mkr_list_by_frame_list(
        mkr_list, root_frame_list)
    if len(root_mkr_list) == 0:
        # TODO: Test we have enough markers to solve with, if not warn
        #  the user.
        # action = api_action.Action(func='pass', args=[], kwargs={})
        # vaction = api_action.Action(func='', args=[], kwargs={})
        # yield action, vaction
        LOG.warn("Not enough Markers given for root frames.")
        return
    if auto_attr_blocks is True:
        meta_mkr_list, meta_attr_list = _split_mkr_attr_into_categories(
            root_mkr_list, attr_list)
        for new_mkr_list, new_attr_list in zip(meta_mkr_list, meta_attr_list):
            sol = solverstep.SolverStep()
            sol.set_max_iterations(block_iter_num)
            sol.set_frame_list(root_frame_list)
            sol.set_attributes_use_animated(True)
            sol.set_attributes_use_static(True)
            sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD)
            sol.set_use_smoothness(False)
            sol.set_use_stiffness(False)
            sol.set_precomputed_data(precomputed_data)

            cache = api_compile.create_compile_solver_cache()
            generator = api_compile.compile_solver_with_cache(
                sol, col, new_mkr_list, new_attr_list, withtest, cache)
            for action, vaction in generator:
                yield action, vaction

    # TODO: Create a list of markers specially for root frames.
    #  Loop over all given markers, determine which markers have 2
    #  or more root frames, only use those markers for root frame
    #  computation. Overall, we must filter out all markers that
    #  cannot/should not be used for different solves.
    #
    # TODO: We must make sure to allow the solver to detect that
    #  not enough markers are being used, and warn the user.
    #
    # TODO: All markers that do not have enough root frames to solve
    #  correctly, but the Bundle is still in the solver, then it should
    #  be triangulated after the initial root frame solve is performed.
    #
    # TODO: Run the solver multiple times for a hierarchy. First,
    #  solve DAG level 0 nodes, then add DAG level 1, then level 2,
    #  etc. This will allow us to incrementally add solving of
    #  hierarchy, without getting the optimiser confused which
    #  attributes to solve first to get a stable solve.

    if root_frame_strategy == const.ROOT_FRAME_STRATEGY_GLOBAL_VALUE:
        # Global solve of root frames.
        sol = solverstep.SolverStep()
        sol.set_max_iterations(root_iter_num)
        sol.set_frame_list(root_frame_list)
        sol.set_attributes_use_animated(True)
        sol.set_attributes_use_static(True)
        sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD)
        sol.set_use_smoothness(False)
        sol.set_use_stiffness(False)
        sol.set_precomputed_data(precomputed_data)

        cache = api_compile.create_compile_solver_cache()
        generator = api_compile.compile_solver_with_cache(
            sol, col, root_mkr_list, attr_list, withtest, cache)
        for action, vaction in generator:
            yield action, vaction
    else:
        # Get the order of frames to solve with.
        batch_frame_list = []
        if root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_VALUE:
            # Two frames at a time, moving forward, plus a global solve
            # at the end.
            batch_frame_list = _gen_two_frame_fwd(root_frame_list_num)
            batch_frame_list.append(root_frame_list)
        elif root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_AND_GLOBAL_VALUE:
            # Two frames at a time, moving forward.
            batch_frame_list = _gen_two_frame_fwd(root_frame_list_num)
        else:
            # TODO: Root frame ordering can be determined by the
            #  count of markers available at each frame. After we
            #  have an ordering of these frames, we can solve the
            #  frames incrementally, starting with the first
            #  highest, then add the next highest, etc. This
            #  should ensure stability of the solver is maximum.
            raise NotImplementedError
        generator = _compile_multi_root_frames(col, mkr_list, attr_list,
                                               batch_frame_list, root_iter_num,
                                               precomputed_data, withtest,
                                               verbose)
        for action, vaction in generator:
            yield action, vaction

    # Clear out all the frames between the solved root frames, this
    # helps us use the new solve root frames to hint the 'in-between'
    # frame solve.
    generator = _compile_remove_inbetween_frames(attr_list,
                                                 non_root_frame_list,
                                                 start_frame, end_frame,
                                                 withtest, verbose)
    for action, vaction in generator:
        yield action, vaction
    if only_root_frames is True:
        return

    # Perform an euler filter on all unlocked rotation attributes.
    if use_euler_filter is True:
        generator = solverutils.compile_euler_filter(attr_list, withtest)
        for action, vaction in generator:
            yield action, vaction

    generator = _compile_multi_inbetween_frames(
        col,
        mkr_list,
        attr_list,
        all_frame_list,
        global_solve,
        anim_iter_num,
        precomputed_data,
        withtest,
        verbose,
    )
    for action, vaction in generator:
        yield action, vaction
    return
예제 #2
0
def _compile_multi_frame(mkr_list,
                         attr_list,
                         root_frame_list,
                         frame_list,
                         auto_attr_blocks,
                         block_iter_num,
                         only_root_frames,
                         root_iter_num,
                         anim_iter_num,
                         global_solve,
                         root_frame_strategy,
                         triangulate_bundles,
                         test,
                         verbose):
    assert len(root_frame_list) >= 2
    assert len(frame_list) >= 2
    root_frame_list_num = [x.get_number() for x in root_frame_list]
    frame_list_num = [x.get_number() for x in frame_list]
    non_root_frame_list_num = set(frame_list_num) - set(root_frame_list_num)
    non_root_frame_list = [frame.Frame(x) for x in non_root_frame_list_num]

    all_frame_list_num = list(set(frame_list_num + root_frame_list_num))
    all_frame_list_num = list(sorted(all_frame_list_num))
    all_frame_list = [frame.Frame(x) for x in all_frame_list_num]
    start_frame = all_frame_list[0]
    end_frame = all_frame_list[-1]

    # Triangulate the (open) bundles here. We triangulate all
    #  valid bundles after the root frames have solved.
    #
    # NOTE: Bundle triangulation can only happen if the camera
    # is not nodal.
    if triangulate_bundles is True:
        sol = solvertriangulate.SolverTriangulate()
        # sol.root_frame_list = root_frame_list_num
        cache = api_compile.create_compile_solver_cache()
        generator = api_compile.compile_solver_with_cache(
            sol, mkr_list, attr_list, test, cache
        )
        for action, vaction in generator:
            yield action, vaction

    # Solver root frames, breaking attributes into little blocks
    # to solve.
    root_mkr_list, non_root_mkr_list = _filter_mkr_list_by_frame_list(
        mkr_list,
        root_frame_list
    )
    if auto_attr_blocks is True:
        meta_mkr_list, meta_attr_list = _split_mkr_attr_into_categories(
            root_mkr_list,
            attr_list
        )
        for new_mkr_list, new_attr_list in zip(meta_mkr_list, meta_attr_list):
            sol = solverstep.SolverStep()
            sol.set_verbose(verbose)
            sol.set_max_iterations(block_iter_num)
            sol.set_frame_list(root_frame_list)
            sol.set_attributes_use_animated(True)
            sol.set_attributes_use_static(True)
            sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD)

            cache = api_compile.create_compile_solver_cache()
            generator = api_compile.compile_solver_with_cache(
                sol, new_mkr_list, new_attr_list, test, cache
            )
            for action, vaction in generator:
                yield action, vaction

    # TODO: Create a list of markers specially for root frames.
    #  Loop over all given markers, determine which markers have 2
    #  or more root frames, only use those markers for root frame
    #  computation. Overall, we must filter out all markers that
    #  cannot/should not be used for different solves.
    #
    # TODO: We must make sure to allow the solver to detect that
    #  not enough markers are being used, and warn the user.
    #
    # TODO: All markers that do not have enough root frames to solve
    #  correctly, but the Bundle is still in the solver, then it should
    #  be triangulated after the initial root frame solve is performed.
    #
    # TODO: Run the solver multiple times for a hierarchy. First,
    #  solve DAG level 0 nodes, then add DAG level 1, then level 2,
    #  etc. This will allow us to incrementally add solving of
    #  hierarchy, without getting the optimiser confused which
    #  attributes to solve first to get a stable solve.

    if root_frame_strategy == const.ROOT_FRAME_STRATEGY_GLOBAL_VALUE:
        # Global solve of root frames.
        sol = solverstep.SolverStep()
        sol.set_verbose(verbose)
        sol.set_max_iterations(root_iter_num)
        sol.set_frame_list(root_frame_list)
        sol.set_attributes_use_animated(True)
        sol.set_attributes_use_static(True)
        sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD)

        cache = api_compile.create_compile_solver_cache()
        generator = api_compile.compile_solver_with_cache(
            sol, root_mkr_list, attr_list, test, cache
        )
        for action, vaction in generator:
            yield action, vaction
    else:
        # Get the order of frames to solve with.
        batch_frame_list = []
        if root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_VALUE:
            # Two frames at a time, moving forward, plus a global solve
            # at the end.
            batch_frame_list = _gen_two_frame_fwd(root_frame_list_num)
            batch_frame_list.append(root_frame_list)
        elif root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_AND_GLOBAL_VALUE:
            # Two frames at a time, moving forward.
            batch_frame_list = _gen_two_frame_fwd(root_frame_list_num)
        else:
            # TODO: Root frame ordering can be determined by the
            #  count of markers available at each frame. After we
            #  have an ordering of these frames, we can solve the
            #  frames incrementally, starting with the first
            #  highest, then add the next highest, etc. This
            #  should ensure stability of the solver is maximum.
            raise NotImplementedError
        generator = _compile_multi_root_frames(
            mkr_list,
            attr_list,
            batch_frame_list,
            root_iter_num,
            test,
            verbose
        )
        for action, vaction in generator:
            yield action, vaction

    # Clear out all the frames between the solved root frames, this
    # helps us use the new solve root frames to hint the 'in-between'
    # frame solve.
    generator = _compile_remove_inbetween_frames(
        attr_list,
        non_root_frame_list,
        start_frame,
        end_frame,
        test,
        verbose
    )
    for action, vaction in generator:
        yield action, vaction
    if only_root_frames is True:
        return

    generator = _compile_multi_inbetween_frames(
        mkr_list,
        attr_list,
        all_frame_list,
        global_solve,
        anim_iter_num,
        test,
        verbose,
    )
    for action, vaction in generator:
        yield action, vaction
    return