-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDetectors.py
118 lines (90 loc) · 3.91 KB
/
Detectors.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from IPython.display import display
from collections import Counter
from ultralytics import YOLO
from PIL import Image
import sys
from dataclasses import dataclass, field
import torch
@dataclass
class ScanResult:
wbc: Counter = field(default_factory=Counter)
rbc: int = 0
class Singleton(type):
# https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class WhiteBloodCellDetector(metaclass=Singleton):
def __init__(self, classify_model_path, DEBUG=False):
self.CONFIDENCE_THRESHOLD = {"L": 0.5, "M": 0.25, "N": 0.1, "E": 0.8, "B": 0.1}
self.DETECTION_SIZE = 1024
self.IMAGE_SIZE_RATIO_THRESHOLD = 0.5
self.DEBUG = DEBUG
self.DEVICE = "0" if torch.cuda.is_available() else "cpu"
self.cmodel = YOLO(classify_model_path)
def is_gpu(self) -> bool:
return self.DEVICE != "cpu"
def detect(self, image: Image) -> Counter:
wbcs = Counter()
r = self.cmodel(image, device=self.DEVICE, imgsz=self.DETECTION_SIZE, verbose=False)[0] # results always a list of length 1
if self.DEBUG:
im_array = r.plot() # plot wbcs
im = Image.fromarray(im_array[..., ::-1])
if 'ipykernel' in sys.modules:
display(im) # show image
else:
im.show()
if self.is_gpu():
r.boxes = r.boxes.cpu()
r.boxes = r.boxes.numpy()
for conf, xywh, cls in zip(r.boxes.conf, r.boxes.xywh, r.boxes.cls):
_, _, width, height = xywh
wbc_classname = r.names[cls]
if conf > self.CONFIDENCE_THRESHOLD[wbc_classname] and (self.IMAGE_SIZE_RATIO_THRESHOLD < width / height < 1 / self.IMAGE_SIZE_RATIO_THRESHOLD):
wbcs[wbc_classname] += 1
return wbcs
class RedBloodCellDetector(metaclass=Singleton):
def __init__(self, detect_model_path, DEBUG=False):
self.CONFIDENCE_THRESHOLD = 0.4
self.IMAGE_SIZE_RATIO_THRESHOLD = 0.7
self.DEVICE = "0" if torch.cuda.is_available() else "cpu"
self.DEBUG = DEBUG
self.model = YOLO(detect_model_path)
def is_gpu(self) -> bool:
return self.DEVICE != "cpu"
def detect(self, image: Image) -> int:
rbc = 0
r = self.model(image, device=self.DEVICE, verbose=False)[0] # results always a list of length 1
if self.DEBUG:
im_array = r.plot(font_size=0.01, line_width=1) # plot rbcs
im = Image.fromarray(im_array[..., ::-1])
if 'ipykernel' in sys.modules:
display(im) # show image in Jupyter Notebook
else:
im.show() # show image
if self.is_gpu():
r.boxes = r.boxes.cpu()
r.boxes = r.boxes.numpy()
for conf, xywh in zip(r.boxes.conf, r.boxes.xywh):
_, _, width, height = xywh
if conf > self.CONFIDENCE_THRESHOLD and height > 0 and (self.IMAGE_SIZE_RATIO_THRESHOLD < width / height < 1 / self.IMAGE_SIZE_RATIO_THRESHOLD):
rbc += 1
return rbc
class BloodDensityDetector(metaclass=Singleton):
def __init__(self, density_model_path, DEBUG=False):
self.model = YOLO(density_model_path)
self.DEBUG = DEBUG
def hasGoodDensity(self, image: Image) -> int:
r = self.model(image, verbose=False)[0] # results always a list of length 1
if self.DEBUG:
im_array = r.plot(labels=False) # plot density
im = Image.fromarray(im_array[..., ::-1])
if 'ipykernel' in sys.modules:
display(im) # show image in Jupyter Notebook
else:
im.show()
cls_idx = r.probs.top1
cls_name = r.names[cls_idx]
return cls_name == "Good"