opencv入侵检测算法笔记

opencv入侵检测算法笔记

import cv2
import numpy as np

# 定义多个感兴趣区域(ROI)的边界
rois = [
    #三个大触点
    (610, 650, 590, 630),   # ROI 2: (top, bottom, left, right)
    (610, 650, 665, 715),   # ROI 3: (top, bottom, left, right)
    (610, 650, 750, 790),   # ROI 4: (top, bottom, left, right)
     #四个小触点
    (524, 550, 620, 641),
    (524, 550, 660, 678),
    (524, 550, 693, 711),
    (524, 550, 729, 749)
]

# 读取视频文件
video_capture = cv2.VideoCapture("test_video.mp4")

# 获取视频的帧率、宽度和高度
fps = int(video_capture.get(cv2.CAP_PROP_FPS))
width = int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 创建视频写入对象
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('out.mp4', fourcc, fps, (width, height))

# 创建文本文件来存储识别结果
output_file = open("intrusion_results.txt", "w")

# 定义矩形框绘制时的颜色
normal_color = (0, 255, 0)    # 正常状态下的颜色为绿色
intrusion_color = (0, 0, 255) # 入侵状态下的颜色为红色

# 定义每个ROI的背景和初始帧中的物体轮廓
roi_bgs = []
initial_contours = [[] for _ in rois]

# 定义最小运动物体的面积阈值
threshold_area = 5

# 读取第一帧,并提取每个ROI的背景
ret, frame = video_capture.read()
for idx, (top, bottom, left, right) in enumerate(rois):
    roi = frame[top:bottom, left:right]
    roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
    roi_bg = cv2.GaussianBlur(roi_gray, (15, 15), 0)
    roi_bgs.append(roi_bg)

frame_count = 0

# 主循环,处理视频帧
while True:
    # 读取一帧视频
    ret, frame = video_capture.read()
    
    # 检查是否成功读取帧
    if not ret:
        break
    
    frame_count += 1
    
    # 处理每一个ROI
    for roi_idx, (top, bottom, left, right) in enumerate(rois):
        # 提取当前ROI的区域
        roi_frame = frame[top:bottom, left:right]
       
        
        # 将ROI区域转换为灰度图像
        gray = cv2.cvtColor(roi_frame, cv2.COLOR_BGR2GRAY)
        #高斯模糊
        gray = cv2.GaussianBlur(gray, (7, 7), 0)
        # 计算当前帧与ROI背景之间的差异
        frame_delta = cv2.absdiff(roi_bgs[roi_idx], gray)
        
        # 手动设置固定阈值进行二值化
        _, thresh = cv2.threshold(frame_delta, 50, 255, cv2.THRESH_BINARY)
        
        # 对运动区域进行形态学操作
        kernel = np.ones((5, 5), np.uint8)
        thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
        
        # 寻找轮廓并筛选出有效运动对象
        contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        # 检测是否有入侵发生
        intrusion_detected = False
        for contour in contours:
            if cv2.contourArea(contour) < threshold_area:
                continue
            
            # 在原始帧上绘制矩形框
            (x, y, w, h) = cv2.boundingRect(contour)
            cv2.rectangle(frame, (left+x, top+y), (left+x+w, top+y+h), intrusion_color, 2)
            
            # 将入侵对象的位置信息保存到文本文件中
            output_file.write(f"Intrusion detected at frame: {frame_count}, ROI: {roi_idx+1}, Position: ({left+x}, {top+y})\n")
            
            intrusion_detected = True
        
        # 记录初始帧中的物体轮廓
        if frame_count == 1:
            initial_contours[roi_idx] = contours
        
        # 绘制检测范围的矩形框
        cv2.rectangle(frame, (left, top), (right, bottom), normal_color, 2)
        
        # 如果没有入侵发生,则将检测范围的颜色设置为绿色
        if not intrusion_detected:
            cv2.rectangle(frame, (left, top), (right, bottom), normal_color, 2)
    
    # 将带有检测结果的帧写入新视频文件
    out.write(frame)
    
# 关闭视频写入对象
out.release()

# 关闭输出文件
output_file.close()

# 释放视频捕获对象
video_capture.release()

高斯模糊和开闭操作有何不同
高斯模糊开闭操作
目的主要用于平滑图像,减少噪声。主要用于去除噪声和填补空洞,保持图像中物体的形状。
应用场景适用于需要去除随机噪声的场景,如预处理边缘检测。适用于去除特定形状噪声或填补小孔的场景,如二值图像处理和形态分析。
处理方式使用高斯核对图像进行卷积,是一种线性平滑技术。使用结构元素进行腐蚀和膨胀,是非线性的形态学处理技术。

为了对图像进行处理,消除物体对反光的影响,可以进行高斯模糊和开关运算操作

高斯模糊(Gaussian Blur),也叫高斯平滑。通常用它来减少图像噪声以及降低细节层次。gray = cv2.GaussianBlur(gray, (21, 21), 0)
闭运算(MORPH_CLOSE):闭运算是先膨胀后腐蚀的过程。其作用是消除小的黑色点(噪声),填补小的白色区域(目标内部的空洞),从而使得目标区域更加完整和连贯。# 对运动区域进行形态学操作 kernel = np.ones((5, 5), np.uint8) thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
sift识别算法
import cv2
import numpy as np

# 加载图像
image1 = cv2.imread('tanzhen09.jpg')
image2 = cv2.imread('sa.jpg')

# # 定义感兴趣区域(ROI)
# x, y, w, h = (500, 400, 550, 750)
# x, y, w, h = (759, 444, 170, 120)
x, y, w, h = (780, 440, 100, 90)
roi = image2[y:y+h, x:x+w]
cv2.imwrite('roi_check.jpg', roi)

# 转换为灰度图像
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

# 高斯模糊
gray1_blurred = cv2.GaussianBlur(gray1, (11, 11), 0)
gray2_blurred = cv2.GaussianBlur(gray2, (11, 11), 0)

# 二值化图像
_, gray1_binary = cv2.threshold(gray1_blurred, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
_, gray2_binary = cv2.threshold(gray2_blurred, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 保存结果
out_path1 = 'bingray_check01.jpg'
cv2.imwrite(out_path1, gray1_binary)
out_path2 = 'bingray_check02.jpg'
cv2.imwrite(out_path2, gray2_binary)

# 初始化 SIFT 检测器
sift = cv2.SIFT_create()

# 检测 SIFT 关键点和计算描述符
keypoints1, descriptors1 = sift.detectAndCompute(gray1_binary, None)
keypoints2, descriptors2 = sift.detectAndCompute(gray2_binary, None)

# 使用 FLANN 匹配器进行描述符匹配
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)

flann = cv2.FlannBasedMatcher(index_params, search_params)

# 使用 knnMatch() 找到每个描述符的两个最佳匹配
matches = flann.knnMatch(descriptors1, descriptors2, k=2)

# 使用比率测试找到好的匹配点
good_matches = []
for m, n in matches:
    if m.distance < 0.9 * n.distance:
        good_matches.append(m)

# 输出匹配结果
print(f"好的匹配数量:{len(good_matches)}")

# 设置匹配阈值
threshold = 10  # 根据具体情况调整阈值

if len(good_matches) > threshold:
    print("图像匹配")
else:
    print("图像不匹配")

# 如果匹配成功,找到目标位置并绘制白色框
if len(good_matches) > threshold:
    # 获取关键点的坐标
    src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 2)
    dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 2)

    # 计算单应性矩阵
    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)

    # 获取模板的轮廓
    h1, w1 = gray1.shape
    pts = np.float32([[0, 0], [0, h1 - 1], [w1 - 1, h1 - 1], [w1 - 1, 0]]).reshape(-1, 1, 2)

    # 使用单应性矩阵将轮廓映射到目标图像上
    dst = cv2.perspectiveTransform(pts, M)

    # 绘制白色框
    roi_with_box = cv2.polylines(roi, [np.int32(dst)], True, (255, 255, 255), 3, cv2.LINE_AA)
    cv2.imwrite('roi_with_box.jpg', roi_with_box)

    # 在原始图像中标记框的位置信息
    image2_with_box = image2.copy()
    box_top_left = (x + int(dst[0][0][0]), y + int(dst[0][0][1]))
    box_bottom_right = (x + int(dst[2][0][0]), y + int(dst[2][0][1]))
    cv2.rectangle(image2_with_box, box_top_left, box_bottom_right, (255, 255, 255), 3)

    # 保存结果图像
    cv2.imwrite('matched_image_with_box.jpg', image2_with_box)

print("finish")

sift与入侵检测相结合

import cv2
import numpy as np

# 定义多个感兴趣区域(ROI)的边界(左上右下)
rois = {
    "roiA": {"coords": (600, 650, 670, 700), "flag": False, "count": 0},
    "roiB": {"coords": (760, 650, 830, 700), "flag": False, "count": 0},
    "roiC": {"coords": (920, 650, 990, 700), "flag": False, "count": 0},
    "roi0": {"coords": (860, 490, 910, 530), "flag": False, "count": 0},
    "roia": {"coords": (800, 490, 840, 530), "flag": False, "count": 0},
    "roib": {"coords": (750, 490, 790, 530), "flag": False, "count": 0},
    "roic": {"coords": (690, 490, 730, 530), "flag": False, "count": 0},
    "rois1":{"coords": (540, 430, 590, 480), "flag": False, "count": 0},
    "rois2":{"coords": (550, 560, 600, 610), "flag": False, "count": 0},
    # 可以继续添加更多的ROI区域
}

# 设置匹配阈值
threshold = 10

# 加载参考图像
image1 = cv2.imread('tanzhen09.jpg')
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
gray1_blurred = cv2.GaussianBlur(gray1, (15, 15), 0)
_, gray1_binary = cv2.threshold(gray1_blurred, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 初始化SIFT检测器
sift = cv2.SIFT_create()
keypoints1, descriptors1 = sift.detectAndCompute(gray1_binary, None)

# 使用FLANN匹配器
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)

# 读取视频文件
video_capture = cv2.VideoCapture("test_video.mp4")

# 获取视频的帧率
fps = int(video_capture.get(cv2.CAP_PROP_FPS))
time_per_frame = 1 / fps

# 创建视频写入对象
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
width = int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
out = cv2.VideoWriter('output_video.mp4', fourcc, fps, (width, height))

# 创建文本文件来存储识别结果
output_file = open("intrusion_results.txt", "w")

# 定义矩形框绘制时的颜色
normal_color = (255, 255, 255)  # 正常状态下的颜色为黄色(BGR格式)
stay_color = (0, 255, 255)  # 停留超过颜色为绿色(BGR格式)
intrusion_color = (0, 0, 255)  # 入侵状态下的颜色为红色(BGR格式)
in_sift_color = (0, 255, 0)    # 进入SIFT检测的颜色为绿色(BGR格式)

# 定义最小运动物体的面积阈值
threshold_area = 5

# 存储检测到的触点停留时间
detection_timers = [0 for _ in rois]
stay_threshold = 0.3  # 停留超过0.2秒认为入侵

# 读取第一帧,并提取每个ROI的背景
ret, frame = video_capture.read()
if ret:
    for roi_name, roi_info in rois.items():
        left, top, right, bottom = roi_info["coords"]
        roi = frame[top:bottom, left:right]  # 提取当前ROI区域的图像
        roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
        roi_bg = cv2.GaussianBlur(roi_gray, (3, 3), 0)  # 对ROI区域进行高斯模糊
        roi_info["bg"] = roi_gray  # 将处理后的ROI背景保存

frame_count = 0

while True:
    # 读取一帧视频
    ret, frame = video_capture.read()
    # 检查是否成功读取帧
    if not ret:
        break
    frame_count += 1
    # 遍历每个ROI区域进行处理
    for roi_name, roi_info in rois.items():

        left, top, right, bottom = roi_info["coords"]
        roi_frame = frame[top:bottom, left:right]  # 提取当前ROI区域的图像
        gray = cv2.cvtColor(roi_frame, cv2.COLOR_BGR2GRAY)

        #高斯模糊
        gray = cv2.GaussianBlur(gray, (3, 3), 0)

        frame_delta = cv2.absdiff(roi_info["bg"], gray)  # 计算当前帧与背景之间的差异

        # 手动设置固定阈值进行二值化
        _, thresh = cv2.threshold(frame_delta, 60, 255, cv2.THRESH_BINARY)

        # 形态学操作,消除光照影响
        kernel = np.ones((5, 5), np.uint8)
        thresh = cv2.erode(thresh, kernel, iterations=2)
        thresh = cv2.dilate(thresh, kernel, iterations=2)


        # 寻找轮廓
        contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)

        intrusion_detected = False
        # 遍历每个轮廓
        for contour in contours:
            if cv2.contourArea(contour) < threshold_area:
                continue
            (x, y, w, h) = cv2.boundingRect(contour)
            cv2.rectangle(frame, (left + x, top + y), (left + x + w, top + y + h), intrusion_color, 2)

            # 记录入侵事件到输出文件
            output_file.write(
                f"Intrusion detected at frame: {frame_count}, ROI: {roi_name}, Position: ({left + x}, {top + y})\n")
            intrusion_detected = True

        # 更新停留时间计时器
        if intrusion_detected:
            detection_timers[list(rois.keys()).index(roi_name)] += time_per_frame
        else:
            detection_timers[list(rois.keys()).index(roi_name)] = 0

        # 如果停留时间超过阈值,记录停留事件到输出文件并标记为停留状态
        if detection_timers[list(rois.keys()).index(roi_name)] >= stay_threshold:
            output_file.write(
                f"Stay detected at frame: {frame_count}, ROI: {roi_name}, Duration: {detection_timers[list(rois.keys()).index(roi_name)]:.2f} seconds\n")
            cv2.rectangle(frame, (left, top), (right, bottom), stay_color, 2)
        else:
            cv2.rectangle(frame, (left, top), (right, bottom), normal_color, 2)
        if roi_info.get("flag", False):  # 检查ROI是否有标志为True
            cv2.rectangle(frame, (left, top), (right, bottom), in_sift_color, 2)
        # 如果检测到入侵,扩展ROI区域并进行SIFT特征匹配
        if intrusion_detected:
            # 扩展ROI区域的边界
            new_top = max(bottom - 90, 0)
            new_left = max(right - 110, 0)
            new_bottom = min(bottom , height)
            new_right = min(right , width)
            #cv2.rectangle(frame, (new_left, new_top), (new_right, new_bottom), in_sift_color, 2)
            # 提取扩展后的ROI区域
            extended_roi = frame[new_top:new_bottom, new_left:new_right]

            # 高斯模糊
            extended_roi_gray = cv2.cvtColor(extended_roi, cv2.COLOR_BGR2GRAY)
            extended_roi_blurred = cv2.GaussianBlur(extended_roi_gray, (15, 15), 0)

            # 二值化
            _, extended_roi_binary = cv2.threshold(extended_roi_blurred, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

            # 检测并计算扩展后ROI区域的SIFT特征点和描述符
            keypoints2, descriptors2 = sift.detectAndCompute(extended_roi_binary, None)

            # 如果检测到足够的特征点对
            if descriptors2 is not None and len(descriptors2) >= 2:
                # 使用FLANN匹配器进行特征点匹配
                matches = flann.knnMatch(descriptors1, descriptors2, k=2)
                good_matches = [m for m, n in matches if m.distance < 0.9 * n.distance]
                #print(len(good_matches))

                # 如果匹配到的良好特征点对数目超过阈值
                if len(good_matches) > threshold:
                    # 增加ROI区域的计数器
                    roi_info["count"] += 1

                    # 如果连续检测到足够帧数的目标
                    if roi_info["count"] >= int(fps * 0.15):
                        # 设置ROI区域标志为检测到目标
                        roi_info["flag"] = True
                else:
                    # 如果未匹配到足够的良好特征点对,重置ROI区域计数器
                    roi_info["count"] = 0

     # 将处理后的帧写入输出视频
    out.write(frame)


# 释放资源
out.release()
output_file.close()
video_capture.release()
print("视频处理完成。")

# 输出每个区域的flag值
for roi_name, roi_info in rois.items():
    print(f"区域 {roi_name} 的检测结果: {'检测到目标' if roi_info['flag'] else '未检测到目标'}")

# 输出完成信息
print("视频处理完成。")

注意python循环里的进退格,写错一个位置就可能导致循环次数发生巨大改变。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值