You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

YOLOv8+Python3使用RTSP视频源时频繁重连、不稳定问题求助

YOLOv8+Python3使用RTSP视频源时频繁重连、不稳定问题求助

我现在在做一个基于YOLOv8、Python3的实验,视频源用的是RTSP。原本设计程序的时候,我以为RTSP能保持稳定运行,不会频繁重连,但实际情况却是RTSP协议一直在反复重连,稳定性特别差,而且我用的YOLO模型越大,这个重连问题就越严重。

我已经做了详细的硬件排查:

  • 我的UTP网络连接非常稳定,延迟极低,已经用多种工具验证过了
  • 我的电脑性能很强,支持CUDA加速,所以应该不是电脑性能导致的问题
  • 我试过RTSP的TCP和UDP两种传输方式,但结果没什么区别

我怀疑是Python3环境下的OpenCV对RTSP的支持不太理想,不仅运行慢还有bug,没法处理较大的视频延迟——毕竟现在目标检测的结果确实有明显的延迟。

下面是我目前在用的程序代码:

import numpy as np
from ultralytics import YOLO
import cv2
import cvzone
import time, math, datetime, os
from sort import *

# os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "rtsp_transport;udp"
os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "rtsp_transport;udp,max_delay=10000000"


output_folder = "Captured"
if not os.path.exists(output_folder):
    os.makedirs(output_folder)

error_detection = 0

int_counting = 0

# RTSP Source
rtsp_source = "rtsp://admin:gcc12345@192.168.6.7:554/Streaming/Channels/101/" # HIKVISION
# rtsp_source = "rtsp://admin:admin12345@192.168.6.2:554/cam/realmonitor?channel=3&subtype=0" # DAHUA
# rtsp_source = "rtsp://admin:admin12345@192.168.6.2:554/cam/realmonitor?channel=2&subtype=0" # DAHUA
# rtsp_source = "rtsp://admin:admin12345@192.168.6.2:554/cam/realmonitor?channel=4&subtype=0" # DAHUA

# rtsp_source = "../Videos/cars.mp4" # VIDEO

mask = cv2.imread("mask.png")

# Tracking
tracker = Sort(max_age=20, min_hits=3, iou_threshold=0.5)

# limits = [300, 350, 673, 350]

limits = [550, 220, 550, 670]

# Inisialisasi model YOLO
model = YOLO("../Yolo-Weights/yolov8x.pt")

className = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train',
 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter',
 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear',
 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase',
 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat',
 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle',
 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut',
 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet',
 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave',
 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase',
 'scissors', 'teddy bear', 'hair drier', 'toothbrush']

# Fungsi untuk mereset jumlah upaya koneksi ulang
def reset_attempts():
    return 50

# Fungsi untuk memproses video dan mengatur reconnect
def process_video(attempts):
    global error_detection, tracker, int_counting
    totalCount = []
    # Inisialisasi waktu untuk perhitungan FPS
    prev_time = time.time()

    while True:
        success, img = camera.read()
        start_time = time.time()

        if not success:
            error_detection += 1
            print("[ERROR] Gagal mendapatkan frame, mencoba reconnect..." + datetime.datetime.now().strftime("%m-%d-%Y %I:%M:%S%p"))
            camera.release()

            if attempts > 0:
                time.sleep(min(5, (50 - attempts) / 10))
                return True
            else:
                return False

        # RESET Tracker
        if time.time() - start_time > 300:  # Reset setiap 5 menit (300 detik)
            tracker = Sort(max_age=20, min_hits=3, iou_threshold=0.3)
            totalCount.clear()
            start_time = time.time()  # Reset waktu mulai
            print("[INFO] Tracker di-reset secara berkala.")

        # Menghitung waktu sekarang
        current_time = time.time()

        # Hitung FPS
        fps = 1 / (current_time - prev_time)
        prev_time = current_time

        print(img)

        img_resized = cv2.resize(img, (1300, 700))  # Resize frame

        # img_resized = img

        # Tampilkan FPS di frame
        cv2.putText(img_resized, f"FPS: {int(fps)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

        img_region = cv2.bitwise_and(img_resized, mask)

        # Deteksi dengan YOLO
        results = model(img_region, stream=True)

        # Tracker
        detections = np.empty((0,5))
        for r in results:
            boxes = r.boxes
            for box in boxes:
                # Bounding Box
                x1, y1, x2, y2 = box.xyxy[0]
                x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
                w, h = x2 - x1, y2 - y1

                # Menampilkan Tulisan Persentase
                conf = math.ceil((box.conf[0] * 100)) / 100

                # Class Name
                cls = int(box.cls[0])

                currentClass = className[cls]

                if currentClass == "car" or currentClass == "truck" or currentClass == "bus" or currentClass == "motorcycle" and conf > 0.5:
                    # cvzone.putTextRect(img_resized, f'{className[cls]} {conf}', (max(0, x1), max(35, y1)), scale=0.7, thickness=1, offset=3)
                    # cvzone.cornerRect(img_resized, (x1, y1, w, h), l=5, rt=5)
                    currentArray = np.array([x1,y1,x2,y2,conf])
                    detections = np.vstack((detections,currentArray))

        # Tracker
        resultsTracker = tracker.update(detections)
        cv2.line(img_resized,(limits[0], limits[1]), (limits[2], limits[3]),(0, 0, 255), 5)
        # cv2.line(img_region, (limits[0], limits[1]), (limits[2], limits[3]), (0, 0, 255), 5)

        for result in resultsTracker:
            x1, y1, x2, y2, Id = result
            x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
            # print(result)
            w, h = x2 - x1, y2 - y1
            cvzone.cornerRect(img_resized, (x1, y1, w, h), l=9, rt=2, colorR=(255,0,255))
            cvzone.putTextRect(img_resized, f'{int(Id)}', (max(0, x1), max(35, y1)), scale=2, thickness=3, offset=10)

            cx, cy = x1+w//2, y1+h//2
            cv2.circle(img_resized,(cx,cy),5,(255,0,255),cv2.FILLED)

            if limits[0] - 20 < cx < limits[0] + 20 and limits[1]  < cy < limits[3]:
                if totalCount.count(Id) == 0:
                    totalCount.append(Id)

                    int_counting += 1

                    # Capture gambar ketika objek melewati batas
                    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                    file_name = f"capture_{Id}_{timestamp}.png"
                    file_path = os.path.join(output_folder, file_name)

                    # Simpan gambar yang ditangkap ke dalam folder
                    cv2.imwrite(file_path, img_resized)
                    print(f"Gambar disimpan: {file_path}")

        cvzone.putTextRect(img_resized,f'Count: {int_counting} Error Detection: {int(error_detection)}',(50, 650))

        # Tampilkan hasil frame
        cv2.imshow("Image", img_resized)
        # cv2.imshow("ImageRegion", img_region)

        # Tekan 'q' untuk keluar
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        # cv2.waitKey(0)

    return False

# Inisialisasi variabel recall untuk reconnect dan attempts untuk jumlah upaya
recall = True
attempts = reset_attempts()

while recall:
    # Membuka stream RTSP
    camera = cv2.VideoCapture(rtsp_source, cv2.CAP_FFMPEG)
    camera.set(cv2.CAP_PROP_BUFFERSIZE, 1)
    camera.set(cv2.CAP_PROP_FPS, 10)

    if camera.isOpened():
        print("[INFO] Camera connected at " +
              datetime.datetime.now().strftime("%m-%d-%Y %I:%M:%S%p"))
        attempts = reset_attempts()  # Reset attempts saat berhasil terkoneksi
        recall = process_video(attempts)  # Proses video
    else:
        print("[ERROR] Camera not opened " +
              datetime.datetime.now().strftime("%m-%d-%Y %I:%M:%S%p"))
        camera.release()
        attempts -= 1
        print(f"Remaining attempts: {attempts}")

        # Beri jeda untuk mencoba kembali
        time.sleep(5)
        continue

# Tutup jendela dan stream
cv2.destroyAllWindows()

环境依赖:

absl-py==2.1.0
antlr4-python3-runtime==4.9.3
asttokens==2.4.1
certifi==2024.8.30
charset-normalizer==3.3.2
colorama==0.4.6
contourpy==1.3.0
cvzone==1.5.6
cycler==0.12.1
decorator==5.1.1
exceptiongroup==1.2.2
executing==2.1.0
filelock==3.16.1
filterpy==1.4.5
fonttools==4.54.1
fsspec==2024.9.0
grpcio==1.66.1
hydra-core==1.3.2
idna==3.10
imageio==2.35.1
ipython==8.27.0
jedi==0.19.1
Jinja2==3.1.4
kiwisolver==1.4.7
lap==0.4.0
Markdown==3.7
MarkupSafe==2.1.5
matplotlib==3.9.2
matplotlib-inline==0.1.7
mpmath==1.3.0
networkx==3.3
numpy==1.26.4
omegaconf==2.3.0
opencv-python==4.10.0.84
packaging==24.1
pandas==2.2.3
parso==0.8.4
pillow==10.4.0
prompt_toolkit==3.0.47
protobuf==5.28.2
psutil==6.0.0
pure_eval==0.2.3
py-cpuinfo==9.0.0
Pygments==2.18.0
pyparsing==3.1.4
python-dateutil==2.9.0.post0
pytz==2024.2
PyWavelets==1.7.0
PyYAML==6.0.2
requests==2.32.3
scikit-image==0.19.3
scipy==1.14.1
seaborn==0.13.2
sentry-sdk==2.14.0
six==1.16.0
stack-data==0.6.3
sympy==1.13.3
tensorboard==2.17.1
tensorboard-data-server==0.7.2
thop==0.1.1.post22090722

备注:内容来源于stack exchange,提问作者EMAIL KERJA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:04:28