当前位置: 首页 > article >正文

摄像头监视脚本

摄像头监视脚本,若检测到摄像头画面有变化,保存这一段视频

一、使用方法

1.运行脚本
默认参数Threshold=3, Period=3, path=./recordings

python cam.py --threshold=30 --period=3 --path=./recordings
2.参数说明
threshold:摄像头捕获到的画面变化量阈值,阈值越小越敏感
period:摄像头捕获周期,单位秒
path:捕获图片保存路径


import cv2
import numpy as np
import time
import argparse
import os


def detect_motion(img1, img2, threshold=25):
    """
    检测两帧之间的变化区域
    :param img1: 当前帧
    :param img2: 上一帧
    :param threshold: 像素差异阈值
    :return: 变化区域掩码和是否检测到变化
    """
    # 转换为灰度图
    gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

    # 计算差异
    frame_diff = cv2.absdiff(gray1, gray2)

    # 应用阈值
    _, thresh = cv2.threshold(frame_diff, threshold, 255, cv2.THRESH_BINARY)

    # 应用形态学操作去噪
    kernel = np.ones((5, 5), np.uint8)
    thresh = cv2.dilate(thresh, kernel, iterations=2)
    thresh = cv2.erode(thresh, kernel, iterations=1)

    # 找到轮廓
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # 判断是否检测到显著变化
    has_motion = False
    min_area = 500  # 最小变化区域面积
    for contour in contours:
        if cv2.contourArea(contour) > min_area:
            has_motion = True
            break

    return thresh, has_motion


def camera_monitor(period=3, video_duration=5):
    """
    监视程序入口
    :param period: 检查周期(秒)
    :param video_duration: 录制视频长度(秒)
    """
    print(f'监视器启动!\nParams:\nThreshold={args.threshold}, Period={period}, Save Path={args.path}')

    # 构建RTSP URL
    rtsp_url = f'rtsp://{args.username}:{args.password}@{args.ip}:{args.port}{args.channel}'
    print(f'连接到 RTSP 流: {rtsp_url}')

    # 设置RTSP连接
    cap = cv2.VideoCapture(rtsp_url)

    # 设置RTSP缓冲区大小
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

    if not cap.isOpened():
        print('错误:无法连接到 RTSP 流')
        return

    # 获取视频参数
    frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = 20.0

    # 读取第一帧
    _, last_frame = cap.read()

    while True:
        ret, current_frame = cap.read()
        if not ret:
            print('错误:无法读取帧')
            break

        # 检测变化
        motion_mask, has_motion = detect_motion(current_frame, last_frame, args.threshold)

        if has_motion:
            print("检测到运动!录制视频...")

            # 创建视频写入器,修改为MP4格式
            timestamp = time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime())
            video_path = os.path.join(args.path, f'motion_{timestamp}.mp4')
            
            # 使用H.264编码器
            if os.name == 'nt':  # Windows系统
                video_writer = cv2.VideoWriter(
                    video_path,
                    cv2.VideoWriter_fourcc(*'H264'),
                    fps,
                    (frame_width, frame_height)
                )
            else:  # Linux/Mac系统
                video_writer = cv2.VideoWriter(
                    video_path,
                    cv2.VideoWriter_fourcc(*'avc1'),
                    fps,
                    (frame_width, frame_height)
                )

            # 记录检测到运动的时间点
            start_time = time.time()

            # 录制视频片段
            while time.time() - start_time < video_duration:
                ret, frame = cap.read()
                if not ret:
                    break

                # 标记变化区域
                motion_mask, _ = detect_motion(frame, last_frame, args.threshold)
                contours, _ = cv2.findContours(motion_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

                # 在原图上画出变化区域
                frame_marked = frame.copy()
                for contour in contours:
                    if cv2.contourArea(contour) > 500:
                        cv2.drawContours(frame_marked, [contour], -1, (0, 255, 0), 2)

                video_writer.write(frame_marked)
                last_frame = frame.copy()

            video_writer.release()
            print(f'视频保存到: {video_path}')

        last_frame = current_frame.copy()
        time.sleep(period)

    cap.release()


# 参数设置
parser = argparse.ArgumentParser(description='移动侦测摄像机监视器')
parser.add_argument('--threshold', type=int, default=3, help='移动侦测阈值')
parser.add_argument('--period', type=int, default=1, help='监控周期(秒)')
parser.add_argument('--path', type=str, default='./recordings', help='保存录制文件的路径')

# 添加RTSP相关参数
parser.add_argument('--ip', type=str, default='192.168.11.23', help='摄像机的 IP 地址')
parser.add_argument('--port', type=str, default='554', help='RTSP 端口(默认值:554)')
parser.add_argument('--username', type=str, default='admin', help='RTSP 用户名')
parser.add_argument('--password', type=str, default='admin123', help='RTSP 密码')
parser.add_argument('--channel', type=str, default='/cam/realmonitor?channel=1&subtype=1', help='RTSP 通道或流路径')

args = parser.parse_args()

# 确保存储目录存在
if not os.path.exists(args.path):
    os.makedirs(args.path)

if __name__ == '__main__':
    try:
        camera_monitor(period=args.period)
    except KeyboardInterrupt:
        print("\n用户停止的监控")
    finally:
        cv2.destroyAllWindows()



http://www.kler.cn/a/460382.html

相关文章:

  • Spring Boot 中的 classpath详解
  • 计算机的错误计算(一百九十九)
  • 深入剖析MySQL数据库架构:核心组件、存储引擎与优化策略(一)
  • Java重要面试名词整理(二十):GatewaySkyWalking
  • Microsoft Visual Studio中的/MT, /MTd,/MD,/MDd分别是什么意思?
  • 面试题:@Transactional 注解在自调用情况下会失效原因
  • Wonder Dynamics技术浅析(一)
  • [算法] [leetcode-1137] 第 N 个泰波那契数
  • 【自动驾驶汽车通讯协议】RGMII通信技术详解
  • 自学记录:鸿蒙5使用ArkTS和ArkUI实现Live View功能
  • 【经管】上市公司供应链风险数据测算数据集+dofile(2008-2023年)
  • gitlab的搭建及使用
  • udp分片报文发送和接收
  • 经典排序算法:冒泡排序与选择排序
  • List排序的方法
  • JVM和异常
  • 【华为OD-E卷 - 机房布局 100分(python、java、c++、js、c)】
  • Edge如何获得纯净的启动界面
  • XIAO Esp32 S3 轻松发送 HTTP 请求,打造智能物联网应用
  • 优化咨询行业团队协作:通过有效的项目管理工具实现高效协作
  • 爬虫代码中如何添加异常处理?
  • torch.nn.Linear(p_input, p_output,bias)
  • 2024Jinger的前端学习内容总结——前端学习路线(超全)
  • 使用 Python 和 LabelMe 实现图片验证码的自动标注
  • 【ArcGISPro/GeoScenePro】检查多光谱影像的属性并优化其外观
  • Spring Boot 3 文件上传、多文件上传、大文件分片上传、文件流处理以及批量操作