PYTHON: как автоматически захватывать изображение из RTSP каждую минуту до 24 часов - PullRequest
1 голос
/ 04 апреля 2020

Итак, я хочу написать код в python, где я извлекаю фотографии в виде кадров с камеры rtsp (прямая трансляция). Но я бы хотел, чтобы эти фотографии также сохранялись с отметкой времени и даты, что, я думаю, я сделал. Моя единственная проблема заключается в том, что я хочу, чтобы эти фотографии автоматически сохранялись на моем локальном компьютере каждую минуту и ​​заканчивались через 24 часа.

Как мне go об этом?

Это мой текущий код

 imagesFolder = "C:/Users/<user>/documents"
cap = cv2.VideoCapture("rtsp://username:password@cameraIP/axis-media/media.amp")
frameRate = cap.get(5) #frame rate
count = 0

while cap.isOpened():
    frameId = cap.get(1)  # current frame number
    ret, frame = cap.read()

    if (ret != True):
        break
    if (frameId % math.floor(frameRate) == 0):
        filename = imagesFolder + "/image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
        cv2.imwrite(filename, frame)

    cap.release()
    print ("Done!")

cv2.destroyAllWindows()

Ответы [ 3 ]

0 голосов
/ 08 апреля 2020

Я пытался использовать API apscheduler, но безрезультатно. Может быть, кто-то может взглянуть на это иначе и заставить это работать.

    import cv2
    import math
    import datetime
    from datetime import datetime
    from apscheduler.schedulers.blocking import BlockingScheduler


imagesFolder = "C:/Users/" + getpass.getuser() + "/documents"
cap = cv2.VideoCapture("rtsp://username:password@CameraIP/axis-media/media.amp")
frameRate = cap.get(5) #frame rate
count = 0




def some_job():
    while cap.isOpened():
        frameId = cap.get(1)
        ret, frame = cap.read()
        if (ret != True):
            break
        if (frameId % math.floor(frameRate) == 0):
                filename = imagesFolder + "/image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
                cv2.imwrite(filename, frame)
                scheduler = BlockingScheduler()
                scheduler.add_job(some_job, 'interval', seconds=60, start_date='2020-04-07 16:23:00', end_date='2020-04-08 16:23:00')
                scheduler.start()
        cap.release()
print ("Done!")
# Closes all the frames
cv2.destroyAllWindows()
0 голосов
/ 08 апреля 2020

Это работает несколько лучше, чем другие решения. Единственная проблема здесь состоит в том, что фотографии перестают сохраняться после первых 3 минут (первые 3 фотографии, которые были сделаны в секундах, но сохранены позже в течение каждой минуты) были сохранены. Решение теперь состоит в том, чтобы гарантировать, что это экономит каждую минуту до 24 часов, прежде чем это останавливается.

    import cv2
    import time
    import getpass
    import numpy as np
    import subprocess as sp
    from datetime import datetime

imagesFolder = "C:/Users/" + getpass.getuser() + "/documents"

# RTSP Streaming:
in_stream = "rtsp://username:password@cameraIP/axis-media/media.amp"
cap = cv2.VideoCapture(in_stream)

frameRate = cap.get(5) #frame rate

# Get resolution of input video
width  = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# Release VideoCapture - it was used just for getting video resolution
cap.release()

in_stream = "rtsp://username:password@cameraIP/axis-media/media.amp"

FFMPEG_BIN = "ffmpeg.exe" # on Windows

# Suspecting camera supports TCP protocol hence added: '-rtsp_transport', 'tcp'
command = [ FFMPEG_BIN,
            '-rtsp_transport', 'tcp',
            '-i', in_stream,
            '-f', 'image2pipe',
            '-pix_fmt', 'bgr24',
            '-vcodec', 'rawvideo', '-an', '-']

# Open sub-process that gets in_stream as input and uses stdout as an output PIPE.
pipe = sp.Popen(command, stdout=sp.PIPE, bufsize=10**8)


cur_time = time.time()  # Get current time

# start_time_24h measures 24 hours
start_time_24h = cur_time

# start_time_1min measures 1 minute
start_time_1min = cur_time - 30  # Subtract 30 seconds for start grabbing first frame after 30 seconds (instead of waiting a minute for the first frame).



while True:
    # read width*height*3 bytes from stdout (= 1 frame)
    raw_frame = pipe.stdout.read(width*height*3)

    if len(raw_frame) != (width*height*3):
        print('Error reading frame!!!')  # Break the loop in case of an error (too few bytes were read).
        break

    cur_time = time.time()  # Get current time
    elapsed_time_1min = cur_time - start_time_1min  # Time elapsed from previous image saving.

    # If 60 seconds were passed, reset timer, and store image.
    if elapsed_time_1min >= 60:
        # Reset the timer that is used for measuring 60 seconds
        start_time_1min = cur_time

        # Transform the byte read into a numpy array, and reshape it to video frame dimensions
        frame = np.fromstring(raw_frame, np.uint8)
        frame = frame.reshape((height, width, 3))

        filename = imagesFolder + "/image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
        #filename = "image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
        cv2.imwrite(filename, frame)

        # Show frame for testing
        cv2.imshow('frame', frame)
        cv2.waitKey(1)

    elapsed_time_24h = time.time() - start_time_24h

    #Break loop after 24*60*60 seconds
    if elapsed_time_24h > 24*60*60:
        break

    #time.sleep(60 - elapsed_time) # Sleeping is a bad idea - we need to grab all the frames.


print ("Done!")

pipe.kill()  # Kill the sub-process after 24 hours
cv2.destroyAllWindows()
0 голосов
/ 04 апреля 2020

Вы можете просто подождать 60 секунд между захватом кадра и прервать l oop после 24 * 60 циклов.

Я пытался протестировать свой код с использованием RTSP-потока publi c, но я становлюсь черным кадров, поэтому я не могу проверить свой код.

Вот код:


Обновление:

Пример кода выше не работает - первый кадр повторяется каждую минуту.

Предлагаемое решение:

  • Захватите весь видеокадр и сохраняйте кадр каждую минуту.
    Дельта времени в одну минуту будет точной до 0,2 секунды в случае, если видео 5 Гц.
  • Используйте отдельный таймер для измерения 24 часов.

Вот обновленный код (чтение из publi c RTSP):

import cv2
import time
from datetime import datetime
import getpass

imagesFolder = "C:/Users/" + getpass.getuser() + "/documents"
#cap = cv2.VideoCapture("rtsp://username:password@cameraIP/axis-media/media.amp")

# Use public RTSP Streaming for testing:
cap = cv2.VideoCapture("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov")

#cap = cv2.VideoCapture("test2.mp4")
frameRate = cap.get(5) #frame rate

cur_time = time.time()  # Get current time

# start_time_24h measures 24 hours
start_time_24h = cur_time

# start_time_1min measures 1 minute
start_time_1min = cur_time - 59  # Subtract 59 seconds for start grabbing first frame after one second (instead of waiting a minute for the first frame).

while cap.isOpened():
    frameId = cap.get(1)  # current frame number
    ret, frame = cap.read()

    if (ret != True):
        break

    cur_time = time.time()  # Get current time
    elapsed_time_1min = cur_time - start_time_1min  # Time elapsed from previous image saving.

    # If 60 seconds were passed, reset timer, and store image.
    if elapsed_time_1min >= 60:
        # Reset the timer that is used for measuring 60 seconds
        start_time_1min = cur_time

        filename = imagesFolder + "/image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
        #filename = "image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
        cv2.imwrite(filename, frame)

        # Show frame for testing
        cv2.imshow('frame', frame)
        cv2.waitKey(1)

    elapsed_time_24h = time.time() - start_time_24h

    #Break loop after 24*60*60 seconds
    if elapsed_time_24h > 24*60*60:
        break

    #time.sleep(60 - elapsed_time) # Sleeping is a bad idea - we need to grab all the frames.


cap.release()
print ("Done!")

cv2.destroyAllWindows()

Теперь изображения из publi c RTSP выглядят нормально:

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here


Обновление:

Вы можете попробовать захватить видеопоток, используя FFmpeg (вместо OpenCV).

Прочитайте следующий блог: Чтение и запись видеокадров в Python Использование FFMPEG

Если вы используете Windows ОС, загрузите последнюю версию стабильная 64-разрядная версия c версия здесь (в настоящее время 4.2.2).
Извлеките zip-файл и поместите ffmpeg.exe в ту же папку, что и скрипт Python ,

Вот код (захват с использованием FFmpeg в качестве подпроцесса и stdout в качестве PIPE):

import cv2
import time
from datetime import datetime
import getpass
import numpy as np
import subprocess as sp

imagesFolder = "C:/Users/" + getpass.getuser() + "/documents"
#cap = cv2.VideoCapture("rtsp://username:password@cameraIP/axis-media/media.amp")

# Use public RTSP Streaming for testing:
in_stream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"
cap = cv2.VideoCapture(in_stream)

#cap = cv2.VideoCapture("test2.mp4")
frameRate = cap.get(5) #frame rate

# Get resolution of input video
width  = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# Release VideoCapture - it was used just for getting video resolution
cap.release()

#in_stream = "rtsp://xxx.xxx.xxx.xxx:xxx/Streaming/Channels/101?transportmode=multicast",

#Use public RTSP Streaming for testing
in_stream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"


# http://zulko.github.io/blog/2013/09/27/read-and-write-video-frames-in-python-using-ffmpeg/
FFMPEG_BIN = "ffmpeg" # on Linux ans Mac OS (also works on Windows when ffmpeg.exe is in the path)
#FFMPEG_BIN = "ffmpeg.exe" # on Windows

command = [ FFMPEG_BIN,
            '-i', in_stream,
            '-f', 'image2pipe',
            '-pix_fmt', 'bgr24',
            '-vcodec', 'rawvideo', '-an', '-']

# Open sub-process that gets in_stream as input and uses stdout as an output PIPE.
pipe = sp.Popen(command, stdout=sp.PIPE, bufsize=10**8)


cur_time = time.time()  # Get current time

# start_time_24h measures 24 hours
start_time_24h = cur_time

# start_time_1min measures 1 minute
start_time_1min = cur_time - 30  # Subtract 30 seconds for start grabbing first frame after 30 seconds (instead of waiting a minute for the first frame).



while True:
    # read width*height*3 bytes from stdout (= 1 frame)
    raw_frame = pipe.stdout.read(width*height*3)

    if len(raw_frame) != (width*height*3):
        print('Error reading frame!!!')  # Break the loop in case of an error (too few bytes were read).
        break

    cur_time = time.time()  # Get current time
    elapsed_time_1min = cur_time - start_time_1min  # Time elapsed from previous image saving.

    # If 60 seconds were passed, reset timer, and store image.
    if elapsed_time_1min >= 60:
        # Reset the timer that is used for measuring 60 seconds
        start_time_1min = cur_time

        # Transform the byte read into a numpy array, and reshape it to video frame dimensions
        frame = np.fromstring(raw_frame, np.uint8)
        frame = frame.reshape((height, width, 3))

        filename = imagesFolder + "/image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
        #filename = "image_" + str(datetime.now().strftime("%d-%m-%Y_%I-%M-%S_%p"))  + ".jpg"
        cv2.imwrite(filename, frame)

        # Show frame for testing
        cv2.imshow('frame', frame)
        cv2.waitKey(1)

    elapsed_time_24h = time.time() - start_time_24h

    #Break loop after 24*60*60 seconds
    if elapsed_time_24h > 24*60*60:
        break

    #time.sleep(60 - elapsed_time) # Sleeping is a bad idea - we need to grab all the frames.


print ("Done!")

pipe.kill()  # Kill the sub-process after 24 hours
cv2.destroyAllWindows()
...