LocalBinaryPatternizer.py 3.4 KB

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