@@ -134,7 +134,7 @@ async def get_vignettes(
134134 # Segmenter
135135 sep_img_path = multiples_to_check_dir / a_vignette
136136 assert sep_img_path .is_file ()
137- _ , rois = segment_mask (processor , sep_img_path )
137+ _ , rois = segment_mask_file (processor , sep_img_path )
138138 segmenter_output = []
139139 for i in range (len (rois )):
140140 seg_name = (
@@ -211,7 +211,7 @@ async def get_vignette_image(
211211 multiple_name = img_path .rsplit ("/" , 1 )[1 ]
212212 sep_img_path = multiples_to_check_dir / multiple_name
213213 assert sep_img_path .is_file (), f"Not a file: { sep_img_path } "
214- sep_img , rois = segment_mask (processor , sep_img_path )
214+ sep_img , rois = segment_mask_file (processor , sep_img_path )
215215 vignette_in_vignette = processor .extractor .extract_image_at_ROI (
216216 sep_img , rois [int (seg_num )], erasing_background = True
217217 )
@@ -352,6 +352,73 @@ async def update_a_vignette_mask(
352352 }
353353
354354
355+ DRAWING_FEATURES = {"object_bx" , "object_by" , "object_width" , "object_height" ,
356+ "object_x" , "object_y" , "object_major" , "object_minor" , "object_angle" }
357+
358+
359+ @router .post ("/vignette_mask_maybe/{project_hash}/{sample_hash}/{subsample_hash}/{img_path}" )
360+ async def simulate_a_vignette_mask (
361+ project_hash : str ,
362+ sample_hash : str ,
363+ subsample_hash : str ,
364+ img_path : str ,
365+ file : UploadFile = File (...),
366+ db : Session = Depends (get_db ),
367+ ) -> dict :
368+ """Update _virtually_ a vignette using the drawn mask
369+
370+ Args:
371+ project_hash (str): The ID of the project
372+ sample_hash (str): The hash of the sample
373+ subsample_hash (str): The hash of the subsample
374+ img_path (str): The path to the original image
375+ file (UploadFile): The uploaded file containing the mask
376+ db (Session): Database session
377+
378+ Returns:
379+ dict: Status of the simulation operation
380+ """
381+ logger .info (
382+ f"simulate_a_vignette_mask: { project_hash } /{ sample_hash } /{ subsample_hash } /{ img_path } "
383+ )
384+ # Validate the project, sample, and subsample hashes
385+ zoo_drive , zoo_project , sample_name , subsample_name = validate_path_components (
386+ db , project_hash , sample_hash , subsample_hash
387+ )
388+ img_path = img_path .replace (API_PATH_SEP , "/" )
389+ assert img_path .startswith (
390+ V10_THUMBS_SUBDIR
391+ ) # Convention with UI, ref is original image in cut directory
392+ assert img_path .endswith (".png" )
393+ _ , img_name = img_path .rsplit ("/" , 1 )
394+ processor , thumbs_dir , multiples_to_check_dir , meta_dir = processing_context (
395+ zoo_project , sample_name , subsample_name
396+ )
397+ # Read the content of the uploaded file
398+ content = await file .read ()
399+ # Validate that the content is a gzip or zip-encoded matrix
400+ if not is_valid_compressed_matrix (content ):
401+ raise_422 ("Invalid compressed matrix" )
402+ assert False
403+ mask = load_matrix_from_compressed (content )
404+ scan_path = thumbs_dir / img_name
405+ scan_img = load_image (scan_path , cv2 .IMREAD_GRAYSCALE )
406+ check_mask_sanity (scan_img , mask , subsample_name , img_name [:- 4 ], meta_dir )
407+ masked_img = apply_matrix_onto (scan_img , mask , True )
408+ # Segment the masked image
409+ assert processor .config is not None
410+ rois , _ = processor .segmenter .find_ROIs_in_cropped_image (
411+ masked_img , processor .config .resolution
412+ )
413+ calcs = processor .calculator .ecotaxa_measures_list_from_roi_list (masked_img , processor .config .resolution , rois ,
414+ DRAWING_FEATURES )
415+ return {
416+ "status" : "success" ,
417+ "rois" : calcs ,
418+ "image" : str (img_name ),
419+ }
420+
421+
355422def all_pngs_in_dir (a_dir : Path ) -> List [str ]:
356423 ret = []
357424 if a_dir is None :
@@ -365,10 +432,14 @@ def all_pngs_in_dir(a_dir: Path) -> List[str]:
365432 return ret
366433
367434
368- def segment_mask (
435+ def segment_mask_file (
369436 processor : Processor , sep_img_path : Path
370437) -> Tuple [np .ndarray , List [ROI ]]:
371438 sep_img = load_image (sep_img_path , cv2 .IMREAD_COLOR_BGR )
439+ return segment_mask_image (processor , sep_img )
440+
441+
442+ def segment_mask_image (processor : Processor , sep_img : np .ndarray ) -> Tuple [np .ndarray , List [ROI ]]:
372443 sep_img2 = cv2 .extractChannel (sep_img , 1 )
373444 sep_img2 [sep_img [:, :, 2 ] == BGR_RED_COLOR [2 ]] = 255
374445 assert processor .config is not None
0 commit comments