218 lines
6.1 KiB
Python
218 lines
6.1 KiB
Python
import time
|
|
import json
|
|
|
|
from cam_3.multispectral_service import MultiSpectralService
|
|
from cam_3.stream_receiver import StreamReceiver
|
|
from cam_3.pi.raw_processor_core import RawProcessorCore
|
|
from cam_3.pi.raw_processor_preview import RawProcessorPreview
|
|
|
|
|
|
class MultiSpectralClient:
|
|
def __init__(
|
|
self,
|
|
pi_host="192.168.105.6",
|
|
pc_host="192.168.105.5",
|
|
server_port=5000,
|
|
stream_port=6001,
|
|
timeout=10,
|
|
width=640,
|
|
height=480,
|
|
bayer="GBRG",
|
|
fps=15,
|
|
frame_type="RAW_BRUTO",
|
|
output_dtype="uint8",
|
|
capture_mode="AUTO",
|
|
raw_policy="allow_single",
|
|
module_calibration_json=None,
|
|
):
|
|
self.pi_host = pi_host
|
|
self.pc_host = pc_host
|
|
self.server_port = server_port
|
|
self.stream_port = stream_port
|
|
|
|
self.width = width
|
|
self.height = height
|
|
self.bayer = bayer
|
|
self.fps = fps
|
|
self.frame_type = frame_type
|
|
self.output_dtype = output_dtype
|
|
self.capture_mode = capture_mode
|
|
self.raw_policy = raw_policy
|
|
self.module_calibration_json = module_calibration_json
|
|
|
|
self.svc = MultiSpectralService(
|
|
host=pi_host,
|
|
port=server_port,
|
|
timeout=timeout,
|
|
)
|
|
|
|
self.receiver = StreamReceiver(
|
|
host="0.0.0.0",
|
|
port=stream_port,
|
|
)
|
|
|
|
self.core = RawProcessorCore(
|
|
sensor_width=width,
|
|
sensor_height=height,
|
|
bayer_pattern=bayer,
|
|
calibration_json_path=module_calibration_json,
|
|
)
|
|
|
|
self.preview = RawProcessorPreview(
|
|
sensor_width=width,
|
|
sensor_height=height,
|
|
bayer_pattern=bayer,
|
|
)
|
|
|
|
self.last_frame_id = None
|
|
self.status = None
|
|
self.begin_resp = None
|
|
self.applied_params = None
|
|
|
|
def __enter__(self):
|
|
self.start()
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc, tb):
|
|
self.stop()
|
|
|
|
def start(self, print_debug=True):
|
|
if print_debug:
|
|
print(f"[INFO] Verificando módulo em {self.pi_host}:{self.server_port}...")
|
|
|
|
if not self.svc.check_connection(2):
|
|
raise RuntimeError("Módulo não encontrado ou não respondeu ao ping.")
|
|
|
|
self.receiver.start()
|
|
time.sleep(0.5)
|
|
|
|
self.svc.connect()
|
|
|
|
if print_debug:
|
|
print("[OK] Módulo conectado.")
|
|
|
|
self._configure_module(print_debug=print_debug)
|
|
self._begin_module(print_debug=print_debug)
|
|
self._apply_module_params(print_debug=print_debug)
|
|
self._start_stream(print_debug=print_debug)
|
|
|
|
return self
|
|
|
|
def _configure_module(self, print_debug=True):
|
|
r0 = self.svc.set_resolution(self.width, self.height)
|
|
r1 = self.svc.set_bayer(self.bayer)
|
|
r2 = self.svc.set_fps(self.fps)
|
|
r3 = self.svc.set_capture_mode(self.capture_mode)
|
|
r4 = self.svc.set_frame_type(self.frame_type)
|
|
r5 = self.svc.set_output_dtype(self.output_dtype)
|
|
if print_debug:
|
|
print("SET RES:", r0)
|
|
print("SET BAYER:", r1)
|
|
print("SET FPS:", r2)
|
|
print("SET CAPTURE MODE:", r3)
|
|
print("SET FRAME TYPE:", r4)
|
|
print("SET OUTPUT DTYPE:", r5)
|
|
|
|
def _begin_module(self, print_debug=True):
|
|
self.begin_resp = self.svc.begin(
|
|
frame_type=self.frame_type,
|
|
output_dtype=self.output_dtype,
|
|
capture_mode=self.capture_mode,
|
|
)
|
|
|
|
self.status = self.svc.get_status()
|
|
|
|
self.svc.validate_module_ready(
|
|
self.status,
|
|
self.frame_type,
|
|
self.raw_policy,
|
|
self.capture_mode,
|
|
)
|
|
|
|
if print_debug:
|
|
print("BEGIN:", self.begin_resp)
|
|
print("STATUS:", json.dumps({
|
|
"status": self.status.get("status"),
|
|
"detected_mode": self.status.get("detected_mode"),
|
|
"camera_count_active": self.status.get("camera_count_active"),
|
|
"active_camera_ids": self.status.get("active_camera_ids"),
|
|
}, ensure_ascii=False))
|
|
|
|
def _apply_module_params(self, print_debug=True):
|
|
if not self.module_calibration_json:
|
|
return None
|
|
|
|
self.applied_params = self.svc.apply_camera_params_json(
|
|
self.module_calibration_json
|
|
)
|
|
|
|
if print_debug:
|
|
print("[OK] Parâmetros do módulo aplicados:")
|
|
print(json.dumps(self.applied_params.get("applied"), ensure_ascii=False, indent=2))
|
|
|
|
return self.applied_params
|
|
|
|
def _start_stream(self, print_debug=True):
|
|
resp = self.svc.start_stream(
|
|
self.pc_host,
|
|
self.stream_port,
|
|
fps=self.fps,
|
|
)
|
|
|
|
if print_debug:
|
|
print("START STREAM:", resp)
|
|
|
|
return resp
|
|
|
|
def get_latest(self):
|
|
return self.receiver.last_frame, self.receiver.last_meta
|
|
|
|
def get_next_frame(self, timeout=2.0):
|
|
t0 = time.perf_counter()
|
|
|
|
while time.perf_counter() - t0 < timeout:
|
|
frame = self.receiver.last_frame
|
|
meta = self.receiver.last_meta
|
|
|
|
if frame is None or meta is None:
|
|
time.sleep(0.001)
|
|
continue
|
|
|
|
frame_id = meta.get("frame_id")
|
|
|
|
if frame_id != self.last_frame_id:
|
|
self.last_frame_id = frame_id
|
|
return frame, meta
|
|
|
|
time.sleep(0.001)
|
|
|
|
raise TimeoutError("Timeout aguardando novo frame do stream.")
|
|
|
|
def build_infer_tensor(self, frame, meta, channels_expected, target_size=None):
|
|
return self.core.build_infer_tensor_from_stream(
|
|
frame,
|
|
meta,
|
|
channels_expected=channels_expected,
|
|
target_size=target_size,
|
|
)
|
|
|
|
def stop(self):
|
|
try:
|
|
self.svc.stop_stream()
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
self.svc.stop()
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
self.svc.disconnect()
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
self.receiver.stop()
|
|
except Exception:
|
|
pass |