如何将OAK相机当作可移除背景的网络摄像头?

如何将OAK相机当作可移除背景的网络摄像头?

我们之前出过一个教程,是说如何将OAK相机当作网络摄像头使用,本期教程在这个基础上再增加了一个移除背景的效果。教程来源于Victor Sonck,由OAK中国整理发布。

本教程演示使用的设备是单目的OAK-1,当然你也可以用其他OAK相机,比如OAK-DOAK-D-Lite等。

OAK简介

Victor最开始是在kickstarter上看到OpenCV的众筹活动,而心动买了一台OAK-1和OAK-D。OpenCV人工智能套件(OAK)本质上是开源相机板,内置Myriad X芯片,用于板上计算机视觉处理。鉴于它们的嵌入式性质,这意味着与NVIDIA Jetson系列等全Linux板相比,它们的功耗低,速度快。有什么理由不喜欢呢?

硬件展示

OAK-1的包装盒内容
OAK-D的包装盒内容
OAK-D,NVIDIA Jetson Nano Devboard,OAK-1尺寸对比

OAK-1自带一根USB-C线,仅此而已。OAK-D配备了一个额外的5v电源适配器,旁边是与OAK-1相同的USB-C线。

Victor对于相机的铝制外壳质量印象深刻,看起来很不错,相机背面有一个标准的摄像头支架,便于安装。总的来说,它看起来真的很整洁!

两个OAK都有相同的IMX378 4K 60fps传感器,OAK-D有2个额外的双目摄像头。更多的规格信息可在产品页面查看:OAK-1OAK-D。甚至还提供每个的3d模型,所以你可以自己围绕它们设计配件!厉害!

快速启动

根据这个文档来安装、启动、运行,Victor用起来表示这些都是轻而易举的事。只需按照上面链接中的说明操作,你马上就可以开始运行了。

使用OAK-1作为网络摄像头

Victor是一个开源迷,喜欢使用Firefox作为日常驱动程序,但谷歌会议(Google Meet)不支持Firefox中的背景移除。是时候改变了!

让我们构建一个定制的OpenCV AI Kit管道,运行一个背景替换模型,并将其连接到一个虚拟网络摄像头,以便在任何会议软件中使用!

模型

谷歌会议,像许多其他会议软件一样,允许你删除你的背景,并以模糊的版本甚至任何其他你想要的图像来取代它。但与其他会议软件不同的是,谷歌在Apache许可证下免费提供了他们的背景去除模型

你可以在Google ai的博文中读到更多的信息。他们深入研究了他们如何将TensorFlow Lite模型部署到浏览器上,并在非常低规格的硬件上运行后台分割。

作为Edge社区CV的真正英雄,PINTO0309将该模型移植到了takes a breath。TFJS(Float32/Flot16),TF-TRT(Float32/Float16),TFLite(Float32/Float16,INT8),OpenVINO(FP32/FP16)和CoreML。

所有这些以及更多的东西都可以在他的model zoo里找到,强烈推荐!

转换模型格式

OAK建立在英特尔Myriad X芯片之上,该芯片也在英特尔的神经计算棒2中。这意味着我们需要将任何模型转换成Myriad可以读取的blob格式。OAK背后的公司Luxonis提供了一个很好的转换工具,可以将Caffe、Tensorflow或OpenVINO模型转换成所需的blob格式。你也可以通过安装OpenVINO或运行英特尔自己的docker容器来自己做。

这个步骤对于边缘加速器来说是很正常的。例如,Coral边缘TPU就必须做类似的转换步骤。

管道

作为嵌入式设备也意味着没有Linux发行版,一切都必须通过USB线。然而,幸运的是,使用他们的管道-节点模型,部署代码是令人耳目一新的简单。你使用不同的节点建立一个管道,然后将它们相互连接或连接到输入或输出队列。这些节点实际上就是Python队列,你可以从其中获取(),然后做你想做的事情。

彩色摄像机有两个输出:视频和预览。这些可以同时被处理。它是为ML设计的:将预览尺寸设置为神经网络输入,并将其发送给神经网络。把视频放到一个不同的队列中,并把这些帧保留到以后,当我们想要高质量的结果时。


def create_pipeline(self):
        # Create pipeline and set version
        pipeline = dai.Pipeline()
        pipeline.setOpenVINOVersion(version=dai.OpenVINO.Version.VERSION_2021_3)

        # Camera specific settings
        cam = pipeline.createColorCamera()
        cam.setPreviewSize(*self.nn_shape)
        cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
        cam.setInterleaved(False)
        cam.setBoardSocket(dai.CameraBoardSocket.RGB)
        cam.setColorOrder(dai.ColorCameraProperties.ColorOrder.RGB)
        cam.setPreviewKeepAspectRatio(False)

        # Set camera high quality output
        cam_xout = pipeline.createXLinkOut()
        cam_xout.setStreamName("high_quality_out")
        cam_xout.input.setBlocking(False)

        # Define a neural network that will make predictions based on the source frames
        detection_nn = pipeline.createNeuralNetwork()
        detection_nn.setBlobPath(self.nn_path)
        detection_nn.input.setBlocking(False)

        # Create neural network output
        detection_nn_xout = pipeline.createXLinkOut()
        detection_nn_xout.setStreamName("detection_out")
        detection_nn_xout.input.setBlocking(False)

        # Link different inputs and outputs
        # Send the resized 'preview' stream to the nn, while the high quality output is sent to another queue
        cam.video.link(cam_xout.input)
        cam.preview.link(detection_nn.input)
        detection_nn.out.link(detection_nn_xout.input)
        
        return pipeline

现在我们需要启动管道,定义2个输出队列:detections和hq_images,然后把它们混在一起,生成一个替换了背景的帧。将生成的帧推送到最后一个队列,该队列将把它发布到一个虚拟的网络摄像头上,供任何会议软件使用。

def run(self):
    pipeline = self.create_pipeline()
    # Pipeline defined, now the device is connected to
    with dai.Device(pipeline) as device:
        # Start pipeline
        device.startPipeline()

        # Set queues to be read from later
        self.high_quality_out = device.getOutputQueue(name="high_quality_out", maxSize=4, blocking=False)
        self.detection_out = device.getOutputQueue(name="detection_out", maxSize=4, blocking=False)

        # Create a separate thread which will read the final frames from a queue
        # and ingest them in a virtual webcam
        t = threading.Thread(target=self.pipe_to_virtual_webcam)
        t.start()

        # Start processing the detections frame by frame by reading from the 2 queues above
        final_frame = self.process_detections()

        # Add the final frame (with background replaced) to the queue for the virtual webcam to read from
        self.webcam_queue.put(cv2.cvtColor(final_frame, cv2.COLOR_BGR2RGB))

        # Wait for thread to finish
        t.join()
        self.webcam_queue.join()

虚拟网络摄像头

Python有一个很好的包来处理向虚拟网络摄像头发布帧。它也有很好的关于如何设置的文档。我们只需创建一个线程,从webcam_queue中读取并将这些帧发布到虚拟摄像机中。

一个虚拟摄像机在你的系统中看起来就像一个普通的网络摄像机,但你可以自己控制摄像机 “看到 “的东西。

def pipe_to_virtual_webcam(self):
    with pyvirtualcam.Camera(width=854, height=480, fps=30) as cam:
        print(f'Using virtual camera: {cam.device}')
        while self.is_running:
            frame = self.webcam_queue.get()
            cam.send(frame)
            cam.sleep_until_next_frame()

演示

谷歌做了更多复杂的后期处理来使悲剧变得漂亮和干净。本教程只是把处理能力扔给了一个jointiblinefilter(联合双线性过滤器),但是结果还不错!这就是了,在火狐上运行!

Victor的使用感受

OpenCV AI Kit玩起来真的很酷,它构建得很好,文档也很好,社区支持也很棒。使用python(还有一个C++ API)很容易构建一个管道并与之交互。乍一看,与类似的TFLite型号相比,我确实看到了性能上的损失,但我没有进行正面比较,所以我不能支持这一点。

一定要看看谷歌会议背景分割模型,这是一个很酷的小模型和附带的博客帖子也很值得一读。

现在,我还可以在Firefox中替换我的背景,我甚至可以添加MP4背景,这是Google meet目前还不支持的。

最后,我现在只真正玩过OAK-1,我很高兴在以后的博客或YouTube视频中与OAK-D及其深度视觉进行较量!

Tags: