Changed x/y to r/c notation. Documentation correction.

This commit is contained in:
dan
2015-06-15 22:04:09 +02:00
parent fe85552596
commit c3e23b0604
4 changed files with 106 additions and 102 deletions
@@ -28,17 +28,15 @@ import numpy as np
from numpy.testing import assert_equal
from skimage.transform import integral_image
# Create test matrix where first and fifth
# rectangles starting from top left clockwise
# have greater value than the central one.
# Create test matrix where first and fifth rectangles starting
# from top left clockwise have greater value than the central one.
test_img = np.zeros((9, 9), dtype='uint8')
test_img[3:6, 3:6] = 1
test_img[:3, :3] = 50
test_img[6:, 6:] = 50
# First and fifth bits should be filled.
# This correct value will be compared to
# the computed one.
# First and fifth bits should be filled. This correct value will
# be compared to the computed one.
correct_answer = 0b10001000
int_img = integral_image(test_img)
@@ -48,7 +46,8 @@ lbp_code = multiblock_lbp(int_img, 0, 0, 3, 3)
assert_equal(correct_answer, lbp_code)
"""
Now let's apply the operator to a real image and see how the visualization works.
Now let's apply the operator to a real image and see how the
visualization works.
"""
from skimage import data
from matplotlib import pyplot as plt
@@ -69,8 +68,8 @@ plt.imshow(img, interpolation='nearest')
"""
.. image:: PLOT2RST.current_figure
On the above plot we see the result of computing a MB-LBP and visualization
of the computed feature. The rectangles that have less intensities' sum than the central
rectangle are marked in cyan. The ones that have higher intensity values
are marked in white. The central rectangle is left untouched.
On the above plot we see the result of computing a MB-LBP and visualization of
the computed feature. The rectangles that have less intensities' sum than the
central rectangle are marked in cyan. The ones that have higher intensity
values are marked in white. The central rectangle is left untouched.
"""
+37 -32
View File
@@ -267,28 +267,29 @@ def _local_binary_pattern(double[:, ::1] image,
return np.asarray(output)
# Constant values that are used by `multiblock_local_binary_pattern` function.
# Constant values that are used by `_multiblock_lbp` function.
# Values represent offsets of neighbour rectangles relative to central one.
# It has order starting from top left and going clockwise.
cdef:
Py_ssize_t[::1] mlbp_x_offsets = np.asarray([-1, 0, 1, 1, 1, 0, -1, -1])
Py_ssize_t[::1] mlbp_y_offsets = np.asarray([-1, -1, -1, 0, 1, 1, 1, 0])
Py_ssize_t[::1] mlbp_r_offsets = np.asarray([-1, -1, -1, 0, 1, 1, 1, 0])
Py_ssize_t[::1] mlbp_c_offsets = np.asarray([-1, 0, 1, 1, 1, 0, -1, -1])
def _multiblock_lbp(float[:, ::1] int_image,
Py_ssize_t x,
Py_ssize_t y,
Py_ssize_t r,
Py_ssize_t c,
Py_ssize_t width,
Py_ssize_t height):
"""Multi-block local binary pattern.
"""Multi-block local binary pattern (MB-LBP) [1]_.
Parameters
----------
int_image : (N, M) float array
Integral image.
x : int
X-coordinate of top left corner of a rectangle containing feature.
y : int
Y-coordinate of top left corner of a rectangle containing feature.
r : int
Row-coordinate of top left corner of a rectangle containing feature.
c : int
Column-coordinate of top left corner of a rectangle containing feature.
width : int
Width of one of 9 equal rectangles that will be used to compute
a feature.
@@ -309,36 +310,43 @@ def _multiblock_lbp(float[:, ::1] int_image,
http://www.cbsr.ia.ac.cn/users/scliao/papers/Zhang-ICB07-MBLBP.pdf
"""
# Top-left coordinates of central rectangle
cdef:
Py_ssize_t central_rect_x = x + width
Py_ssize_t central_rect_y = y + height
# Top-left coordinates of central rectangle.
Py_ssize_t central_rect_r = r + height
Py_ssize_t central_rect_c = c + width
# Sum of intensity values of central rectangle
cdef float central_rect_val = integrate(int_image, central_rect_y, central_rect_x,
central_rect_y + height - 1,
central_rect_x + width - 1)
Py_ssize_t r_shift = height - 1
Py_ssize_t c_shift = width - 1
cdef:
Py_ssize_t element_num, offset_x, offset_y
Py_ssize_t current_rect_x, current_rect_y
# Copy offset array to multiply it by width and height later.
Py_ssize_t[::1] r_offsets = mlbp_r_offsets.copy()
Py_ssize_t[::1] c_offsets = mlbp_c_offsets.copy()
Py_ssize_t current_rect_r, current_rect_c
Py_ssize_t element_num, i
double current_rect_val
int has_greater_value
int lbp_code = 0
# Pre-multiply offsets with width and height.
for i in range(8):
r_offsets[i] = r_offsets[i]*height
c_offsets[i] = c_offsets[i]*width
# Sum of intensity values of central rectangle.
cdef float central_rect_val = integrate(int_image, central_rect_r, central_rect_c,
central_rect_r + r_shift,
central_rect_c + c_shift)
for element_num in range(8):
offset_x = mlbp_x_offsets[element_num]
offset_y = mlbp_y_offsets[element_num]
current_rect_r = central_rect_r + r_offsets[element_num]
current_rect_c = central_rect_c + c_offsets[element_num]
current_rect_x = central_rect_x + offset_x * width
current_rect_y = central_rect_y + offset_y * height
current_rect_val = integrate(int_image, current_rect_y, current_rect_x,
current_rect_y + height - 1,
current_rect_x + width - 1)
current_rect_val = integrate(int_image, current_rect_r, current_rect_c,
current_rect_r + r_shift,
current_rect_c + c_shift)
has_greater_value = current_rect_val >= central_rect_val
@@ -348,6 +356,3 @@ def _multiblock_lbp(float[:, ::1] int_image,
lbp_code |= has_greater_value << (7 - element_num)
return lbp_code
+7 -10
View File
@@ -1,10 +1,8 @@
import numpy as np
from skimage.feature import (
greycomatrix,
from skimage.feature import (greycomatrix,
greycoprops,
local_binary_pattern,
multiblock_lbp
)
multiblock_lbp)
from skimage._shared.testing import test_parallel
from skimage.transform import integral_image
@@ -239,17 +237,16 @@ class TestMBLBP():
def test_single_mblbp(self):
# Create dummy matrix where first and fifth
# rectangles have greater value than the central one
# Therefore, the following bits should be 1.
# Create dummy matrix where first and fifth rectangles have greater
# value than the central one. Therefore, the following bits
# should be 1.
test_img = np.zeros((9, 9), dtype='uint8')
test_img[3:6, 3:6] = 1
test_img[:3, :3] = 255
test_img[6:, 6:] = 255
# MB-LBP is filled in reverse order.
# So the first and fifth bits from the end should
# be filled.
# MB-LBP is filled in reverse order. So the first and fifth bits from
# the end should be filled.
correct_answer = 0b10001000
int_img = integral_image(test_img)
+52 -49
View File
@@ -297,27 +297,27 @@ def local_binary_pattern(image, P, R, method='default'):
return output
def multiblock_lbp(int_image, x, y, width, height):
"""Multi-block local binary pattern.
def multiblock_lbp(int_image, r, c, width, height):
"""Multi-block local binary pattern (MB-LBP) [1]_.
The features are calculated similarly to local binary patterns (LBPs),
except that summed blocks are used instead of individual pixel values.
(See :py:meth:`local_binary_pattern`) except that summed blocks are
used instead of individual pixel values.
MB-LBP is an extension of LBP that can be computed on multiple scales
in constant time using the integral image.
9 equally-sized rectangles are used to compute a feature.
For each rectangle, the sum of the pixel intensities is computed.
Comparisons of these sums to that of the central rectangle determine
the feature, similarly to LBP.
in constant time using the integral image. Nine equally-sized rectangles
are used to compute a feature. For each rectangle, the sum of the pixel
intensities is computed. Comparisons of these sums to that of the central
rectangle determine the feature, similarly to LBP.
Parameters
----------
int_image : (N, M) array
Integral image.
x : int
X-coordinate of top left corner of a rectangle containing feature.
y : int
Y-coordinate of top left corner of a rectangle containing feature.
r : int
Row-coordinate of top left corner of a rectangle containing feature.
c : int
Column-coordinate of top left corner of a rectangle containing feature.
width : int
Width of one of the 9 equal rectangles that will be used to compute
a feature.
@@ -339,11 +339,11 @@ def multiblock_lbp(int_image, x, y, width, height):
"""
int_image = np.ascontiguousarray(int_image, dtype=np.float32)
lbp_code = _multiblock_lbp(int_image, x, y, width, height)
lbp_code = _multiblock_lbp(int_image, r, c, width, height)
return lbp_code
def draw_multiblock_lbp(img, x, y, width, height,
def draw_multiblock_lbp(img, r, c, width, height,
lbp_code=0,
color_greater_block=[1, 1, 1],
color_less_block=[0, 0.69, 0.96],
@@ -351,19 +351,18 @@ def draw_multiblock_lbp(img, x, y, width, height,
):
"""Multi-block local binary pattern visualization.
Blocks with higher sums are colored with transparent white rectangles,
whereas blocks with lower sums are colored cyan.
The colors can also be specified.
Opacity of visualization is controlled with `alpha` parameter.
Blocks with higher sums are colored with alpha-blended white rectangles,
whereas blocks with lower sums are colored alpha-blended cyan. Colors
and the `alpha` parameter can be changed.
Parameters
----------
img :
img : ndarray of float or uint
Image on which to visualize the pattern.
x : int
X-coordinate of top left corner of a rectangle containing feature.
y : int
Y-coordinate of top left corner of a rectangle containing feature.
r : int
Row-coordinate of top left corner of a rectangle containing feature.
c : int
Column-coordinate of top left corner of a rectangle containing feature.
width : int
Width of one of 9 equal rectangles that will be used to compute
a feature.
@@ -371,26 +370,25 @@ def draw_multiblock_lbp(img, x, y, width, height,
Height of one of 9 equal rectangles that will be used to compute
a feature.
lbp_code : int
The descriptor of feature to visualize. If not provided,
the descriptor with 0 value will be used.
The descriptor of feature to visualize. If not provided, the
descriptor with 0 value will be used.
color_greater_block : list of 3 floats
Floats specifying the color for the block that
has greater intensity value. They should be
in the range [0, 1]. Corresponding values define
(R, G, B) values. Default value is white [1, 1, 1].
Floats specifying the color for the block that has greater
intensity value. They should be in the range [0, 1].
Corresponding values define (R, G, B) values. Default value
is white [1, 1, 1].
color_greater_block : list of 3 floats
Floats specifying the color for the block that
has greater intensity value. They should be
in the range [0, 1]. Corresponding values define
Floats specifying the color for the block that has greater intensity
value. They should be in the range [0, 1]. Corresponding values define
(R, G, B) values. Default value is cyan [0, 0.69, 0.96].
alpha : float
Value in the range [0, 1] that specifies opacity of
visualization. 1 - fully transparent, 0 - opaque.
Value in the range [0, 1] that specifies opacity of visualization.
1 - fully transparent, 0 - opaque.
Returns
-------
output : ndarray of float
Image with visualization.
Image with MB-LBP visualization.
References
----------
@@ -403,8 +401,8 @@ def draw_multiblock_lbp(img, x, y, width, height,
# Default colors for regions.
# White is for the blocks that are brighter.
# Cyan is for the blocks that has less intensity.
color_greater_block = np.asarray(color_greater_block, dtype=np.double)
color_less_block = np.asarray(color_less_block, dtype=np.double)
color_greater_block = np.asarray(color_greater_block, dtype=np.float64)
color_less_block = np.asarray(color_less_block, dtype=np.float64)
# Copy array to avoid the changes to the original one.
output = np.copy(img)
@@ -418,31 +416,36 @@ def draw_multiblock_lbp(img, x, y, width, height,
# Offsets of neighbour rectangles relative to central one.
# It has order starting from top left and going clockwise.
neighbour_rect_offsets = ((-1, -1), (0, -1), (1, -1),
(1, 0), (1, 1), (0, 1),
(-1, 1), (-1, 0))
neighbour_rect_offsets = ((-1, -1), (-1, 0), (-1, 1),
(0, 1), (1, 1), (1, 0),
(1, -1), (0, -1))
# Pre-multiply the offsets with width and height.
neighbour_rect_offsets = np.array(neighbour_rect_offsets)
neighbour_rect_offsets[:, 0] *= height
neighbour_rect_offsets[:, 1] *= width
# Top-left coordinates of central rectangle.
central_rect_x = x + width
central_rect_y = y + height
central_rect_r = r + height
central_rect_c = c + width
for element_num, offset in enumerate(neighbour_rect_offsets):
offset_x, offset_y = offset
offset_r, offset_c = offset
curr_x = central_rect_x + offset_x * width
curr_y = central_rect_y + offset_y * height
curr_r = central_rect_r + offset_r
curr_c = central_rect_c + offset_c
has_greater_value = lbp_code & (1 << (7-element_num))
# Mix-in the visualization colors.
if has_greater_value:
new_value = ((1-alpha) * output[curr_y:curr_y+height, curr_x:curr_x+width]
new_value = ((1-alpha) * output[curr_r:curr_r+height, curr_c:curr_c+width]
+ alpha * color_greater_block)
output[curr_y:curr_y+height, curr_x:curr_x+width] = new_value
output[curr_r:curr_r+height, curr_c:curr_c+width] = new_value
else:
new_value = ((1-alpha) * output[curr_y:curr_y+height, curr_x:curr_x+width]
new_value = ((1-alpha) * output[curr_r:curr_r+height, curr_c:curr_c+width]
+ alpha * color_less_block)
output[curr_y:curr_y+height, curr_x:curr_x+width] = new_value
output[curr_r:curr_r+height, curr_c:curr_c+width] = new_value
return output