MIF_E31230910_MP-HRIS-WEB/python_scripts/lbp_features.py

109 lines
3.1 KiB
Python

"""
Modul ekstraksi fitur wajah: Multi-scale LBP (Local Binary Pattern).
Menggunakan LBP pada dua skala (radius 1 dan radius 2) dengan
spatial histogram grid 8x8 untuk diskriminasi identitas.
"""
import cv2
import numpy as np
FACE_SIZE = (128, 128)
GRID_X = 8
GRID_Y = 8
def apply_clahe(gray_img):
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
return clahe.apply(gray_img)
def _lbp_uniform(image, n_points=8, radius=1):
rows, cols = image.shape
img = image.astype(np.float64)
r = radius
if r >= rows // 2 or r >= cols // 2:
return np.zeros((rows, cols), dtype=np.float64)
center = img[r:rows - r, r:cols - r]
out_h, out_w = center.shape
n_bins = n_points + 2
angles = np.linspace(0, 2 * np.pi, n_points, endpoint=False)
bits = np.zeros((n_points, out_h, out_w), dtype=np.uint8)
for i, angle in enumerate(angles):
dy = -radius * np.cos(angle)
dx = radius * np.sin(angle)
iy, ix = int(round(dy)), int(round(dx))
neighbor = img[r + iy:r + iy + out_h, r + ix:r + ix + out_w]
if neighbor.shape == center.shape:
bits[i] = (neighbor >= center).astype(np.uint8)
pattern = np.zeros((out_h, out_w), dtype=np.int32)
for i in range(n_points):
pattern |= bits[i].astype(np.int32) << i
transitions = np.zeros((out_h, out_w), dtype=np.int32)
for i in range(n_points):
bit_cur = (pattern >> i) & 1
bit_next = (pattern >> ((i + 1) % n_points)) & 1
transitions += (bit_cur != bit_next).astype(np.int32)
bit_count = np.zeros((out_h, out_w), dtype=np.float64)
for i in range(n_points):
bit_count += ((pattern >> i) & 1).astype(np.float64)
output = np.full((rows, cols), float(n_points + 1))
uniform_mask = transitions <= 2
result = np.where(uniform_mask, bit_count, float(n_points + 1))
output[r:rows - r, r:cols - r] = result
return output
def _extract_lbp_hist(lbp_map, n_bins, grid_x, grid_y):
h, w = lbp_map.shape
region_h = h // grid_y
region_w = w // grid_x
features = []
for gy in range(grid_y):
for gx in range(grid_x):
region = lbp_map[
gy * region_h:(gy + 1) * region_h,
gx * region_w:(gx + 1) * region_w
]
hist, _ = np.histogram(
region, bins=n_bins, range=(0, n_bins), density=True
)
features.extend(hist)
return features
def extract_lbp_features(image):
if len(image.shape) == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
if image.shape != FACE_SIZE:
image = cv2.resize(image, FACE_SIZE, interpolation=cv2.INTER_AREA)
image = cv2.GaussianBlur(image, (3, 3), 0)
image = apply_clahe(image)
all_features = []
lbp_r1 = _lbp_uniform(image, n_points=8, radius=1)
n_bins_r1 = 8 + 2
hist_r1 = _extract_lbp_hist(lbp_r1, n_bins_r1, GRID_X, GRID_Y)
all_features.extend(hist_r1)
lbp_r2 = _lbp_uniform(image, n_points=16, radius=2)
n_bins_r2 = 16 + 2
hist_r2 = _extract_lbp_hist(lbp_r2, n_bins_r2, GRID_X, GRID_Y)
all_features.extend(hist_r2)
return np.array(all_features, dtype=np.float64)