dc_a, dc_b, simisize=simisize, similim=similim) stopwatch += time() print("\t{} matches made".format(len(nodes1))) print("\tDone in {0:.3f}s\n".format(stopwatch)) #%% Detect silhouette key points if dosilhouette: print("Detecting silhouette points ...") stopwatch = -time() base = np.row_stack((nodes0[4:], nodes1)) if docorners else nodes0[4:] sp_a = algo.spawn(Ea, base[:, [0, 1]], spawnpoints, r_min=simisize) sp_b = algo.spawn(Eb, base[:, [2, 3]], spawnpoints, r_min=simisize) sp_at = algo.swirl(sp_a, com_a, com_b) stopwatch += time() print("\t{} silhouette points in A".format(len(sp_a))) print("\t{} silhouette points in B".format(len(sp_b))) print("\tDone in {0:.3f}s\n".format(stopwatch)) #%% Match key points if dosilhouette: print("Matching silhouette points ...") n_spawn = int(spawnpoints / 2) stopwatch = -time()
#%% Center of mass print("Center of mass computation ...\n\t", end="") stopwatch = -time() com = algo.commie(S) stopwatch += time() print("\tDone in {0:.3f}s\n".format(stopwatch)) #%% Detect silhouette key points print("Detecting silhouette points ...", end="") stopwatch = -time() nodes0 = algo.seed(*E.shape, com, com) base = nodes0[4:] sp = algo.spawn(E, base[:, [0, 1]], spawnpoints, r_min=simisize) stopwatch += time() print("\t{} silhouette points".format(len(sp))) print("\tDone in {0:.3f}s\n".format(stopwatch)) ########### # Cactify # ########### #%% Mini center of mass evaluation for each evaluation point print("Cactification ... ", end="") stopwatch = -time() h, w = K.shape[:2] vv = np.zeros(sp.shape)
else: Ga = algo.desaturate(Da, cutoff=cutoff) Gb = algo.desaturate(Db, cutoff=cutoff) print("done") # Center of mass determines translation print("A ", end="") com_a = algo.commie(Sa) print("B ", end="") com_b = algo.commie(Sb) base = np.array([[com_a['x'], com_a['y'], com_b['x'], com_b['y']]]) # Detect key points target = int(np.floor(min([Ea.sum(), Eb.sum()]) * keyfill)) print("Picking key points ... ", end="") kp_a = algo.spawn(Ea, base[:, [0, 1]], target, r_min=detail) kp_b = algo.spawn(Eb, base[:, [2, 3]], target, r_min=detail) print("done") # Match key points print("Matching key points ... ", end="") stopwatch = -time() extractor = BRIEF(patch_size=patch_size, sigma=0) extractor.extract(Ga, kp_a[:, [1, 0]]) dc_a = extractor.descriptors extractor.extract(Gb, kp_b[:, [1, 0]]) dc_b = extractor.descriptors matches = match_descriptors(dc_a, dc_b)
def trajectory(settings, m, recycle=False, thread=None, X=None, Y=None, Ka=None, Kb=None, Ea=None, Eb=None, com_a=None, com_b=None, kp_a=None, kp_b=None, dc_a=None, dc_b=None): """ Figure out node trajectories for the given morph sequence *m*, based on silhouette map and corner descriptors. Two temporary analysis files are generated: - nodes.csv node trajectory coordinates. - move.png node trajectory chart. Usage ----- >>> nodes, Ka, Kb, com_a, com_b = trajectory(settings, m, recycle, thread) Parameters ---------- recycle : bool, optional If set to True and if output exists from a previous run, then that will be recycled. thread : object, optional Send status reports back through this channel, presumably a PyQt Qthread activated by the grapical user interface. This can be any object though, as long as it contains: - *abort*. A boolean status flag (True/False) that signals whether the user has had enough, and pressed a cancel button or such. - *report*. A progress report signal. Must have a method *emit* that accepts strings (which will either an image file name or one-line status report). Returns ------- None in case of user abort, node trajectory coordinate array otherwise. Notes ----- If silhouette map and corner keypoint coordinates are not available, then *silhouette* and *cornercatch* will be called to create these. """ # Tell everyone about the fantastic voyage we are about to embark upon if count_morphs(settings) > 1: label = ' for morph {}'.format(m + 1) else: label = '' shoutout(msg='Detecting trajectories' + label, thread=thread) # Start the timer stopwatch = -time() # Key frame indices and output files a, b = morph_key_indices(settings, m) folder_m = path.join(settings['temppath'], 'm{0:03d}'.format(m + 1)) folder_a = path.join(settings['temppath'], 'k{0:03d}'.format(a + 1)) folder_b = path.join(settings['temppath'], 'k{0:03d}'.format(b + 1)) f1 = path.join(folder_m, 'move.png') f2 = path.join(folder_m, 'nodes.csv') # Assemble the settings s = settings['traject'] docorners = s['corners' ][m] dosilhouette = s['silhouette'][m] arc = s['arc' ][m] spin = s['spin' ][m] and arc similim = s['similim' ][m] * 1e-2 maxmove = s['maxmove' ][m] * 1e-2 maxpoints = s['maxpoints' ][m] neighbours = s['neighbours'][m] # Detect silhouette of key frame A if Ka is None or Ea is None or com_a is None: msg = 'Extracting silhouette for key {}'.format(a + 1) shoutout(msg=msg, thread=thread) result = silhouette(settings, a, K=Ka, X=X, Y=Y, recycle=True) fsa, Ka, Ea, com_a = result shoutout(img=fsa, thread=thread) if thread and thread.abort: return # Detect silhouette of key frame B if Kb is None or Eb is None or com_b is None: msg = 'Extracting silhouette for key {}'.format(b + 1) shoutout(msg, thread=thread) result = silhouette(settings, b, K=Kb, X=X, Y=Y, recycle=True) fsb, Kb, Eb, com_b = result shoutout(img=fsb, thread=thread) if thread and thread.abort: return # Catch corners if docorners: shoutout('Catching corners for key {}'.format(a + 1), thread=thread) fca, kp_a, dc_a = cornercatch(settings, a, K=Ka, recycle=True) shoutout(img=fca, thread=thread) if thread and thread.abort: return shoutout('Catching corners for key {}'.format(b + 1), thread=thread) fcb, kp_b, dc_b = cornercatch(settings, b, K=Kb, recycle=True) shoutout(img=fcb, thread=thread) if thread and thread.abort: return # Nothing can beat the need for shear speed if recycle and path.isfile(f1) \ and path.isfile(f2): shoutout(img=f1, thread=thread) nodes = loadit(f2) return nodes, Ka, Kb, com_a, com_b # Convert detail zone units from promille to pixels # FIXME: Remove this after testing new traject detail setting #se = settings['edge' ] #detail = 0.5 * se['detail'][a] * 1e-3 + \ # 0.5 * se['detail'][b] * 1e-3 detail = settings['traject']['detail'][m] * 1e-3 simisize = max(int(np.ceil(max(Ka.shape[:2]) * detail)) + 1, 4) # Show the nitty gritty details print(timestamp() + 'Similim = {} %' .format(s['similim'][m])) print(timestamp() + 'Detail = {0:.3f}'.format(detail)) print(timestamp() + 'Simisize = {} px' .format(simisize)) # Start with the foundation; # The four screen corners and center of mass if dosilhouette: if Ea is None: Ea = loadit(path.join(folder_a, 'edgy.png')) if Eb is None: Eb = loadit(path.join(folder_b, 'edgy.png')) if com_a is None: com_a = loadit(path.join(folder_a, 'com.json')) if com_b is None: com_b = loadit(path.join(folder_b, 'com.json')) nodes0 = algo.seed(*Ka.shape[:2], com_a, com_b) if not spin: com_a['a'], com_b['a'] = 0, 0 else: nodes0 = algo.seed(*Ka.shape[:2]) com_a = dict(x=0, y=0, r=0, a=0.0) com_b = dict(x=0, y=0, r=0, a=0.0) # Use CoM as repellant for edge nodes base = nodes0[4:] if thread and thread.abort: return # Match corners if docorners: shoutout('Matching corners' + label, thread=thread) if Ka is None: Ka = algo.load_rgba(settings['keyframes'][a]) if Kb is None: Kb = algo.load_rgba(settings['keyframes'][b]) catcher = settings['edge']['cornercatcher'] catch_a = path.join(folder_a, catcher[a].lower()) catch_b = path.join(folder_b, catcher[b].lower()) if kp_a is None: kp_a = loadit(catch_a + '.csv') if kp_b is None: kp_b = loadit(catch_b + '.csv') if dc_a is None: dc_a = loadit(catch_a + '.png') if dc_b is None: dc_b = loadit(catch_b + '.png') nodes1, simi1 = algo.matchpoint(Ka, Kb, kp_a, kp_b, dc_a, dc_b, simisize=simisize, similim=similim) base = np.row_stack((base, nodes1)) if thread and thread.abort: return # Extract and match silhouette key points if dosilhouette: shoutout('Matching silhouettes' + label, thread=thread) spawnpoints = min(1000, *settings['traject']['maxpoints']) sp_a = algo.spawn(Ea, base[:, [0, 1]], spawnpoints, r_min=simisize) sp_b = algo.spawn(Eb, base[:, [2, 3]], spawnpoints, r_min=simisize) n_half = int(spawnpoints / 2) nodes2, simi2 = algo.proximatch(Ka, Kb, Ea, sp_a, sp_b, com_a, com_b, neighbours=neighbours, n=n_half, simisize=simisize, similim=similim) nodes3, simi3 = algo.proximatch(Kb, Ka, Eb, sp_b, sp_a, com_b, com_a, neighbours=neighbours, n=n_half, simisize=simisize, similim=similim) try: nodes4 = np.row_stack((nodes2, nodes3[:, [2, 3, 0, 1]])) simi4 = np.append(simi2, simi3) except IndexError: nodes4, simi4 = nodes2, simi2 if thread and thread.abort: return # Combine the results. One big happy family! if dosilhouette and docorners: nodez = np.row_stack((nodes1, nodes4)) simiz = np.append(simi1, simi4) elif dosilhouette: nodez, simiz = nodes4, simi4 elif docorners: nodez, simiz = nodes1, simi1 else: nodez = [] # Combine duplicates if len(nodez): shoutout('Combining duplicate trajectories' + label, thread=thread) nodez, simiz = algo.gettogether(nodez, simiz, simisize) # Discard excessive moves if len(nodez): shoutout('Discarding excessive moves' + label, thread=thread) diago = np.ceil(np.sqrt(Ka.shape[0] ** 2 + \ Ka.shape[1] ** 2)) lim = int(maxmove * diago) keep = algo.notsofast(nodez, lim, com_a, com_b) nodez = nodez[keep] simiz = simiz[keep] # Are we doing sensible things in this joint? print(timestamp() + 'Max move = {} px'.format(lim)) if thread and thread.abort: return # In case of crossing paths discard the longest trajectory if len(nodez): shoutout('Discarding crossing paths' + label, thread=thread) keep = np.zeros_like(nodez, dtype=bool) repeat = 1 while np.any(~keep) and repeat <= 10: if thread and thread.abort: return keep = algo.straightenup(nodez) nodez = nodez[keep] simiz = simiz[keep] repeat += 1 # Cherry pick nodes with the highest similarity score if len(nodez) > maxpoints: shoutout('Cherry picking' + label, thread=thread) seq = np.argsort(simiz)[::-1] nodez = nodez[seq][:maxpoints] simiz = simiz[seq][:maxpoints] # Pack it all together into one cozy bundle if len(nodes0) and len(nodez): nodes = np.row_stack((nodes0, nodez)) elif len(nodes0): nodes = nodes0 else: nodes = nodez # Save the harvest saveit(nodes, f2) if thread and thread.abort: return # Fade to gray baby shoutout('Making trajectory chart' + label, thread=thread) channel_a = settings['edge']['channel'][a] channel_b = settings['edge']['channel'][b] if channel_a.lower().startswith('a'): channel_a = 'lightness' if channel_b.lower().startswith('a'): channel_b = 'lightness' Ga = algo.desaturate(Ka, channel_a) Gb = algo.desaturate(Kb, channel_b) # Produce a tingly trajectory chart fig = algo.big_figure('MuddyMorph - Trajectories', *Ga.shape) if arc: comp_a, comp_b = com_a, com_b else: comp_a, comp_b = None, None try: tweens = settings['motion']['inbetweens'][m] except IndexError: tweens = algo.most_frequent_value(settings['motion']['inbetweens']) algo.movemap(Ga, Gb, nodes, comp_a, comp_b, tweens=tweens) plt.axis('off') plt.savefig(f1, **chartopts) plt.close(fig) # Our work here is done stopwatch += time() msg = 'Trajectory extraction took ' + duration(stopwatch) shoutout(msg, f1, thread) return nodes, Ka, Kb, com_a, com_b
#%% Compute CoM print("A ", end="") com_a = algo.commie(Sa) print("B ", end="") com_b = algo.commie(Sb) if not dorotate: com_a['a'] = 0 com_b['a'] = 0 base = np.array([[com_a['x'], com_a['y'], com_b['x'], com_b['y']]]) #%% Detect key points target = int(np.floor(min([Ea.sum(), Eb.sum()]) * keyfill)) print("Selecting up to {} key points ... ".format(target), end="") kp_a = algo.spawn(Ea, base[:, [0, 1]], target, r_min=simisize) kp_b = algo.spawn(Eb, base[:, [2, 3]], target, r_min=simisize) kp_at = algo.swirl(kp_a, com_a, com_b) print("done") #%% Match key points print("Matching key points ... ", end="") stopwatch = -time() nodes_ab, simi_ab = algo.proximatch(Ka, Kb, kp_a, kp_b, com_a, com_b, neighbours=neighbours, simisize=simisize,
print("Edge detection ... ", end="") D, S, E = algo.edgy(K, channel = se['channel' ], threshold = se['threshold'], blur = se['blur' ], dolines = se['dolines' ]) print("done") # CoM detection com = algo.commie(S) base = algo.seed(com, com, *S.shape)[:, :2] # Pick edge points print("Picking {} edge points ... ".format(n), end="") stopwatch = - time() kp = algo.spawn(E, base, n) stopwatch += time() print("done in {0:.0f} ms".format(stopwatch * 1000.)) ########## # Review # ########## print("Plotting result ... ", end="") plt.close('all') fig = plt.figure(figsize=(14, 9)) # Show silhouette plt.subplot(1, 2, 1) algo.edgeplot(D, S, E)