• AI项目二十三:危险区域识别系统


    若该文为原创文章,转载请注明原文出处。

    一、介绍

    IPC监控视频中,很多IPC现在支持区域检测,当在区域内检测到有人闯入时,发送报警并联动报警系统,以保障生命和财产安全具有重大意义。它能够在第一时间检测到人员进入危险区域的行为,并发出及时警告,从而防止潜在事故的发生。

    简单说是,在地图上标记出禁区(多边形),用计算机视觉技术监控进入禁区的物体。

    现在很多摄像头模组,都自带了移动侦测功能,比如海思,君正,RK等。

    以前有在RV1126上实现过类似的,现在想在RK3568上实现。

    记录下PC端测试情况。

    检测流程:

    1、使用YOLOV5识别人物

    2、使用ByteTrack实现多目标跟踪

    3、使用射线法判断点是否在区域内

    二、环境搭建

    环境搭建参考AI项目二十二:行人属性识别-CSDN博客

    项目结构

    ByteTrack是git下载的源码

    fonts存放了字体文件

    weights存放yolov5s.pt模型

    yolov5是git下载的源码

    main.py主程序

    mask_face.py是人脸遮挡代码

    track.py是多目标根据和闯入识别代码

    三、代码解析

    代码功能不多,直接附上源码

    main.py

    1. import cv2
    2. import torch
    3. import numpy as np
    4. from PIL import Image, ImageDraw, ImageFont
    5. print("0")
    6. from mask_face import mask_face
    7. print("2")
    8. from track import PersonTrack
    9. print("1")
    10. def cv2_add_chinese_text(img, text, position, text_color=(0, 255, 0), tex_size=30):
    11. img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    12. draw = ImageDraw.Draw(img)
    13. font_style = ImageFont.truetype(
    14. "./fonts/MSYH.ttc", tex_size, encoding="utf-8")
    15. draw.text(position, text, text_color, font=font_style)
    16. return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
    17. print("2")
    18. class BreakInDetection:
    19. def __init__(self):
    20. self.yolov5_model = torch.hub.load('yolov5'
    21. , 'custom'
    22. , path='./weights/yolov5s.pt'
    23. , source='local')
    24. self.yolov5_model.conf = 0.7
    25. self.tracker = PersonTrack()
    26. @staticmethod
    27. def yolo_pd_to_numpy(yolo_pd):
    28. box_list = yolo_pd.to_numpy()
    29. detections = []
    30. for box in box_list:
    31. l, t = int(box[0]), int(box[1])
    32. r, b = int(box[2]), int(box[3])
    33. conf = box[4]
    34. detections.append([l, t, r, b, conf])
    35. return np.array(detections, dtype=float)
    36. def plot_detection(self, person_track_dict, penalty_zone_point_list, frame, frame_idx):
    37. print(frame_idx)
    38. break_in_num = 0
    39. for track_id, detection in person_track_dict.items():
    40. l, t, r, b = detection.ltrb
    41. track_id = detection.track_id
    42. print(track_id, detection.is_break_in)
    43. if detection.is_break_in:
    44. box_color = (0, 0, 255)
    45. id_color = (0, 0, 255)
    46. break_in_num += 1
    47. else:
    48. box_color = (0, 255, 0)
    49. id_color = (255, 0, 0)
    50. frame[t:b, l:r] = mask_face(frame[t:b, l:r])
    51. # 人体框
    52. cv2.rectangle(frame, (l, t), (r, b), box_color, 1)
    53. cv2.putText(frame, f'id-{track_id}', (l + 2, t - 3), cv2.FONT_HERSHEY_PLAIN, 3, id_color, 2)
    54. # 绘制禁区
    55. pts = np.array(penalty_zone_point_list, np.int32)
    56. pts = pts.reshape((-1, 1, 2))
    57. cv2.polylines(frame, [pts], True, (0, 0, 255), 2)
    58. cover = np.zeros((frame.shape[0], frame.shape[1], 3), np.uint8)
    59. cover = cv2.fillPoly(cover, [pts], (0, 0, 255))
    60. frame = cv2.addWeighted(frame, 0.9, cover, 0.3, 0)
    61. frame = cv2_add_chinese_text(frame, f'禁区', (600, 450), (255, 0, 0), 30)
    62. # 统计区
    63. info_frame_h, info_frame_w = 200, 400
    64. info_frame = np.zeros((info_frame_h, info_frame_w, 3), np.uint8)
    65. if_l, if_t = 100, 100
    66. if_r, if_b = if_l + info_frame_w, if_t + info_frame_h
    67. frame_part = frame[if_t:if_b, if_l:if_r]
    68. mixed_frame = cv2.addWeighted(frame_part, 0.6, info_frame, 0.7, 0)
    69. frame[if_t:if_b, if_l:if_r] = mixed_frame
    70. frame = cv2_add_chinese_text(frame, f'统计', (if_l + 150, if_t + 10), (255, 0, 0), 40)
    71. frame = cv2_add_chinese_text(frame, f'当前闯入禁区 {break_in_num} 人', (if_l + 60, if_t + 80), (255, 0, 0), 35)
    72. return frame
    73. def detect(self):
    74. cap = cv2.VideoCapture('./video.mp4')
    75. video_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    76. video_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    77. fps = round(cap.get(cv2.CAP_PROP_FPS))
    78. print(fps)
    79. video_writer = cv2.VideoWriter('./video_result.mp4', cv2.VideoWriter_fourcc(*'H264'), fps, (video_w, video_h))
    80. frame_idx = 0
    81. while cap.isOpened():
    82. frame_idx += 1
    83. success, frame = cap.read()
    84. if not success:
    85. print("Ignoring empty camera frame.")
    86. break
    87. results = self.yolov5_model(frame[:, :, ::-1])
    88. pd = results.pandas().xyxy[0]
    89. person_pd = pd[pd['name'] == 'person']
    90. person_det_boxes = self.yolo_pd_to_numpy(person_pd)
    91. if len(person_det_boxes) > 0:
    92. person_track_dict, penalty_zone_point_list = self.tracker.update_track(person_det_boxes, frame)
    93. frame = self.plot_detection(person_track_dict, penalty_zone_point_list, frame, frame_idx)
    94. cv2.imshow('Break in Detection', frame)
    95. video_writer.write(frame)
    96. if cv2.waitKey(1) & 0xFF == ord("q"):
    97. break
    98. cap.release()
    99. cv2.destroyAllWindows()
    100. print("3")
    101. if __name__ == '__main__':
    102. BreakInDetection().detect()

    mask_face.py

    1. import cv2
    2. import mediapipe as mp
    3. face_detection = mp.solutions.face_detection.FaceDetection(model_selection=1, min_detection_confidence=0.3)
    4. def mask_face(frame):
    5. frame.flags.writeable = False
    6. frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    7. results = face_detection.process(frame)
    8. frame_h, frame_w = frame.shape[:2]
    9. frame.flags.writeable = True
    10. frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
    11. if results.detections:
    12. for detection in results.detections:
    13. face_box = detection.location_data.relative_bounding_box
    14. xmin, ymin, face_w, face_h = face_box.xmin, face_box.ymin, face_box.width, face_box.height
    15. l, t = int(xmin*frame_w), int(ymin*frame_h)
    16. r, b = l+int(face_w*frame_w), t+int(face_h*frame_h)
    17. cv2.rectangle(frame, (l, t), (r, b), (203, 192, 255), -1)
    18. return frame

    track.py 

    1. from dataclasses import dataclass
    2. import numpy as np
    3. from collections import deque
    4. import cv2
    5. import paddleclas
    6. import sys
    7. sys.path.append('./ByteTrack/')
    8. from yolox.tracker.byte_tracker import BYTETracker, STrack
    9. @dataclass(frozen=True)
    10. class BYTETrackerArgs:
    11. track_thresh: float = 0.25
    12. track_buffer: int = 30
    13. match_thresh: float = 0.8
    14. aspect_ratio_thresh: float = 3.0
    15. min_box_area: float = 1.0
    16. mot20: bool = False
    17. class Detection(object):
    18. def __init__(self, ltrb, track_id, is_break_in):
    19. self.track_id = track_id
    20. self.ltrb = ltrb
    21. self.is_break_in = is_break_in # 是否闯入
    22. self.track_list = deque(maxlen=30)
    23. def update(self, ltrb, is_break_in):
    24. self.ltrb = ltrb
    25. self.is_break_in = is_break_in
    26. l, t, r, b = ltrb
    27. self.track_list.append(((l+r)//2, b))
    28. class PersonTrack(object):
    29. def __init__(self):
    30. self.byte_tracker = BYTETracker(BYTETrackerArgs())
    31. self.detection_dict = {}
    32. # 禁区多边形
    33. point1 = (400, 440)
    34. point2 = (460, 579)
    35. point3 = (920, 600)
    36. point4 = (960, 450)
    37. self.penalty_zone_point_list = [point1, point2, point3, point4]
    38. def is_point_in_polygon(self, vertices, point):
    39. """
    40. 判断点是否在多边形内
    41. :param vertices: 多边形顶点坐标列表 [(x1, y1), (x2, y2), ..., (xn, yn)]
    42. :param point: 需要判断的点坐标 (x, y)
    43. :return: True or False
    44. """
    45. n = len(vertices)
    46. inside = False
    47. p1x, p1y = vertices[0]
    48. for i in range(1, n + 1):
    49. p2x, p2y = vertices[i % n]
    50. if point[1] > min(p1y, p2y):
    51. if point[1] <= max(p1y, p2y):
    52. if point[0] <= max(p1x, p2x):
    53. if p1y != p2y:
    54. xints = (point[1] - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
    55. if p1x == p2x or point[0] <= xints:
    56. inside = not inside
    57. p1x, p1y = p2x, p2y
    58. return inside
    59. def update_track(self, boxes, frame):
    60. tracks = self.byte_tracker.update(
    61. output_results=boxes,
    62. img_info=frame.shape,
    63. img_size=frame.shape
    64. )
    65. new_detection_dict = {}
    66. for track in tracks:
    67. l, t, r, b = track.tlbr.astype(np.int32)
    68. track_id = track.track_id
    69. # 判断人是否闯入
    70. detect_point = ((l + r)//2, b)
    71. is_break_in = self.is_point_in_polygon(self.penalty_zone_point_list, detect_point)
    72. if track_id in self.detection_dict:
    73. detection = self.detection_dict[track_id]
    74. detection.update((l, t, r, b), is_break_in)
    75. else:
    76. detection = Detection((l, t, r, b), track_id, is_break_in)
    77. new_detection_dict[track_id] = detection
    78. self.detection_dict = new_detection_dict
    79. return self.detection_dict, self.penalty_zone_point_list

    代码需要注意的是:

    一、区域位置

    二、显示参数位置

    这几个参数需要根据视频的大小,去调整位置,不然会报错。

    三、检测点是否在区域内

    转成C语言直接部署到RK3568上。

    后续将部署到RK3568,参考git和讯为电子多目标检测已实现。

    如有侵权,或需要完整代码,请及时联系博主。

  • 相关阅读:
    MongoDB与Pymongo深度实践:从基础概念到无限级评论应用示例
    LeetCode刷题笔记之 94. 二叉树的中序遍历(史上最全的二叉树遍历的算法-Java)
    【数理方程】傅氏变换&拉氏变换
    InnoDB之Undo log写入和恢复
    Github Copilot Chat 初体验
    【数据结构】测试4 串
    vscode快捷键设置
    nacos配置中心的核心概念
    设计模式之访问者模式
    Visual Studio中的四款代码格式化工具
  • 原文地址:https://blog.csdn.net/weixin_38807927/article/details/139785621