use image::{GenericImage, Luma};
use std::cmp;
pub fn local_binary_pattern<I>(image: &I, x: u32, y: u32) -> Option<u8>
where
I: GenericImage<Pixel = Luma<u8>>,
{
let (width, height) = image.dimensions();
if width == 0 || height == 0 {
return None;
}
if x == 0 || x >= width - 1 || y == 0 || y >= height - 1 {
return None;
}
let mut pattern = 0u8;
let (center, neighbors) = unsafe {
(
image.unsafe_get_pixel(x, y)[0],
[
image.unsafe_get_pixel(x, y - 1)[0],
image.unsafe_get_pixel(x + 1, y - 1)[0],
image.unsafe_get_pixel(x + 1, y)[0],
image.unsafe_get_pixel(x + 1, y + 1)[0],
image.unsafe_get_pixel(x, y + 1)[0],
image.unsafe_get_pixel(x - 1, y + 1)[0],
image.unsafe_get_pixel(x - 1, y)[0],
image.unsafe_get_pixel(x - 1, y - 1)[0],
],
)
};
for i in 0..8 {
pattern |= (1 & (neighbors[i] < center) as u8) << i;
}
Some(pattern)
}
pub fn min_shift(byte: u8) -> u8 {
let mut min = byte;
for i in 1..8 {
min = cmp::min(min, byte.rotate_right(i));
}
min
}
pub fn count_transitions(byte: u8) -> u32 {
(byte ^ byte.rotate_right(1)).count_ones()
}
pub static UNIFORM_REPRESENTATIVE_2: [u8; 256] = [
0, 1, 1, 3, 1, 170, 3, 7, 1, 170, 170, 170, 3, 170, 7, 15, 1, 170, 170, 170, 170, 170, 170, 170, 3, 170, 170, 170, 7, 170, 15, 31, 1, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 3, 170, 170, 170, 170, 170, 170, 170, 7, 170, 170, 170, 15, 170, 31, 63, 1, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 3, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 7, 170, 170, 170, 170, 170, 170, 170, 15, 170, 170, 170, 31, 170, 63, 127, 1, 3, 170, 7, 170, 170, 170, 15, 170, 170, 170, 170, 170, 170, 170, 31, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 63, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 127, 3, 7, 170, 15, 170, 170, 170, 31, 170, 170, 170, 170, 170, 170, 170, 63, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 127, 7, 15, 170, 31, 170, 170, 170, 63, 170, 170, 170, 170, 170, 170, 170, 127, 15, 31, 170, 63, 170, 170, 170, 127, 31, 63, 170, 127, 63, 127, 127, 255, ];
pub static MIN_SHIFT: [u8; 256] = [
0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1, 17, 9, 19, 5, 21, 11, 23, 3, 25, 13, 27, 7, 29, 15, 31, 1, 9, 17, 25, 9, 37, 19, 39, 5, 37, 21, 43, 11, 45, 23, 47, 3, 19, 25, 51, 13, 53, 27, 55, 7, 39, 29, 59, 15, 61, 31, 63, 1, 5, 9, 13, 17, 21, 25, 29, 9, 37, 37, 45, 19, 53, 39, 61, 5, 21, 37, 53, 21, 85, 43, 87, 11, 43, 45, 91, 23, 87, 47, 95, 3, 11, 19, 27, 25, 43, 51, 59, 13, 45, 53, 91, 27, 91, 55, 111, 7, 23, 39, 55, 29, 87, 59, 119, 15, 47, 61, 111, 31, 95, 63, 127, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 9, 25, 37, 39, 37, 43, 45, 47, 19, 51, 53, 55, 39, 59, 61, 63, 5, 13, 21, 29, 37, 45, 53, 61, 21, 53, 85, 87, 43, 91, 87, 95, 11, 27, 43, 59, 45, 91, 91, 111, 23, 55, 87, 119, 47, 111, 95, 127, 3, 7, 11, 15, 19, 23, 27, 31, 25, 39, 43, 47, 51, 55, 59, 63, 13, 29, 45, 61, 53, 87, 91, 95, 27, 59, 91, 111, 55, 119, 111, 127, 7, 15, 23, 31, 39, 47, 55, 63, 29, 61, 87, 95, 59, 111, 119, 127, 15, 31, 47, 63, 61, 95, 111, 127, 31, 63, 95, 127, 63, 127, 127, 255, ];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_uniform_representative_2() {
let a = 0b11110000;
assert_eq!(UNIFORM_REPRESENTATIVE_2[a], 0b00001111);
let b = 0b00000000;
assert_eq!(UNIFORM_REPRESENTATIVE_2[b], 0b00000000);
let c = 0b10011001;
assert_eq!(UNIFORM_REPRESENTATIVE_2[c], 0b10101010);
}
}
#[cfg(not(miri))]
#[cfg(test)]
mod benches {
use super::*;
use image::{GrayImage, Luma};
use test::{black_box, Bencher};
#[bench]
fn bench_local_binary_pattern(b: &mut Bencher) {
let image = GrayImage::from_fn(100, 100, |x, y| Luma([x as u8 % 2 + y as u8 % 2]));
b.iter(|| {
for y in 0..20 {
for x in 0..20 {
let pattern = local_binary_pattern(&image, x, y);
black_box(pattern);
}
}
});
}
}