Coverage for tests/images/test_labeled_server.py: 100%
233 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-31 11:24 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-31 11:24 +0000
1import geojson
2import numpy as np
3import random
4from qubalab.objects.image_feature import ImageFeature
5from qubalab.objects.classification import Classification
6from qubalab.images.labeled_server import LabeledImageServer
7from qubalab.images.region_2d import Region2D
8from qubalab.images.metadata.image_metadata import ImageMetadata
9from qubalab.images.metadata.image_shape import ImageShape
10from qubalab.images.metadata.pixel_calibration import PixelCalibration, PixelLength
13sample_metadata = ImageMetadata(
14 "/path/to/img.tiff",
15 "Image name",
16 (ImageShape(10, 6),),
17 PixelCalibration(
18 PixelLength.create_microns(2.5),
19 PixelLength.create_microns(2.5)
20 ),
21 True,
22 np.uint8
23)
24large_metadata = ImageMetadata(
25 "/path/to/img.tiff",
26 "Image name",
27 (ImageShape(500, 250),),
28 PixelCalibration(
29 PixelLength.create_microns(2.5),
30 PixelLength.create_microns(2.5)
31 ),
32 True,
33 np.uint8
34)
38def test_image_width_with_downsample():
39 downsample = 1.5
40 expected_width = sample_metadata.shape.x
41 labeled_server = LabeledImageServer(sample_metadata, [], downsample=downsample)
43 width = labeled_server.metadata.width
45 assert width == expected_width
47 labeled_server.close()
50def test_image_height_with_downsample():
51 downsample = 1.5
52 expected_height = sample_metadata.shape.y
53 labeled_server = LabeledImageServer(sample_metadata, [], downsample=downsample)
55 height = labeled_server.metadata.height
57 assert height == expected_height
59 labeled_server.close()
62def test_image_width_with_no_downsample():
63 expected_width = sample_metadata.shape.x
64 labeled_server = LabeledImageServer(sample_metadata, [])
66 width = labeled_server.metadata.width
68 assert width == expected_width
70 labeled_server.close()
73def test_image_height_with_no_downsample():
74 expected_height = sample_metadata.shape.y
75 labeled_server = LabeledImageServer(sample_metadata, [])
77 height = labeled_server.metadata.height
79 assert height == expected_height
81 labeled_server.close()
84def test_number_of_channels_when_not_multichannel():
85 some_classification = Classification("Some classification")
86 some_other_classification = Classification("Some other classification")
87 features = [
88 ImageFeature(geojson.Point((2, 5)), some_classification),
89 ImageFeature(geojson.Point((5, 7)), some_classification),
90 ImageFeature(geojson.Point((17, 7)), some_other_classification),
91 ]
92 expected_number_of_channels = 1
93 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False)
95 n_channels = labeled_server.metadata.n_channels
97 assert n_channels == expected_number_of_channels
99 labeled_server.close()
102def test_number_of_channels_when_multi_channel_and_no_label_map_given():
103 some_classification = Classification("Some classification")
104 some_other_classification = Classification("Some other classification")
105 features = [
106 ImageFeature(geojson.Point((2, 5)), some_classification),
107 ImageFeature(geojson.Point((5, 7)), some_classification),
108 ImageFeature(geojson.Point((17, 7)), some_other_classification),
109 ]
110 expected_number_of_channels = 4
111 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=True)
113 n_channels = labeled_server.metadata.n_channels
115 assert n_channels == expected_number_of_channels
117 labeled_server.close()
120def test_number_of_channels_when_multi_channel_and_label_map_given():
121 some_classification = Classification("Some classification")
122 some_other_classification = Classification("Some other classification")
123 features = [
124 ImageFeature(geojson.Point((2, 5)), some_classification),
125 ImageFeature(geojson.Point((5, 7)), some_classification),
126 ImageFeature(geojson.Point((17, 7)), some_other_classification),
127 ]
128 label_map = {
129 some_classification: 1,
130 some_other_classification: 2,
131 }
132 expected_number_of_channels = 3
133 labeled_server = LabeledImageServer(sample_metadata, features, label_map=label_map, multichannel=True)
135 n_channels = labeled_server.metadata.n_channels
137 assert n_channels == expected_number_of_channels
139 labeled_server.close()
142def test_image_n_timepoints():
143 expected_n_timepoints = 1
144 labeled_server = LabeledImageServer(sample_metadata, [])
146 n_timepoints = labeled_server.metadata.n_timepoints
148 assert n_timepoints == expected_n_timepoints
150 labeled_server.close()
153def test_image_n_z_slices():
154 expected_n_z_slices = 1
155 labeled_server = LabeledImageServer(sample_metadata, [])
157 n_z_slices = labeled_server.metadata.n_z_slices
159 assert n_z_slices == expected_n_z_slices
161 labeled_server.close()
164def test_image_n_resolutions():
165 expected_n_resolutions = 1
166 labeled_server = LabeledImageServer(sample_metadata, [])
168 n_resolutions = labeled_server.metadata.n_resolutions
170 assert n_resolutions == expected_n_resolutions
172 labeled_server.close()
175def test_x_pixel_length_with_downsample():
176 downsample = 1.5
177 expected_length_x = sample_metadata.pixel_calibration.length_x.length
178 labeled_server = LabeledImageServer(sample_metadata, [], downsample=downsample)
180 length_x = labeled_server.metadata.pixel_calibration.length_x.length
182 assert length_x == expected_length_x
184 labeled_server.close()
187def test_x_pixel_length_with_no_downsample():
188 expected_length_x = sample_metadata.pixel_calibration.length_x.length
189 labeled_server = LabeledImageServer(sample_metadata, [])
191 length_x = labeled_server.metadata.pixel_calibration.length_x.length
193 assert length_x == expected_length_x
195 labeled_server.close()
198def test_dtype_when_not_multi_channel():
199 expected_dtype = np.uint32
200 labeled_server = LabeledImageServer(sample_metadata, [], multichannel=False)
202 dtype = labeled_server.metadata.dtype
204 assert dtype == expected_dtype
206 labeled_server.close()
209def test_dtype_when_multi_channel():
210 expected_dtype = bool
211 labeled_server = LabeledImageServer(sample_metadata, [], multichannel=True)
213 dtype = labeled_server.metadata.dtype
215 assert dtype == expected_dtype
217 labeled_server.close()
220def test_read_points_in_single_channel_image_without_label_map_without_downsample():
221 some_classification = Classification("Some classification")
222 some_other_classification = Classification("Some other classification")
223 features = [
224 ImageFeature(geojson.Point((5, 2)), some_classification),
225 ImageFeature(geojson.Point((7, 4)), some_classification),
226 ImageFeature(geojson.Point((1, 0)), some_other_classification),
227 ]
228 expected_image = np.array(
229 [[[0, 3, 0, 0, 0, 0, 0, 0, 0, 0],
230 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
231 [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
232 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
233 [0, 0, 0, 0, 0, 0, 0, 2, 0, 0],
234 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]
235 )
236 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False)
238 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
240 np.testing.assert_array_equal(image, expected_image)
243def test_read_points_in_multi_channel_image_without_label_map_without_downsample():
244 some_classification = Classification("Some classification")
245 some_other_classification = Classification("Some other classification")
246 features = [
247 ImageFeature(geojson.Point((5, 2)), some_classification),
248 ImageFeature(geojson.Point((7, 4)), some_classification),
249 ImageFeature(geojson.Point((1, 0)), some_other_classification),
250 ]
251 expected_image = np.array(
252 [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
253 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
254 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
255 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
256 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
257 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
259 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
260 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
261 [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
262 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
263 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
264 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
266 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
267 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
268 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
269 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
270 [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
271 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
273 [[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
274 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
275 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
276 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
277 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
278 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]
279 )
280 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=True)
282 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
284 np.testing.assert_array_equal(image, expected_image)
287def test_read_points_in_single_channel_image_with_label_map_without_downsample():
288 some_classification = Classification("Some classification")
289 some_other_classification = Classification("Some other classification")
290 features = [
291 ImageFeature(geojson.Point((5, 2)), some_classification),
292 ImageFeature(geojson.Point((7, 4)), some_classification),
293 ImageFeature(geojson.Point((1, 0)), some_other_classification),
294 ]
295 label_map = {
296 some_classification: 1,
297 some_other_classification: 2,
298 }
299 expected_image = np.array(
300 [[[0, 2, 0, 0, 0, 0, 0, 0, 0, 0],
301 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
302 [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
303 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
304 [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
305 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]
306 )
307 labeled_server = LabeledImageServer(sample_metadata, features, label_map=label_map, multichannel=False)
309 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
311 np.testing.assert_array_equal(image, expected_image)
314def test_read_points_in_single_channel_image_without_label_map_with_downsample():
315 downsample = 2
316 some_classification = Classification("Some classification")
317 some_other_classification = Classification("Some other classification")
318 features = [
319 ImageFeature(geojson.Point((6, 2)), some_classification),
320 ImageFeature(geojson.Point((8, 4)), some_classification),
321 ImageFeature(geojson.Point((2, 0)), some_other_classification),
322 ]
323 expected_image = np.array(
324 [[[0, 3, 0, 0, 0],
325 [0, 0, 0, 1, 0],
326 [0, 0, 0, 0, 2]]]
327 )
328 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False, downsample=downsample)
330 image = labeled_server.read_region(downsample, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
332 np.testing.assert_array_equal(image, expected_image)
335def test_read_line_in_single_channel_image_without_label_map_without_downsample():
336 features = [ImageFeature(geojson.LineString([(6, 2), (8, 2)]), Classification("Some classification"))]
337 expected_image = np.array(
338 [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
339 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
340 [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
341 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
342 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
343 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]
344 )
345 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False)
347 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
349 np.testing.assert_array_equal(image, expected_image)
352def test_read_line_in_single_channel_image_without_label_map_with_downsample():
353 downsample = 2
354 features = [ImageFeature(geojson.LineString([(6, 2), (8, 2)]), Classification("Some classification"))]
355 expected_image = np.array(
356 [[[0, 0, 0, 0, 0],
357 [0, 0, 0, 1, 1],
358 [0, 0, 0, 0, 0]]]
359 )
360 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False, downsample=downsample)
362 image = labeled_server.read_region(downsample, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
364 np.testing.assert_array_equal(image, expected_image)
367def test_read_polygon_in_single_channel_image_without_label_map_without_downsample():
368 features = [ImageFeature(geojson.Polygon([[(6, 2), (8, 2), (8, 4), (4, 4)]]), Classification("Some classification"))]
369 expected_image = np.array(
370 [[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
371 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
372 [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
373 [0, 0, 0, 0, 0, 1, 1, 1, 1, 0],
374 [0, 0, 0, 0, 1, 1, 1, 1, 1, 0],
375 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]
376 )
377 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False)
379 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
381 np.testing.assert_array_equal(image, expected_image)
384def test_read_polygon_in_single_channel_image_without_label_map_with_downsample():
385 downsample = 2
386 features = [ImageFeature(geojson.Polygon([[(6, 2), (8, 2), (8, 4), (4, 4)]]), Classification("Some classification"))]
387 expected_image = np.array(
388 [[[0, 0, 0, 0, 0],
389 [0, 0, 0, 1, 1],
390 [0, 0, 1, 1, 1]]]
391 )
392 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False, downsample=downsample)
394 image = labeled_server.read_region(downsample, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
396 np.testing.assert_array_equal(image, expected_image)
398def test_label_can_hold_many_values():
399 downsample = 1
400 max_objects = 1000
401 random.seed(1)
402 def rands():
403 x = random.randint(0, int(large_metadata.shape.x / downsample))
404 y = random.randint(0, int(large_metadata.shape.x / downsample))
405 return (
406 (x, y),
407 (x + 1, y),
408 (x + 1, y + 1),
409 (x, y + 1)
410 )
412 features = [ImageFeature(geojson.Polygon([rands()])) for i in range(max_objects)]
413 labeled_server = LabeledImageServer(large_metadata, features, multichannel=False, downsample=downsample)
415 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height))
417 assert np.max(image) == max_objects
420def test_single_channel_labeled_image_with_region_request():
421 downsample = 1
422 features = [ImageFeature(geojson.LineString([(7, 5), (9, 5)]))]
423 expected_image = np.array(
424 [[[0, 0, 0, 0, 0],
425 [0, 0, 0, 0, 0],
426 [0, 0, 1, 1, 1]]]
427 )
428 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False, downsample=downsample)
429 region = Region2D(5, 3, labeled_server.metadata.width-5, labeled_server.metadata.height-3)
430 image = labeled_server.read_region(1, region)
432 np.testing.assert_array_equal(image, expected_image)
436def test_single_channel_labeled_image_with_starting_downsample():
437 features = [ImageFeature(geojson.LineString([(6, 5), (9, 5)]))]
438 # when resizing, we lose the labels with bicubic
439 expected_image = np.array(
440 [[[0, 0, 0, 0, 0],
441 [0, 0, 0, 0, 0],
442 [0, 0, 0, 1, 1]]]
443 )
444 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False, downsample=1)
445 downsample = 2
446 region = Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)
447 image = labeled_server.read_region(downsample, region)
449 np.testing.assert_array_equal(image, expected_image)
452def test_single_channel_labeled_image_with_request_downsample():
453 # we downsample
454 features = [ImageFeature(geojson.LineString([(6, 5), (9, 5)]))]
455 expected_image = np.array(
456 [[[0, 0, 0, 0, 0],
457 [0, 0, 0, 0, 0],
458 [0, 0, 0, 1, 1]]]
459 )
460 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=False, downsample=1)
461 region = Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)
462 image = labeled_server.read_region(2, region)
464 np.testing.assert_array_equal(image, expected_image)
468def test_multi_channel_labeled_image_with_region_request():
469 features = [ImageFeature(geojson.LineString([(7, 5), (9, 5)]))]
470 expected_image = np.array(
471 [[[False, False, False, False, False],
472 [False, False, False, False, False],
473 [False, False, False, False, False]],
474 [[False, False, False, False, False],
475 [False, False, False, False, False],
476 [False, False, True, True, True]]]
477 )
478 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=True, downsample=1)
479 region = Region2D(5, 3, labeled_server.metadata.width-5, labeled_server.metadata.height-3)
480 image = labeled_server.read_region(1, region)
482 np.testing.assert_array_equal(image, expected_image)
487def test_multi_channel_labeled_image_with_starting_downsample():
488 # we downsample the feature, then request at the same downsample
489 features = [ImageFeature(geojson.LineString([(6, 5), (9, 5)]))]
490 expected_image = np.array(
491 [[[False, False, False, False, False],
492 [False, False, False, False, False],
493 [False, False, False, False, False]],
494 [[False, False, False, False, False],
495 [False, False, False, False, False],
496 [False, False, False, True, True]]]
497 )
498 downsample = 2
499 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=True, downsample=downsample)
500 region = Region2D(0, 0, sample_metadata.width, sample_metadata.height)
501 image = labeled_server.read_region(2, region)
503 np.testing.assert_array_equal(image, expected_image)
505def test_multi_channel_labeled_image_with_request_downsample():
506 features = [ImageFeature(geojson.LineString([(6, 5), (9, 5)]))]
507 ## because we resize the image after reading, we lose the small region
508 expected_image = np.array(
509 [[[False, False, False, False, False],
510 [False, False, False, False, False],
511 [False, False, False, False, False]],
512 [[False, False, False, False, False],
513 [False, False, False, False, False],
514 [False, False, False, False, False]]]
515 )
516 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=True, downsample=1)
517 downsample = 2
518 region = Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)
519 image = labeled_server.read_region(downsample, region)
521 np.testing.assert_array_equal(image, expected_image)
524def test_multi_channel_labeled_image_with_starting_downsample_upsampled():
525 # we downsample the feature, then request at a downsample of 1, so upsampled!
526 # therefore the feature gets much bigger
527 features = [ImageFeature(geojson.LineString([(5, 5), (9, 5)]))]
528 expected_image = np.array(
529 [[[False, False, False, False, False],
530 [False, False, False, False, False],
531 [False, False, False, False, False]],
533 [[False, False, False, False, False],
534 [False, False, False, False, False],
535 [False, False, True, True, True]]]
536 )
537 labeled_server = LabeledImageServer(sample_metadata, features, multichannel=True, downsample=2)
538 image = labeled_server.read_region(2)
540 np.testing.assert_array_equal(image, expected_image)