Coverage for src/bob/bio/vein/extractor/WideLineDetector.py: 100%

39 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-07-12 23:27 +0200

1#!/usr/bin/env python 

2# vim: set fileencoding=utf-8 : 

3 

4import numpy 

5import scipy 

6 

7from PIL import Image 

8 

9from bob.bio.base.extractor import Extractor 

10 

11 

12class WideLineDetector(Extractor): 

13 """Wide Line Detector feature extractor 

14 

15 Based on B. Huang, Y. Dai, R. Li, D. Tang and W. Li. [HDLTL10]_ 

16 """ 

17 

18 def __init__( 

19 self, 

20 radius=5, # Radius of the circular neighbourhood region 

21 threshold=1, # Neigborhood threshold 

22 g=41, # Sum of neigbourhood threshold 

23 rescale=True, 

24 ): 

25 # call base class constructor 

26 Extractor.__init__( 

27 self, 

28 radius=radius, 

29 threshold=threshold, 

30 g=g, 

31 rescale=rescale, 

32 ) 

33 

34 # block parameters 

35 self.radius = radius 

36 self.threshold = threshold 

37 self.g = g 

38 self.rescale = rescale 

39 

40 def wide_line_detector(self, finger_image, mask): 

41 """Computes and returns the Wide Line Detector features for the given input 

42 fingervein image""" 

43 

44 finger_image = finger_image.astype(numpy.float64) 

45 

46 finger_mask = numpy.zeros(mask.shape) 

47 finger_mask[mask == True] = 1 # noqa: E712 

48 

49 # Rescale image if required 

50 if self.rescale: 

51 scaling_factor = 0.24 

52 

53 new_size = tuple( 

54 (numpy.array(finger_image.shape) * scaling_factor).astype(int) 

55 ) 

56 finger_image = numpy.array( 

57 Image.fromarray(finger_image).resize(size=new_size) 

58 ).T 

59 

60 new_size = tuple( 

61 (numpy.array(finger_mask.shape) * scaling_factor).astype(int) 

62 ) 

63 finger_mask = numpy.array( 

64 Image.fromarray(finger_mask).resize(size=new_size) 

65 ).T 

66 

67 # To eliminate residuals from the scalation of the binary mask 

68 finger_mask = scipy.ndimage.binary_dilation( 

69 finger_mask, structure=numpy.ones((1, 1)) 

70 ).astype(int) 

71 

72 x = numpy.arange((-1) * self.radius, self.radius + 1) 

73 y = numpy.arange((-1) * self.radius, self.radius + 1) 

74 X, Y = numpy.meshgrid(x, y) 

75 

76 N = X**2 + Y**2 <= self.radius**2 # Neighbourhood mask 

77 

78 img_h, img_w = finger_image.shape # Image height and width 

79 

80 veins = numpy.zeros(finger_image.shape) 

81 

82 for y in range(self.radius, img_h - self.radius): 

83 for x in range(self.radius, img_w - self.radius): 

84 s = ( 

85 finger_image[ 

86 y - self.radius : y + self.radius + 1, 

87 x - self.radius : x + self.radius + 1, 

88 ] 

89 - finger_image[y, x] 

90 ) <= self.threshold 

91 m = (s * N).sum() 

92 veins[y, x] = float(m <= self.g) 

93 

94 # Mask the vein image with the finger region 

95 img_veins_bin = veins * finger_mask 

96 

97 return img_veins_bin 

98 

99 def __call__(self, image): 

100 """Reads the input image, extract the features based on Wide Line Detector 

101 of the fingervein image, and writes the resulting template""" 

102 # For debugging 

103 

104 finger_image = image[0] # Normalized image with histogram equalization 

105 finger_mask = image[1] 

106 

107 return self.wide_line_detector(finger_image, finger_mask)