Skip to content

Commit df766d6

Browse files
committed
dev(export):expose some data which is needed for exporting to EcoTaxa
1 parent 9ce6502 commit df766d6

File tree

4 files changed

+68
-46
lines changed

4 files changed

+68
-46
lines changed

src/ZooProcess_lib/Extractor.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,29 @@ def extract_all_with_border_to_dir(
4242
for index, a_roi in enumerate(rois, 1):
4343
img = self.extract_image_at_ROI(image, a_roi, True)
4444
resized_img = self._add_border_and_legend(img, longline)
45-
for extension in [".png"]:
46-
img_filename = (
47-
naming_prefix + "_" + unique_visible_key(a_roi) + extension
48-
)
49-
img_path = destination_dir / img_filename
50-
if extension == ".jpg":
51-
# Convert the image to 3 channels before saving, like legacy
52-
img_to_save = cv2.merge([resized_img, resized_img, resized_img])
53-
else:
54-
# Save 1 byte/pixel, grey
55-
img_to_save = resized_img
45+
img_filename = self.vignette_name(a_roi, naming_prefix)
46+
img_path = destination_dir / img_filename
47+
# Save 1 byte/pixel, grey
48+
img_to_save = resized_img
49+
save_jpg_or_png_image(
50+
img_to_save,
51+
resolution,
52+
img_path,
53+
)
54+
if False:
55+
# Convert the image to 3 channels before saving, like legacy
56+
# Note: unreachable code kept for later
57+
img_to_save_3chan = cv2.merge([resized_img, resized_img, resized_img])
5658
save_jpg_or_png_image(
57-
img_to_save,
59+
img_to_save_3chan,
5860
resolution,
59-
img_path,
61+
img_path[:-4] + ".jpg",
6062
)
6163

64+
@staticmethod
65+
def vignette_name(a_roi, naming_prefix):
66+
return naming_prefix + "_" + unique_visible_key(a_roi) + ".png"
67+
6268
def extract_all_to_images(
6369
self,
6470
image: np.ndarray,

src/ZooProcess_lib/Features.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,3 +449,41 @@ def legacy_measures_list_from_roi_list(
449449
Features(image, resolution, p, self.threshold).as_measures(only)
450450
for p in roi_list
451451
]
452+
453+
def ecotaxa_measures_list_from_roi_list(
454+
self,
455+
image: ndarray,
456+
resolution: int,
457+
roi_list: List[ROI],
458+
) -> list[dict[str, int | float]]:
459+
return [
460+
Features(image, resolution, p, self.threshold).as_ecotaxa()
461+
for p in roi_list
462+
]
463+
464+
465+
ECOTAXA_TSV_ROUNDINGS = { # from Zooscan_print_pid_5.txt
466+
"object_major": 1,
467+
"object_minor": 1,
468+
"object_angle": 1,
469+
"object_feret": 1,
470+
"object_x": 2,
471+
"object_y": 2,
472+
"object_xm": 2,
473+
"object_ym": 2,
474+
"object_perim.": 2,
475+
"object_%area": 2,
476+
"object_mean": 2,
477+
"object_stddev": 3,
478+
"object_circ.": 3,
479+
"object_skew": 3,
480+
"object_kurt": 3,
481+
"object_fractal": 3,
482+
"object_slope": 3,
483+
"object_fcons": 3,
484+
"object_symetrieh": 3,
485+
"object_symetriev": 3,
486+
"object_thickr": 3,
487+
}
488+
ECOTAXA_TSV_ROUNDINGS.update
489+
{"object_meanpos": 3}

src/ZooProcess_lib/Segmenter.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,20 @@ def get_mask_from_image(self, image: ndarray) -> np.ndarray:
6060
# mask is black (255) objects on white (0) background, it's for human eye
6161
return mask
6262

63+
@staticmethod
64+
def pixel_size(resolution):
65+
return 25.4 / resolution
66+
6367
def find_ROIs_in_image(
6468
self, image: ndarray, resolution: int, method: int = METH_TOP_CONTOUR_SPLIT
6569
) -> Tuple[List[ROI], List[int]]:
6670
""":return: (list of ROIs, elimination statistics i.e. number of particles eliminated at different stages)"""
67-
pixel = 25.4 / resolution
71+
pixel_sz = self.pixel_size(resolution)
6872
sm_min = (3.1416 / 4) * pow(self.minsize, 2)
6973
sm_max = (3.1416 / 4) * pow(self.maxsize, 2)
7074
# part_size_* are in pixel^2
71-
part_size_min: int = round(sm_min / (pow(pixel, 2)))
72-
part_size_max: int = round(sm_max / (pow(pixel, 2)))
75+
part_size_min: int = round(sm_min / (pow(pixel_sz, 2)))
76+
part_size_max: int = round(sm_max / (pow(pixel_sz, 2)))
7377
assert image.dtype == np.uint8
7478
height, width = image.shape[:2]
7579
# Threshold the source image to have a b&w mask

tests/test_calculators.py

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
from math import exp
22

3-
import cv2
43
import numpy as np
54
import pytest
65

7-
from ZooProcess_lib.Features import Features, TYPE_BY_ECOTAXA
6+
from ZooProcess_lib.Features import Features, TYPE_BY_ECOTAXA, ECOTAXA_TSV_ROUNDINGS
87
from ZooProcess_lib.ROI import ecotaxa_tsv_unq
98
from ZooProcess_lib.Segmenter import Segmenter
109
from ZooProcess_lib.calculators.Custom import fractal_mp, ij_perimeter
@@ -68,33 +67,6 @@ def test_ij_like_perimeter():
6867
assert round(perim, 3) == 359.772
6968

7069

71-
ECOTAXA_TSV_ROUNDINGS = { # from Zooscan_print_pid_5.txt
72-
"object_major": 1,
73-
"object_minor": 1,
74-
"object_angle": 1,
75-
"object_feret": 1,
76-
"object_x": 2,
77-
"object_y": 2,
78-
"object_xm": 2,
79-
"object_ym": 2,
80-
"object_perim.": 2,
81-
"object_%area": 2,
82-
"object_mean": 2,
83-
"object_stddev": 3,
84-
"object_circ.": 3,
85-
"object_skew": 3,
86-
"object_kurt": 3,
87-
"object_fractal": 3,
88-
"object_slope": 3,
89-
"object_fcons": 3,
90-
"object_symetrieh": 3,
91-
"object_symetriev": 3,
92-
"object_thickr": 3,
93-
}
94-
ECOTAXA_TSV_ROUNDINGS.update
95-
{"object_meanpos": 3}
96-
97-
9870
@pytest.mark.parametrize(
9971
"img",
10072
[
@@ -106,7 +78,9 @@ def test_ij_like_features(img: str):
10678
image = loadimage(MEASURES_DIR / f"crop_{img}.png")
10779
THRESHOLD = 243
10880
segmenter = Segmenter(0.3, 100, THRESHOLD)
109-
rois, _ = segmenter.find_ROIs_in_cropped_image(image, 2400, Segmenter.METH_TOP_CONTOUR_SPLIT)
81+
rois, _ = segmenter.find_ROIs_in_cropped_image(
82+
image, 2400, Segmenter.METH_TOP_CONTOUR_SPLIT
83+
)
11084
assert len(rois) == 1
11185
feat = Features(image=image, resolution=2400, roi=rois[0], threshold=THRESHOLD)
11286
exp = read_ecotaxa_tsv(FEATURES_DIR / f"ecotaxa_{img}.tsv", TYPE_BY_ECOTAXA)

0 commit comments

Comments
 (0)