分享

使用Streamlight开发基于Web的实时视频/音频处理应用程序

 新用户0118F7lQ 2022-06-23 发布于福建

图片

Streamlit是一个Python框架,开发者可以使用它快速构建web应用程序,而无需前端编码。除此之外,开发者还可以制作实时视频/音频处理应用程序,从用户的媒体设备接收视频/音频流,在最简单的例子中,只需大约10行代码。

由于这类应用是基于网络的,它们可以部署到云端,方便地与用户共享,并具有现代且用户友好的UI。

此技术可用于创建视频/音频应用程序的演示和原型设计,如人体或物体检测、样式转换、语音识别、视频聊天应用程序等。

图片
图片

你可以在下面的示例部分看到更多例子。

注意:这些示例应用程序托管在公共云(Streamlight cloud)上,视频和音频流被传输到云服务器并在云服务器上进行处理。虽然这些数据只在内存中处理,不保存到任何存储器中,但是,如果你担心,请不要使用它们。

至于本文中的以下内容,我们可以在本地执行。此外,你可以按照下面示例部分的说明,在本地尝试上述示例。

基于网络的应用程序的优势

我们通常使用OpenCV构建图像或视频处理的实时演示应用程序。你们中的一些人(尤其是这类领域的开发人员或研究人员)可能已经多次看到以下代码或类似代码。

import cv2

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()

    img = cv2.Canny(frame, 100200)  # Some image processing

    cv2.imshow('frame', img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

与上面使用cv2.VideoCapture和cv2.imshow相比,基于网络的应用程序具有以下优点。

易于分享和运行:

  • 如果我们在云上部署应用程序,我们可以通过发送URL与用户共享应用程序。

  • 用户只能通过网络浏览器访问这些应用。它不需要任何设置或外部依赖项。

可在智能手机上使用:

  • 因为用户只需要网络浏览器,所以用户可以在智能手机上使用这些应用。如果我们能在这样的便携式设备上展示演示会很方便。

用户友好界面:

  • 开发人员可以使用文本输入、滑块或其他基于web的组件来接受用户输入或显示数据。最近几天,这种基于网络的UI比桌面GUI对用户更友好。

教程

我们将创建一个简单的基于网络的实时视频处理应用程序。请在有摄像头和麦克风的环境中尝试本教程。

你可以在此存储库中查看本教程的最终结果:

https://github.com/whitphx/streamlit-webrtc-article-tutorial-sample

在本教程中,我们将编写app.py。请创建一个空应用。

$ touch app.py

安装必要的软件包

接下来,我们必须安装本教程所需的软件包。

$ pip install -U streamlit streamlit-webrtc opencv-python-headless
  • streamlit:streamlit主包。
  • streamlit-webrtc:streamlit的一个自定义组件,用于处理实时视频和音频流。
  • opencv-python-headless。我们在这里选择headless版本,因为我们将使用Streamlight构建UI。

Streamlight

注意:如果你有Streamlight方面的经验,请跳过本节。

首先,使用下面的命令启动streamlight。请在应用程序的同一目录中运行该命令。

$ streamlit run app.py

一段时间后,Streamlight服务器进程将启动。然后进入http://localhost:8501,如下图所示(或默认情况下在浏览器中自动打开)。这里的屏幕截图是在暗模式下,如果你使用的是光模式,它看起来就不同了。

目前,由于应用程序的原因,网页上没有内容。我们将在应用程序中添加代码行。

图片

打开应用程序。使用你的编辑器进行编辑,并编写下面的代码。

import streamlit as st

st.title('My first Streamlit app')
st.write('Hello, world')

保存文件时,Streamlight将检测文件更改,并在屏幕右上角显示“Rerun”和“Always rerun”按钮。

图片

如果单击“Always rerun”按钮,每次文件更改时,页面都会自动重新加载。

图片

现在,我们已经了解了Streamlight应用程序的基本开发流程。使用Streamlit组件(如st.title()和st.write())编写Python代码,并将其传递给Streamlit run命令,然后Streamlit在网页上生成相应的前端内容。

介绍实时视频/音频流组件

更新应用程序。如下图所示。

import streamlit as st
from streamlit_webrtc import webrtc_streamer

st.title('My first Streamlit app')
st.write('Hello, world')

webrtc_streamer(key='example')

我们使用webrtc_streamer()添加了一条代码。该web应用程序与下面的屏幕截图类似。

图片

在第一次试用时,可能需要一些时间来编译包,以便页面在单击“重新运行”按钮后保持显示“正在运行”消息一段时间。在这种情况下,等待过程完成。

点击“开始”按钮开始视频和音频流。在开始时,你可能会被要求获得访问网络摄像头和麦克风的许可。在那种情况下给予许可。

图片

上面的webrtc_streamer(key=“example”)是一个Streamlight组件,通过web浏览器处理视频和音频实时I/O。

key参数是脚本中用于标识组件实例的唯一ID。我们在这里将其设置为“example”,但你可以使用任何字符串。

本例中的组件仅从客户端网络摄像头和麦克风接收视频和音频,并输出原始流。这是组件的最基本版本。我们将通过在以下部分中添加其他选项来增强其功能。

实时视频处理应用程序的开发

更新应用程序:

import streamlit as st
from streamlit_webrtc import webrtc_streamer
import av
import cv2

st.title('My first Streamlit app')
st.write('Hello, world')


class VideoProcessor:
    def recv(self, frame):
        img = frame.to_ndarray(format='bgr24')

        img = cv2.cvtColor(cv2.Canny(img, 100200), cv2.COLOR_GRAY2BGR)

        return av.VideoFrame.from_ndarray(img, format='bgr24')


webrtc_streamer(key='example', video_processor_factory=VideoProcessor)

像上一节一样,点击“开始”按钮进行尝试。通过这个新示例,你可以发现图像过滤器应用于视频流。

图片

我们定义了一个类及其方法VideoProcessor#recv(),一个接收输入帧并返回输出帧。我们还将图像处理(本例中为边缘检测)代码放入回调函数中。因此,我们通过回调将图像处理代码注入实时视频应用程序。

下面是关于代码的详细解释。

  • webrtc_streamer()使用video_processor_factory的.recv方法。

  • 这个recv()接收并返回输入和输出图像帧。这些是PyAV中VideoFrame类的实例。PyAV库是ffmpeg的Python绑定,提供视频和音频功能。它作为Streamlight webrtc的依赖项安装。

  • .recv()的输入是来自网络摄像头的图像帧。它可以使用frame.to_ndarray()转换为NumPy数组。

  • .recv()的输出将显示在屏幕上。在上面的示例中,使用av.VideoFrame.from_ndarray(img, format='bgr24')返回。

  • 任何代码都可以放入回调中。在上面的例子中,我们使用了边缘检测滤波器cv2.Canny(img, 100, 200),和灰度转换器cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)为例。

现在,我们已经创建了一个支持浏览器的实时视频处理应用程序!在本例中,我们使用了一个简单的Canny边缘检测器,你可以用原始应用程序中的任何图像处理代码替换它。

如果我们在这一部分使用对象检测或样式转换,该应用程序将与本文开头的屏幕截图类似ffff。

接收用户输入

更新应用程序:

import streamlit as st
from streamlit_webrtc import webrtc_streamer
import av
import cv2

st.title('My first Streamlit app')
st.write('Hello, world')


class VideoProcessor:
    def __init__(self) -> None:
        self.threshold1 = 100
        self.threshold2 = 200

    def recv(self, frame):
        img = frame.to_ndarray(format='bgr24')

        img = cv2.cvtColor(cv2.Canny(img, self.threshold1, self.threshold2), cv2.COLOR_GRAY2BGR)

        return av.VideoFrame.from_ndarray(img, format='bgr24')


ctx = webrtc_streamer(key='example', video_processor_factory=VideoProcessor)
if ctx.video_processor:
    ctx.video_processor.threshold1 = st.slider('Threshold1', min_value=0, max_value=1000, step=1, value=100)
    ctx.video_processor.threshold2 = st.slider('Threshold2', min_value=0, max_value=1000, step=1, value=200)

然后点击“开始”按钮。你会发现在这个例子中有两个滑块。你可以通过滑块修改cv2.Canny()的参数,即使在实时执行过程中也是如此。

图片

代码的解释:

  • 我们对VideoProcessor添加.threshold1和.threshold2属性。它们被用作cv2.Canny()的参数。

  • webrtc_streamer返回一个上下文对象,因此我们将其分配给ctx变量。

  • 通过video_processor_factory参数传递给webrtc_streamer()的类对象将被实例化并设置为ctx。当视频流不活动时,它不会被设置,所以我们用if子句检查它的存在。

  • 因此,在本例中,VideoProcessor类的实例将设置为ctx.video_processor,我们可以访问它的阈.threshold1.threshold2属性。然后我们将滑块值分配给这些属性,以便cv2.Canny()可以通过滑块进行更改参数。稍后我将解释为什么我们不能将滑块值传递给cv2.Canny()。

  • slider UI是在Streamlight应用程序中使用st.slider()创建的。st.slider()是一个内置的Streamlight组件。它的官方API参考是https://docs./library/api-reference/widgets/st.slider.

recv()的执行模型及其重要注意事项

与OpenCV不同,Streamlight webrtc需要回调来处理图像和音频。.recv()是OpenCV GUI和Streamlight webrtc之间的一个主要区别,关于它,你需要注意一些事情。

请注意.recv()是在分叉线程中执行的,与streamlight应用程序代码运行的主线程不同。它做出了如下限制。

  • 全局关键字在内部无法按预期工作。

  • 不能在内部使用streamlight方法,如st.write() ,recv()。

  • 内部和外部之间的沟通必须是线程安全的。

在上一个示例中,我们将值从全局的域传递到.recv(),因为我们不能在recv()内部使用全局域的值。

将应用程序部署到云端

我们将通过将web应用部署到云端,让每个人都能使用它。

配置WebRTC

要将应用部署到云端,我们必须将rtc_configuration参数添加到webrtc_streamer()。

ctx = webrtc_streamer(
    key='example',
    video_processor_factory=VideoProcessor,
    rtc_configuration={  # Add this line
        'iceServers': [{'urls': ['stun:stun.l.google.com:19302']}]
    }
)

当服务器位于远程主机上时,此配置是建立媒体流连接所必需的。

在上面的例子中,我们使用谷歌提供的免费STUN服务器。你还可以使用任何其他可用的STUN服务器。

rtc_configuration参数的值将传递给前端的RTCPeerConnection构造函数。

HTTPS

我们必须通过HTTPS在远程主机上提供网络应用,才能使用网络摄像头或麦克风。

不仅我们在这里使用的webrtc_streamer()组件,而且任何访问客户端网络摄像头或麦克风的前端应用程序都使用MediaDevices.getUserMedia() API。此API不能在“不安全的环境”中工作

文档说

简而言之,安全上下文是使用HTTPS或file:///URL方案加载的页面,或从localhost加载的页面。

因此,我们需要HTTPS来为远程主机上的web应用提供服务,远程主机可以访问客户端网络摄像头或麦克风。

Streamlit Cloud

推荐Streamlit Cloud作为Streamlit应用程序的宿主。只需点击几下,你就可以从GitHub存储库部署应用程序,它会通过HTTPS自动为应用程序提供服务。

与Heroku free tier相比,Streamlight Cloud似乎提供了更好的运行时环境,免费提供了很大的部署容量。

有关其用法,请参阅官方文档:https://docs./streamlit-cloud。

实际上,在Streamlight Cloud上部署了本文中看到的应用程序:https://share./whitphx/streamlit-webrtc-article-tutorial-sample/main/app.py .

它的GitHub存储库是https://github.com/whitphx/streamlit-webrtc-article-tutorial-sample .

请注意,requirements.txt包含必要的依赖项(streamlit webrtc和opencv python headless):https://github.com/whitphx/streamlit-webrtc-article-tutorial-sample/blob/main/requirements.txt

注意

如上所述,来自客户端设备的视频和音频流被传输到服务器并在服务器上进行处理。

因此,这个库是不可扩展的,依赖于网络连接。你可能认为它主要是为了原型或演示目的。

如果担心将媒体传输到远程云服务器,你还必须考虑在本地网络中托管应用程序。

例子

本部分是位于https://github.com/whitphx/streamlit-webrtc的实例

展示包括以下示例和更多内容

在线演示:https://share./whitphx/streamlit-webrtc-example/main/app.py

  • 目标检测(这是一个示例应用,其屏幕截图在本文开头)

  • OpenCV过滤器

  • 音频处理

你可以在本地环境上使用以下命令尝试此示例应用程序。

$ pip install streamlit-webrtc opencv-python-headless matplotlib pydub

$ streamlit run https://raw./whitphx/streamlit-webrtc-example/main/app.py

实时语音文本转换

在线演示:https://github.com/whitphx/streamlit-webrtc-example

它可以将你的声音实时转换成文本。这个应用程序是独立的;它不依赖于任何外部API。

图片

实时视频风格传输

在线演示:https://share./whitphx/style-transfer-web-app/main/app.py

它对实时视频流应用了多种风格的传输过滤器。

图片

视频聊天

存储库:https://github.com/whitphx/streamlit-video-chat-example

你可以用大约100行Python代码创建视频聊天应用。

图片

音频

你可以像处理视频一样处理音频流。定义.recv()方法,并将其传递给audio_processor_factory参数,则将使用音频帧执行回调。回调的输入参数和返回值是AudioFrame类的实例。


☆ END ☆

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多