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
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