Skip to content

Commit

Permalink
Diagnostic button_save_img
Browse files Browse the repository at this point in the history
  • Loading branch information
MaticTonin committed Dec 10, 2024
1 parent c917bef commit d8d572c
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 57 deletions.
14 changes: 14 additions & 0 deletions crates/re_viewer/src/depthai/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,20 @@ impl BackendCommChannel {
.unwrap(),
);
}

pub fn Camera_Diagnostics(&mut self, number: u32) {
self.ws.send(
serde_json::to_string(
&(WsMessage {
kind: WsMessageType::Camera_Diagnostics,
data: WsMessageData::Camera_Diagnostics(number),
..Default::default()
}),
)
.unwrap(),
);
}

pub fn receive(&mut self) -> Option<WsMessage> {
self.ws.receive()
}
Expand Down
8 changes: 8 additions & 0 deletions crates/re_viewer/src/depthai/depthai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,9 @@ impl State {
WsMessageData::Reset_factory(number)=> {
re_log::debug!("Reset to factory calibration recieved from backend.")
}
WsMessageData::Camera_Diagnostics(number)=> {
re_log::debug!("Running device diagnostics.")
}
}
}

Expand Down Expand Up @@ -1136,6 +1139,11 @@ impl State {
self.backend_comms.flash_factorycalibration(recalib);
}

pub fn Camera_Diagnostics(&mut self, recalib: u32) {
println!("Running device diagnostics");
self.backend_comms.Camera_Diagnostics(recalib);
}

pub fn reset(&mut self) {
*self = Self::default();
}
Expand Down
9 changes: 7 additions & 2 deletions crates/re_viewer/src/depthai/ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ pub enum WsMessageData {
Recalibrate(u32),
Calib_check(u32),
Flash_calib(u32),
Reset_factory(u32)
Reset_factory(u32),
Camera_Diagnostics(u32)
}

#[derive(Deserialize, Serialize, fmt::Debug)]
Expand All @@ -111,7 +112,8 @@ pub enum WsMessageType {
Recalibrate,
Calib_check,
Flash_calib,
Reset_factory
Reset_factory,
Camera_Diagnostics
}

impl Default for WsMessageType {
Expand Down Expand Up @@ -185,6 +187,9 @@ impl<'de> Deserialize<'de> for BackWsMessage {
WsMessageType::Reset_factory => {
WsMessageData::Reset_factory(serde_json::from_value(message.data).unwrap())
}
WsMessageType::Camera_Diagnostics => {
WsMessageData::Camera_Diagnostics(serde_json::from_value(message.data).unwrap())
}
};

Ok(Self {
Expand Down
118 changes: 65 additions & 53 deletions crates/re_viewer/src/ui/device_settings_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,63 +414,75 @@ impl DeviceSettingsPanel {
..Default::default()
})
.show(ui, |ui| {
ui.vertical(|ui| {
ui.scope(|ui| {
let mut style = ui.style_mut().clone();
let color = style.visuals.selection.bg_fill;
style.visuals.widgets.hovered.bg_fill = color;
style.visuals.widgets.inactive.bg_fill = color;
style.visuals.widgets.inactive.fg_stroke.color =
egui::Color32::WHITE;
style.visuals.widgets.hovered.fg_stroke.color =
egui::Color32::WHITE;
style.spacing.button_padding =
egui::Vec2::new(24.0, 4.0);
ui.set_style(style);
ui.horizontal(|ui| {
ui.vertical(|ui| {
ui.collapsing(
egui::RichText::new("Recalibrate_device").color(text_color),
|ui| {
ui.vertical(|ui| {
ui.scope(|ui| {
let mut style = ui.style_mut().clone();
let color = style.visuals.selection.bg_fill;
style.visuals.widgets.hovered.bg_fill = color;
style.visuals.widgets.inactive.bg_fill = color;
style.visuals.widgets.inactive.fg_stroke.color = egui::Color32::WHITE;
style.visuals.widgets.hovered.fg_stroke.color = egui::Color32::WHITE;
style.spacing.button_padding = egui::Vec2::new(24.0, 4.0);
ui.set_style(style);

if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Recalibration"),
)
.clicked()
{
ctx.depthai_state.start_recalibration(1);
}
if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Recalibration"),
)
.clicked()
{
ctx.depthai_state.start_recalibration(1);
}

if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Calibration Check"),
)
.clicked()
{
ctx.depthai_state.calibration_check(1);
}
if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Calibration Check"),
)
.clicked()
{
ctx.depthai_state.calibration_check(1);
}

if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Flash Calibration"),
)
.clicked()
{
ctx.depthai_state.flash_calibration(1);
}
if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Flash Calibration"),
)
.clicked()
{
ctx.depthai_state.flash_calibration(1);
}

if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Restore Factory Calibration"),
)
.clicked()
{
ctx.depthai_state.flash_factorycalibration(1);
}
});
});
ui.horizontal(|ui| {
ui.vertical(|ui| {
if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Restore Factory Calibration"),
)
.clicked()
{
ctx.depthai_state.flash_factorycalibration(1);
}

if ui
.add_sized(
[CONFIG_UI_WIDTH, re_ui::ReUi::box_height()],
egui::Button::new("Save Device Diagnostics"),
)
.clicked()
{
ctx.depthai_state.Camera_Diagnostics(1);
}
});
});
},
);
Self::camera_config_ui(ctx, ui, &mut device_config);
ui.collapsing(
egui::RichText::new("AI settings").color(text_color),
Expand Down
3 changes: 3 additions & 0 deletions rerun_py/depthai_viewer/_backend/config_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Action(Enum):
CALIB_CHECK = auto()
FLASH_CALIB = auto()
FLASH_FACTORY_CALIB = auto()
CAMERA_DIAGNOSTICS = auto()


def dispatch_action(action: Action, **kwargs) -> Message: # type: ignore[no-untyped-def]
Expand Down Expand Up @@ -172,6 +173,8 @@ async def ws_api(websocket: WebSocketServerProtocol) -> None:
message = dispatch_action(Action.FLASH_CALIB)
elif message_type == MessageType.FLASH_FACTORY_CALIB:
message = dispatch_action(Action.FLASH_FACTORY_CALIB)
elif message_type == MessageType.CAMERA_DIAGNOSTICS:
message = dispatch_action(Action.CAMERA_DIAGNOSTICS)
else:
print("Unknown message type: ", message_type)
continue
Expand Down
16 changes: 16 additions & 0 deletions rerun_py/depthai_viewer/_backend/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,22 @@ def update(self) -> None:
self._component_outputs[list(self._component_outputs.keys())[0]]["component"], packets
)
else:
camera_board_sockets = [name for name, packet in packets.items() if "CameraBoardSocket" in name]
for name, packet in packets.items():
if "CameraBoardSocket" in name and self._packet_handler.save_diagnostics != "":
camera_board_sockets.remove(name)
self._packet_handler._save_packet(name, packet.msg.getCvFrame())
if camera_board_sockets == []:
import shutil
shutil.make_archive(self._packet_handler.save_diagnostics, 'zip', self._packet_handler.save_diagnostics)
print("\n")
print("----------------------------------------")
print(f"Diagnostics saved to {self._packet_handler.save_diagnostics}.zip.")
print(f"Please send them to Luxonis via mail.")
print("----------------------------------------")
print("\n")
self._packet_handler.save_diagnostics = ""
camera_board_sockets = [name for name, packet in packets.items() if "CameraBoardSocket" in name]
self._packet_handler.log_packet(self._component_outputs[name]["component"], packet)
if self._packet_handler.stereo and self._packet_handler.new_calib is not None:
self._oak.device.setCalibration(self._packet_handler.new_calib)
Expand All @@ -696,6 +711,7 @@ def update(self) -> None:
self._oak.device.flashCalibration(self._packet_handler._dynamic_recalibration.calib_edit.factoryCalib)
self._packet_handler.resetFactoryCalibration = False
self._packet_handler._display_flashing = "Factory"

except QueueEmpty:
pass

Expand Down
15 changes: 15 additions & 0 deletions rerun_py/depthai_viewer/_backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ def handle_action(self, action: Action, **kwargs) -> Message: # type: ignore[no
elif action == Action.FLASH_FACTORY_CALIB:
if self._device._packet_handler.stereo and not self._device._packet_handler.display_bar:
self._device._packet_handler.resetFactoryCalibration = True

elif action == Action.CAMERA_DIAGNOSTICS:
self._device._packet_handler.diagnostics_display = True
import tempfile
import os
import time
base_tmp_dir = tempfile.gettempdir()
new_dirname = os.path.join(base_tmp_dir, self._device._oak.device.getMxId())
if not os.path.exists(new_dirname):
os.makedirs(new_dirname) # Create the directory if it doesn't exist
self._device._packet_handler.save_diagnostics = str(new_dirname)
self._device._oak.device.readCalibration().eepromToJsonFile(os.path.join(str(new_dirname), "calib_user.json"))
self._device._oak.device.readFactoryCalibration().eepromToJsonFile(os.path.join(str(new_dirname), "calib_factory.json"))
self._device._packet_handler._calib_time = time.time()
print(f"Saving to {new_dirname}")
return ErrorMessage(f"Action: {action} not implemented")

def run(self) -> None:
Expand Down
1 change: 1 addition & 0 deletions rerun_py/depthai_viewer/_backend/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class MessageType:
CALIB_CHECK = "Calib_check"
FLASH_CALIB = "Flash_calib"
FLASH_FACTORY_CALIB = "Reset_factory"
CAMERA_DIAGNOSTICS = "Camera_Diagnostics"


class ErrorAction(Enum):
Expand Down
49 changes: 47 additions & 2 deletions rerun_py/depthai_viewer/_backend/packet_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from depthai_viewer.components.rect2d import RectFormat
from depthai_viewer._backend.obscured_utilities.utilities.calibration_handler import Recalibration
from depthai_viewer._backend.obscured_utilities.utilities.display_handler import Display
import os

class PacketHandlerContext(BaseModel): # type: ignore[misc]
class Config:
Expand Down Expand Up @@ -94,6 +95,8 @@ def __init__(self, store: Store, calibration_handler: dai.CalibrationHandler, fa
self._ahrs.Q = np.array([1, 0, 0, 0], dtype=np.float64)
self._calibration_handler = CachedCalibrationHandler(calibration_handler)
self.stereo = stereo
self.save_diagnostics = ""
self.diagnostics_display = False
if self.stereo:
self._dynamic_recalibration = Recalibration(calibration_handler, factoryCalibration_handler)
self._dynamic_recalibration.min_pts_for_calib = 4000
Expand Down Expand Up @@ -275,6 +278,10 @@ def _log_img_frame(
self._dynamic_recalibration.resolution = img_frame.shape[1::-1]
elif (is_left_socket or is_right_socket) and self._display_flashing != "":
self._display.draw_center_center_box(img_frame,f"Flashing {self._display_flashing} calibration ...")

elif (is_left_socket or is_right_socket) and self.diagnostics_display:
self._display.draw_center_center_box(img_frame,f"Saving to:")
self.draw_center_center_box(img_frame, self.file_path)
viewer.log_image(entity_path, img_frame)
if is_left_socket:
self._display.create_window((img_frame.shape[1], img_frame.shape[0]))
Expand Down Expand Up @@ -328,6 +335,8 @@ def _log_img_frame(
self.display_bar = False
self._dynamic_recalibration.reset_aggregation()
self._calib_time = None
self.diagnostics_display = False


if not self._dynamic_recalibration.result_queue.empty():
self.new_calib, out_before, out_after, fillrate_before, fillrate_after = self._dynamic_recalibration.result_queue.get()
Expand Down Expand Up @@ -547,8 +556,44 @@ def _start_optimization(self) -> None:
print("Starting feature collection and optimization...")
self._dynamic_recalibration.start_optimization(8)



def draw_center_center_box(self, image, text, box_color=(0, 0, 0, 128), font_scale=0.3, font_color=(255, 255, 255)):
img_height, img_width = image.shape[:2]

# Calculate text size
text_size = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, 1)[0]
text_width, text_height = text_size

# Define box dimensions
box_padding = 10
box_width = text_width + box_padding * 2
box_height = text_height + box_padding * 2
box_x = (img_width - box_width) // 2
box_y = (img_height - box_height) // 2 +50

# Draw semi-transparent background box
overlay = image.copy()
box_start = (box_x, box_y)
box_end = (box_x + box_width, box_y + box_height)
alpha = box_color[3] / 255.0
cv2.rectangle(overlay, box_start, box_end, box_color[:3], -1)
cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0, image)

# Draw text at the center of the box
text_x = box_x + (box_width - text_width) // 2
text_y = box_y + (box_height + text_height) // 2
cv2.putText(image, text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, font_scale, font_color, 1)

return image

def _save_packet(self, name, frame):
base_path = self.save_diagnostics
self.file_path = os.path.join(base_path, f"{name}.png")

counter = 1
while os.path.exists(self.file_path):
self.file_path = os.path.join(base_path, f"{name}_{counter}.png")
counter += 1
cv2.imwrite(self.file_path, frame)

def cam_kind_from_frame_type(dtype: dai.RawImgFrame.Type) -> str:
"""Returns camera kind string for given dai.RawImgFrame.Type."""
Expand Down

0 comments on commit d8d572c

Please sign in to comment.