Coverage for /scratch/builds/bob/bob.ip.binseg/miniconda/conda-bld/bob.ip.binseg_1673966692152/_test_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_p/lib/python3.10/site-packages/bob/ip/common/test/test_transforms.py: 100%

239 statements  

« prev     ^ index     » next       coverage.py v7.0.5, created at 2023-01-17 15:03 +0000

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3 

4import os 

5import random 

6 

7import numpy 

8import PIL.Image 

9import PIL.ImageDraw 

10import PIL.ImageOps 

11import pkg_resources 

12import torch 

13import torchvision.transforms.functional 

14 

15from ..data.transforms import ( 

16 CenterCrop, 

17 ColorJitter, 

18 Compose, 

19 Crop, 

20 GaussianBlur, 

21 Pad, 

22 RandomHorizontalFlip, 

23 RandomRotation, 

24 RandomVerticalFlip, 

25 Resize, 

26 ShrinkIntoSquare, 

27 SingleAutoLevel16to8, 

28 ToTensor, 

29) 

30 

31 

32def _create_img(size): 

33 t = torch.randn(size) 

34 pil = torchvision.transforms.functional.to_pil_image(t) 

35 return pil 

36 

37 

38def test_center_crop(): 

39 

40 # parameters 

41 im_size = (3, 22, 20) # (planes, height, width) 

42 crop_size = (10, 12) # (height, width) 

43 

44 # test 

45 bh = (im_size[1] - crop_size[0]) // 2 

46 bw = (im_size[2] - crop_size[1]) // 2 

47 idx = (slice(bh, -bh), slice(bw, -bw), slice(0, im_size[0])) 

48 transforms = CenterCrop(crop_size) 

49 img, gt, mask = [_create_img(im_size) for i in range(3)] 

50 assert img.size == (im_size[2], im_size[1]) # confirms the above 

51 img_t, gt_t, mask_t = transforms(img, gt, mask) 

52 assert img_t.size == (crop_size[1], crop_size[0]) # confirms the above 

53 # notice that PIL->array does array.transpose(1, 2, 0) 

54 # so it creates an array that is (height, width, planes) 

55 assert numpy.all(numpy.array(img_t) == numpy.array(img)[idx]) 

56 assert numpy.all(numpy.array(gt_t) == numpy.array(gt)[idx]) 

57 assert numpy.all(numpy.array(mask_t) == numpy.array(mask)[idx]) 

58 

59 

60def test_center_crop_uneven(): 

61 

62 # parameters - WARNING: notice that modern implementations of centercrop in 

63 # torchvision (noticed with version 0.10.x) may provide slightly different 

64 # outputs depending on the multiplicity of pixels that need to be cropped 

65 # from both sides. In the current configuration, the output is such that 

66 # the centercrop is 0.5 pixel to the right/bottom from an actual center 

67 # crop. With other configurations, it may be that the crop is 0.5 pixel to 

68 # the left/top part of the image, which makes testing this function a bit 

69 # hard. If you have issues with this function, try different 

70 # configurations here, or to change the setting of "idx" a few lines down. 

71 im_size = (3, 21, 20) # (planes, height, width) 

72 crop_size = (10, 13) # (height, width) 

73 

74 # test 

75 bh = (im_size[1] - crop_size[0]) // 2 

76 bw = (im_size[2] - crop_size[1]) // 2 

77 # when the crop size is uneven, this is what happens - notice here that the 

78 # image height is uneven, and the crop width as well - the attributions of 

79 # extra pixels will depend on what is uneven (original image or crop) 

80 # crop is 0.5 pixel to the right/bottom: 

81 idx = (slice(bh + 1, -bh), slice(bw + 1, -bw), slice(0, im_size[0])) 

82 # crop is 0.5 pixel to the left/top: 

83 # idx = (slice(bh, -(bh + 1)), slice(bw, -(bw + 1)), slice(0, im_size[0])) 

84 transforms = CenterCrop(crop_size) 

85 img, gt, mask = [_create_img(im_size) for i in range(3)] 

86 assert img.size == (im_size[2], im_size[1]) # confirms the above 

87 img_t, gt_t, mask_t = transforms(img, gt, mask) 

88 assert img_t.size == (crop_size[1], crop_size[0]) # confirms the above 

89 # notice that PIL->array does array.transpose(1, 2, 0) 

90 # so it creates an array that is (height, width, planes) 

91 assert numpy.all(numpy.array(img_t) == numpy.array(img)[idx]) 

92 assert numpy.all(numpy.array(gt_t) == numpy.array(gt)[idx]) 

93 assert numpy.all(numpy.array(mask_t) == numpy.array(mask)[idx]) 

94 

95 

96def test_pad_default(): 

97 

98 # parameters 

99 im_size = (3, 22, 20) # (planes, height, width) 

100 pad_size = 2 

101 

102 # test 

103 idx = ( 

104 slice(pad_size, -pad_size), 

105 slice(pad_size, -pad_size), 

106 slice(0, im_size[0]), 

107 ) 

108 transforms = Pad(pad_size) 

109 img, gt, mask = [_create_img(im_size) for i in range(3)] 

110 assert img.size == (im_size[2], im_size[1]) # confirms the above 

111 img_t, gt_t, mask_t = transforms(img, gt, mask) 

112 # notice that PIL->array does array.transpose(1, 2, 0) 

113 # so it creates an array that is (height, width, planes) 

114 assert numpy.all(numpy.array(img_t)[idx] == numpy.array(img)) 

115 assert numpy.all(numpy.array(gt_t)[idx] == numpy.array(gt)) 

116 assert numpy.all(numpy.array(mask_t)[idx] == numpy.array(mask)) 

117 

118 # checks that the border introduced with padding is all about "fill" 

119 img_t = numpy.array(img_t) 

120 img_t[idx] = 0 

121 # border_size_plane = img_t[:, :, 0].size - numpy.array(img)[:, :, 0].size 

122 assert img_t.sum() == 0 

123 

124 gt_t = numpy.array(gt_t) 

125 gt_t[idx] = 0 

126 assert gt_t.sum() == 0 

127 

128 mask_t = numpy.array(mask_t) 

129 mask_t[idx] = 0 

130 assert mask_t.sum() == 0 

131 

132 

133def test_pad_2tuple(): 

134 

135 # parameters 

136 im_size = (3, 22, 20) # (planes, height, width) 

137 pad_size = (1, 2) # left/right, top/bottom 

138 fill = (3, 4, 5) 

139 

140 # test 

141 idx = ( 

142 slice(pad_size[1], -pad_size[1]), 

143 slice(pad_size[0], -pad_size[0]), 

144 slice(0, im_size[0]), 

145 ) 

146 transforms = Pad(pad_size, fill) 

147 img, gt, mask = [_create_img(im_size) for i in range(3)] 

148 assert img.size == (im_size[2], im_size[1]) # confirms the above 

149 img_t, gt_t, mask_t = transforms(img, gt, mask) 

150 # notice that PIL->array does array.transpose(1, 2, 0) 

151 # so it creates an array that is (height, width, planes) 

152 assert numpy.all(numpy.array(img_t)[idx] == numpy.array(img)) 

153 assert numpy.all(numpy.array(gt_t)[idx] == numpy.array(gt)) 

154 assert numpy.all(numpy.array(mask_t)[idx] == numpy.array(mask)) 

155 

156 # checks that the border introduced with padding is all about "fill" 

157 img_t = numpy.array(img_t) 

158 img_t[idx] = 0 

159 border_size_plane = img_t[:, :, 0].size - numpy.array(img)[:, :, 0].size 

160 expected_sum = sum((fill[k] * border_size_plane) for k in range(3)) 

161 assert img_t.sum() == expected_sum 

162 

163 gt_t = numpy.array(gt_t) 

164 gt_t[idx] = 0 

165 assert gt_t.sum() == expected_sum 

166 

167 mask_t = numpy.array(mask_t) 

168 mask_t[idx] = 0 

169 assert mask_t.sum() == expected_sum 

170 

171 

172def test_pad_4tuple(): 

173 

174 # parameters 

175 im_size = (3, 22, 20) # (planes, height, width) 

176 pad_size = (1, 2, 3, 4) # left, top, right, bottom 

177 fill = (3, 4, 5) 

178 

179 # test 

180 idx = ( 

181 slice(pad_size[1], -pad_size[3]), 

182 slice(pad_size[0], -pad_size[2]), 

183 slice(0, im_size[0]), 

184 ) 

185 transforms = Pad(pad_size, fill) 

186 img, gt, mask = [_create_img(im_size) for i in range(3)] 

187 assert img.size == (im_size[2], im_size[1]) # confirms the above 

188 img_t, gt_t, mask_t = transforms(img, gt, mask) 

189 # notice that PIL->array does array.transpose(1, 2, 0) 

190 # so it creates an array that is (height, width, planes) 

191 assert numpy.all(numpy.array(img_t)[idx] == numpy.array(img)) 

192 assert numpy.all(numpy.array(gt_t)[idx] == numpy.array(gt)) 

193 assert numpy.all(numpy.array(mask_t)[idx] == numpy.array(mask)) 

194 

195 # checks that the border introduced with padding is all about "fill" 

196 img_t = numpy.array(img_t) 

197 img_t[idx] = 0 

198 border_size_plane = img_t[:, :, 0].size - numpy.array(img)[:, :, 0].size 

199 expected_sum = sum((fill[k] * border_size_plane) for k in range(3)) 

200 assert img_t.sum() == expected_sum 

201 

202 gt_t = numpy.array(gt_t) 

203 gt_t[idx] = 0 

204 assert gt_t.sum() == expected_sum 

205 

206 mask_t = numpy.array(mask_t) 

207 mask_t[idx] = 0 

208 assert mask_t.sum() == expected_sum 

209 

210 

211def test_resize_downscale_w(): 

212 

213 # parameters 

214 im_size = (3, 22, 20) # (planes, height, width) 

215 new_size = 10 # (smallest edge) 

216 

217 # test 

218 transforms = Resize(new_size) 

219 img, gt, mask = [_create_img(im_size) for i in range(3)] 

220 assert img.size == (im_size[2], im_size[1]) # confirms the above 

221 img_t, gt_t, mask_t = transforms(img, gt, mask) 

222 new_size = (new_size, (new_size * im_size[1]) / im_size[2]) 

223 assert img_t.size == new_size 

224 assert gt_t.size == new_size 

225 assert mask_t.size == new_size 

226 

227 

228def test_resize_downscale_hw(): 

229 

230 # parameters 

231 im_size = (3, 22, 20) # (planes, height, width) 

232 new_size = (10, 12) # (height, width) 

233 

234 # test 

235 transforms = Resize(new_size) 

236 img, gt, mask = [_create_img(im_size) for i in range(3)] 

237 assert img.size == (im_size[2], im_size[1]) # confirms the above 

238 img_t, gt_t, mask_t = transforms(img, gt, mask) 

239 assert img_t.size == (new_size[1], new_size[0]) 

240 assert gt_t.size == (new_size[1], new_size[0]) 

241 assert mask_t.size == (new_size[1], new_size[0]) 

242 

243 

244def test_crop(): 

245 

246 # parameters 

247 im_size = (3, 22, 20) # (planes, height, width) 

248 crop_size = (3, 2, 10, 12) # (upper, left, height, width) 

249 

250 # test 

251 idx = ( 

252 slice(crop_size[0], crop_size[0] + crop_size[2]), 

253 slice(crop_size[1], crop_size[1] + crop_size[3]), 

254 slice(0, im_size[0]), 

255 ) 

256 transforms = Crop(*crop_size) 

257 img, gt, mask = [_create_img(im_size) for i in range(3)] 

258 assert img.size == (im_size[2], im_size[1]) # confirms the above 

259 img_t, gt_t, mask_t = transforms(img, gt, mask) 

260 # notice that PIL->array does array.transpose(1, 2, 0) 

261 # so it creates an array that is (height, width, planes) 

262 assert numpy.all(numpy.array(img_t) == numpy.array(img)[idx]) 

263 assert numpy.all(numpy.array(gt_t) == numpy.array(gt)[idx]) 

264 assert numpy.all(numpy.array(mask_t) == numpy.array(mask)[idx]) 

265 

266 

267def test_to_tensor(): 

268 

269 transforms = ToTensor() 

270 img, gt, mask = [_create_img((3, 5, 5)) for i in range(3)] 

271 gt = gt.convert("1", dither=None) 

272 mask = mask.convert("1", dither=None) 

273 img_t, gt_t, mask_t = transforms(img, gt, mask) 

274 assert img_t.dtype == torch.float32 

275 assert gt_t.dtype == torch.float32 

276 assert mask_t.dtype == torch.float32 

277 

278 

279def test_horizontal_flip(): 

280 

281 transforms = RandomHorizontalFlip(p=1) 

282 

283 im_size = (3, 24, 42) # (planes, height, width) 

284 img, gt, mask = [_create_img(im_size) for i in range(3)] 

285 img_t, gt_t, mask_t = transforms(img, gt, mask) 

286 

287 # notice that PIL->array does array.transpose(1, 2, 0) 

288 # so it creates an array that is (height, width, planes) 

289 assert numpy.all(numpy.flip(img_t, axis=1) == numpy.array(img)) 

290 assert numpy.all(numpy.flip(gt_t, axis=1) == numpy.array(gt)) 

291 assert numpy.all(numpy.flip(mask_t, axis=1) == numpy.array(mask)) 

292 

293 

294def test_vertical_flip(): 

295 

296 transforms = RandomVerticalFlip(p=1) 

297 

298 im_size = (3, 24, 42) # (planes, height, width) 

299 img, gt, mask = [_create_img(im_size) for i in range(3)] 

300 img_t, gt_t, mask_t = transforms(img, gt, mask) 

301 

302 # notice that PIL->array does array.transpose(1, 2, 0) 

303 # so it creates an array that is (height, width, planes) 

304 assert numpy.all(numpy.flip(img_t, axis=0) == numpy.array(img)) 

305 assert numpy.all(numpy.flip(gt_t, axis=0) == numpy.array(gt)) 

306 assert numpy.all(numpy.flip(mask_t, axis=0) == numpy.array(mask)) 

307 

308 

309def test_rotation(): 

310 

311 im_size = (3, 24, 42) # (planes, height, width) 

312 transforms = RandomRotation(degrees=90, p=1) 

313 img = _create_img(im_size) 

314 

315 # asserts all images are rotated the same 

316 # and they are different from the original 

317 random.seed(42) 

318 img1_t, img2_t, img3_t = transforms(img, img, img) 

319 assert img1_t.size == (im_size[2], im_size[1]) 

320 assert numpy.all(numpy.array(img1_t) == numpy.array(img2_t)) 

321 assert numpy.all(numpy.array(img1_t) == numpy.array(img3_t)) 

322 assert numpy.any(numpy.array(img1_t) != numpy.array(img)) 

323 

324 # asserts two random transforms are not the same 

325 (img_t2,) = transforms(img) 

326 assert numpy.any(numpy.array(img_t2) != numpy.array(img1_t)) 

327 

328 

329def test_color_jitter(): 

330 

331 im_size = (3, 24, 42) # (planes, height, width) 

332 transforms = ColorJitter(p=1) 

333 img = _create_img(im_size) 

334 

335 # asserts only the first image is jittered 

336 # and it is different from the original 

337 # all others match the input data 

338 random.seed(42) 

339 img1_t, img2_t, img3_t = transforms(img, img, img) 

340 assert img1_t.size == (im_size[2], im_size[1]) 

341 assert numpy.any(numpy.array(img1_t) != numpy.array(img)) 

342 assert numpy.any(numpy.array(img1_t) != numpy.array(img2_t)) 

343 assert numpy.all(numpy.array(img2_t) == numpy.array(img3_t)) 

344 assert numpy.all(numpy.array(img2_t) == numpy.array(img)) 

345 

346 # asserts two random transforms are not the same 

347 img1_t2, img2_t2, img3_t2 = transforms(img, img, img) 

348 assert numpy.any(numpy.array(img1_t2) != numpy.array(img1_t)) 

349 assert numpy.all(numpy.array(img2_t2) == numpy.array(img)) 

350 assert numpy.all(numpy.array(img3_t2) == numpy.array(img)) 

351 

352 

353def test_blur(): 

354 

355 im_size = (1, 256, 256) # (planes, height, width) 

356 transforms = GaussianBlur(p=1) 

357 img = _create_img(im_size) 

358 

359 # asserts only the first image is blurred 

360 # and it is different from the original 

361 # all others match the input data 

362 random.seed(42) 

363 img1_t, img2_t, img3_t = transforms(img, img, img) 

364 assert img1_t.size == (im_size[2], im_size[1]) 

365 assert numpy.any(numpy.array(img1_t) != numpy.array(img)) 

366 assert numpy.any(numpy.array(img1_t) != numpy.array(img2_t)) 

367 assert numpy.all(numpy.array(img2_t) == numpy.array(img3_t)) 

368 assert numpy.all(numpy.array(img2_t) == numpy.array(img)) 

369 

370 

371def test_compose(): 

372 

373 transforms = Compose( 

374 [ 

375 RandomVerticalFlip(p=1), 

376 RandomHorizontalFlip(p=1), 

377 RandomVerticalFlip(p=1), 

378 RandomHorizontalFlip(p=1), 

379 ] 

380 ) 

381 

382 img, gt, mask = [_create_img((3, 24, 42)) for i in range(3)] 

383 img_t, gt_t, mask_t = transforms(img, gt, mask) 

384 assert numpy.all(numpy.array(img_t) == numpy.array(img)) 

385 assert numpy.all(numpy.array(gt_t) == numpy.array(gt)) 

386 assert numpy.all(numpy.array(mask_t) == numpy.array(mask)) 

387 

388 

389def test_16bit_autolevel(): 

390 

391 path = pkg_resources.resource_filename( 

392 __name__, os.path.join("data", "img-16bit.png") 

393 ) 

394 # the way to load a 16-bit PNG image correctly, according to: 

395 # https://stackoverflow.com/questions/32622658/read-16-bit-png-image-file-using-python 

396 # https://github.com/python-pillow/Pillow/issues/3011 

397 img = PIL.Image.fromarray( 

398 numpy.array(PIL.Image.open(path)).astype("uint16") 

399 ) 

400 assert img.mode == "I;16" 

401 assert img.getextrema() == (0, 65281) 

402 

403 timg = SingleAutoLevel16to8()(img) 

404 assert timg.mode == "L" 

405 assert timg.getextrema() == (0, 255) 

406 # timg.show() 

407 # import ipdb; ipdb.set_trace() 

408 

409 

410def test_shrink_into_square(): 

411 

412 # parameters 

413 im_size = (3, 128, 140) # (planes, height, width) 

414 mask_gt_size = (1, 128, 140) # (planes, height, width) 

415 crop_size = (30, 30, 91, 91) # (left,up , right ,down) 

416 size_after_crop = (61, 61) 

417 

418 idx = (slice(crop_size[0], crop_size[2]), slice(crop_size[1], crop_size[3])) 

419 

420 # Create random image and a mask with a circle inside 

421 img, gt = _create_img(im_size), _create_img(mask_gt_size) 

422 mask = PIL.Image.new("L", (140, 128), "black") 

423 dr = PIL.ImageDraw.Draw(mask) 

424 dr.ellipse((30, 30, 90, 90), "white") 

425 

426 # Test 

427 transform = ShrinkIntoSquare(reference=2, threshold=0) 

428 img_, gt_, mask_ = transform(img, gt, mask) 

429 

430 assert img_.size == size_after_crop 

431 assert gt_.size == size_after_crop 

432 assert mask_.size == size_after_crop 

433 

434 assert img_.mode == "RGB" 

435 assert gt_.mode == "L" 

436 assert mask_.mode == "L" 

437 

438 assert numpy.all(numpy.array(img_) == numpy.array(img)[idx]) 

439 assert numpy.all(numpy.array(gt_) == numpy.array(gt)[idx]) 

440 assert numpy.all(numpy.array(mask_) == numpy.array(mask)[idx])