是否可以在 IPython /JuPyter Notebook 中显示 OpenCV 视频?

Posted

技术标签:

【中文标题】是否可以在 IPython /JuPyter Notebook 中显示 OpenCV 视频?【英文标题】:Is it possible to display an OpenCV video inside the IPython /JuPyter Notebook? 【发布时间】:2015-03-09 01:18:28 【问题描述】:

在运行 OpenCV 视频处理 python 教程中的示例时,它们都会在专用窗口中弹出。我知道 IPython notebook 可以显示来自磁盘和 YouTube 的视频,所以我想知道是否有办法将 OpenCV 视频播放定向到 Notebook 浏览器并让它在输出单元格而不是单独的窗口中播放(最好不保存它到磁盘,然后从那里播放)。

以下是 OpenCV 教程中的代码。

import cv2

cap = cv2.VideoCapture('/path/to/video') 

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Our operations on the frame come here
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resulting frame
    cv2.imshow('frame',gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

【问题讨论】:

我也在寻找这个,但还没有找到任何解决方案......我想这是不可能的,因为只要窗口存在,内核就会保持活动状态。因此,如果窗口在工作簿内,则我们无法关闭它,这意味着当前单元格将运行其代码等... 检查这个:github.com/bikz05/ipython-notebooks/blob/master/computer-vision/… @EzerK 提供的链接可以作为解决方案 我尝试了@EzerK 提供的解决方案。它确实在笔记本电脑中显示视频,但帧速率非常低,因此视频看起来断断续续。我尝试使用 python3.5 和 opencv3 v3.1.0 从我的网络摄像头流式传输。我磁盘上的视频根本无法播放。 @moondra 不,但自从我上次发表评论以来,我一直没有积极追求这个,所以如果你环顾四周,你可能会找到一些东西。 【参考方案1】:

你可以用 Bokeh 做到这一点,而且可能会快一点。

from bokeh.plotting import figure
from bokeh.io import output_notebook, show, push_notebook
import cv2
import time
output_notebook()

cap = cv2.VideoCapture(0)
ret, frame = cap.read()
frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA) # because Bokeh expects a RGBA image
frame=cv2.flip(frame, -1) # because Bokeh flips vertically
width=frame.shape[1]
height=frame.shape[0]
p = figure(x_range=(0,width), y_range=(0,height), output_backend="webgl", width=width, height=height)
myImage = p.image_rgba(image=[frame], x=0, y=0, dw=width, dh=height)
show(p, notebook_handle=True)
while True:
    ret, frame = cap.read()
    frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
    frame=cv2.flip(frame, -1)
    myImage.data_source.data['image']=[frame]
    push_notebook()
    time.sleep(0.3)

【讨论】:

感谢您的建议。不幸的是,它对我不起作用。我尝试使用磁盘中的文件,但视频明显滞后,并且每隔几秒只前进 1 帧(我尝试了 JupyterNotebook 和 JupyterLab)。您是否像在 VLC 等专用播放器中播放视频一样流畅? 效果很好!您可以轻松地从菜单中中断。 请注意,最近版本的散景需要 uint32 的 (w, h) 数组,而 opencv 输出 uint8 的 (w, h, 4) 数组。所以有必要在它们之间进行转换。 (例如使用 frame = frame.view(dtype=numpy.uint8).reshape(frame.shape[:2]))虽然我仍然觉得这个方法比使用 jpeg 格式的 IPython.display 慢一点(见my answer ),并且比单独窗口中的 cv2.imshow 慢得多。【参考方案2】:

为了使显示速度更快,请在笔记本内仅使用 IPython.display.display 和 JPG 格式而不是 PNG。 (注意在笔记本外部以 cv2.imshow 显示要快得多,但这不是问题所要求的):

下面的代码将测试所有支持的文件格式以找到最快的一种(用正则表达式从__doc__提取,不可靠)

from IPython.display import clear_output, Image, display, html
import cv2

# Read one frame from the camera for testing
video = cv2.VideoCapture(0)
_, frame = video.read()
video.release()

import re
from timeit import timeit
import math

extensions=re.findall(r"\\\*(\.\w*)", cv2.imread.__doc__)

def test(extension):
    try:
        totalTime=0
        numTry=3
        for _ in range(numTry):
            totalTime+=timeit(lambda: display(Image(data=cv2.imencode(extension, frame)[1])), number=1)
            clear_output(wait=True)
        return totalTime/numTry, extension

    except cv2.error as e: #usually "unsupported file type"
        return (math.inf, extension, e)
for x in sorted(
    [test(extension) for extension in extensions], key=lambda x: x[0]
): print(x)

就我而言,.jpeg 是最快的。确保浏览器显示也支持该扩展:

Image(data=cv2.imencode(".jpeg", frame)[1].tobytes())

然后,播放视频:

import cv2
from IPython.display import display, Image

video = cv2.VideoCapture(0)
display_handle=display(None, display_id=True)
try:
    while True:
        _, frame = video.read()
        frame = cv2.flip(frame, 1) # if your camera reverses your image
        _, frame = cv2.imencode('.jpeg', frame)
        display_handle.update(Image(data=frame.tobytes()))
except KeyboardInterrupt:
    pass
finally:
    video.release()
    display_handle.update(None)

update 每次都比clear_output + display 快一点;但是与渲染相比,它并不是一个显着的改进。

【讨论】:

备注:在测试时这比 Bokeh 快。此外,您也可以使用Image(data=<numpy array>),尽管这种用法不是explicitly documented【参考方案3】:

视频编码数据(如果采用浏览器可以解码的格式,例如 ISO mp4 容器中的 h264 编码)可以使用 HTML <video> 标记和 IPython.core.display.HTML() 显示,这将提供标准的播放性能。

<video> 可以是一个链接,也可以是嵌入 base64 的数据(例如,后者是 matplotlib.animation 所做的),它的数据当然可以使用 OpenCV 在您的笔记本中生成(例如。 VideoWriter)。

【讨论】:

【参考方案4】:

是的。但它会slooowwww....

使用 Python 3 和 OpenCV 3.3 从网络摄像头读取的代码(从文件中,只需更改 cv2.VideoCapture("filename.mp4")):

from IPython.display import clear_output, Image, display, HTML
import numpy as np
import cv2
import base64

def arrayShow (imageArray):
    ret, png = cv2.imencode('.png', imageArray)
    encoded = base64.b64encode(png)
    return Image(data=encoded.decode('ascii'))
video = cv2.VideoCapture(0)
while(True):
    try:
        clear_output(wait=True)
        _, frame = video.read()
        lines, columns, _ =  frame.shape
        frame = cv2.resize(frame, (int(columns/4), int(lines/4))) 
        img = arrayShow(frame)
        display(img)
    except KeyboardInterrupt:
        video.release()

您可能需要更改 IOPub 数据速率限制。 您可以在 .jupyter 配置中更改此设置,或者直接运行 jupyter notebook --NotebookApp.iopub_data_rate_limit=1000000000

但是,键盘中断不能正常工作。

【讨论】:

在python3中你应该把Image(data=encoded.decode('ascii'))改成Image(data=png) 您需要在except块中添加break【参考方案5】:
from IPython.display import clear_output, Image, display

import ipywidgets

import cv2

video = cv2.VideoCapture(0)

display_handle=display(None, display_id=True)

image_widget = ipywidgets.Image(format='jpeg')


while True:

    try:
        clear_output(wait=True)
        _, frame = video.read()
        lines, columns, _ =  frame.shape
        frame = cv2.resize(frame, (int(columns/4), int(lines/4))) 
        image_widget.value =cv2.imencode('.jpeg', frame)[1].tobytes()
        display(image_widget)
    except KeyboardInterrupt:
        video.release()
        break

【讨论】:

以上是关于是否可以在 IPython /JuPyter Notebook 中显示 OpenCV 视频?的主要内容,如果未能解决你的问题,请参考以下文章

在笔记本中组合jupyter / ipython内核

如何禁用jupyter笔记本历史记录

jupyter 和 ipython的区别

IPython(jupyter)中的完成现在可以工作(意外的关键字参数'column')

为啥 PyQt4 在 Jupyter 和 IPython 笔记本之间的行为不同?

如何在运行 IPython 的 Jupyter 中抑制输出?