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

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 

11 

12 

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) 

35 

36 

37 

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) 

42 

43 width = labeled_server.metadata.width 

44 

45 assert width == expected_width 

46 

47 labeled_server.close() 

48 

49 

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) 

54 

55 height = labeled_server.metadata.height 

56 

57 assert height == expected_height 

58 

59 labeled_server.close() 

60 

61 

62def test_image_width_with_no_downsample(): 

63 expected_width = sample_metadata.shape.x 

64 labeled_server = LabeledImageServer(sample_metadata, []) 

65 

66 width = labeled_server.metadata.width 

67 

68 assert width == expected_width 

69 

70 labeled_server.close() 

71 

72 

73def test_image_height_with_no_downsample(): 

74 expected_height = sample_metadata.shape.y 

75 labeled_server = LabeledImageServer(sample_metadata, []) 

76 

77 height = labeled_server.metadata.height 

78 

79 assert height == expected_height 

80 

81 labeled_server.close() 

82 

83 

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) 

94 

95 n_channels = labeled_server.metadata.n_channels 

96 

97 assert n_channels == expected_number_of_channels 

98 

99 labeled_server.close() 

100 

101 

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) 

112 

113 n_channels = labeled_server.metadata.n_channels 

114 

115 assert n_channels == expected_number_of_channels 

116 

117 labeled_server.close() 

118 

119 

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) 

134 

135 n_channels = labeled_server.metadata.n_channels 

136 

137 assert n_channels == expected_number_of_channels 

138 

139 labeled_server.close() 

140 

141 

142def test_image_n_timepoints(): 

143 expected_n_timepoints = 1 

144 labeled_server = LabeledImageServer(sample_metadata, []) 

145 

146 n_timepoints = labeled_server.metadata.n_timepoints 

147 

148 assert n_timepoints == expected_n_timepoints 

149 

150 labeled_server.close() 

151 

152 

153def test_image_n_z_slices(): 

154 expected_n_z_slices = 1 

155 labeled_server = LabeledImageServer(sample_metadata, []) 

156 

157 n_z_slices = labeled_server.metadata.n_z_slices 

158 

159 assert n_z_slices == expected_n_z_slices 

160 

161 labeled_server.close() 

162 

163 

164def test_image_n_resolutions(): 

165 expected_n_resolutions = 1 

166 labeled_server = LabeledImageServer(sample_metadata, []) 

167 

168 n_resolutions = labeled_server.metadata.n_resolutions 

169 

170 assert n_resolutions == expected_n_resolutions 

171 

172 labeled_server.close() 

173 

174 

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) 

179 

180 length_x = labeled_server.metadata.pixel_calibration.length_x.length 

181 

182 assert length_x == expected_length_x 

183 

184 labeled_server.close() 

185 

186 

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, []) 

190 

191 length_x = labeled_server.metadata.pixel_calibration.length_x.length 

192 

193 assert length_x == expected_length_x 

194 

195 labeled_server.close() 

196 

197 

198def test_dtype_when_not_multi_channel(): 

199 expected_dtype = np.uint32 

200 labeled_server = LabeledImageServer(sample_metadata, [], multichannel=False) 

201 

202 dtype = labeled_server.metadata.dtype 

203 

204 assert dtype == expected_dtype 

205 

206 labeled_server.close() 

207 

208 

209def test_dtype_when_multi_channel(): 

210 expected_dtype = bool 

211 labeled_server = LabeledImageServer(sample_metadata, [], multichannel=True) 

212 

213 dtype = labeled_server.metadata.dtype 

214 

215 assert dtype == expected_dtype 

216 

217 labeled_server.close() 

218 

219 

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) 

237 

238 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

239 

240 np.testing.assert_array_equal(image, expected_image) 

241 

242 

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]], 

258 

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]], 

265 

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]], 

272 

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) 

281 

282 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

283 

284 np.testing.assert_array_equal(image, expected_image) 

285 

286 

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) 

308 

309 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

310 

311 np.testing.assert_array_equal(image, expected_image) 

312 

313 

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) 

329 

330 image = labeled_server.read_region(downsample, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

331 

332 np.testing.assert_array_equal(image, expected_image) 

333 

334 

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) 

346 

347 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

348 

349 np.testing.assert_array_equal(image, expected_image) 

350 

351 

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) 

361 

362 image = labeled_server.read_region(downsample, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

363 

364 np.testing.assert_array_equal(image, expected_image) 

365 

366 

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) 

378 

379 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

380 

381 np.testing.assert_array_equal(image, expected_image) 

382 

383 

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) 

393 

394 image = labeled_server.read_region(downsample, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

395 

396 np.testing.assert_array_equal(image, expected_image) 

397 

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 ) 

411 

412 features = [ImageFeature(geojson.Polygon([rands()])) for i in range(max_objects)] 

413 labeled_server = LabeledImageServer(large_metadata, features, multichannel=False, downsample=downsample) 

414 

415 image = labeled_server.read_region(1, Region2D(0, 0, labeled_server.metadata.width, labeled_server.metadata.height)) 

416 

417 assert np.max(image) == max_objects 

418 

419 

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) 

431 

432 np.testing.assert_array_equal(image, expected_image) 

433 

434 

435 

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) 

448 

449 np.testing.assert_array_equal(image, expected_image) 

450 

451 

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) 

463 

464 np.testing.assert_array_equal(image, expected_image) 

465 

466 

467 

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) 

481 

482 np.testing.assert_array_equal(image, expected_image) 

483 

484 

485 

486 

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) 

502 

503 np.testing.assert_array_equal(image, expected_image) 

504 

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) 

520 

521 np.testing.assert_array_equal(image, expected_image) 

522 

523 

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]], 

532 

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) 

539 

540 np.testing.assert_array_equal(image, expected_image)