快速的Python绘图库,可直接在2D numpy数组图像缓冲区上绘制图形?

10

我经常使用opencv的绘图函数直接在从opencv网络摄像头流中获取的2D numpy数组图像缓冲区上绘制2D图。然后,我将numpy数组发送到imshow和video writer以监视和创建视频。

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
ret, frame = cap.read()  # frame is a 2D numpy array w640 h480
h,w,_ = frame.shape # (480,640,3)
x = np.arange(w)

writer = cv2.VideoWriter( 'out.avi', cv2.cv.FOURCC('D','I','V','3'),
            fps=30, frameSize=(w,h), isColor=True )

while True:
    ret, frame = cap.read()  # frame is a 2D numpy array w640 h480

    B = frame[:,:,0].sum(axis=0)
    B = h - h * B / B.max()
    G = frame[:,:,1].sum(axis=0)
    G = h - h * G / G.max()
    R = frame[:,:,2].sum(axis=0)
    R = h - h * R / R.max()

    pts = np.vstack((x,B)).astype(np.int32).T
    cv2.polylines(frame, [pts], isClosed=False, color=(255,0,0))
    pts = np.vstack((x,G)).astype(np.int32).T
    cv2.polylines(frame, [pts], isClosed=False, color=(0,255,0))
    pts = np.vstack((x,R)).astype(np.int32).T
    cv2.polylines(frame, [pts], isClosed=False, color=(0,0,255))

    writer.write(frame)

    cv2.imshow('frame', frame)
    key = cv2.waitKey(33) & 0xFF # for 64 bit PC
    if key in 27: # ESC key
        break

cap.release()
writer.release()

在此输入图片描述

这个方法很不错,但是我想知道是否可以像matplotlib一样做更多的事情,例如轴、刻度、网格、标题、柱状图等,而不需要使用基本的cv2绘图函数来制作自己的绘图库,虽然这是可能的,但我不想重复造轮子。

https://wiki.python.org/moin/NumericAndScientific/Plotting中,有很多绘图库。所以,我觉得其中一个可能已经实现了这个功能。

我考虑使用matplotlib并通过savefig将绘图导出为图像。但这对于视频捕获来说会很慢。

(编辑) 我可以像接受的答案建议的那样使用mplfig_to_npimage将matplotlib绘图嵌入到帧中!它似乎足够快以支持视频速率。

import cv2
from pylab import *
from moviepy.video.io.bindings import mplfig_to_npimage

fp = r'C:/Users/Public/Videos/Sample Videos/Wildlife.wmv'

cap = cv2.VideoCapture(fp)
ret, frame = cap.read()  # frame is a 2D numpy array
h,w,_ = frame.shape
writer = cv2.VideoWriter( 'out.avi', cv2.cv.FOURCC('D','I','V','3'),
                fps=30, frameSize=(w,h), isColor=True )

# prepare a small figure to embed into frame
fig, ax = subplots(figsize=(4,3), facecolor='w')
B = frame[:,:,0].sum(axis=0)
line, = ax.plot(B, lw=3)
xlim([0,w])
ylim([40000, 130000])  # setup wide enough range here
box('off')
tight_layout()

graphRGB = mplfig_to_npimage(fig)
gh, gw, _ = graphRGB.shape

while True:
    ret, frame = cap.read()  # frame is a 2D numpy array
    B = frame[:,:,0].sum(axis=0)
    line.set_ydata(B)
    frame[:gh,w-gw:,:] = mplfig_to_npimage(fig)

    cv2.imshow('frame', frame)
    writer.write(frame)

    key = cv2.waitKey(33) & 0xFF # for 64 bit
    if key in 27: # ESC key
        break

cap.release()
writer.release()

enter image description here


请查看这个答案scikit image - Miki
感谢您的评论,但OpenCV有一组非常类似于Scikit-Image和PIL / Pillow中的原始绘图功能。我的想法是比线条,多边形,圆形更高级的绘图功能。例如,具有良好间隔标记的x轴和y轴等等。 - otterb
1
我注意到另一个解决方案是最近合并的opencv_contrib绘图模块。https://github.com/Itseez/opencv_contrib/pull/186 - otterb
听起来很棒!谢谢分享。 - Miki
1个回答

5

所以,如果我理解正确,你希望:

  • 在图像上绘制概念性的图形(路径、多边形),并使用开箱即用的指标(轴、自动包含绘图)
  • 视频转储和希望实时流。

如果是这样,我建议使用matplotlib和moviepy

确实,使用savefig来流式传输视频并不是最好的方法,但你可以很容易地让这两个方法一起工作。

以下是来自上述链接的小例子(注意许可证):

import matplotlib.pyplot as plt
import numpy as np
from moviepy.video.io.bindings import mplfig_to_npimage
import moviepy.editor as mpy

# DRAW A FIGURE WITH MATPLOTLIB

duration = 2

fig_mpl, ax = plt.subplots(1,figsize=(5,3), facecolor='white')
xx = np.linspace(-2,2,200) # the x vector
zz = lambda d: np.sinc(xx**2)+np.sin(xx+d) # the (changing) z vector
ax.set_title("Elevation in y=0")
ax.set_ylim(-1.5,2.5)
line, = ax.plot(xx, zz(0), lw=3)

# ANIMATE WITH MOVIEPY (UPDATE THE CURVE FOR EACH t). MAKE A GIF.

def make_frame_mpl(t):
    line.set_ydata( zz(2*np.pi*t/duration))  # <= Update the curve
    return mplfig_to_npimage(fig_mpl) # RGB image of the figure

animation =mpy.VideoClip(make_frame_mpl, duration=duration)
animation.write_gif("sinc_mpl.gif", fps=20)

1
哇,这个 mplfig_to_npimage 看起来正是我在找的东西... 我会试一试! - otterb
截至2022年中期,mplfig_to_npimage会导致matplotlib的set_dataset_xdata抛出ValueError,禁用基本绘图更新;根据moviepy项目对维护者的恳求,这个bug并不令人惊讶,并且很可能会持续存在。我采用了一种笨拙的方法,将matplotlib绘制的图形(大致按照答案和编辑问题所示的代码生成)写入PNG文件,然后使用cv2.imread()导入该文件,并将导入的矩阵写入图像。 - Merlin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接