3

So, I would like to simply take an existing plot that I have made via plt.plot(x,y), convert it into an "image", so that I can then give it to OpenCV's video writer via:

cv2.VideoWriter('myMovie.avi', fourcc, 20.0, (640,480))
writer.write(image)

My problem is, given the figure I have already plotted, how do I get "image"?

Thanks.

Spacey
  • 2,941
  • 10
  • 47
  • 63
  • How about convert figure to `numpy.array` first as in [here](http://stackoverflow.com/questions/7821518/matplotlib-save-plot-to-numpy-array). – Quang Hoang Mar 05 '17 at 01:06
  • @QuangHoang So I am using fig, ax = plt.subplots(1); ax.plot(...). May you give an example as an answer? I can then accept. Thanks. – Spacey Mar 05 '17 at 01:17
  • 1
    This question would be improved with a [Minimal, Complete, and Verifiable](http://stackoverflow.com/help/mcve) example. – Stephen Rauch Mar 05 '17 at 02:48

1 Answers1

7

Before posting a solution, it may be easier if you just use matplotlib's animation to save a video. And here's the solution using opencv:

import numpy as np
import cv2
import matplotlib.pyplot as plt

fig = plt.figure()


x1 = np.linspace(0.0, 5.0)
x2 = np.linspace(0.0, 2.0)

y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) 
y2 = np.cos(2 * np.pi * x2)

ax = fig.add_subplot(2,1,1)
line1, = ax.plot(x1, y1, 'ko-')        # so that we can update data later
ax.set_title('A tale of 2 subplots')
ax.set_ylabel('Damped oscillation')

ay = fig.add_subplot(2, 1, 2)
ay.plot(x2, y2, 'r.-')
ay.set_xlabel('time (s)')
ay.set_ylabel('Undamped')

for i in range(1000):
    # update data
    line1.set_ydata(np.cos(2 * np.pi * (x1+i*3.14/2) ) * np.exp(-x1) )

    # redraw the canvas
    fig.canvas.draw()

    # convert canvas to image
    img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    img  = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    # img is rgb, convert to opencv's default bgr
    img = cv2.cvtColor(img,cv2.COLOR_RGB2BGR)

    # display image with opencv or any operation you like
    cv2.imshow("plot",img)
    k = cv2.waitKey(33) & 0xFF
    if k == 27:
        break
Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
  • Thank you, this was helpful. – Spacey Mar 05 '17 at 04:51
  • 3
    It's possible to replace the canvas to image conversion with `cv2.cvtColor(np.asarray(figure.canvas.buffer_rgba()), cv2.COLOR_RGBA2BGR)` for a considerable speedup, at least for the `TkAgg` matplotlib backend. I could imagine other backends use other color spaces. I'm adding this here because this is the result I found on google for converting a matplotlib image to an openCV image. – enra64 Feb 09 '21 at 12:48