|
|
@ -1,20 +1,17 @@ |
|
|
|
import gc |
|
|
|
from datetime import datetime |
|
|
|
import json |
|
|
|
import queue |
|
|
|
import time |
|
|
|
from time import sleep |
|
|
|
from dataclasses import asdict |
|
|
|
import cv2 |
|
|
|
import numpy as np |
|
|
|
import signal |
|
|
|
import sys |
|
|
|
import threading |
|
|
|
import logging |
|
|
|
|
|
|
|
import configSer |
|
|
|
import models.target |
|
|
|
import models.sampleMsg |
|
|
|
import tcp_Ser |
|
|
|
import upload.DataReporter |
|
|
|
import utils |
|
|
|
from models.msg import Msg |
|
|
@ -59,9 +56,9 @@ def add_rectangle(event, x, y, flags, param): |
|
|
|
"test add", |
|
|
|
area, |
|
|
|
radius, |
|
|
|
models.target.Threshold(128,9), |
|
|
|
models.target.Threshold(190,9), |
|
|
|
False) |
|
|
|
new_target = models.target.CircleTarget(t_info,None,None,None,None) |
|
|
|
new_target = models.target.CircleTarget(t_info,None,None) |
|
|
|
logging.info(f"新增区域[{target_id}] => {start_point, end_point}") |
|
|
|
configObj.config_info.targets[target_id] = new_target |
|
|
|
|
|
|
@ -69,7 +66,8 @@ def read_target_rectangle(): |
|
|
|
return configObj.config_info.targets |
|
|
|
class VideoProcessor: |
|
|
|
reporter: upload.DataReporter.DataReporter |
|
|
|
|
|
|
|
capture: cv2.VideoCapture |
|
|
|
is_opened: bool= False |
|
|
|
def __init__(self, reporter:upload.DataReporter.DataReporter): |
|
|
|
self.reporter = reporter |
|
|
|
|
|
|
@ -78,33 +76,56 @@ class VideoProcessor: |
|
|
|
logging.info(f"msg={msg}") |
|
|
|
match msg.cmd: |
|
|
|
case "getPoints": |
|
|
|
data_dict = {k: asdict(v.info) for k, v in configObj.config_info.targets.items()} |
|
|
|
resp_msg = models.msg.Msg(_from="dev", cmd="getPoints", values={"targets": data_dict}) |
|
|
|
targets=configObj.config_info.targets.copy() |
|
|
|
for k,v in targets.items(): |
|
|
|
targets[k].handler_info=None |
|
|
|
|
|
|
|
resp_msg = models.msg.Msg(_from="dev", cmd="getPoints", values={"targets": targets}) |
|
|
|
resp_json = resp_msg.to_json_() |
|
|
|
return resp_json |
|
|
|
case "setPoints": |
|
|
|
v=msg.values |
|
|
|
ts=v["targets"] |
|
|
|
|
|
|
|
# 清空原配置 |
|
|
|
configObj.config_info.targets={} |
|
|
|
# # 清空原配置 |
|
|
|
# configObj.config_info.targets={} |
|
|
|
for _,t in ts.items(): |
|
|
|
t_str=json.dumps(t) |
|
|
|
t_info = models.target.TargetInfo.from_json(t_str) |
|
|
|
c_target=models.target.CircleTarget.init_by_info(t_info) |
|
|
|
configObj.config_info.targets[c_target.info.id] =c_target |
|
|
|
new_c_target = models.target.CircleTarget.from_json(t_str) |
|
|
|
configObj.config_info.targets[new_c_target.info.id] =new_c_target |
|
|
|
|
|
|
|
configObj.save2json_file() |
|
|
|
resp_msg = models.msg.Msg(_from="dev", cmd="setPoints", values={"operate": True}) |
|
|
|
resp_json = resp_msg.to_json() |
|
|
|
return resp_json |
|
|
|
case "videoFps": |
|
|
|
v = msg.values |
|
|
|
fps = v["fps"] |
|
|
|
self.reporter.adjust_rate(fps,"image") |
|
|
|
configObj.config_info.fps.video = fps |
|
|
|
configObj.save2json_file() |
|
|
|
resp_msg = models.msg.Msg(_from="dev", cmd="setPoints", values={"operate": True}) |
|
|
|
resp_json = resp_msg.to_json() |
|
|
|
return resp_json |
|
|
|
case "dataFps": |
|
|
|
v = msg.values |
|
|
|
fps = v["fps"] |
|
|
|
self.reporter.adjust_rate(fps,"data") |
|
|
|
configObj.config_info.fps.data=fps |
|
|
|
configObj.save2json_file() |
|
|
|
resp_msg = models.msg.Msg(_from="dev", cmd="setPoints", values={"operate": True}) |
|
|
|
resp_json = resp_msg.to_json() |
|
|
|
return resp_json |
|
|
|
case "setCap": |
|
|
|
v = msg.values |
|
|
|
cap = v["cap"] |
|
|
|
self.switch_video(cap) |
|
|
|
resp_msg = models.msg.Msg(_from="dev", cmd="setPoints", values={"operate": True}) |
|
|
|
resp_json = resp_msg.to_json() |
|
|
|
return resp_json |
|
|
|
print("==") |
|
|
|
|
|
|
|
|
|
|
|
def update_thresh_binary(self,v:int): |
|
|
|
self.thresh_binary = v |
|
|
|
|
|
|
|
|
|
|
|
def pre_handler_img(self,gray_frame,now_str:str): |
|
|
|
# 将灰度图压缩为 JPEG 格式,并存储到内存缓冲区 |
|
|
|
img_base64 = utils.frame_to_base64(gray_frame, format="JPEG") |
|
|
@ -139,7 +160,7 @@ class VideoProcessor: |
|
|
|
|
|
|
|
ret, sub_binary_frame = cv2.threshold(sub_image, tr.info.threshold.binary, 255, cv2.THRESH_BINARY) |
|
|
|
# 高斯滤波 |
|
|
|
sub_binary_frame = cv2.GaussianBlur(sub_binary_frame, (tr.info.threshold.gauss, tr.info.threshold.gauss), 1) |
|
|
|
sub_binary_frame = cv2.GaussianBlur(sub_binary_frame, (tr.info.threshold.gauss, tr.info.threshold.gauss), 10,borderType=cv2.BORDER_REPLICATE) |
|
|
|
cv2.imshow(f'{tr.info.id}_binaryImg', sub_binary_frame) |
|
|
|
|
|
|
|
# 覆盖原图 |
|
|
@ -149,30 +170,29 @@ class VideoProcessor: |
|
|
|
circles = self.circle2_detect(sub_binary_frame) |
|
|
|
if len(circles) == 0: |
|
|
|
continue |
|
|
|
center,radius=self.circle_show(img,circles,_start_point) |
|
|
|
center,radius_pix=self.circle_show(img,circles,_start_point) |
|
|
|
# 纪录圆心位置 |
|
|
|
tr.center_point=center |
|
|
|
tr.radius_pix=radius |
|
|
|
if tr.is_init: |
|
|
|
tr.center_init=tr.center_point |
|
|
|
tr.is_init=False |
|
|
|
if tr.handler_info is None: |
|
|
|
tr.handler_info= models.target.HandlerInfo() |
|
|
|
if tr.handler_info.is_init: |
|
|
|
tr.handler_info.is_init=False |
|
|
|
tr.handler_info.center_init = center |
|
|
|
|
|
|
|
tr.handler_info.center_point=center |
|
|
|
tr.handler_info.radius_pix=radius_pix |
|
|
|
tr.circle_displacement() |
|
|
|
|
|
|
|
all_upload_data.data.append( |
|
|
|
models.sampleMsg.SensorData( |
|
|
|
str(tr.info.id), |
|
|
|
tr.displacement_phy.x, |
|
|
|
tr.displacement_phy.y) |
|
|
|
tr.handler_info.displacement_phy.x, |
|
|
|
tr.handler_info.displacement_phy.y) |
|
|
|
) |
|
|
|
|
|
|
|
#过滤无效空数据 |
|
|
|
if len(all_upload_data.data)==0: |
|
|
|
return |
|
|
|
# json_str = json.dumps( |
|
|
|
# {k:asdict(v) for k, v in once_upload.items() if v.is_init==False} |
|
|
|
# ) |
|
|
|
|
|
|
|
# print(f"标靶数据={json_str}",json_str) |
|
|
|
self.enqueue_data(all_upload_data) |
|
|
|
|
|
|
|
|
|
|
@ -235,30 +255,58 @@ class VideoProcessor: |
|
|
|
|
|
|
|
|
|
|
|
def open_video(self,video_id): |
|
|
|
cap = cv2.VideoCapture(video_id) |
|
|
|
# cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1600) # 宽度 |
|
|
|
# cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 900) # 高度 |
|
|
|
if not cap.isOpened(): |
|
|
|
logging.info("无法打开摄像头") |
|
|
|
exit() |
|
|
|
return cap |
|
|
|
print(f"打开摄像头 -> {video_id}") |
|
|
|
self.capture = cv2.VideoCapture(video_id) |
|
|
|
frame_width = int(self.capture.get(cv2.CAP_PROP_FRAME_WIDTH)) |
|
|
|
frame_height = int(self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
|
|
|
print(f"默认分辨率= {frame_width}*{frame_height}") |
|
|
|
logging.info(f"{video_id}地址->{self.capture}") |
|
|
|
fps = self.capture.get(cv2.CAP_PROP_FPS) |
|
|
|
print(f"fps={fps},video_id={video_id},") |
|
|
|
# self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1600) # 宽度 |
|
|
|
# self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 900) # 高度 |
|
|
|
if not self.capture.isOpened(): |
|
|
|
self.capture.release() |
|
|
|
logging.info(f"无法打开摄像头{video_id},release 地址 -> {self.capture}") |
|
|
|
return |
|
|
|
self.is_opened=True |
|
|
|
|
|
|
|
def switch_video(self,video_id:str): |
|
|
|
print(f"切换摄像头 -> {video_id}") |
|
|
|
self.is_opened = False |
|
|
|
self.capture.release() |
|
|
|
cv2.destroyAllWindows() |
|
|
|
if str.isdigit(video_id): |
|
|
|
video_id=int(video_id) |
|
|
|
self.open_video(video_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_video(self,cap): |
|
|
|
def show_video(self): |
|
|
|
global sigExit,start_point, end_point, drawing |
|
|
|
cv2.namedWindow('Frame') |
|
|
|
cv2.setMouseCallback('Frame', add_rectangle) |
|
|
|
# 读取一帧图像 |
|
|
|
while True: |
|
|
|
ret, frame = cap.read() |
|
|
|
if not self.is_opened: |
|
|
|
print(f"摄像头 标记is_opened={self.is_opened}") |
|
|
|
sleep(5) |
|
|
|
continue |
|
|
|
ret, frame = self.capture.read() |
|
|
|
if ret: |
|
|
|
self.frame_handle(frame) |
|
|
|
else: |
|
|
|
logging.info("无法读取帧") |
|
|
|
logging.info(f"无法读取帧,cap地址- >{self.capture}") |
|
|
|
sleep(1) |
|
|
|
# self.capture.release() |
|
|
|
# self.capture= cv2.VideoCapture(0) # 再次尝试 |
|
|
|
if cv2.waitKey(1) & 0xFF == ord('q'): # 按'q'退出循环 |
|
|
|
break |
|
|
|
if sigExit: |
|
|
|
break |
|
|
|
# 显示图像 |
|
|
|
if frame is not None: |
|
|
|
cv2.imshow('Frame', frame) |
|
|
|
def show_image(self,frame): |
|
|
|
global start_point, end_point, drawing |
|
|
|
cv2.namedWindow('Frame') |
|
|
@ -279,8 +327,6 @@ class VideoProcessor: |
|
|
|
if drawing: |
|
|
|
cv2.rectangle(frame, tuple(start_point), tuple(end_point), (0, 200, 200), 4) |
|
|
|
# print(f"鼠标位置 {start_point} -> {end_point}") |
|
|
|
# 显示图像 |
|
|
|
cv2.imshow('Frame', frame) |
|
|
|
|
|
|
|
# 读取图像 |
|
|
|
#img_copy = img.copy() # 复制图像用于还原 |
|
|
@ -292,24 +338,26 @@ class VideoProcessor: |
|
|
|
self.show_image(img_raw) |
|
|
|
|
|
|
|
# 支持 |
|
|
|
def video_mode(self,video_id): |
|
|
|
capture = self.open_video(video_id) |
|
|
|
fps = capture.get(cv2.CAP_PROP_FPS) |
|
|
|
print(f"fps={fps}") |
|
|
|
self.show_video(capture) |
|
|
|
def video_mode(self,video_id:str): |
|
|
|
if str.isdigit(video_id): |
|
|
|
video_id=int(video_id) |
|
|
|
self.open_video(video_id) |
|
|
|
# if self.is_opened: |
|
|
|
self.show_video() |
|
|
|
# 释放摄像头资源并关闭所有窗口 |
|
|
|
capture.release() |
|
|
|
print("退出 video") |
|
|
|
self.capture.release() |
|
|
|
cv2.destroyAllWindows() |
|
|
|
|
|
|
|
def rtsp_mode(self,rtsp_url:str): |
|
|
|
# rtsp_url ="rtsp://admin:123456abc@192.168.1.64:554" |
|
|
|
# rtsp_url ="rtsp://admin:123456abc@192.168.1.64:554/h264/ch1/main/av_stream" |
|
|
|
capture = self.open_video(rtsp_url) |
|
|
|
fps = capture.get(cv2.CAP_PROP_FPS) |
|
|
|
print(f"fps={fps}") |
|
|
|
self.show_video(capture) |
|
|
|
self.open_video(rtsp_url) |
|
|
|
fps = self.capture.get(cv2.CAP_PROP_FPS) |
|
|
|
print(f"rtsp fps={fps}") |
|
|
|
self.show_video() |
|
|
|
# 释放摄像头资源并关闭所有窗口 |
|
|
|
capture.release() |
|
|
|
self.capture.release() |
|
|
|
cv2.destroyAllWindows() |
|
|
|
|
|
|
|
def enqueue_data(self,data): |
|
|
@ -321,7 +369,8 @@ class VideoProcessor: |
|
|
|
try: |
|
|
|
self.reporter.data_queue.put((dt, data), block=False) |
|
|
|
except queue.Full: |
|
|
|
self.reporter.data_dropped += 1 |
|
|
|
# self.reporter.data_dropped += 1 |
|
|
|
pass |
|
|
|
def enqueue_image(self,data): |
|
|
|
# 获取当前时间戳 |
|
|
|
timestamp = time.time() |
|
|
@ -331,7 +380,8 @@ class VideoProcessor: |
|
|
|
try: |
|
|
|
self.reporter.image_queue.put((dt, data), block=False) |
|
|
|
except queue.Full: |
|
|
|
self.reporter.image_dropped += 1 |
|
|
|
pass |
|
|
|
#self.reporter.image_dropped += 1 |
|
|
|
|
|
|
|
#数据广播 |
|
|
|
def check_exit(sig, frame): |
|
|
|