-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdetect.py
148 lines (114 loc) · 5 KB
/
detect.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import cv2
import time
from ultralytics import YOLO
# 화재 인식 모델 불러오기
model = YOLO('best.pt', task='detect')
class FireDetector:
"""
화재 감지 클래스
Args:
index (int): 실제 카메라의 ID
changed_index (int): 카메라와 층 수가 맞지 않을 경우 변경할 번호
Attributes:
index (int): 카메라의 ID
changed_index (int): 바꿀 ID
fire (bool): 화재 감지 플래그
detected_people (int): 카메라에 감지된 인원 수
result_frame: 출력 프레임
done (bool): 동작 완료 플래그
detect_ready (bool): 인식 준비 완료 플래그
cap (VideoCapture): 카메라 객체
"""
def __init__(self, index, changed_index):
self.index = index
self.changed_index = changed_index
self.fire = False
self.detected_people = 0
self.result_frame = None
self.done = False
self.detect_ready = False
self.cap = cv2.VideoCapture(index)
def detect(self) -> None:
"""
화재 인식 스레드 함수
"""
print(f"{self.index}: 감지 스레드 시작")
while not self.done:
# 카메라에서 프레임 읽어오기
success, frame = self.cap.read()
if success:
self.original_frame = frame
detect_start_time = time.time()
try:
# 화재 감지 모델로 화재 감지
results = model.predict(frame, half=True, device='cpu', verbose=False)
except Exception as e:
print(f"ERROR: {e}")
continue
result_frame = frame
detected_objects = {
'fire': 0,
'person': 0
}
for result in results:
boxes = result.boxes
# 감지된 물체들을 하나씩 화면에 추가
for box in boxes:
# 외곽선 색을 인식된 물체가 불인 경우 초록색, 아닐 경우 붉은색으로 설정
color: tuple[int, int, int] = (0, 255, 0) if box.cls == 0 else (0, 0, 255)
position = list(map(int, box.xyxy.tolist()[0])) # 출력값은 float인데 int로 변환
# 감지된 물체 Class ID가 다음 값으로 저장됨
# 0: 불
# 1: 사람
detect_class_id = int(box.cls.tolist()[0])
detect_class_label: str = 'person' if detect_class_id == 1 else 'fire' # 문자열 값으로 변경 1: 'person', 0: 'fire'
# 감지된 물체가 감지 범위 외에 있을 경우 무시하고 진행
if position[0] > 400:
continue
if detect_class_id == 0: # 불이 감지되었을 때 감지된 물체 목록에 1 추가
detected_objects['fire'] += 1
if detect_class_id == 1: # 사람이 감지되었을 때 사람에 1 추가
detected_objects['person'] += 1
# 감지된 물체 외곽선
result_frame = cv2.rectangle(result_frame, (position[0], position[1]), (position[2], position[3]), color, 2)
# 감지된 물체 종류 텍스트
result_frame = cv2.putText(result_frame, detect_class_label, (position[0], position[1]), cv2.FONT_HERSHEY_PLAIN, 1, (255, 255 ,255), 1, cv2.LINE_AA)
# 화면에 층 수 표시
result_frame = cv2.putText(result_frame, f"{self.changed_index+1}Floor", (0, 50), cv2.FONT_HERSHEY_DUPLEX, 2, (255, 255, 0), 2, cv2.LINE_AA)
self.detect_ready = True # 준비 완료 설정
self.detected_people = detected_objects['person']
self.fire = detected_objects['fire'] > 0 # 불이 감지된 경우 True, 아닌 경우 False
self.result_frame = result_frame
else:
self.cap = cv2.VideoCapture(self.index)
def release_camera(self):
"""
카메라를 연결 해제하고 스레드 정지
"""
print(f"Releasing Camera ID: {self.index}")
self.done = True
self.cap.release()
@property
def isReady(self):
"""
감지 준비 완료 값
"""
return self.detect_ready
@property
def personCount(self):
"""
감지된 인원 수
"""
return self.detected_people
@property
def fireDetectedFloor(self) -> str:
"""
불이 감지되었을 경우 층 수를 반환
"""
return str(self.changed_index + 1) if self.fire else '0'
@property
def originalFrame(self):
return self.original_frame
@property
def resultFrame(self):
return self.result_frame