调用海康相机实现事件监测并拍照

我的摄像机不支持人形检查和车辆检测,所以我就在后台设置了一个简单的区域入侵检测,如下图所示,我施划了这个区域的多边形。

然后我编写如下代码:

python 复制代码
import requests
import time
import threading
import cv2
import xml.etree.ElementTree as ET
from requests.auth import HTTPDigestAuth

# 摄像机配置
CAMERA_IP = "192.168.1.64"
USERNAME = "admin"
PASSWORD = "123456qwer"

# RTSP 主码流
RTSP_URL = f"rtsp://{USERNAME}:{PASSWORD}@{CAMERA_IP}:554/Streaming/Channels/101"

# 事件流地址
EVENT_STREAM_URL = f"http://{CAMERA_IP}/ISAPI/Event/notification/alertStream"

# 抓拍接口
SNAPSHOT_URL = f"http://{CAMERA_IP}/ISAPI/Streaming/channels/1/picture"

# 序号计数器
event_counter = 0


# ============================
#   抓拍函数
# ============================
def capture_snapshot(event_type):
    global event_counter
    event_counter += 1

    timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime())
    filename = f"{event_type}_{event_counter:04d}_{timestamp}.jpg"

    try:
        r = requests.get(SNAPSHOT_URL, auth=HTTPDigestAuth(USERNAME, PASSWORD), timeout=5)
        if r.status_code == 200:
            with open(filename, "wb") as f:
                f.write(r.content)
            print(f"📸 已保存抓拍:{filename}")
        else:
            print(f"❌ 抓拍失败,状态码:{r.status_code}")
    except Exception as e:
        print("❌ 抓拍异常:", e)


# ============================
#   事件监听线程
# ============================
def listen_event_stream():
    print("开始监听事件流...")

    with requests.get(EVENT_STREAM_URL, auth=HTTPDigestAuth(USERNAME, PASSWORD), stream=True) as r:
        if r.status_code != 200:
            print("无法连接事件流,状态码:", r.status_code)
            return

        buffer = ""

        for chunk in r.iter_content(chunk_size=1024):
            if not chunk:
                continue

            text = chunk.decode(errors="ignore")
            buffer += text

            # 每个事件以 </EventNotificationAlert> 结尾
            while "</EventNotificationAlert>" in buffer:
                # 截取完整 XML
                xml_block, buffer = buffer.split("</EventNotificationAlert>", 1)
                xml_block = xml_block + "</EventNotificationAlert>"

                # print(xml_block)

                # 去掉 boundary 和 HTTP 头,只保留 XML
                # 找到第一个 "<EventNotificationAlert"
                start_index = xml_block.find("<EventNotificationAlert")
                if start_index == -1:
                    # 不是 XML,跳过
                    continue

                xml_str = xml_block[start_index:]

                try:
                    root = ET.fromstring(xml_str)
                    ns = {"ns": "http://www.hikvision.com/ver20/XMLSchema"}

                    event_type = root.find("ns:eventType", ns).text
                    event_state = root.find("ns:eventState", ns).text

                    print(f"收到事件:{event_type}, 状态:{event_state}")

                    # 区域入侵事件
                    if event_type == "Intrusion" and event_state == "active":
                        capture_snapshot(event_type)

                except Exception as e:
                    print("❌ XML 解析失败:", e)
                    print("❌ 原始 XML:")
                    print(xml_str)
                    print("--------------------------------------------------")


# ============================
#   视频显示线程(缩放 30%)
# ============================
def show_video():
    print("打开视频流...")
    cap = cv2.VideoCapture(RTSP_URL)

    if not cap.isOpened():
        print("❌ 无法打开 RTSP 视频流")
        return

    while True:
        ret, frame = cap.read()
        if not ret:
            print("⚠️ 视频帧读取失败,重试中...")
            time.sleep(1)
            continue

        # 缩放到 30%
        frame_small = cv2.resize(frame, None, fx=0.3, fy=0.3)

        cv2.imshow("Camera Preview (30%)", frame_small)

        # 按 q 退出
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()


# ============================
#   主程序入口
# ============================
if __name__ == "__main__":
    # 启动事件监听线程
    t1 = threading.Thread(target=listen_event_stream, daemon=True)
    t1.start()

    # 主线程显示视频
    show_video()

就可以实现了。

但有个问题,我们可能会在测试的时候收到:

python 复制代码
收到事件:videoloss, 状态:inactive

具体的事件信息为:

python 复制代码
--boundary
Content-Type: application/xml; charset="UTF-8"
Content-Length: 518

<EventNotificationAlert version="2.0" xmlns="http://www.hikvision.com/ver20/XMLSchema">
<ipAddress>192.168.1.64</ipAddress>
<portNo>80</portNo>
<protocol>HTTP</protocol>
<macAddress>44:a6:42:46:a2:73</macAddress>
<channelID>1</channelID>
<dateTime>2026-02-04T16:14:17+08:00</dateTime>
<activePostCount>0</activePostCount>
<eventType>videoloss</eventType>
<eventState>inactive</eventState>
<eventDescription>videoloss alarm</eventDescription>
<channelName>Camera 01</channelName>
</EventNotificationAlert>

这个就是我们收到的事件,只不过事件类型是videoloss,代表这重新连接了一次rtsp。这可能是因为视频拥塞导致的,我也没找到原因。

相关推荐
长江后浪博客1 小时前
黑色滴灌带三角结构视觉检测光源设计方案——200mm高角度环光 + 低角度条形暗场补光
人工智能·数码相机·视觉检测·机器视觉·光源设计·暗场补光·环形光
长江后浪博客1 天前
陶瓷浮雕盘印刷视觉定位方案:8K线扫相机 + 暗场光源 + 旋转平台
人工智能·数码相机·机器视觉·视觉定位·线扫相机·暗场光源·陶瓷印刷
爱分享的康康1 天前
破解座舱数采五大痛点:DMS/OMS多路相机数采工程方案
数码相机·自动驾驶
k4m7v2pz2 天前
Godot 4 窗口拉伸黑边与变形:stretch 配置全解析
数码相机·游戏引擎·godot·2d游戏·黑边·stretch·画面比例
成都佳洋光电科技有限公司2 天前
一文了解工业相机是怎么实现触发的?
数码相机·工业相机·工业镜头·短波红外
YH行业报告分析2 天前
2026碲化镉汞相机技术升级:红外热成像应用如何推动高性能探测器市场增长?
数码相机
光电的一只菜鸡2 天前
相机光学(五十二)——PDAF标定测试卡参数如何确定
数码相机
蒲公英内测分发2 天前
运动相机卖到海外,配套 App 没上架当地应用商店,用户怎么安装?
人工智能·数码相机·测试工具·智能硬件·web app
格林威2 天前
C# 相机图像配合频闪光源:实现高速稳定拍摄的几个方法
开发语言·网络·人工智能·数码相机·计算机视觉·c#·视觉检测
光锥智能2 天前
出货量突破1000万台!影石Insta360上半年营收55.16亿元,同比上涨50%
数码相机