mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-09 23:11:31 +08:00
Merge pull request #704 from alexis-mignon/master
Adding non rotation invariant uniform LBPs
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user