DAQ: updated ALC to use updated mlbox.py and to give more information to the DB

This commit is contained in:
2025-10-29 13:38:12 +01:00
parent 9f2d8dce21
commit ecf6bf0dac
+96 -57
View File
@@ -785,18 +785,19 @@ class AareDAQ:
time.sleep(0.2) # Just to be sure image is stable
#curr_image = self.camera_image
#box = self.__mlbox.predict(curr_image)
bgr_image = cv2.cvtColor(self.camera_image, cv2.COLOR_RGB2BGR)
box = self.__mlbox.predict(bgr_image, pref_class=(3,0))
if box is None:
curr_image = cv2.cvtColor(self.camera_image, cv2.COLOR_RGB2BGR)
m = self.__mlbox.predict(curr_image, preferred_class=(3,0))
if m is None:
if filename is not None:
cv2.imwrite(f"{filename}_no_detection.jpg", bgr_image)
self.__aare.upload_image(sample_id, f"{filename}_no_detection", bgr_image)
cv2.imwrite(f"{filename}_no_detection.jpg", curr_image)
self.__aare.upload_image(sample_id, f"{filename}_no_detection", curr_image)
return None
_, x1, y1, x2, y2 = box
x1, y1, x2, y2 = m.box.top_x, m.box.top_y, m.box.bottom_x, m.box.bottom_y
if filename is not None:
cv2.rectangle(bgr_image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
cv2.imwrite(f"{filename}.jpg", bgr_image)
self.__aare.upload_image(sample_id, filename, bgr_image)
cv2.rectangle(curr_image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
cv2.imwrite(f"{filename}.jpg", curr_image)
self.__aare.upload_image(sample_id, filename, curr_image)
geom = self.sample_geometry
@@ -817,41 +818,74 @@ class AareDAQ:
omega_deg=geom.omega_deg
)
def __ml_loop_centre_box(self, sample_id: int | None = None, filename: str | None = None) -> SmargonCoordinate | None:
time.sleep(0.2) # Just to be sure image is stable
def __ml_loop_centre_box(self, sample_id: int | None = None, filename: str | None = None) -> tuple[SmargonCoordinate | None, int| None, list[int] | None]:
#time.sleep(0.2) # Just to be sure image is stable
bgr_image = cv2.cvtColor(self.camera_image, cv2.COLOR_RGB2BGR)
box = self.__mlbox.predict(bgr_image, filename)
boxes = self.__mlbox.predict_all_best(bgr_image, overlap_with_pin = 0.5, confidence_min=0.3)
if box is None:
if boxes is None:
if filename is not None:
#cv2.imwrite(f"{filename}_no_detection.jpg", bgr_image)
self.__aare.upload_image(sample_id, f"{filename}_no_detection", bgr_image)
return None
return None, None, None
cls, x1, y1, x2, y2 = box
classes: list[int] = []
pin = None
centre_x, centre_y = None, None
for box in boxes.boxes.values():
if box and box.cls is not None:
classes.append(int(box.cls.value))
if int(box.cls.value) == 1:
pin=box
best_box = self.__mlbox.get_preferred_class_box(boxes, (2,3,0,1))
if best_box is None or best_box.box is None or best_box.cls is None:
return None, None, classes if classes else None
cls = int(best_box.cls.value)
x1 = best_box.box.top_x
y1 = best_box.box.top_y
x2 = best_box.box.bottom_x
y2 = best_box.box.bottom_y
if filename is not None:
#cv2.rectangle(bgr_image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
#cv2.imwrite(f"{filename}.jpg", bgr_image)
self.__aare.upload_image(sample_id, filename, bgr_image)
geom = self.sample_geometry
if cls == 0: # loop_all
centre_y = y1 + (y2 - y1)/2
centre_x = x1
if y1 + y2 <= x1 + x2:
centre_y = y1 + (y2 - y1) / 2
centre_x = x1
elif pin:
position_dict = self.__mlbox.check_box_relation(pin, best_box)
if position_dict["overlap_y"] and position_dict["overlap_x"]:
centre_y = y1 + (y2 - y1) / 2
centre_x = x1
cls = 1
logger.debug("significant overlap between pin and loop_all not picked up by ML")
else:
centre_y = y2 if position_dict["top"] else y1
centre_x = x1 + (x2 - x1) / 2
else:
centre_y = y1
centre_x = x1 + (x2 - x1) / 2
elif cls == 1: # pin
centre_y = y1 + (y2 - y1)/2
centre_x = x1
elif cls == 2 or cls == 3: #crystal or loop_face
centre_y = y1 + (y2 - y1)/2
centre_x = x1 + (x2 - x1)/2
else:
print(f"unknown box class {cls}")
return None
return None, cls, classes if classes else None
coord = geom.picture_to_smargon(Coordinate(x=centre_x, y=centre_y))
return SmargonCoordinate(sh_mm=coord)
return SmargonCoordinate(sh_mm=coord), cls, classes
def ml_bounding_box(self, sample_id: int | None = None, filename: str | None = None) -> RasterGridRequest | None:
try:
@@ -1014,71 +1048,74 @@ class AareDAQ:
def __loop_center_sequence(self, sample_id: int | None = None) -> bool:
self.__set_state(BeamlineStateEnum.SampleAlignment)
self.__devs.lamp_light = 2.5
found_classes_count: dict[int, int] = {0:0, 1:0, 2:0, 3:0}
try:
i = 0
self.__cfg.zoom_mode = ZoomModeEnum.LoopCenter
zoom_settings = self.__cfg.zoom_settings.z
for zoom_value in zoom_settings:
for zoom_iter, zoom_value in enumerate(zoom_settings):
exposure = zoom_settings[zoom_value].exposure
gain = zoom_settings[zoom_value].gain
max_attempt = 2
attempt = 0
found = 0
angles = (0, -90)
base_angles = (0, 45, 90) if (zoom_iter % 2 == 0) else (90, 45, 0)
if sample_id is not None:
self.save_screenshot_db(sample_id, f"pre_alc")
while attempt < max_attempt:
logger.debug('new loop center settings')
self.__devs.samcam_settings = SampleCameraSettings(exposure=exposure, gain=gain)
self.__devs.zoom_sync(zoom_value)
logger.debug(f'zoom={zoom_value},gain={gain}, exp={exposure}')
found_flag = False
found_angle = None
targets_found_this_attempt = 0
exp = int(exposure * 1000)
gn = int(gain)
self.__devs.zoom_sync(zoom_value)
logger.debug(f'zoom={zoom_value},gain={gn}, exp={exp}ms')
for loop, angle in enumerate(angles):
found_flag = False
found_angle: int | None = None
targets_found_this_attempt = 0
for angle in base_angles:
logger.debug(f"Moving to new omega: {angle}")
# if sample_id is not None and i == 0:
# self.save_screenshot_db(sample_id, f"pre_alc_{sample_id}_{angle}_{zoom_value:.0f}_{exp}_{gn}")
time_to_move_aerotech= time.perf_counter()
self.__devs.aerotech.move(angle, wait=True)
logger.info(f"time to move: {time.perf_counter()-time_to_move_aerotech}")
#time.sleep(0.1)
filename = None
if sample_id is not None:
filename = f"{sample_id}_{angle}_{zoom_value:.0f}_{exp}_{gn}"
target = self.__ml_loop_centre_box(sample_id, filename)
filename = f"{sample_id}_{angle}_{zoom_value:.0f}_{exp}_{gn}" if sample_id is not None else None
if target is not None:
try:
target, cls, classes = self.__ml_loop_centre_box(sample_id, filename)
except:
target, cls, classes = None, None, None
if target is None:
continue
if classes:
for c in classes:
found_classes_count[int(c)] += 1
if cls is not None and cls != 1:
targets_found_this_attempt += 1
found_flag = True
found_angle = angle
found += 1
targets_found_this_attempt += 1
time_to_move_smargon = time.perf_counter()
self.__devs.smargon.target = target
self.__devs.smargon.wait(60)
logger.info(f"time to move smargon: {time.perf_counter() - time_to_move_smargon}")
if sample_id is not None:
self.__aare.sample_centered(self.__cfg.current_sample)
self.save_screenshot_db(sample_id, f"{sample_id}_{angle}_{zoom_value:.0f}_{exp}_{gn}")
time_to_move_smargon = time.perf_counter()
self.__devs.smargon.target = target
self.__devs.smargon.wait(60)
logger.info(f"time to move smargon: {time.perf_counter() - time_to_move_smargon}")
if targets_found_this_attempt == 0:
raise LoopCenteringFailed
else:
if found >= 3 or targets_found_this_attempt >= 3:
logger.debug(f"sucessfully found {found} or {targets_found_this_attempt} targets in {attempt} attempts")
if targets_found_this_attempt >= len(base_angles):
logger.debug(f"sucessfully found {targets_found_this_attempt} targets in attempt {attempt + 1} ")
break
if found_flag is not None and found_angle is not None:
logger.debug(f"found a target at angle {found_angle} in attempt {attempt}")
angles = (found_angle, found_angle + 45, found_angle + 90)
logger.debug(f"found a target at angle {found_angle} in attempt {attempt + 1}")
base_angles = (found_angle, found_angle + 45, found_angle + 90)
attempt += 1
logger.debug(f"attempt {attempt} of {max_attempt}")
if attempt >= max_attempt:
@@ -1086,8 +1123,11 @@ class AareDAQ:
#i += 1
logger.debug("alc success")
#self.face_detection_sequence()
self.__aare.sample_centered(self.__cfg.current_sample)
if sample_id is not None:
self.save_screenshot_db(sample_id, f"{sample_id}_centered")
return True
except Exception as e:
logger.info(f"Error in loop centering: {e}")
return False
@@ -1097,7 +1137,6 @@ class AareDAQ:
try:
self.__cfg.try_set_busy(timeout=360)
if not self.__loop_center_sequence(sample_id):
self.__aare.alc_failed(self.sample)
raise LoopCenteringFailed
self.__cfg.state_busy = False