agrobot_base/Python/raspi/cam_3/multispectral_client.py

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