使用OpenCV cv2.VideoCapture在Python中从IP摄像机进行视频流传输

10

我正在尝试从IP摄像头中使用Python获取视频流,但是出现了错误。我正在使用Pycharm IDE。

import cv2
scheme = '192.168.100.23'


host = scheme
cap = cv2.VideoCapture('http://admin:Ebmacs8485867@'+host+':81/web/admin.html')

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

    # Place options to overlay on the video here.
    # I'll go over that later.

    cv2.imshow('Camera', frame)

    k = cv2.waitKey(0) & 0xFF
    if k == 27:  # esc key ends process
        cap.release()
        break
cv2.destroyAllWindows()
Error:
"E:\Digital Image Processing\python\ReadingAndDisplayingImages\venv\Scripts\python.exe" "E:/Digital Image Processing/python/ReadingAndDisplayingImages/ReadandDisplay.py"
Traceback (most recent call last):
  File "E:/Digital Image Processing/python/ReadingAndDisplayingImages/ReadandDisplay.py", line 14, in <module>
    cv2.imshow('Camera', frame)
cv2.error: OpenCV(4.0.1) C:\projects\opencv-python\opencv\modules\highgui\src\window.cpp:352: error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'cv::imshow'

warning: Error opening file (/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:901)
warning: http://admin:Ebmacs8485867@192.168.100.23:81/web/admin.html (/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:902)

你的意思是cv2.imshow不能捕获帧吗? - Moazam Shahid
不是imshow(),而是cap.read()。 - Bahramdun Adil
我也尝试使用RTSP,但它也无法工作。 - Moazam Shahid
这不是一个RTSP链接,在某些相机中它看起来像是rtsp://192.168.100.23:554/11... 这个链接因型号而异。你正在传递一个HTML网页进行连接。这不是一个流,而是一个网页。有时这个网页通过JavaScript、Flash或其他方式连接到流。 - api55
我在 while 循环之前使用了 if 语句编写了 cap.isOpened() 这一行代码……当我运行代码时,它会打印出 not opened。 - Moazam Shahid
显示剩余5条评论
1个回答

16

您很可能由于无效的流链接而收到该错误。将您的流链接插入到VLC播放器中以确认它是否有效。这是一个使用OpenCV和cv2.VideoCapture.read()的IP摄像机视频流小部件。此实现使用线程在不同的线程中获取帧,因为read()是一种阻塞操作。通过将这个操作放入一个专门用于获取帧的分离线程中,可以通过I/O延迟减少来提高性能。我使用了自己的IP摄像机RTSP流链接。将stream_link更改为您自己的IP摄像机链接。

enter image description here

根据您的IP摄像机不同,您的RTSP流链接也会有所不同,以下是我的例子:

rtsp://username:password@192.168.1.49:554/cam/realmonitor?channel=1&subtype=0
rtsp://username:password@192.168.1.45/axis-media/media.amp

代码

from threading import Thread
import cv2

class VideoStreamWidget(object):
    def __init__(self, src=0):
        # Create a VideoCapture object
        self.capture = cv2.VideoCapture(src)

        # Start the thread to read frames from the video stream
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # Read the next frame from the stream in a different thread
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()

    def show_frame(self):
        # Display frames in main program
        if self.status:
            self.frame = self.maintain_aspect_ratio_resize(self.frame, width=600)
            cv2.imshow('IP Camera Video Streaming', self.frame)

        # Press Q on keyboard to stop recording
        key = cv2.waitKey(1)
        if key == ord('q'):
            self.capture.release()
            cv2.destroyAllWindows()
            exit(1)

    # Resizes a image and maintains aspect ratio
    def maintain_aspect_ratio_resize(self, image, width=None, height=None, inter=cv2.INTER_AREA):
        # Grab the image size and initialize dimensions
        dim = None
        (h, w) = image.shape[:2]

        # Return original image if no need to resize
        if width is None and height is None:
            return image

        # We are resizing height if width is none
        if width is None:
            # Calculate the ratio of the height and construct the dimensions
            r = height / float(h)
            dim = (int(w * r), height)
        # We are resizing width if height is none
        else:
            # Calculate the ratio of the 0idth and construct the dimensions
            r = width / float(w)
            dim = (width, int(h * r))

        # Return the resized image
        return cv2.resize(image, dim, interpolation=inter)

if __name__ == '__main__':
    stream_link = 'your stream link!'
    video_stream_widget = VideoStreamWidget(stream_link)
    while True:
        try:
            video_stream_widget.show_frame()
        except AttributeError:
            pass

相关的摄像机/IP/RTSP、FPS、视频、线程和多进程文章

  1. Python OpenCV从摄像头进行流式传输-多线程、时间戳

  2. 使用OpenCV cv2.VideoCapture在Python中从IP相机进行视频流传输

  3. 如何使用OpenCV捕获多个摄像机流?

  4. OpenCV实时流视频捕捉速度较慢。如何丢帧或与实时同步?

  5. 使用OpenCV VideoWriter将RTSP流存储为视频文件

  6. Python OpenCV视频保存

  7. Python OpenCV多进程cv2.VideoCapture mp4


这是好东西。谢谢。您能否对 self.thread.daemon = True 发表评论?谢谢。 - user1965074
3
如果你不将daemon设置为True,当主程序关闭时它将变成僵尸进程。我们设置daemonTrue,这样当父进程关闭时,所有子进程也会被杀死。请参阅守护进程 - nathancy
1
我创建了一个get_frame函数,如果第一帧没有设置,则返回self.frame或np.empty,并为我提供了一组在类外显示或处理的帧。与VLC播放器相比,我惊讶地发现这种方法几乎没有延迟,物体离开摄像头后几秒钟才出现。 - brianlmerritt
self.frame需要锁定以避免捕获操作和显示操作发生冲突吗? - Kenji Noguchi
1
@KenjiNoguchi 我找到了你问题的答案 - BaKeR

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