napari-microplate 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- napari_microplate/__init__.py +3 -0
- napari_microplate/_dock.py +113 -0
- napari_microplate/_models.py +39 -0
- napari_microplate/_pipeline.py +194 -0
- napari_microplate/_vendor/ultralytics/__init__.py +30 -0
- napari_microplate/_vendor/ultralytics/cfg/__init__.py +873 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/Argoverse.yaml +74 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/DOTAv1.5.yaml +36 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/DOTAv1.yaml +35 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/GlobalWheat2020.yaml +53 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/ImageNet.yaml +2024 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/Objects365.yaml +442 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/SKU-110K.yaml +57 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/VOC.yaml +99 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/VisDrone.yaml +72 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/african-wildlife.yaml +24 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/brain-tumor.yaml +22 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/carparts-seg.yaml +43 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/coco-pose.yaml +38 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/coco.yaml +114 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/coco128-seg.yaml +100 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/coco128.yaml +100 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/coco8-pose.yaml +25 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/coco8-seg.yaml +100 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/coco8.yaml +100 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/crack-seg.yaml +21 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/dota8.yaml +34 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/hand-keypoints.yaml +25 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/lvis.yaml +1235 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/open-images-v7.yaml +660 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/package-seg.yaml +21 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/signature.yaml +20 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/tiger-pose.yaml +24 -0
- napari_microplate/_vendor/ultralytics/cfg/datasets/xView.yaml +152 -0
- napari_microplate/_vendor/ultralytics/cfg/default.yaml +128 -0
- napari_microplate/_vendor/ultralytics/cfg/models/11/yolo11-cls.yaml +30 -0
- napari_microplate/_vendor/ultralytics/cfg/models/11/yolo11-obb.yaml +47 -0
- napari_microplate/_vendor/ultralytics/cfg/models/11/yolo11-pose.yaml +48 -0
- napari_microplate/_vendor/ultralytics/cfg/models/11/yolo11-seg.yaml +47 -0
- napari_microplate/_vendor/ultralytics/cfg/models/11/yolo11.yaml +47 -0
- napari_microplate/_vendor/ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +50 -0
- napari_microplate/_vendor/ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +54 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v10/yolov10b.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v10/yolov10l.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v10/yolov10m.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v10/yolov10n.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v10/yolov10s.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v10/yolov10x.yaml +42 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v3/yolov3-spp.yaml +46 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v3/yolov3-tiny.yaml +37 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v3/yolov3.yaml +46 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v5/yolov5-p6.yaml +59 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v5/yolov5.yaml +48 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v6/yolov6.yaml +53 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +25 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +25 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-cls.yaml +29 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +54 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +56 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-ghost.yaml +47 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-obb.yaml +46 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-p2.yaml +54 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-p6.yaml +56 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +57 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-pose.yaml +47 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +46 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +56 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-seg.yaml +46 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-world.yaml +48 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8-worldv2.yaml +46 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v8/yolov8.yaml +46 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v9/yolov9c-seg.yaml +38 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v9/yolov9c.yaml +38 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v9/yolov9e-seg.yaml +61 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v9/yolov9e.yaml +61 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v9/yolov9m.yaml +38 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v9/yolov9s.yaml +38 -0
- napari_microplate/_vendor/ultralytics/cfg/models/v9/yolov9t.yaml +38 -0
- napari_microplate/_vendor/ultralytics/cfg/trackers/botsort.yaml +18 -0
- napari_microplate/_vendor/ultralytics/cfg/trackers/bytetrack.yaml +11 -0
- napari_microplate/_vendor/ultralytics/data/__init__.py +26 -0
- napari_microplate/_vendor/ultralytics/data/annotator.py +54 -0
- napari_microplate/_vendor/ultralytics/data/augment.py +2740 -0
- napari_microplate/_vendor/ultralytics/data/base.py +314 -0
- napari_microplate/_vendor/ultralytics/data/build.py +207 -0
- napari_microplate/_vendor/ultralytics/data/converter.py +637 -0
- napari_microplate/_vendor/ultralytics/data/dataset.py +532 -0
- napari_microplate/_vendor/ultralytics/data/explorer/__init__.py +5 -0
- napari_microplate/_vendor/ultralytics/data/explorer/explorer.py +460 -0
- napari_microplate/_vendor/ultralytics/data/explorer/gui/__init__.py +1 -0
- napari_microplate/_vendor/ultralytics/data/explorer/gui/dash.py +282 -0
- napari_microplate/_vendor/ultralytics/data/explorer/utils.py +167 -0
- napari_microplate/_vendor/ultralytics/data/loaders.py +577 -0
- napari_microplate/_vendor/ultralytics/data/split_dota.py +298 -0
- napari_microplate/_vendor/ultralytics/data/utils.py +673 -0
- napari_microplate/_vendor/ultralytics/engine/__init__.py +1 -0
- napari_microplate/_vendor/ultralytics/engine/exporter.py +1196 -0
- napari_microplate/_vendor/ultralytics/engine/model.py +1130 -0
- napari_microplate/_vendor/ultralytics/engine/predictor.py +434 -0
- napari_microplate/_vendor/ultralytics/engine/results.py +1741 -0
- napari_microplate/_vendor/ultralytics/engine/trainer.py +822 -0
- napari_microplate/_vendor/ultralytics/engine/tuner.py +241 -0
- napari_microplate/_vendor/ultralytics/engine/validator.py +346 -0
- napari_microplate/_vendor/ultralytics/hub/__init__.py +146 -0
- napari_microplate/_vendor/ultralytics/hub/auth.py +140 -0
- napari_microplate/_vendor/ultralytics/hub/google/__init__.py +159 -0
- napari_microplate/_vendor/ultralytics/hub/session.py +390 -0
- napari_microplate/_vendor/ultralytics/hub/utils.py +246 -0
- napari_microplate/_vendor/ultralytics/models/__init__.py +9 -0
- napari_microplate/_vendor/ultralytics/models/fastsam/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/fastsam/model.py +55 -0
- napari_microplate/_vendor/ultralytics/models/fastsam/predict.py +146 -0
- napari_microplate/_vendor/ultralytics/models/fastsam/utils.py +24 -0
- napari_microplate/_vendor/ultralytics/models/fastsam/val.py +40 -0
- napari_microplate/_vendor/ultralytics/models/nas/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/nas/model.py +94 -0
- napari_microplate/_vendor/ultralytics/models/nas/predict.py +57 -0
- napari_microplate/_vendor/ultralytics/models/nas/val.py +50 -0
- napari_microplate/_vendor/ultralytics/models/rtdetr/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/rtdetr/model.py +54 -0
- napari_microplate/_vendor/ultralytics/models/rtdetr/predict.py +84 -0
- napari_microplate/_vendor/ultralytics/models/rtdetr/train.py +102 -0
- napari_microplate/_vendor/ultralytics/models/rtdetr/val.py +135 -0
- napari_microplate/_vendor/ultralytics/models/sam/__init__.py +6 -0
- napari_microplate/_vendor/ultralytics/models/sam/amg.py +193 -0
- napari_microplate/_vendor/ultralytics/models/sam/build.py +350 -0
- napari_microplate/_vendor/ultralytics/models/sam/model.py +175 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/__init__.py +1 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/blocks.py +1129 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/decoders.py +518 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/encoders.py +794 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/memory_attention.py +237 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/sam.py +956 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/tiny_encoder.py +1012 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/transformer.py +373 -0
- napari_microplate/_vendor/ultralytics/models/sam/modules/utils.py +293 -0
- napari_microplate/_vendor/ultralytics/models/sam/predict.py +787 -0
- napari_microplate/_vendor/ultralytics/models/utils/__init__.py +1 -0
- napari_microplate/_vendor/ultralytics/models/utils/loss.py +358 -0
- napari_microplate/_vendor/ultralytics/models/utils/ops.py +259 -0
- napari_microplate/_vendor/ultralytics/models/yolo/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/yolo/classify/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/yolo/classify/predict.py +64 -0
- napari_microplate/_vendor/ultralytics/models/yolo/classify/train.py +154 -0
- napari_microplate/_vendor/ultralytics/models/yolo/classify/val.py +113 -0
- napari_microplate/_vendor/ultralytics/models/yolo/detect/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/yolo/detect/predict.py +41 -0
- napari_microplate/_vendor/ultralytics/models/yolo/detect/train.py +143 -0
- napari_microplate/_vendor/ultralytics/models/yolo/detect/val.py +338 -0
- napari_microplate/_vendor/ultralytics/models/yolo/model.py +111 -0
- napari_microplate/_vendor/ultralytics/models/yolo/obb/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/yolo/obb/predict.py +53 -0
- napari_microplate/_vendor/ultralytics/models/yolo/obb/train.py +42 -0
- napari_microplate/_vendor/ultralytics/models/yolo/obb/val.py +203 -0
- napari_microplate/_vendor/ultralytics/models/yolo/pose/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/yolo/pose/predict.py +56 -0
- napari_microplate/_vendor/ultralytics/models/yolo/pose/train.py +79 -0
- napari_microplate/_vendor/ultralytics/models/yolo/pose/val.py +282 -0
- napari_microplate/_vendor/ultralytics/models/yolo/segment/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/models/yolo/segment/predict.py +55 -0
- napari_microplate/_vendor/ultralytics/models/yolo/segment/train.py +62 -0
- napari_microplate/_vendor/ultralytics/models/yolo/segment/val.py +318 -0
- napari_microplate/_vendor/ultralytics/models/yolo/world/__init__.py +5 -0
- napari_microplate/_vendor/ultralytics/models/yolo/world/train.py +92 -0
- napari_microplate/_vendor/ultralytics/models/yolo/world/train_world.py +109 -0
- napari_microplate/_vendor/ultralytics/nn/__init__.py +29 -0
- napari_microplate/_vendor/ultralytics/nn/autobackend.py +671 -0
- napari_microplate/_vendor/ultralytics/nn/modules/__init__.py +159 -0
- napari_microplate/_vendor/ultralytics/nn/modules/activation.py +21 -0
- napari_microplate/_vendor/ultralytics/nn/modules/block.py +1108 -0
- napari_microplate/_vendor/ultralytics/nn/modules/conv.py +332 -0
- napari_microplate/_vendor/ultralytics/nn/modules/head.py +597 -0
- napari_microplate/_vendor/ultralytics/nn/modules/transformer.py +427 -0
- napari_microplate/_vendor/ultralytics/nn/modules/utils.py +84 -0
- napari_microplate/_vendor/ultralytics/nn/tasks.py +1183 -0
- napari_microplate/_vendor/ultralytics/solutions/__init__.py +24 -0
- napari_microplate/_vendor/ultralytics/solutions/ai_gym.py +127 -0
- napari_microplate/_vendor/ultralytics/solutions/analytics.py +307 -0
- napari_microplate/_vendor/ultralytics/solutions/distance_calculation.py +139 -0
- napari_microplate/_vendor/ultralytics/solutions/heatmap.py +259 -0
- napari_microplate/_vendor/ultralytics/solutions/object_counter.py +243 -0
- napari_microplate/_vendor/ultralytics/solutions/parking_management.py +241 -0
- napari_microplate/_vendor/ultralytics/solutions/queue_management.py +127 -0
- napari_microplate/_vendor/ultralytics/solutions/speed_estimation.py +116 -0
- napari_microplate/_vendor/ultralytics/solutions/streamlit_inference.py +149 -0
- napari_microplate/_vendor/ultralytics/trackers/__init__.py +7 -0
- napari_microplate/_vendor/ultralytics/trackers/basetrack.py +124 -0
- napari_microplate/_vendor/ultralytics/trackers/bot_sort.py +233 -0
- napari_microplate/_vendor/ultralytics/trackers/byte_tracker.py +476 -0
- napari_microplate/_vendor/ultralytics/trackers/track.py +104 -0
- napari_microplate/_vendor/ultralytics/trackers/utils/__init__.py +1 -0
- napari_microplate/_vendor/ultralytics/trackers/utils/gmc.py +377 -0
- napari_microplate/_vendor/ultralytics/trackers/utils/kalman_filter.py +491 -0
- napari_microplate/_vendor/ultralytics/trackers/utils/matching.py +158 -0
- napari_microplate/_vendor/ultralytics/utils/__init__.py +1298 -0
- napari_microplate/_vendor/ultralytics/utils/autobatch.py +91 -0
- napari_microplate/_vendor/ultralytics/utils/benchmarks.py +574 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/__init__.py +5 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/base.py +217 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/clearml.py +153 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/comet.py +374 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/dvc.py +145 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/hub.py +112 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/mlflow.py +137 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/neptune.py +112 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/raytune.py +29 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/tensorboard.py +107 -0
- napari_microplate/_vendor/ultralytics/utils/callbacks/wb.py +163 -0
- napari_microplate/_vendor/ultralytics/utils/checks.py +754 -0
- napari_microplate/_vendor/ultralytics/utils/dist.py +72 -0
- napari_microplate/_vendor/ultralytics/utils/downloads.py +507 -0
- napari_microplate/_vendor/ultralytics/utils/errors.py +22 -0
- napari_microplate/_vendor/ultralytics/utils/files.py +222 -0
- napari_microplate/_vendor/ultralytics/utils/instance.py +416 -0
- napari_microplate/_vendor/ultralytics/utils/loss.py +745 -0
- napari_microplate/_vendor/ultralytics/utils/metrics.py +1291 -0
- napari_microplate/_vendor/ultralytics/utils/ops.py +834 -0
- napari_microplate/_vendor/ultralytics/utils/patches.py +104 -0
- napari_microplate/_vendor/ultralytics/utils/plotting.py +1357 -0
- napari_microplate/_vendor/ultralytics/utils/tal.py +355 -0
- napari_microplate/_vendor/ultralytics/utils/torch_utils.py +721 -0
- napari_microplate/_vendor/ultralytics/utils/triton.py +92 -0
- napari_microplate/_vendor/ultralytics/utils/tuner.py +152 -0
- napari_microplate/_viz.py +58 -0
- napari_microplate/_weights.py +81 -0
- napari_microplate/napari.yaml +10 -0
- napari_microplate-0.1.0.dist-info/METADATA +157 -0
- napari_microplate-0.1.0.dist-info/RECORD +234 -0
- napari_microplate-0.1.0.dist-info/WHEEL +5 -0
- napari_microplate-0.1.0.dist-info/entry_points.txt +2 -0
- napari_microplate-0.1.0.dist-info/licenses/LICENSE +651 -0
- napari_microplate-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""napari dock widget cho full microplate pipeline.
|
|
2
|
+
|
|
3
|
+
npe2 manifest trỏ tới `MicroplateWidget` (callable trả widget). Khi click "Run
|
|
4
|
+
Pipeline": lấy ảnh từ layer đang chọn → chạy 3 stage → thêm 2 layer (plate
|
|
5
|
+
aligned image + wells shapes màu theo class) + thông báo counts + tuỳ chọn save PNG.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
from magicgui import magic_factory
|
|
12
|
+
|
|
13
|
+
from ._pipeline import CLASS_COLORS, CLASS_NAMES, get_pipeline
|
|
14
|
+
from ._viz import draw_result, save_png
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _to_gray_uint8(data):
|
|
18
|
+
"""Ép dữ liệu layer napari về uint8 grayscale 2D."""
|
|
19
|
+
arr = np.asarray(data)
|
|
20
|
+
if arr.ndim == 3: # (H,W,3) hoặc (H,W,4)
|
|
21
|
+
if arr.shape[-1] >= 3:
|
|
22
|
+
# napari dùng RGB; OpenCV muốn BGR → đảo kênh cho đúng trước gray
|
|
23
|
+
arr = arr[..., :3][..., ::-1]
|
|
24
|
+
arr = arr.mean(axis=-1) if arr.ndim == 3 else arr
|
|
25
|
+
if arr.dtype != np.uint8:
|
|
26
|
+
arr = arr.astype(np.float32)
|
|
27
|
+
if arr.max() <= 1.0:
|
|
28
|
+
arr = arr * 255.0
|
|
29
|
+
arr = np.clip(arr, 0, 255).astype(np.uint8)
|
|
30
|
+
return arr
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _bgr_to_rgb01(bgr):
|
|
34
|
+
"""BGR uint8 (0..255) → RGB float (0..1) cho face_color của napari Shapes."""
|
|
35
|
+
r, g, b = int(bgr[2]), int(bgr[1]), int(bgr[0])
|
|
36
|
+
return (r / 255.0, g / 255.0, b / 255.0, 1.0)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@magic_factory(
|
|
40
|
+
call_button="Run Pipeline",
|
|
41
|
+
layout="vertical",
|
|
42
|
+
input_layer={"label": "Image layer"},
|
|
43
|
+
save_png={"label": "Save PNG"},
|
|
44
|
+
save_dir={"label": "Save dir", "mode": "d"},
|
|
45
|
+
)
|
|
46
|
+
def _pipeline_widget(
|
|
47
|
+
viewer: "napari.Viewer",
|
|
48
|
+
input_layer: "napari.layers.Image",
|
|
49
|
+
save_png: bool = False,
|
|
50
|
+
save_dir: Path = Path.home(),
|
|
51
|
+
):
|
|
52
|
+
if input_layer is None:
|
|
53
|
+
from napari.utils.notifications import warning
|
|
54
|
+
warning("Chọn 1 image layer chứa ảnh microplate raw trước.")
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
from napari.utils.notifications import info
|
|
58
|
+
|
|
59
|
+
img_gray = _to_gray_uint8(input_layer.data)
|
|
60
|
+
|
|
61
|
+
pipe = get_pipeline()
|
|
62
|
+
out = pipe.run_array(img_gray)
|
|
63
|
+
|
|
64
|
+
# ── Layer 1: plate aligned (grayscale image) ──
|
|
65
|
+
# Gỡ layer cũ cùng tên để chạy lại không chồng
|
|
66
|
+
for nm in ("aligned_plate", "wells"):
|
|
67
|
+
if nm in viewer.layers:
|
|
68
|
+
del viewer.layers[nm]
|
|
69
|
+
viewer.add_image(out['plate'], name="aligned_plate", colormap="gray")
|
|
70
|
+
|
|
71
|
+
# ── Layer 2: well bbox (shapes), màu theo class ──
|
|
72
|
+
rects = []
|
|
73
|
+
face_colors = []
|
|
74
|
+
for (x1, y1, x2, y2, _), cls in zip(out['boxes'], out['classes']):
|
|
75
|
+
# napari toạ độ theo (row, col) = (y, x)
|
|
76
|
+
rects.append(np.array([[y1, x1], [y1, x2], [y2, x2], [y2, x1]]))
|
|
77
|
+
name = CLASS_NAMES.get(int(cls), 'NoGrowth')
|
|
78
|
+
face_colors.append(_bgr_to_rgb01(CLASS_COLORS[name]))
|
|
79
|
+
|
|
80
|
+
counts = {'Growth': 0, 'NoGrowth': 0, 'NoAgar': 0}
|
|
81
|
+
for cls in out['classes']:
|
|
82
|
+
counts[CLASS_NAMES.get(int(cls), 'NoGrowth')] += 1
|
|
83
|
+
|
|
84
|
+
if rects:
|
|
85
|
+
viewer.add_shapes(
|
|
86
|
+
rects,
|
|
87
|
+
shape_type="rectangle",
|
|
88
|
+
face_color=face_colors,
|
|
89
|
+
edge_color="white",
|
|
90
|
+
edge_width=1,
|
|
91
|
+
opacity=0.35,
|
|
92
|
+
name="wells",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
msg = (f"Total wells: {len(out['boxes'])} — "
|
|
96
|
+
f"Growth={counts['Growth']} "
|
|
97
|
+
f"NoGrowth={counts['NoGrowth']} "
|
|
98
|
+
f"NoAgar={counts['NoAgar']}")
|
|
99
|
+
info(msg)
|
|
100
|
+
print(msg)
|
|
101
|
+
|
|
102
|
+
if save_png:
|
|
103
|
+
canvas, _ = draw_result(out, show_labels=True)
|
|
104
|
+
save_dir = Path(save_dir)
|
|
105
|
+
save_dir.mkdir(parents=True, exist_ok=True)
|
|
106
|
+
stem = Path(str(input_layer.name)).stem or "result"
|
|
107
|
+
out_path = save_dir / f"pipeline_{stem}.png"
|
|
108
|
+
save_png(canvas, out_path)
|
|
109
|
+
info(f"Đã lưu: {out_path}")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# npe2 trỏ tới callable này — magic_factory trả widget mới mỗi lần gọi.
|
|
113
|
+
MicroplateWidget = _pipeline_widget
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Định nghĩa model Stage 1 (EfficientNet corner regression) — port từ full_pipeline.ipynb."""
|
|
2
|
+
|
|
3
|
+
import timm
|
|
4
|
+
import torch
|
|
5
|
+
import torch.nn as nn
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EfficientNetCorner(nn.Module):
|
|
9
|
+
"""EfficientNet-B3 backbone + regression head xuất 4 corner (8 giá trị, sigmoid).
|
|
10
|
+
|
|
11
|
+
Input: ảnh grayscale 1 kênh. gray_to_rgb (conv 1x1) nhân bản thành 3 kênh
|
|
12
|
+
trước khi đưa vào backbone timm.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, variant='b3', dropout=0.0):
|
|
16
|
+
super().__init__()
|
|
17
|
+
self.gray_to_rgb = nn.Conv2d(1, 3, kernel_size=1, bias=False)
|
|
18
|
+
nn.init.constant_(self.gray_to_rgb.weight, 1.0 / 3.0)
|
|
19
|
+
self.backbone = timm.create_model(
|
|
20
|
+
f'efficientnet_{variant}', pretrained=False,
|
|
21
|
+
num_classes=0, global_pool='avg',
|
|
22
|
+
)
|
|
23
|
+
feat_dim = self.backbone.num_features
|
|
24
|
+
self.head = nn.Sequential(
|
|
25
|
+
nn.Linear(feat_dim, 512), nn.SiLU(inplace=True), nn.Dropout(p=dropout),
|
|
26
|
+
nn.Linear(512, 256), nn.SiLU(inplace=True), nn.Dropout(p=dropout * 0.5),
|
|
27
|
+
nn.Linear(256, 8), nn.Sigmoid(),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def forward(self, x):
|
|
31
|
+
return self.head(self.backbone(self.gray_to_rgb(x)))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def order_corners_tl_tr_br_bl(pts):
|
|
35
|
+
"""Sort 4 (x,y) points → TL, TR, BR, BL (consistent warp target)."""
|
|
36
|
+
by_y = sorted(pts, key=lambda p: p[1])
|
|
37
|
+
top = sorted(by_y[:2], key=lambda p: p[0])
|
|
38
|
+
bot = sorted(by_y[2:], key=lambda p: p[0])
|
|
39
|
+
return [top[0], top[1], bot[1], bot[0]]
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Full microplate pipeline: Stage 1 align → Stage 2 detect → Stage 3 classify.
|
|
2
|
+
|
|
3
|
+
Port từ full_pipeline.ipynb. Đổi: nhận array grayscale trực tiếp (run_array) để
|
|
4
|
+
dùng trong napari widget mà không cần ghi file tạm. Models lazy-load 1 lần.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import cv2
|
|
12
|
+
import joblib
|
|
13
|
+
import numpy as np
|
|
14
|
+
import torch
|
|
15
|
+
import torch.nn as nn
|
|
16
|
+
|
|
17
|
+
from ._models import EfficientNetCorner, order_corners_tl_tr_br_bl
|
|
18
|
+
from ._weights import resolve_weight
|
|
19
|
+
|
|
20
|
+
# ── Fork ultralytics ch=1 được VENDOR trong package (napari_microplate/_vendor).
|
|
21
|
+
# Đưa _vendor lên đầu sys.path để `import ultralytics` (và các absolute import
|
|
22
|
+
# nội bộ của nó) resolve về bản vendor này, không bị nhầm với pip package. ──
|
|
23
|
+
_VENDOR_DIR = Path(__file__).resolve().parent / "_vendor"
|
|
24
|
+
if str(_VENDOR_DIR) not in sys.path:
|
|
25
|
+
sys.path.insert(0, str(_VENDOR_DIR))
|
|
26
|
+
|
|
27
|
+
# ─────────────────────────────────────────────
|
|
28
|
+
# CONFIG — khớp 1:1 với notebook (đừng sửa lẻ tẻ)
|
|
29
|
+
# ─────────────────────────────────────────────
|
|
30
|
+
STAGE1_VARIANT = 'b3'
|
|
31
|
+
STAGE1_IMG_SIZE = 896
|
|
32
|
+
|
|
33
|
+
STAGE2_CONF = 0.05
|
|
34
|
+
STAGE2_IOU = 0.15
|
|
35
|
+
STAGE2_MAX = 384
|
|
36
|
+
|
|
37
|
+
STAGE3_SIZE = 64
|
|
38
|
+
|
|
39
|
+
# Phải khớp generate_stage2_data.py (PLATE_MARGIN = 0.08).
|
|
40
|
+
PLATE_MARGIN = 0.08
|
|
41
|
+
|
|
42
|
+
CLASS_NAMES = {0: 'Growth', 1: 'NoGrowth', 2: 'NoAgar'}
|
|
43
|
+
CLASS_COLORS = { # BGR
|
|
44
|
+
'Growth': (0, 180, 0),
|
|
45
|
+
'NoGrowth': (0, 0, 220),
|
|
46
|
+
'NoAgar': (200, 0, 200),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _get_device():
|
|
51
|
+
return torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class MicroplatePipeline:
|
|
55
|
+
"""Singleton-ish wrapper load 3 model lần đầu, cache lại cho các lần gọi sau."""
|
|
56
|
+
|
|
57
|
+
def __init__(self, device=None):
|
|
58
|
+
self.device = device or _get_device()
|
|
59
|
+
self._model1 = None # EfficientNetCorner
|
|
60
|
+
self._model2 = None # YOLO
|
|
61
|
+
self._rf_model = None # RandomForest
|
|
62
|
+
self._w1 = None
|
|
63
|
+
self._w2 = None
|
|
64
|
+
self._w3 = None
|
|
65
|
+
|
|
66
|
+
def _ensure_loaded(self):
|
|
67
|
+
if self._model1 is not None:
|
|
68
|
+
return
|
|
69
|
+
print('[MicroplatePipeline] loading models (lần đầu)...')
|
|
70
|
+
self._w1 = resolve_weight('stage1')
|
|
71
|
+
self._w2 = resolve_weight('stage2')
|
|
72
|
+
self._w3 = resolve_weight('stage3')
|
|
73
|
+
|
|
74
|
+
# Stage 1
|
|
75
|
+
self._model1 = EfficientNetCorner(variant=STAGE1_VARIANT, dropout=0.0).to(self.device)
|
|
76
|
+
ckpt = torch.load(str(self._w1), map_location=self.device)
|
|
77
|
+
state = ckpt['model_state'] if isinstance(ckpt, dict) and 'model_state' in ckpt else ckpt
|
|
78
|
+
self._model1.load_state_dict(state)
|
|
79
|
+
self._model1.eval()
|
|
80
|
+
|
|
81
|
+
# Stage 2 — import sau khi đã thêm fork lên sys.path
|
|
82
|
+
from ultralytics import YOLO
|
|
83
|
+
self._model2 = YOLO(str(self._w2))
|
|
84
|
+
|
|
85
|
+
# Stage 3
|
|
86
|
+
bundle = joblib.load(str(self._w3))
|
|
87
|
+
self._rf_model = bundle['model'] if isinstance(bundle, dict) and 'model' in bundle else bundle
|
|
88
|
+
|
|
89
|
+
dev = 'cuda' if self.device.type == 'cuda' else 'cpu'
|
|
90
|
+
print(f'[MicroplatePipeline] ready on {dev}')
|
|
91
|
+
|
|
92
|
+
# ── Stage 1 ──────────────────────────────
|
|
93
|
+
@torch.no_grad()
|
|
94
|
+
def _stage1_align_array(self, img_gray):
|
|
95
|
+
"""img_gray: 2D uint8. Trả (plate_gray, ordered_corners_px)."""
|
|
96
|
+
h_o, w_o = img_gray.shape[:2]
|
|
97
|
+
img_r = cv2.resize(img_gray, (STAGE1_IMG_SIZE, STAGE1_IMG_SIZE)).astype(np.float32) / 255.0
|
|
98
|
+
img_r = (img_r - 0.485) / 0.229
|
|
99
|
+
t = torch.from_numpy(img_r).unsqueeze(0).unsqueeze(0).to(self.device)
|
|
100
|
+
pred = self._model1(t).cpu().numpy().reshape(4, 2)
|
|
101
|
+
corners_px = pred * np.array([w_o, h_o])
|
|
102
|
+
ordered = np.array(order_corners_tl_tr_br_bl(corners_px.tolist()), dtype=np.float32)
|
|
103
|
+
|
|
104
|
+
w_top = np.linalg.norm(ordered[1] - ordered[0])
|
|
105
|
+
w_bottom = np.linalg.norm(ordered[2] - ordered[3])
|
|
106
|
+
h_left = np.linalg.norm(ordered[3] - ordered[0])
|
|
107
|
+
h_right = np.linalg.norm(ordered[2] - ordered[1])
|
|
108
|
+
plate_w = int(round((w_top + w_bottom) / 2))
|
|
109
|
+
plate_h = int(round((h_left + h_right) / 2))
|
|
110
|
+
|
|
111
|
+
out_w = int(round(plate_w * (1 + 2 * PLATE_MARGIN)))
|
|
112
|
+
out_h = int(round(plate_h * (1 + 2 * PLATE_MARGIN)))
|
|
113
|
+
pad_x = int(plate_w * PLATE_MARGIN)
|
|
114
|
+
pad_y = int(plate_h * PLATE_MARGIN)
|
|
115
|
+
dst = np.array([
|
|
116
|
+
[pad_x, pad_y],
|
|
117
|
+
[pad_x + plate_w - 1, pad_y],
|
|
118
|
+
[pad_x + plate_w - 1, pad_y + plate_h - 1],
|
|
119
|
+
[pad_x, pad_y + plate_h - 1],
|
|
120
|
+
], dtype=np.float32)
|
|
121
|
+
M = cv2.getPerspectiveTransform(ordered, dst)
|
|
122
|
+
plate = cv2.warpPerspective(img_gray, M, (out_w, out_h), borderValue=0)
|
|
123
|
+
return plate, ordered
|
|
124
|
+
|
|
125
|
+
# ── Stage 2 ──────────────────────────────
|
|
126
|
+
def _stage2_detect(self, plate_gray):
|
|
127
|
+
H, W = plate_gray.shape[:2]
|
|
128
|
+
res = self._model2(plate_gray, conf=STAGE2_CONF, iou=STAGE2_IOU,
|
|
129
|
+
max_det=STAGE2_MAX, verbose=False, ch=1)[0]
|
|
130
|
+
boxes = []
|
|
131
|
+
if res.boxes is not None and len(res.boxes):
|
|
132
|
+
for b in res.boxes:
|
|
133
|
+
x1, y1, x2, y2 = b.xyxy[0].cpu().numpy().astype(int)
|
|
134
|
+
conf = float(b.conf[0])
|
|
135
|
+
boxes.append((int(x1), int(y1), int(x2), int(y2), conf))
|
|
136
|
+
return boxes
|
|
137
|
+
|
|
138
|
+
# ── Stage 3 ──────────────────────────────
|
|
139
|
+
def _stage3_classify(self, plate_gray, boxes, margin_ratio=0.05):
|
|
140
|
+
if not boxes:
|
|
141
|
+
return []
|
|
142
|
+
H, W = plate_gray.shape[:2]
|
|
143
|
+
crops = []
|
|
144
|
+
for (x1, y1, x2, y2, _) in boxes:
|
|
145
|
+
cx, cy = (x1 + x2) / 2, (y1 + y2) / 2
|
|
146
|
+
bw, bh = x2 - x1, y2 - y1
|
|
147
|
+
half_w = bw * (1 + 2 * margin_ratio) / 2
|
|
148
|
+
half_h = bh * (1 + 2 * margin_ratio) / 2
|
|
149
|
+
x1c, y1c = int(cx - half_w), int(cy - half_h)
|
|
150
|
+
x2c, y2c = int(cx + half_w), int(cy + half_h)
|
|
151
|
+
x1c, y1c = max(0, x1c), max(0, y1c)
|
|
152
|
+
x2c, y2c = min(W, x2c), min(H, y2c)
|
|
153
|
+
crop = (plate_gray[y1c:y2c, x1c:x2c]
|
|
154
|
+
if x2c > x1c and y2c > y1c
|
|
155
|
+
else np.zeros((STAGE3_SIZE, STAGE3_SIZE), dtype=np.uint8))
|
|
156
|
+
crop = cv2.resize(crop, (STAGE3_SIZE, STAGE3_SIZE), interpolation=cv2.INTER_AREA)
|
|
157
|
+
crops.append(crop)
|
|
158
|
+
X = np.stack(crops).reshape(-1, STAGE3_SIZE * STAGE3_SIZE).astype(np.float32) / 255.0
|
|
159
|
+
return list(self._rf_model.predict(X))
|
|
160
|
+
|
|
161
|
+
# ── Public API ───────────────────────────
|
|
162
|
+
def run_array(self, img_gray):
|
|
163
|
+
"""img_gray: 2D uint8 grayscale. Trả dict {plate, corners, boxes, classes}."""
|
|
164
|
+
self._ensure_loaded()
|
|
165
|
+
if img_gray.ndim == 3:
|
|
166
|
+
img_gray = cv2.cvtColor(img_gray, cv2.COLOR_BGR2GRAY)
|
|
167
|
+
plate, corners = self._stage1_align_array(img_gray)
|
|
168
|
+
boxes = self._stage2_detect(plate)
|
|
169
|
+
classes = self._stage3_classify(plate, boxes)
|
|
170
|
+
return {
|
|
171
|
+
'orig': img_gray,
|
|
172
|
+
'corners': corners,
|
|
173
|
+
'plate': plate,
|
|
174
|
+
'boxes': boxes,
|
|
175
|
+
'classes': classes,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
def run(self, img_path):
|
|
179
|
+
"""Tiện ích cho CLI/script: đọc file ảnh → run_array."""
|
|
180
|
+
img = cv2.imread(str(img_path), cv2.IMREAD_GRAYSCALE)
|
|
181
|
+
if img is None:
|
|
182
|
+
raise FileNotFoundError(img_path)
|
|
183
|
+
return self.run_array(img)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# Singleton module-level cho widget dùng chung
|
|
187
|
+
_DEFAULT = None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def get_pipeline():
|
|
191
|
+
global _DEFAULT
|
|
192
|
+
if _DEFAULT is None:
|
|
193
|
+
_DEFAULT = MicroplatePipeline()
|
|
194
|
+
return _DEFAULT
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Ultralytics YOLO 🚀, AGPL-3.0 license
|
|
2
|
+
|
|
3
|
+
__version__ = "8.3.2"
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
# Set ENV Variables (place before imports)
|
|
8
|
+
os.environ["OMP_NUM_THREADS"] = "1" # reduce CPU utilization during training
|
|
9
|
+
|
|
10
|
+
from ultralytics.data.explorer.explorer import Explorer
|
|
11
|
+
from ultralytics.models import NAS, RTDETR, SAM, YOLO, FastSAM, YOLOWorld
|
|
12
|
+
from ultralytics.utils import ASSETS, SETTINGS
|
|
13
|
+
from ultralytics.utils.checks import check_yolo as checks
|
|
14
|
+
from ultralytics.utils.downloads import download
|
|
15
|
+
|
|
16
|
+
settings = SETTINGS
|
|
17
|
+
__all__ = (
|
|
18
|
+
"__version__",
|
|
19
|
+
"ASSETS",
|
|
20
|
+
"YOLO",
|
|
21
|
+
"YOLOWorld",
|
|
22
|
+
"NAS",
|
|
23
|
+
"SAM",
|
|
24
|
+
"FastSAM",
|
|
25
|
+
"RTDETR",
|
|
26
|
+
"checks",
|
|
27
|
+
"download",
|
|
28
|
+
"settings",
|
|
29
|
+
"Explorer",
|
|
30
|
+
)
|