edit : ward_id 적용 (정의된 상수값 사용)
This commit is contained in:
43
cctv.py
43
cctv.py
@@ -116,12 +116,14 @@ class CameraStream:
|
|||||||
print(f"[{self.name}] 재접속 실패")
|
print(f"[{self.name}] 재접속 실패")
|
||||||
|
|
||||||
def get_frame(self):
|
def get_frame(self):
|
||||||
"""현재 저장된 가장 최신 프레임을 반환 (타임아웃 체크 포함)"""
|
"""
|
||||||
|
현재 저장된 가장 최신 프레임을 반환 (타임아웃 체크 포함)
|
||||||
|
"""
|
||||||
with self.lock:
|
with self.lock:
|
||||||
# 마지막 수신 후 3초 이상 지났으면 신호 없음(False) 처리
|
# 마지막 수신 후 3초 이상 지났으면 신호 없음(False) 처리
|
||||||
if time.time() - self.last_read_time > 3.0:
|
if time.time() - self.last_read_time > 3.0:
|
||||||
return False, None
|
return False, None, self.name
|
||||||
return self.ret, self.latest_frame
|
return self.ret, self.latest_frame, self.name
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.running = False
|
self.running = False
|
||||||
@@ -153,6 +155,8 @@ def main():
|
|||||||
|
|
||||||
DISPLAY_TURN_ON = CFG.get('display').get('turn_on') # display 출력 여부
|
DISPLAY_TURN_ON = CFG.get('display').get('turn_on') # display 출력 여부
|
||||||
|
|
||||||
|
SNAPSHOT_SEND = CFG.get('img_snap_shot')
|
||||||
|
|
||||||
current_cam_index = 0 # 현재 보고 있는 카메라 인덱스
|
current_cam_index = 0 # 현재 보고 있는 카메라 인덱스
|
||||||
last_switch_time = time.time() # 마지막 전환 시간
|
last_switch_time = time.time() # 마지막 전환 시간
|
||||||
switch_interval = SWITCH_INTERVAL # 5초마다 자동 전환
|
switch_interval = SWITCH_INTERVAL # 5초마다 자동 전환
|
||||||
@@ -167,6 +171,10 @@ def main():
|
|||||||
fps_sum = 0
|
fps_sum = 0
|
||||||
fps_count = 0
|
fps_count = 0
|
||||||
warmup_frames = 30 # 초반 불안정한 프레임 제외
|
warmup_frames = 30 # 초반 불안정한 프레임 제외
|
||||||
|
|
||||||
|
# pubilsh time check
|
||||||
|
last_publish_time = None
|
||||||
|
delay_after_publish = 4.0 # publish 후 n초 동안은 추가 publish 금지, 0일경우 무제한
|
||||||
|
|
||||||
print("\n=== CCTV 시스템 시작 ===")
|
print("\n=== CCTV 시스템 시작 ===")
|
||||||
print(f"{switch_interval}초마다 자동으로 카메라가 전환됩니다.")
|
print(f"{switch_interval}초마다 자동으로 카메라가 전환됩니다.")
|
||||||
@@ -212,7 +220,7 @@ def main():
|
|||||||
|
|
||||||
# 2. 현재 선택된 카메라의 최신 프레임 가져오기
|
# 2. 현재 선택된 카메라의 최신 프레임 가져오기
|
||||||
target_cam = cameras[current_cam_index]
|
target_cam = cameras[current_cam_index]
|
||||||
ret, frame = target_cam.get_frame()
|
ret, frame, name = target_cam.get_frame()
|
||||||
|
|
||||||
if ret and frame is not None:
|
if ret and frame is not None:
|
||||||
# FPS 계산
|
# FPS 계산
|
||||||
@@ -248,13 +256,31 @@ def main():
|
|||||||
|
|
||||||
od_message = []
|
od_message = []
|
||||||
|
|
||||||
parser.set(msg=hpe_message,img=frame)
|
parser.set(
|
||||||
|
msg=hpe_message,
|
||||||
|
img=frame if SNAPSHOT_SEND else None,
|
||||||
|
ward_id=name)
|
||||||
parsing_msg = parser.parse()
|
parsing_msg = parser.parse()
|
||||||
|
|
||||||
#mqtt publish
|
#mqtt publish
|
||||||
if parsing_msg is not None:
|
if parsing_msg is not None:
|
||||||
mqtt_publisher.client.publish(MQTT_TOPIC, parsing_msg, qos=1)
|
|
||||||
|
#time check
|
||||||
|
if last_publish_time is None:
|
||||||
|
last_publish_time = datetime.now()
|
||||||
|
mqtt_publisher.client.publish(MQTT_TOPIC, parsing_msg, qos=1)
|
||||||
|
else:
|
||||||
|
current_time = datetime.now()
|
||||||
|
time_diff = current_time - last_publish_time
|
||||||
|
time_diff_seconds = time_diff.total_seconds()
|
||||||
|
|
||||||
|
# n초에 한 번만 publish
|
||||||
|
if time_diff_seconds < delay_after_publish:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
last_publish_time = datetime.now()
|
||||||
|
mqtt_publisher.client.publish(MQTT_TOPIC, parsing_msg, qos=1)
|
||||||
|
|
||||||
# 탐지 결과 라벨링 (원본 좌표 기준)
|
# 탐지 결과 라벨링 (원본 좌표 기준)
|
||||||
if DISPLAY_TURN_ON:
|
if DISPLAY_TURN_ON:
|
||||||
detector.hpe_labeling(frame, hpe_message)
|
detector.hpe_labeling(frame, hpe_message)
|
||||||
@@ -298,8 +324,7 @@ def main():
|
|||||||
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA) # 노란색
|
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2, cv2.LINE_AA) # 노란색
|
||||||
|
|
||||||
cv2.imshow(window_name, frame)
|
cv2.imshow(window_name, frame)
|
||||||
|
|
||||||
|
|
||||||
elif DISPLAY_TURN_ON:
|
elif DISPLAY_TURN_ON:
|
||||||
# 신호가 없을 때 보여줄 대기 화면
|
# 신호가 없을 때 보여줄 대기 화면
|
||||||
# MONITOR_RESOLUTION은 (width, height)이므로 numpy shape는 (height, width, 3)이어야 함
|
# MONITOR_RESOLUTION은 (width, height)이므로 numpy shape는 (height, width, 3)이어야 함
|
||||||
|
|||||||
19
config.yaml
19
config.yaml
@@ -16,6 +16,7 @@ use_hpe_frame_check: false # n개 프레임 체크 후 HPE 위험 판단
|
|||||||
|
|
||||||
# --- 디버그 ---
|
# --- 디버그 ---
|
||||||
add_cross_arm: false # cross arm 디버그 모드
|
add_cross_arm: false # cross arm 디버그 모드
|
||||||
|
img_snap_shot: false # 이미지 스냅샷 전송 여부
|
||||||
|
|
||||||
# --- 소스 설정 ---
|
# --- 소스 설정 ---
|
||||||
# RTSP 카메라 프리셋 (source에서 프리셋 이름으로 사용 가능)
|
# RTSP 카메라 프리셋 (source에서 프리셋 이름으로 사용 가능)
|
||||||
@@ -75,8 +76,8 @@ cctv:
|
|||||||
# - {src: 0, name: "Realtek_Webcam_0"}
|
# - {src: 0, name: "Realtek_Webcam_0"}
|
||||||
# - {src: "rtsp://daool:Ekdnfeldpsdptm1@192.168.200.101/axis-media/media.amp", name: "ipcam_1"}
|
# - {src: "rtsp://daool:Ekdnfeldpsdptm1@192.168.200.101/axis-media/media.amp", name: "ipcam_1"}
|
||||||
# - {src: "rtsp://daool:Ekdnfeldpsdptm1@192.168.200.102/axis-media/media.amp", name: "ipcam_2"}
|
# - {src: "rtsp://daool:Ekdnfeldpsdptm1@192.168.200.102/axis-media/media.amp", name: "ipcam_2"}
|
||||||
- {src: "rtsp://192.168.200.231:50199/wd", name: "dev1_stream"}
|
# - {src: "rtsp://192.168.200.231:50199/wd", name: "dev1_stream"}
|
||||||
- {src: "rtsp://192.168.200.232:50299/wd", name: "dev2_stream"}
|
# - {src: "rtsp://192.168.200.232:50299/wd", name: "dev2_stream"}
|
||||||
# - {src: "rtsp://192.168.200.236:8554/videodevice", name: "boss_webcam"}
|
# - {src: "rtsp://192.168.200.236:8554/videodevice", name: "boss_webcam"}
|
||||||
# - {src: "rtsp://192.168.200.236:8554/1.mp4", name: "boss_stream1"}
|
# - {src: "rtsp://192.168.200.236:8554/1.mp4", name: "boss_stream1"}
|
||||||
# - {src: "rtsp://192.168.200.214/1.mp4", name: "sgm_stream1"}
|
# - {src: "rtsp://192.168.200.214/1.mp4", name: "sgm_stream1"}
|
||||||
@@ -85,3 +86,17 @@ cctv:
|
|||||||
# - {src: "rtsp://192.168.200.111/2.mp4", name: "hp_stream2"}
|
# - {src: "rtsp://192.168.200.111/2.mp4", name: "hp_stream2"}
|
||||||
# - {src: "rtsp://192.168.200.215/1.mp4", name: "msk_stream1"}
|
# - {src: "rtsp://192.168.200.215/1.mp4", name: "msk_stream1"}
|
||||||
# - {src: "rtsp://192.168.200.215/2.mp4", name: "msk_stream2"}
|
# - {src: "rtsp://192.168.200.215/2.mp4", name: "msk_stream2"}
|
||||||
|
|
||||||
|
- {src: "rtsp://192.168.200.233:50399/h1", name: "dev3_stream_hospital_1"}
|
||||||
|
- {src: "rtsp://192.168.200.233:50399/h2", name: "dev3_stream_hospital_2"}
|
||||||
|
- {src: "rtsp://192.168.200.233:50399/h3", name: "dev3_stream_hospital_3"}
|
||||||
|
- {src: "rtsp://192.168.200.233:50399/h4", name: "dev3_stream_hospital_4"}
|
||||||
|
- {src: "rtsp://192.168.200.233:50399/h5", name: "dev3_stream_hospital_5"}
|
||||||
|
- {src: "rtsp://192.168.200.233:50399/h6", name: "dev3_stream_hospital_6"}
|
||||||
|
|
||||||
|
# - {src: "rtsp://192.168.200.233:50399/k1", name: "dev3_stream_kepco_1"}
|
||||||
|
# - {src: "rtsp://192.168.200.233:50399/k2", name: "dev3_stream_kepco_2"}
|
||||||
|
# - {src: "rtsp://192.168.200.233:50399/k3", name: "dev3_stream_kepco_3"}
|
||||||
|
# - {src: "rtsp://192.168.200.233:50399/k4", name: "dev3_stream_kepco_4"}
|
||||||
|
# - {src: "rtsp://192.168.200.233:50399/k5", name: "dev3_stream_kepco_5"}
|
||||||
|
# - {src: "rtsp://192.168.200.233:50399/k6", name: "dev3_stream_kepco_6"}
|
||||||
@@ -11,14 +11,18 @@ class ParsingMsg():
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.msg = None
|
self.msg = None
|
||||||
self.img = None
|
self.img = None
|
||||||
|
self.ward_id = None
|
||||||
|
|
||||||
self.parsed_msg = None
|
self.parsed_msg = None
|
||||||
|
|
||||||
def set(self, msg:list, img):
|
def set(self, msg:list, img, ward_id):
|
||||||
self.msg = None
|
self.msg = None
|
||||||
self.img = None
|
self.img = None
|
||||||
|
self.ward_id = None
|
||||||
|
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.img = img
|
self.img = img
|
||||||
|
self.ward_id = ward_id
|
||||||
self.parsed_msg = None
|
self.parsed_msg = None
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
@@ -33,7 +37,7 @@ class ParsingMsg():
|
|||||||
"""
|
"""
|
||||||
_, JPEG = cv2.imencode(".jpg", img_data, [int(cv2.IMWRITE_JPEG_QUALITY), 80])
|
_, JPEG = cv2.imencode(".jpg", img_data, [int(cv2.IMWRITE_JPEG_QUALITY), 80])
|
||||||
# Base64 encode
|
# Base64 encode
|
||||||
b64 = b64encode(JPEG)
|
b64 = b64encode(JPEG.tobytes())
|
||||||
|
|
||||||
return b64.decode("utf-8")
|
return b64.decode("utf-8")
|
||||||
|
|
||||||
@@ -54,7 +58,7 @@ class ParsingMsg():
|
|||||||
"""
|
"""
|
||||||
msg = Header(
|
msg = Header(
|
||||||
camera_id= "CAMERA_001",
|
camera_id= "CAMERA_001",
|
||||||
ward_id= "WARD_001",
|
ward_id= self.ward_id,
|
||||||
timestamp= datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
timestamp= datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
frame_id= 0
|
frame_id= 0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from datetime import datetime
|
|||||||
#=========================================
|
#=========================================
|
||||||
class Header(BaseModel):
|
class Header(BaseModel):
|
||||||
camera_id: str
|
camera_id: str
|
||||||
ward_id: str
|
ward_id: str | None
|
||||||
timestamp: datetime
|
timestamp: str
|
||||||
frame_id: int
|
frame_id: int
|
||||||
#=========================================
|
#=========================================
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user