Merge pull request #704 from alexis-mignon/master

Adding non rotation invariant uniform LBPs
This commit is contained in:
Johannes Schönberger
2013-09-14 01:24:36 -07:00
3 changed files with 94 additions and 13 deletions
+76 -13
View File
@@ -90,12 +90,13 @@ def _local_binary_pattern(double[:, ::1] image,
the angular space).
R : float
Radius of circle (spatial resolution of the operator).
method : {'D', 'R', 'U', 'V'}
method : {'D', 'R', 'U', 'N', 'V'}
Method to determine the pattern.
* 'D': 'default'
* 'R': 'ror'
* 'U': 'uniform'
* 'N': 'nri_uniform'
* 'V': 'var'
Returns
@@ -125,6 +126,9 @@ def _local_binary_pattern(double[:, ::1] image,
cdef double lbp
cdef Py_ssize_t r, c, changes, i
cdef Py_ssize_t rot_index, n_ones
cdef cnp.int8_t first_zero, first_one
for r in range(image.shape[0]):
for c in range(image.shape[1]):
for i in range(P):
@@ -141,24 +145,83 @@ def _local_binary_pattern(double[:, ::1] image,
lbp = 0
# if method == 'uniform' or method == 'var':
if method == 'U' or method == 'V':
if method == 'U' or method == 'N' or method == 'V':
# determine number of 0 - 1 changes
changes = 0
for i in range(P - 1):
changes += abs(signed_texture[i] - signed_texture[i + 1])
if method == 'N':
# Uniform local binary patterns are defined as patterns
# with at most 2 value changes (from 0 to 1 or from 1 to
# 0). Uniform patterns can be caraterized by their number
# `n_ones` of 1. The possible values for `n_ones` range
# from 0 to P.
# Here is an example for P = 4:
# n_ones=0: 0000
# n_ones=1: 0001, 1000, 0100, 0010
# n_ones=2: 0011, 1001, 1100, 0110
# n_ones=3: 0111, 1011, 1101, 1110
# n_ones=4: 1111
#
# For a pattern of size P there are 2 constant patterns
# corresponding to n_ones=0 and n_ones=P. For each other
# value of `n_ones` , i.e n_ones=[1..P-1], there are P
# possible patterns which are related to each other through
# circular permutations. The total number of uniform
# patterns is thus (2 + P * (P - 1)).
# Given any pattern (uniform or not) we must be able to
# associate a unique code:
# 1. Constant patterns patterns (with n_ones=0 and
# n_ones=P) and non uniform patterns are given fixed
# code values.
# 2. Other uniform patterns are indexed considering the
# value of n_ones, and an index called 'rot_index'
# reprenting the number of circular right shifts
# required to obtain the pattern starting from a
# reference position (corresponding to all zeros stacked
# on the right). This number of rotations (or circular
# right shifts) 'rot_index' is efficiently computed by
# considering the positions of the first 1 and the first
# 0 found in the pattern.
if changes <= 2:
for i in range(P):
lbp += signed_texture[i]
else:
lbp = P + 1
if method == 'V':
var = np.var(texture)
if var != 0:
lbp /= var
if changes <= 2:
# We have a uniform pattern
n_ones = 0 # determies the number of ones
first_one = -1 # position was the first one
first_zero = -1 # position of the first zero
for i in range(P):
if signed_texture[i]:
n_ones += 1
if first_one == -1:
first_one = i
else:
if first_zero == -1:
first_zero = i
if n_ones == 0:
lbp = 0
elif n_ones == P:
lbp = P * (P - 1) + 1
else:
if first_one == 0:
rot_index = n_ones - first_zero
else:
rot_index = P - first_one
lbp = 1 + (n_ones - 1) * P + rot_index
else: # changes > 2
lbp = P * (P - 1) + 2
else: # method != 'N'
if changes <= 2:
for i in range(P):
lbp += signed_texture[i]
else:
lbp = np.nan
lbp = P + 1
if method == 'V':
var = np.var(texture)
if var != 0:
lbp /= var
else:
lbp = np.nan
else:
# method == 'default'
for i in range(P):
+11
View File
@@ -199,5 +199,16 @@ class TestLBP():
np.testing.assert_array_almost_equal(lbp, ref)
def test_nri_uniform(self):
lbp = local_binary_pattern(self.image, 8, 1, 'nri_uniform')
ref = np.array([[ 0, 54, 0, 57, 12, 57],
[34, 0, 58, 58, 3, 22],
[58, 57, 15, 50, 0, 47],
[10, 3, 40, 42, 35, 0],
[57, 7, 57, 58, 0, 56],
[ 9, 58, 0, 57, 7, 14]])
np.testing.assert_array_almost_equal(lbp, ref)
if __name__ == '__main__':
np.testing.run_module_suite()
+7
View File
@@ -248,6 +248,8 @@ def local_binary_pattern(image, P, R, method='default'):
* 'uniform': improved rotation invariance with uniform patterns and
finer quantization of the angular space which is gray scale and
rotation invariant.
* 'nri_uniform': non rotation-invariant uniform patterns variant
which is only gray scale invariant [2].
* 'var': rotation invariant variance measures of the contrast of local
image texture which is rotation but not gray scale invariant.
@@ -263,12 +265,17 @@ def local_binary_pattern(image, P, R, method='default'):
Timo Ojala, Matti Pietikainen, Topi Maenpaa.
http://www.rafbis.it/biplab15/images/stories/docenti/Danielriccio/\
Articoliriferimento/LBP.pdf, 2002.
.. [2] Face recognition with local binary patterns.
Timo Ahonen, Abdenour Hadid, Matti Pietikainen,
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.214.6851,
2004.
"""
methods = {
'default': ord('D'),
'ror': ord('R'),
'uniform': ord('U'),
'nri_uniform': ord('N'),
'var': ord('V')
}
image = np.ascontiguousarray(image, dtype=np.double)