dsa-helpers 0.6.dev0__tar.gz → 0.7__tar.gz
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.
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/.gitignore +2 -1
- {dsa_helpers-0.6.dev0/dsa_helpers.egg-info → dsa_helpers-0.7}/PKG-INFO +1 -1
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/girder_utils.py +148 -5
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/mongo_utils.py +7 -1
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7/dsa_helpers.egg-info}/PKG-INFO +1 -1
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/pyproject.toml +1 -1
- dsa_helpers-0.7/tests/test.ipynb +209 -0
- dsa_helpers-0.6.dev0/tests/test.ipynb +0 -133
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/LICENSE +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/README.md +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/app.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/dash/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/dash/dash_paperdragon_utils.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/dash/header.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/dash/header_callbacks.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/image_utils.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/imread.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/imwrite.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/datasets/SegFormerSegmentationDataset.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/datasets/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/datasets/utils.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/metrics/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/metrics/binary_dice_coefficient_metric.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/object_detection/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/object_detection/get_pearce_roi_images.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/object_detection/tile_image.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/object_detection/utils.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/segformer_semantic_segmentation/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/segformer_semantic_segmentation/inference.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/transforms/__init__.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/ml/transforms/segformer_transforms.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers/utils.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers.egg-info/SOURCES.txt +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers.egg-info/dependency_links.txt +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers.egg-info/requires.txt +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/dsa_helpers.egg-info/top_level.txt +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/requirements.txt +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/setup.cfg +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/tests/app/Dockerfile +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/tests/app/app.py +0 -0
- {dsa_helpers-0.6.dev0 → dsa_helpers-0.7}/tests/docker-compose.yaml +0 -0
|
@@ -63,7 +63,9 @@ def get_thumbnail(
|
|
|
63
63
|
elif len(fill) == 4:
|
|
64
64
|
fill = f"rgba({fill[0]},{fill[1]},{fill[2]},{fill[3]})"
|
|
65
65
|
|
|
66
|
-
params.extend(
|
|
66
|
+
params.extend(
|
|
67
|
+
[f"width={width}", f"height={height}", f"fill={fill}"]
|
|
68
|
+
)
|
|
67
69
|
elif width is not None:
|
|
68
70
|
params.append(f"width={width}")
|
|
69
71
|
elif height is not None:
|
|
@@ -246,7 +248,10 @@ def _rotate_point_list(point_list, rotation, center=(0, 0)):
|
|
|
246
248
|
y = point[1] - center[1]
|
|
247
249
|
|
|
248
250
|
point_list_rotated.append(
|
|
249
|
-
(
|
|
251
|
+
(
|
|
252
|
+
int(x * cos - y * sin + center[0]),
|
|
253
|
+
int(x * sin + y * cos + center[1]),
|
|
254
|
+
)
|
|
250
255
|
)
|
|
251
256
|
|
|
252
257
|
return point_list_rotated
|
|
@@ -274,12 +279,19 @@ def get_rectangle_element_coords(element):
|
|
|
274
279
|
x_max = center_x + w // 2
|
|
275
280
|
y_min = center_y - h // 2
|
|
276
281
|
y_max = center_y + h // 2
|
|
277
|
-
corner_coords = [
|
|
282
|
+
corner_coords = [
|
|
283
|
+
(x_min, y_min),
|
|
284
|
+
(x_max, y_min),
|
|
285
|
+
(x_max, y_max),
|
|
286
|
+
(x_min, y_max),
|
|
287
|
+
]
|
|
278
288
|
|
|
279
289
|
# if there is rotation rotate
|
|
280
290
|
if element["rotation"]:
|
|
281
291
|
corner_coords = _rotate_point_list(
|
|
282
|
-
corner_coords,
|
|
292
|
+
corner_coords,
|
|
293
|
+
rotation=element["rotation"],
|
|
294
|
+
center=(center_x, center_y),
|
|
283
295
|
)
|
|
284
296
|
|
|
285
297
|
corner_coords = np.array(corner_coords, dtype=np.int32)
|
|
@@ -332,7 +344,13 @@ def get_items(gc: GirderClient, parend_id: str) -> list[dict]:
|
|
|
332
344
|
list[dict]: The list of items.
|
|
333
345
|
|
|
334
346
|
"""
|
|
335
|
-
params = {
|
|
347
|
+
params = {
|
|
348
|
+
"type": "folder",
|
|
349
|
+
"limit": 0,
|
|
350
|
+
"offset": 0,
|
|
351
|
+
"sort": "_id",
|
|
352
|
+
"sortdir": 1,
|
|
353
|
+
}
|
|
336
354
|
|
|
337
355
|
request_url = f"resource/{parend_id}/items"
|
|
338
356
|
|
|
@@ -344,3 +362,128 @@ def get_items(gc: GirderClient, parend_id: str) -> list[dict]:
|
|
|
344
362
|
items = gc.get(request_url, parameters=params)
|
|
345
363
|
|
|
346
364
|
return items
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def get_roi_with_yolo_labels_from_single_doc(
|
|
368
|
+
gc: GirderClient,
|
|
369
|
+
ann_doc: dict,
|
|
370
|
+
roi_element_group: str,
|
|
371
|
+
group_map: dict[str, int],
|
|
372
|
+
mag: float | None = None,
|
|
373
|
+
rgb_fill: tuple[int, int, int] = (114, 114, 114),
|
|
374
|
+
) -> tuple[np.ndarray, str]:
|
|
375
|
+
"""Get the ROI image with the YOLO labels given a DSA annotation document.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
gc (girder_client.GirderClient): Authenticated girder client.
|
|
379
|
+
ann_doc (dict): Annotation document metadata.
|
|
380
|
+
roi_element_group (str): The group name of the ROI element.
|
|
381
|
+
group_map (dict[str, int]): Mapping of group names to group IDs.
|
|
382
|
+
mag (float, optional): The magnification to use for the ROI. Defaults to
|
|
383
|
+
None which uses the default magnification.
|
|
384
|
+
rgb_fill (tuple[int, int, int], optional): The RGB color to fill the ROI
|
|
385
|
+
with. Defaults to (114, 114, 114).
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
tuple[np.ndarray, str]: The ROI image and YOLO labels data as string.
|
|
389
|
+
|
|
390
|
+
Raises:
|
|
391
|
+
ValueError: If multiple ROI elements are found in the document.
|
|
392
|
+
ValueError: If ROI element type is not polyline.
|
|
393
|
+
|
|
394
|
+
"""
|
|
395
|
+
roi_element = None
|
|
396
|
+
box_elements = []
|
|
397
|
+
|
|
398
|
+
# Loop through all elements in the annotation document.
|
|
399
|
+
for element in ann_doc.get("annotation", {}).get("elements", []):
|
|
400
|
+
if element.get("group") == roi_element_group:
|
|
401
|
+
# Append the ROI element, there can't more than one.
|
|
402
|
+
if roi_element is not None:
|
|
403
|
+
raise ValueError("Multiple ROI elements found in the document.")
|
|
404
|
+
|
|
405
|
+
roi_element = element
|
|
406
|
+
elif element.get("group") in group_map:
|
|
407
|
+
# Append the box elements.
|
|
408
|
+
box_elements.append(element)
|
|
409
|
+
|
|
410
|
+
# Get the large image metadata.
|
|
411
|
+
large_image_metadata = get_item_large_image_metadata(gc, ann_doc["itemId"])
|
|
412
|
+
scan_mag = large_image_metadata["magnification"]
|
|
413
|
+
|
|
414
|
+
# Specify magnification to use.
|
|
415
|
+
if mag is None:
|
|
416
|
+
mag = scan_mag
|
|
417
|
+
|
|
418
|
+
# Calculate the factor to convert from scan mag to desired mag.
|
|
419
|
+
sf = mag / scan_mag
|
|
420
|
+
|
|
421
|
+
# Get the ROI image.
|
|
422
|
+
if roi_element.get("type") == "polyline":
|
|
423
|
+
# Grab the smallest bounding box.
|
|
424
|
+
points = np.array(roi_element["points"])[:, :2] # remove z-axis
|
|
425
|
+
roi_x1, roi_y1 = points.min(axis=0)
|
|
426
|
+
roi_x2, roi_y2 = points.max(axis=0)
|
|
427
|
+
|
|
428
|
+
img = get_region(
|
|
429
|
+
gc,
|
|
430
|
+
ann_doc["itemId"],
|
|
431
|
+
roi_x1,
|
|
432
|
+
roi_y1,
|
|
433
|
+
roi_x2 - roi_x1,
|
|
434
|
+
roi_y2 - roi_y1,
|
|
435
|
+
mag=mag,
|
|
436
|
+
)[
|
|
437
|
+
:, :, :3
|
|
438
|
+
] # make sure it is RGB
|
|
439
|
+
|
|
440
|
+
# Shift the points to be relative to smallest bounding box.
|
|
441
|
+
points -= [roi_x1, roi_y1]
|
|
442
|
+
|
|
443
|
+
# Create a mask and draw the ROI filled on it (handles rotated ROIs).
|
|
444
|
+
mask = np.zeros(img.shape[:2], dtype=np.uint8)
|
|
445
|
+
mask = cv.drawContours(
|
|
446
|
+
mask, [(points * sf).astype(np.int32)], 0, 1, cv.FILLED
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
# Gray out regions outside of ROI.
|
|
450
|
+
img[np.where(mask == 0)] = rgb_fill
|
|
451
|
+
else:
|
|
452
|
+
raise ValueError("Only polyline ROIs are supported.")
|
|
453
|
+
|
|
454
|
+
roi_h, roi_w = img.shape[:2]
|
|
455
|
+
|
|
456
|
+
# Convert the box elements into YOLO format.
|
|
457
|
+
labels_data = ""
|
|
458
|
+
|
|
459
|
+
for element in box_elements:
|
|
460
|
+
if element.get("group") in group_map:
|
|
461
|
+
if element.get("type") != "rectangle":
|
|
462
|
+
print(f"Skipping element: {element.get('type')} not supported.")
|
|
463
|
+
continue
|
|
464
|
+
|
|
465
|
+
group_id = group_map[element.get("group")]
|
|
466
|
+
|
|
467
|
+
# Get the center of box and shift to be relative to ROI.
|
|
468
|
+
x_center, y_center = (
|
|
469
|
+
np.array(element["center"])[:2] - [roi_x1, roi_y1]
|
|
470
|
+
) * sf
|
|
471
|
+
|
|
472
|
+
# Normalize the coordinates.
|
|
473
|
+
x_center /= roi_w
|
|
474
|
+
y_center /= roi_h
|
|
475
|
+
|
|
476
|
+
# Scale the box width and height and then normalize.
|
|
477
|
+
width, height = (
|
|
478
|
+
element["width"] * sf / roi_w,
|
|
479
|
+
element["height"] * sf / roi_h,
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
labels_data += f"{group_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n"
|
|
483
|
+
else:
|
|
484
|
+
print(
|
|
485
|
+
f"Skipping element: group {element.get('group')} not found in group map."
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
# Return the ROI image and labels data.
|
|
489
|
+
return img, labels_data.strip()
|
|
@@ -9,6 +9,7 @@ from typing import Union
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def get_mongo_client(
|
|
12
|
+
protocol: str | None = None,
|
|
12
13
|
host: str | None = None,
|
|
13
14
|
username: str | None = None,
|
|
14
15
|
password: str | None = None,
|
|
@@ -20,6 +21,9 @@ def get_mongo_client(
|
|
|
20
21
|
not present it sets them to default values.
|
|
21
22
|
|
|
22
23
|
Args:
|
|
24
|
+
protocol (str, optional): The protocol of the mongo server. If None it
|
|
25
|
+
look for the environment variable "MONGO_PROTOCOL". If this is
|
|
26
|
+
missing it will default to "mongodb".
|
|
23
27
|
host (str, optional): The host name of the mongo server. If None it will
|
|
24
28
|
look for the environment variable "MONGO_HOST_NAME". If this is
|
|
25
29
|
missing it will default to "mongodb".
|
|
@@ -39,6 +43,8 @@ def get_mongo_client(
|
|
|
39
43
|
The mongo client.
|
|
40
44
|
|
|
41
45
|
"""
|
|
46
|
+
if protocol is None:
|
|
47
|
+
protocol = getenv("MONGO_PROTOCOL", "mongodb")
|
|
42
48
|
if username is None:
|
|
43
49
|
username = getenv("MONGO_INITDB_ROOT_USERNAME", "docker")
|
|
44
50
|
if password is None:
|
|
@@ -48,7 +54,7 @@ def get_mongo_client(
|
|
|
48
54
|
if port is None:
|
|
49
55
|
port = int(getenv("MONGO_HOST_PORT", 27017))
|
|
50
56
|
|
|
51
|
-
return pymongo.MongoClient(f"
|
|
57
|
+
return pymongo.MongoClient(f"{protocol}://{username}:{password}@{host}:{port}")
|
|
52
58
|
|
|
53
59
|
|
|
54
60
|
def chunks(lst: list, n=500):
|