LocalBinaryPatternizer.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. from Histogram import Histogram
  2. from math import ceil
  3. class LocalBinaryPatternizer:
  4. """This class generates a Local Binary Pattern of a given image."""
  5. def __init__(self, image, cell_size=16, neighbours=3):
  6. self.cell_size = cell_size
  7. self.image = image
  8. self.pattern_callback, self.bins = {
  9. 3: (self.pattern_3x3, 256),
  10. 5: (self.pattern_5x5, 4096)
  11. }[neighbours]
  12. def setup_histograms(self):
  13. cells_in_width = int(ceil(self.image.width / float(self.cell_size)))
  14. cells_in_height = int(ceil(self.image.height / float(self.cell_size)))
  15. self.histograms = []
  16. for i in xrange(cells_in_height):
  17. self.histograms.append([])
  18. for j in xrange(cells_in_width):
  19. self.histograms[i].append(Histogram(self.bins, 0, self.bins))
  20. def pattern_3x3(self, y, x, value):
  21. """Create the Local Binary Pattern in the (8,3)-neighbourhood."""
  22. return (self.is_pixel_darker(y - 1, x - 1, value) << 7) \
  23. | (self.is_pixel_darker(y - 1, x , value) << 6) \
  24. | (self.is_pixel_darker(y - 1, x + 1, value) << 5) \
  25. | (self.is_pixel_darker(y , x + 1, value) << 4) \
  26. | (self.is_pixel_darker(y + 1, x + 1, value) << 3) \
  27. | (self.is_pixel_darker(y + 1, x , value) << 2) \
  28. | (self.is_pixel_darker(y + 1, x - 1, value) << 1) \
  29. | (self.is_pixel_darker(y , x - 1, value))
  30. def pattern_5x5_hybrid(self, y, x, value):
  31. """Create the Local Binary Pattern in the (8,5)-neighbourhood."""
  32. return (self.is_pixel_darker(y - 2, x - 2, value) << 7) \
  33. | (self.is_pixel_darker(y - 2, x , value) << 6) \
  34. | (self.is_pixel_darker(y - 2, x + 2, value) << 5) \
  35. | (self.is_pixel_darker(y , x + 2, value) << 4) \
  36. | (self.is_pixel_darker(y + 2, x + 2, value) << 3) \
  37. | (self.is_pixel_darker(y + 2, x , value) << 2) \
  38. | (self.is_pixel_darker(y + 2, x - 2, value) << 1) \
  39. | (self.is_pixel_darker(y , x - 2, value))
  40. def pattern_5x5(self, y, x, value):
  41. """Create the Local Binary Pattern in the (12,5)-neighbourhood."""
  42. return (self.is_pixel_darker(y - 1, x - 2, value) << 11) \
  43. | (self.is_pixel_darker(y , x - 2, value) << 10) \
  44. | (self.is_pixel_darker(y + 1, x - 2, value) << 9) \
  45. | (self.is_pixel_darker(y + 2, x - 1, value) << 8) \
  46. | (self.is_pixel_darker(y + 2, x , value) << 7) \
  47. | (self.is_pixel_darker(y + 2, x + 1, value) << 6) \
  48. | (self.is_pixel_darker(y + 1, x + 2, value) << 5) \
  49. | (self.is_pixel_darker(y , x + 2, value) << 4) \
  50. | (self.is_pixel_darker(y - 1, x + 2, value) << 3) \
  51. | (self.is_pixel_darker(y - 2, x + 1, value) << 2) \
  52. | (self.is_pixel_darker(y - 2, x , value) << 1) \
  53. | (self.is_pixel_darker(y - 2, x - 1, value))
  54. def create_features_vector(self):
  55. '''Walk around the pixels in clockwise order, shifting 1 bit less at
  56. each neighbour starting at 7 in the top-left corner. This gives a 8-bit
  57. feature number of a pixel'''
  58. self.setup_histograms()
  59. for y, x, value in self.image:
  60. cy, cx = self.get_cell_index(y, x)
  61. self.histograms[cy][cx].add(self.pattern_callback(y, x, value))
  62. return self.get_features_as_array()
  63. def is_pixel_darker(self, y, x, value):
  64. return self.image.in_bounds(y, x) and self.image[y, x] > value
  65. def get_cell_index(self, y, x):
  66. return (y / self.cell_size, x / self.cell_size)
  67. def get_features_as_array(self):
  68. f = []
  69. # Concatenate all histogram bins
  70. for row in self.histograms:
  71. for hist in row:
  72. f.extend(hist.bins)
  73. return f
  74. def get_single_histogram(self):
  75. """Create a single histogram of the local binary patterns in the
  76. image."""
  77. h = Histogram(self.bins, 0, self.bins)
  78. for y, x, value in self.image:
  79. h.add(self.pattern_callback(y, x, value))
  80. h.normalize()
  81. return h
  82. def single_cell_features_vector(self):
  83. return self.get_single_histogram().bins