Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV or matplotlib for animation building?

I am currently developing a behavioral system which will utilize moving bars, rotating bars, alternating fields, and even small random moving objects. Originally all of this was programmed in matlab with great results. However due to incompatibility with the hardware which will eventually use the code, the project has since been transferred over to python.

I have started programming the system using the matplotlib modules in python with some good results. I utilized the animation functions in matplotlib to generate consistent and fluid movement of fast moving objects. However as I dig deeper into programming with matplotlib, I noticed a couple issues. One in particular is that the fluid movement of the objects wasn't exactly as fluid as previously thought.

As I will be utilizing opencv for another part of the behavioral system, I was wondering if opencv has any particular advantages over matplotlib, Particularly in regards to drawing rate and animation.

I will go into more detail below.

Here is part of my script for building the animation, note this this version crashes and I haven't figured out why yet.

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 that does work is here. It just that each individual object does not move in sync with each other.

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()
like image 488
Hojo.Timberwolf Avatar asked Feb 18 '26 18:02

Hojo.Timberwolf


1 Answers

Doing an animation inside a while loop seems pretty strange. Therefore the way to go would definitely be the second code version.

The reason the animation seems to be out of sync is not actually related to the times of redraw or similar. It is more an effect of interpolation. The width and position of the rectangles need to be rounded to the screen pixels. Depending on the timesteps the rectangle position can therefore deviate by one pixel; additionally, the width of the bar can deviate by 2 pixels (plus/minus one on each side). This leads to the undesired animation.

To overcome this problem, you would need to think in pixels. Make sure the axes range is a whole number and equals the number of pixels on the screen. Then make the bar width a multiple of one pixel. Control the speed of the animation with the interval argument to the FuncAnimation instead of the steps. Use exactly one pixel as step size.

A complete example:

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

like image 156
ImportanceOfBeingErnest Avatar answered Feb 20 '26 06:02

ImportanceOfBeingErnest



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!