基于OpenCv的视频流处理方法

简介: 基于OpenCv的视频流处理方法

使用VideoCapture读取视频流

在使用OpenCv处理视频时,无论是视频文件还是摄像头画面,都要使用VideoCapture类来进行每一帧图像的处理。当我们使用视频文件作为参数时,OpenCv则打开视频文件,进行每一帧画面的读取。当我们传递摄像机编号时,OpenCv则打开相机,实时读取相机画面。
获取VideoCaptrue实例:

# 读取视频文件
cv2.VideoCapture('video.mp4')
# 打开摄像机
cv2.VideoCapture(0)

使用VideoCapture读取海康RTSP流

RTSP流

在使用OpenCv进行计算机视觉处理时,我们很多时候需要连接外部相机,如海康威视。监控相机的常见视频传输协议有:RTSP、RTMP(以RTSP为主)
RTSP与RTMP比较:

  • RTSP:低时延,实现难度大,适合视频聊天和视频监控
  • RTMP:低时延,实现难度大,适合视频聊天和视频监控

目前市面上的相机大多以RTSP流协议为主。
在读取海康相机时,需要使用VideoCapture读取RTSP流协议的内容,而不是通过相机编号直接读取。

"""
海康相机rtsp格式:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
        username: 用户名。例如admin。
        password: 密码。例如12345。
        ip: 为设备IP。例如 192.0.0.64。
        port: 端口号默认为554,若为默认可不填写。
        codec:有h264、MPEG-4、mpeg4这几种。
        channel: 通道号,起始为1。例如通道1,则为ch1。
        subtype: 码流类型,主码流为main,辅码流为sub。
"""

使用VideoCapture读取RTSP流示例:

# 使用rtsp流打开相机
def open_camera(username: str, password: str, ip: str, port: int):
    """
    使用rtsp流打开相机
    rtsp格式:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
        username: 用户名。例如admin。
        password: 密码。例如12345。
        ip: 为设备IP。例如 192.0.0.64。
        port: 端口号默认为554,若为默认可不填写。
        codec:有h264、MPEG-4、mpeg4这几种。
        channel: 通道号,起始为1。例如通道1,则为ch1。
        subtype: 码流类型,主码流为main,辅码流为sub。
    :return:相机是否打开,相机
    """
    try:
        # 使用rtsp流打开相机
        cam = cv2.VideoCapture(f'rtsp://{username}:{password}@{ip}:{port}/h264/ch1/main/av_stream')
        return True, cam

    except cv2.error:
        # 捕获cv异常
        # 打开相机失败
        return False, None

ping3

在使用RTSP流读取相机内容时,若IP错误,或相机连接异常,则VideoCapture无法访问相机,VideoCapture实例访问超时且程序异常,在使用PyQt等GUI程序中,程序可能出现异常闪退情况,所以在连接RTSP流前,请先对相机IP进行预校验,减少出错概率。可以在访问相机之前,通过ping 相机IP的方式来对IP进行预校验。
在Python中可以使用ping3库对IP进行ping测试。

  • ping3.ping成功默认返回秒为单位
  • ping3.ping参数错误返回False
  • ping3.ping失败时返回None

ping3.ping函数返回说明:

Returns:
The delay in seconds/milliseconds, False on error and None on timeout.

ping3.ping示例:

import ping3

if __name__ == '__main__':
    print(ping3.ping('focus-wind.com'))
    print(ping3.ping('https://focus-wind.com'))
    print(ping3.ping('192.168.1.64'))

ping3.ping运行结果:

# ping focus-wind.com ping成功
0.03125762939453125
# ping https://focus-wind.com 参数异常
False
# ping 192.168.1.64 无法访问对应IP
None

完整访问RTSP流示例

def open_camera(username: str, password: str, ip: str, port: int = 554):
    """
    使用rtsp流打开相机
    rtsp格式:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
        username: 用户名。例如admin。
        password: 密码。例如12345。
        ip: 为设备IP。例如 192.0.0.64。
        port: 端口号默认为554,若为默认可不填写。
        codec:有h264、MPEG-4、mpeg4这几种。
        channel: 通道号,起始为1。例如通道1,则为ch1。
        subtype: 码流类型,主码流为main,辅码流为sub。
    :return:相机是否打开,相机
    """
    try:
        # ping IP,IP预检验
        if ping3.ping(ip) is None or not ping3.ping(ip):
            # ping的结果为None或False,ping失败,不存在该IP
            return False, None
        else:
            # 使用rtsp流打开相机
            cam = cv2.VideoCapture(f'rtsp://{username}:{password}@{ip}:{port}/h264/ch1/main/av_stream')
            return True, cam

    except cv2.error:
        # 捕获cv异常
        # 打开相机失败
        return False, None

获取视频流信息

一般视频流的信息主要包含画面的宽高以及视频显示帧率,对于视频文件,还包括总共有多少帧画面。针对这些信息,我们可以使用VideoCapture类的get方法获取相关信息。

# 获取视频帧的宽
width = cam.get(cv2.CAP_PROP_FRAME_WIDTH)
# 获取视频帧的高
height = cam.get(cv2.CAP_PROP_FRAME_HEIGHT)
# 获取视频帧的帧率
fps = cam.get(cv2.CAP_PROP_FPS)
# 获取视频文件的总帧数
frame_count = cam.get(cv2.CAP_PROP_FRAME_COUNT)

针对获取总帧数函数,若相机不支持获取总帧数,则返回0,获取总帧数仅对视频文件有意义。

获取帧画面

直接调用VideoCapture类的read方法,read方法会返回两个参数,一个为是否成功标志,一个为帧画面。
read方法返回参数:

  • 成功,BGR格式的numpy.ndarray三维数组
  • 失败,None

read使用示例:

# 获取帧画面
ret, frame = cam.read()

在调用read方法时,有时候可能会访问失败,所以为避免访问失败,可以采用while循环确保读取顺利。

# 获取帧画面
ret, frame = cam.read()
# 循环读取,确保读取成功
while not ret:
    ret, frame = cam.read()

读取帧画面优化

OpenCv底层基于ffmpeg读取视频,在OpenCv读取视频流时,会设置缓存区,将视频流读取到缓存区中,但是使用缓存区的话,会导致页面堆积,页面延迟高过,所以为了避免OpenCv缓存区视频流堆积的情况,可以使用线程实时读取OpenCv画面,将读取的每一帧内容存在队列中,在需要获取帧画面时,获取队列中的数据。

import queue
import threading

import cv2


class CameraThread(threading.Thread):
    # 保存实例化相机,通过实例化相机操作相机
    camera = None
    # 保存每一帧从rtsp流中读取到的画面
    queue_image = queue.Queue(maxsize=10)

    # 线程体是否循环执行标志
    flag_run = False

    # 相机线程调用函数
    def run(self) -> None:
        while self.flag_run:
            try:
                # 捕获异常,避免读取视频操作因异常而退出
                # 相机实例存在,判断相机是否打开
                if self.camera.is_opened():
                    # 相机已打开,读取相机内容
                    ret, frame = self.camera.read()
                    if not ret or frame is None:
                        # 读取相机内容失败
                        break
                    if ret:
                        # 将内容添加到队列中
                        # 判断队列是否满
                        if self.queue_image.full():
                            # 队列满,队头出队
                            self.queue_image.get()
                            # 队尾添加数据
                            self.queue_image.put(frame)
                        else:
                            # 队尾添加数据
                            self.queue_image.put(frame)
            except cv2.error as error:
                # 捕获cv异常
                # 因为子线程会一直调用该程序,可对捕获到的异常不进行处理
                print(error)
                pass

            except Exception as error:
                # 捕获Exception异常
                print(error)
                pass

    # setter:设置相机的camera对象
    def set_camera(self, camera):
        """
        设置相机的camera对象
        """
        # 设置相机的camera
        self.camera = camera

    # 获取队列中的RGB图像
    def get_image(self):
        """
        获取队列中的RGB图像
        :return: img: RGB图像
        """
        # 读取队列中的图片
        img = self.queue_image.get()
        # img为None,读取失败,队列还未获取到图片
        while img is None:
            # 一直读取图片,直到读取图片成功
            img = self.queue_image.get()
        # 返回读取到的内容
        return img

    # 停止运行
    def run_stop(self):
        self.flag_run = False

    # 开始运行
    def run_start(self):
        self.flag_run = True
相关文章
|
3月前
|
计算机视觉 索引
OpenCV4学习笔记(2):显示相机视频流的帧率
这篇文章是OpenCV4学习笔记的第二部分,介绍了如何通过OpenCV4在显示相机视频流时计算并显示其帧率,使用`getTickCount`和`getTickFrequency`函数来测量帧时间,并用`putText`在图像上绘制帧率信息。
OpenCV4学习笔记(2):显示相机视频流的帧率
|
1月前
|
编解码 计算机视觉 Python
Opencv学习笔记(九):通过CV2将摄像头视频流保存为视频文件
使用OpenCV库通过CV2将摄像头视频流保存为视频文件,包括定义视频编码格式、设置保存路径、通过write写入视频文件,并提供了相应的Python代码示例。
124 0
|
缓存 编解码 前端开发
基于OpenCv+Django的网络实时视频流传输(前后端分离)
基于OpenCv+Django的网络实时视频流传输(前后端分离)
708 0
|
机器学习/深度学习 存储 人工智能
能去码也能打码!OpenCV实时检测视频流人脸并马赛克之,视频后期福音
能去码也能打码!OpenCV实时检测视频流人脸并马赛克之,视频后期福音
550 0
能去码也能打码!OpenCV实时检测视频流人脸并马赛克之,视频后期福音
|
机器学习/深度学习 存储 人工智能
能去码也能打码!OpenCV实时检测视频流人脸并马赛克之,视频后期福音
我们现在经常用到的马赛克其实起源于建筑上的图案装饰,如今马赛克常用于图像或视频的模糊处理。随着技术的进步,打码与去码变成了一种常见的技术研究方向,同时也掀起了一场技术与道德的“战争”。
|
计算机视觉
OpenCV实时美颜摄像并生成H264视频流
        为什么美颜摄像这么简单的功能,OpenCV这个开源项目网上很少有代码呢?对于在windows平台下,生成h264视频流也比价麻烦,没有现成的api可以使用,需要借助MinGw编译libx264,或者ffmpeg才能使用。
1815 0
|
计算机视觉
【OpenCV学习】基于轮廓寻找的视频流运动检测
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ #include "cv.h" #include "highgui.h" #include #include #include #include #include // vari...
786 0
|
1月前
|
计算机视觉
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
这篇文章详细介绍了OpenCV库中的图像二值化函数`cv2.threshold`,包括二值化的概念、常见的阈值类型、函数的参数说明以及通过代码实例展示了如何应用该函数进行图像二值化处理,并展示了运行结果。
335 0
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
|
2月前
|
算法 计算机视觉
opencv图像形态学
图像形态学是一种基于数学形态学的图像处理技术,它主要用于分析和修改图像的形状和结构。
49 4