Jetson Nano & TX2 (應用)如何調用RTSP攝像頭

查看cpu gpu 以及編解碼模塊的使用:

sudo ~/tegrastats

首先,要先討論下爲什麼需要在OpenCV上用上Gstreamer, 比如我直接一個攝像頭 v4l2 圖像傳給 OpenCV 不行嗎?

Gstreamer是嵌入式平臺處理Media的首選組件, 像Nvdia/TI/NXP/Rockchip平臺, 都是使用Gstreamer來整合Media應用. 在Rockchip平臺上, 我們已經有爲Gstreamer開發了像Decode/Encode/ISP-Camera/2D加速器/DRM-Display-sink這些的Plugin。所以OpenCV如果鏈接上Gstreamer,輸入源就不僅僅是攝像頭, 還可以是RTSP/本地視頻;輸出顯示的代碼可以不用寫, 讓Gstreamer來顯示; 轉換格式讓Gstreamer來轉, 利用硬件加速; 處理的圖像送回Gstreamer編碼。
 

準備條件:

  • 需要在Jetson TX2上構建並安裝具有GStreamerpython支持的OpenCV 。OpenCV3.4以上,我用的是4.1
  • 如果你是用 IP CAM, 你必須構建好,並且知道它的RTSP URI, 比如. rtsp://admin:[email protected]:554.
  • 如果你是用USB 網絡攝像頭(I 使用的是羅技 C920),這個USB攝像頭通常安裝在 /dev/video1, 因爲 Jetson 板載攝像頭已經佔用了 /dev/video0.
  • 安裝 gstreamer1.0-plugins-bad ,這個包含了 h264parse 元素. 這是爲了解碼來自IP攝像頭的H.264 RTSP stream 所需要的(方法:sudo apt-get install gstreamer1.0-plugins-bad)
sudo apt-get install gstreamer1.0-plugins-bad-faad gstreamer1.0-plugins-bad-videoparsers

測試代碼:

import sys
import argparse
import cv2
 
WINDOW_NAME = 'CameraDemo'
 
def parse_args():
    # Parse input arguments
    desc = 'Capture and display live camera video on Jetson TX2/TX1'
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('--rtsp', dest='use_rtsp',
                        help='use IP CAM (remember to also set --uri)',
                        action='store_true')
    parser.add_argument('--uri', dest='rtsp_uri',
                        help='RTSP URI, e.g. rtsp://192.168.1.64:554',
                        default=None, type=str)
    parser.add_argument('--latency', dest='rtsp_latency',
                        help='latency in ms for RTSP [200]',
                        default=200, type=int)
    parser.add_argument('--usb', dest='use_usb',
                        help='use USB webcam (remember to also set --vid)',
                        action='store_true')
    parser.add_argument('--vid', dest='video_dev',
                        help='device # of USB webcam (/dev/video?) [1]',
                        default=1, type=int)
    parser.add_argument('--width', dest='image_width',
                        help='image width [1920]',
                        default=1920, type=int)
    parser.add_argument('--height', dest='image_height',
                        help='image height [1080]',
                        default=1080, type=int)
    args = parser.parse_args()
    return args
 
def open_cam_rtsp(uri, width, height, latency):
    gst_str = ('rtspsrc location={} latency={} ! '
               'rtph264depay ! h264parse ! omxh264dec ! '
               'nvvidconv ! '
               'video/x-raw, width=(int){}, height=(int){}, '
               'format=(string)BGRx ! '
               'videoconvert ! appsink').format(uri, latency, width, height)
    return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
 
def open_cam_usb(dev, width, height):
    # We want to set width and height here, otherwise we could just do:
    #     return cv2.VideoCapture(dev)
    gst_str = ('v4l2src device=/dev/video{} ! '
               'video/x-raw, width=(int){}, height=(int){}, '
               'format=(string)RGB ! '
               'videoconvert ! appsink').format(dev, width, height)
    return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
 
def open_cam_onboard(width, height):
    # On versions of L4T prior to 28.1, add 'flip-method=2' into gst_str
    gst_str = ('nvcamerasrc ! '
               'video/x-raw(memory:NVMM), '
               'width=(int)2592, height=(int)1458, '
               'format=(string)I420, framerate=(fraction)30/1 ! '
               'nvvidconv ! '
               'video/x-raw, width=(int){}, height=(int){}, '
               'format=(string)BGRx ! '
               'videoconvert ! appsink').format(width, height)
    return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
 
def open_window(width, height):
    cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_NORMAL)
    cv2.resizeWindow(WINDOW_NAME, width, height)
    cv2.moveWindow(WINDOW_NAME, 0, 0)
    cv2.setWindowTitle(WINDOW_NAME, 'Camera Demo for Jetson TX2/TX1')
 
def read_cam(cap):
    show_help = True
    full_scrn = False
    help_text = '"Esc" to Quit, "H" for Help, "F" to Toggle Fullscreen'
    font = cv2.FONT_HERSHEY_PLAIN
    while True:
        if cv2.getWindowProperty(WINDOW_NAME, 0) < 0:
            # Check to see if the user has closed the window
            # If yes, terminate the program
            break
        _, img = cap.read() # grab the next image frame from camera
        if show_help:
            cv2.putText(img, help_text, (11, 20), font,
                        1.0, (32, 32, 32), 4, cv2.LINE_AA)
            cv2.putText(img, help_text, (10, 20), font,
                        1.0, (240, 240, 240), 1, cv2.LINE_AA)
        cv2.imshow(WINDOW_NAME, img)
        key = cv2.waitKey(10)
        if key == 27: # ESC key: quit program
            break
        elif key == ord('H') or key == ord('h'): # toggle help message
            show_help = not show_help
        elif key == ord('F') or key == ord('f'): # toggle fullscreen
            full_scrn = not full_scrn
            if full_scrn:
                cv2.setWindowProperty(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN,
                                      cv2.WINDOW_FULLSCREEN)
            else:
                cv2.setWindowProperty(WINDOW_NAME, cv2.WND_PROP_FULLSCREEN,
                                      cv2.WINDOW_NORMAL)
 
def main():
    args = parse_args()
    print('Called with args:')
    print(args)
    print('OpenCV version: {}'.format(cv2.__version__))
 
    if args.use_rtsp:
        cap = open_cam_rtsp(args.rtsp_uri,
                            args.image_width,
                            args.image_height,
                            args.rtsp_latency)
    elif args.use_usb:
        cap = open_cam_usb(args.video_dev,
                           args.image_width,
                           args.image_height)
    else: # by default, use the Jetson onboard camera
        cap = open_cam_onboard(args.image_width,
                               args.image_height)
 
    if not cap.isOpened():
        sys.exit('Failed to open camera!')
 
    open_window(args.image_width, args.image_height)
    read_cam(cap)
 
    cap.release()
    cv2.destroyAllWindows()
 
if __name__ == '__main__':
    main()

板載相機

按照下面步驟利用Jetson板載攝像頭抓取和顯示影像。默認分辨率爲 1920x1080 @ 30fps.

python tegra-cam.py

USB攝像頭

按照下面步驟使用 USB 網絡攝像頭,並且把分辨率設置爲1280x720. 注意‘–vid 1’意思是使用 /dev/video1.

python tegra-cam.py --usb --vid 1 --width 1280 --height 720

IP攝像頭

按照下面步驟使用IP攝像頭,把最後的 RTSP URI 參數設置爲你自己的IP CAM.

python3 tegra-cam.py --rtsp --uri "rtsp://192.168.171.199:554/user=admin&password=&channel=1&stream=0.sdp?"

如果使用上述指令報錯,則輸入以下指令,首先確認相機沒有問題,然後再查找其他原因

gst-launch-1.0 rtspsrc location="rtsp://192.168.171.199:554/user=admin&password=&channel=1&stream=0.sdp?" ! rtph264depay ! h264parse ! omxh264dec ! nveglglessink

這個 腳本的關鍵是依靠GStreamer pipelines 我用來call cv.VideoCapture(). 在我的經驗裏,使用 nvvidconv 做圖像縮放,用BGR做顏色格式轉換(注意: OpenCV 需要 BGR 作爲最後的輸出) 在幀速率方面會有更好效果。

def open_cam_rtsp(uri, width, height, latency):
    gst_str = ("rtspsrc location={} latency={} ! rtph264depay ! h264parse ! omxh264dec ! "
               "nvvidconv ! video/x-raw, width=(int){}, height=(int){}, format=(string)BGRx ! "
               "videoconvert ! appsink").format(uri, latency, width, height)
    return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
 
def open_cam_usb(dev, width, height):
    # We want to set width and height here, otherwise we could just do:
    #     return cv2.VideoCapture(dev)
    gst_str = ("v4l2src device=/dev/video{} ! "
               "video/x-raw, width=(int){}, height=(int){}, format=(string)RGB ! "
               "videoconvert ! appsink").format(dev, width, height)
    return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
 
def open_cam_onboard(width, height):
    # On versions of L4T previous to L4T 28.1, flip-method=2
    # Use Jetson onboard camera
    gst_str = ("nvcamerasrc ! "
               "video/x-raw(memory:NVMM), width=(int)2592, height=(int)1458, format=(string)I420, framerate=(fraction)30/1 ! "
               "nvvidconv ! video/x-raw, width=(int){}, height=(int){}, format=(string)BGRx ! "
               "videoconvert ! appsink").format(width, height)
    return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章