2017-05-25 2 views
2

Ich entwickle derzeit ein Verhaltenssystem, das bewegliche Balken, rotierende Balken, Wechselfelder und sogar kleine zufällig bewegte Objekte verwendet. Ursprünglich wurde all dies in Matlab mit großartigen Ergebnissen programmiert. Aufgrund der Inkompatibilität mit der Hardware, die den Code letztendlich verwenden wird, wurde das Projekt jedoch auf python übertragen.OpenCV oder Matplotlib für Animation Gebäude?

Ich habe begonnen, das System mit den Matplotlib-Modulen in Python mit einigen guten Ergebnissen zu programmieren. Ich habe die Animationsfunktionen in Matplotlib verwendet, um eine konsistente und flüssige Bewegung von sich schnell bewegenden Objekten zu erzeugen. Als ich jedoch tiefer in die Programmierung mit Matplotlib eintauchte, bemerkte ich ein paar Probleme. Eine ist insbesondere, dass die Flüssigkeitsbewegung der Objekte nicht genau so flüssig war, wie bisher angenommen.

Da ich opencv für einen anderen Teil des Verhaltenssystems verwenden werde, habe ich mich gefragt, ob opencv irgendwelche besonderen Vorteile gegenüber Matplotlib hat, insbesondere in Bezug auf Zeichnungsrate und Animation.

Ich werde im Folgenden ausführlicher gehen.

Hier ist ein Teil meines Skripts zum Erstellen der Animation, beachten Sie, dass diese Version abstürzt und ich habe noch nicht herausgefunden warum.

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.patches as patches 
import matplotlib.animation as animation 
import time 

fig = plt.figure() 
ax = fig.add_subplot(111) 
fig.patch.set_facecolor([0,0,0]) 
fig.tight_layout() 

plt.xlim(-100, 100) 
plt.ylim(-100, 100) 
plt.axis('off') 

# List of variables 
width = 1 
bars = 20 
spacing = 20 
step = .01 
direction = -1 

RB = [] # Establish RB as a Python list 
for a in range(bars): 
    RB.append(patches.Rectangle((a*spacing-200,-100), width, 200, 
      color=[1,0,0], alpha=0.50)) 

def init(): 
    for a in range(bars): 
     ax.add_patch(RB[a]) 
    return RB 

def animate(i): 
    for i in range(bars): 
     temp = np.array(RB[i].get_xy()) 
     if temp[0] > 200: 
      temp[0] = -199 
     elif temp[0] < -200: 
      temp[0] = 199 
     else: 
      temp[0] = temp[0] + step*direction; 
     RB[i].set_xy(temp) 
    return RB 

t = time.time() 
plt.show() 

while t < timewidow 
    anim = animation.FuncAnimation(fig, animate, 
          init_func=init, 
          frames=30, 
          interval=1, 
          blit=True) 

fig.clf() 

Code, der funktioniert, ist hier. Es ist nur so, dass sich jedes einzelne Objekt nicht synchron zueinander bewegt.

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.patches as patches 
import matplotlib.animation as animation 
import time 

fig = plt.figure() 
ax = fig.add_subplot(111) 
fig.patch.set_facecolor([0,0,0]) 
fig.tight_layout() 

plt.xlim(-100, 100) 
plt.ylim(-100, 100) 
plt.axis('off') 

# List of variables 
width = 1 
bars = 20 
spacing = 20 
step = .01 
direction = -1 

RB = [] # Establish RB as a Python list 
for a in range(bars): 
    RB.append(patches.Rectangle((a*spacing-200,-100), width, 200, 
      color=[1,0,0], alpha=0.50)) 

def init(): 
    for a in range(bars): 
     ax.add_patch(RB[a]) 
    return RB 

def animate(i): 
    for i in range(bars): 
     temp = np.array(RB[i].get_xy()) 
     if temp[0] > 200: 
      temp[0] = -199 
     elif temp[0] < -200: 
      temp[0] = 199 
     else: 
      temp[0] = temp[0] + step*direction; 
     RB[i].set_xy(temp) 
    return RB 

anim = animation.FuncAnimation(fig, animate, 
          init_func=init, 
          frames=30, 
          interval=1, 
          blit=True) 
plt.show() 

Antwort

2

Eine Animation in einer While-Schleife zu machen, scheint ziemlich seltsam zu sein. Der Weg dorthin wäre also definitiv die zweite Codeversion.

Der Grund, warum die Animation nicht synchronisiert zu sein scheint, hängt nicht wirklich mit der Zeit des Neuzeichnens oder Ähnlichem zusammen. Es ist mehr ein Effekt der Interpolation. Die Breite und Position der Rechtecke muss auf die Bildschirmpixel gerundet werden. Abhängig von den Zeitschritten kann die Rechteckposition daher um ein Pixel abweichen; zusätzlich kann die Breite des Balkens um 2 Pixel (plus/minus eins auf jeder Seite) abweichen. Dies führt zu der unerwünschten Animation.

Um dieses Problem zu lösen, müssten Sie in Pixel denken. Stellen Sie sicher, dass der Achsenbereich eine ganze Zahl ist und der Anzahl der Pixel auf dem Bildschirm entspricht. Dann mache die Balkenbreite ein Vielfaches von einem Pixel. Steuern Sie die Geschwindigkeit der Animation mit dem interval Argument an die FuncAnimation anstelle der Schritte. Verwenden Sie genau ein Pixel als Schrittgröße.

Ein komplettes Beispiel:

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.patches as patches 
import matplotlib.animation as animation 

fig = plt.figure(figsize=(5,3), dpi=100) #figure is 500 pixels wide 
ax = fig.add_subplot(111) 
fig.patch.set_facecolor([0,0,0]) 
fig.subplots_adjust(left=.04, right=1-.04) #axes is now 460 pixels wide 

plt.xlim(-230, 230) # distribute 460 pixels over x range 
plt.ylim(-100, 100) 
plt.axis('off') 

# List of variables 
width = 4 
spacing = 20 
bars = int(460/spacing) # make sure bars fit into range 
direction = -1 

RB = [] # Establish RB as a Python list 
for a in range(bars): 
    RB.append(patches.Rectangle((a*spacing-230,-100), width, 200, 
      color=[1,0,0], alpha=0.50)) 

def init(): 
    for a in range(bars): 
     ax.add_patch(RB[a]) 
    return RB 

def animate(i): 
    for j in range(bars): 
     temp = np.array(RB[j].get_xy()) 
     if temp[0] >= 230: #### use >= instead of > to mimic exactly one step 
      temp[0] = -229 
     elif temp[0] <= -230: 
      temp[0] = 229 
     else: 
      temp[0] = temp[0] + direction # each step should be one pixel 
     RB[j].set_xy(temp) 
    return RB 

anim = animation.FuncAnimation(fig, animate, 
          init_func=init, 
          frames=20, 
          interval=10, # control speed with thie interval 
          blit=True) 
plt.show() 

enter image description here

+0

Dachte nicht, über diesen Aspekt, Vielen Dank für den Hinweis it out. Der Zweck der while-Schleife im ersten Code-Satz bestand darin, zu versuchen, die Figur für eine kurze Zeit zu animieren und dann zu stoppen. Allerdings habe ich versucht, den Code in der Reihenfolge plt.show() -> animate -> plt.clf auszuführen. Die Figur würde auftauchen und sofort verschwinden. –

+1

Um die Animation anzuhalten, können Sie 'anim.event_source.stop()' verwenden, siehe [diese Frage] (https://stackoverflow.com/questions/16732379/stop-start-pause-in-python-matplotlib-animation) . Sie können dies mit einem Mausklick oder [einem anderen Timer] auslösen (https://matplotlib.org/examples/event_handling/timers.html) – ImportanceOfBeingErnest

Verwandte Themen