|
| 1 | +import json |
1 | 2 | import tempfile |
2 | 3 | from pathlib import Path |
3 | 4 | from typing import List |
4 | 5 |
|
| 6 | +import cv2 |
| 7 | +import numpy as np |
5 | 8 | from fastapi import APIRouter, Depends |
6 | 9 | from fastapi.responses import StreamingResponse |
7 | 10 | from sqlalchemy.orm import Session |
8 | 11 |
|
9 | | -from Models import Project, Background, Scan |
| 12 | +from Models import Project, Background, Scan, ScanStats |
10 | 13 | from ZooProcess_lib.ZooscanFolder import ZooscanDrive |
| 14 | +from ZooProcess_lib.img_tools import load_image |
11 | 15 | from config_rdr import config |
12 | 16 | from helpers.auth import get_current_user_from_credentials |
13 | 17 | from helpers.logger import logger |
|
16 | 20 | from legacy.backgrounds import find_final_background_file, find_raw_background_file |
17 | 21 | from legacy_to_remote.importe import import_old_project |
18 | 22 | from local_DB.db_dependencies import get_db |
| 23 | +from modern.filesystem import TOP_V10_DIR, ModernScanFileSystem |
19 | 24 | from modern.from_legacy import ( |
20 | 25 | project_from_legacy, |
21 | 26 | backgrounds_from_legacy_project, |
22 | 27 | scans_from_legacy_project, |
23 | 28 | DEPTH_ALL, |
24 | 29 | ) |
| 30 | +from modern.ids import subsample_name_from_scan_name |
| 31 | +from providers.ML_multiple_separator import RGB_RED_COLOR, BGR_RED_COLOR |
25 | 32 | from remote.DB import DB |
26 | 33 | from .utils import validate_path_components |
27 | 34 |
|
@@ -168,6 +175,69 @@ def get_scans( |
168 | 175 | return scans_from_legacy_project(db, zoo_project) |
169 | 176 |
|
170 | 177 |
|
| 178 | +@router.get("/{project_hash}/stats") |
| 179 | +def get_project_scanning_stats( |
| 180 | + project_hash: str, |
| 181 | + _user=Depends(get_current_user_from_credentials), |
| 182 | + db: Session = Depends(get_db), |
| 183 | +) -> List[ScanStats]: |
| 184 | + zoo_drive, zoo_project, _, _ = validate_path_components(db, project_hash) |
| 185 | + |
| 186 | + result: List[ScanStats] = [] |
| 187 | + |
| 188 | + def files_in_dir(path: Path) -> List[Path]: |
| 189 | + return [a_file for a_file in path.iterdir() if a_file.is_file()] |
| 190 | + |
| 191 | + def is_after(path: Path, path_cmp: Path) -> bool: |
| 192 | + return path.stat().st_mtime > path_cmp.stat().st_mtime |
| 193 | + |
| 194 | + def has_a_separator(image_path: Path) -> bool: |
| 195 | + sep_img = load_image(image_path, cv2.IMREAD_COLOR_BGR) |
| 196 | + return np.any(np.all(sep_img == BGR_RED_COLOR, axis=2)) |
| 197 | + |
| 198 | + v10_work_dir: Path = zoo_project.zooscan_scan.path / TOP_V10_DIR |
| 199 | + if not v10_work_dir.exists(): |
| 200 | + return result |
| 201 | + for scan_dir in v10_work_dir.iterdir(): |
| 202 | + subsample = subsample_name_from_scan_name(scan_dir.name) |
| 203 | + modern_fs = ModernScanFileSystem(zoo_project, "", subsample) |
| 204 | + # We need output directories... |
| 205 | + nb_subdirs = 1 if modern_fs.cut_dir.exists() else 0 |
| 206 | + nb_subdirs += 1 if modern_fs.multiples_vis_dir.exists() else 0 |
| 207 | + if nb_subdirs != 2: |
| 208 | + continue |
| 209 | + # ...and the flag that manual separation is finished |
| 210 | + if not modern_fs.SEP_validated_file_path.exists(): |
| 211 | + continue |
| 212 | + after_seg = len(files_in_dir(modern_fs.cut_dir)) |
| 213 | + with open(modern_fs.scores_file_path, "r") as f: |
| 214 | + scores = json.load(f) |
| 215 | + sent_to_ml_separator = {k: v for k, v in scores.items() if v > 0.4} |
| 216 | + |
| 217 | + # Separation work directory. Written into by ML or user |
| 218 | + in_sep_dir = files_in_dir(modern_fs.multiples_vis_dir) |
| 219 | + # Writes of images in work dir |
| 220 | + auto_sep_log = modern_fs.ensure_meta_dir() / "auto_sep_job.log" |
| 221 | + modified_images = [f for f in in_sep_dir if is_after(f, auto_sep_log)] |
| 222 | + modified_images_names = [f.name for f in modified_images] |
| 223 | + # Images added by user but the ML classifier did not see them |
| 224 | + added_by_user = set(modified_images_names).difference(sent_to_ml_separator) |
| 225 | + # Writes of a separator-less image |
| 226 | + cleared_images = [f for f in modified_images if not has_a_separator(f)] |
| 227 | + stats_for_scan = ScanStats( |
| 228 | + name=subsample, |
| 229 | + segmented=after_seg, |
| 230 | + sentToSeparator=len(sent_to_ml_separator), |
| 231 | + untouchedByUser=len(in_sep_dir) - len(modified_images), |
| 232 | + addedByUser=len(added_by_user), |
| 233 | + separatedByUser=len(modified_images) - len(cleared_images), |
| 234 | + clearedByUser=len(cleared_images), |
| 235 | + ) |
| 236 | + result.append(stats_for_scan) |
| 237 | + |
| 238 | + return result |
| 239 | + |
| 240 | + |
171 | 241 | @router.get("/{project_hash}/background/{background_id}") |
172 | 242 | async def get_image_for_background( |
173 | 243 | project_hash: str, |
|
0 commit comments