Facial-feature-detector / src /face_texture.py
paresh95
PS | Add face comparison feature
988dde3
import cv2
import numpy as np
from skimage.feature import local_binary_pattern
import dlib
import imutils
from PIL import Image as PILImage
from src.cv_utils import get_image, resize_image_height
from typing import Tuple, List, Union
class GetFaceTexture:
def __init__(self) -> None:
pass
@staticmethod
def preprocess_image(image) -> np.array:
image = imutils.resize(image, width=500)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
return gray_image
@staticmethod
def get_face(gray_image: np.array) -> np.array:
detector = dlib.get_frontal_face_detector()
faces = detector(gray_image, 1)
if len(faces) == 0:
return "No face detected."
x, y, w, h = (
faces[0].left(),
faces[0].top(),
faces[0].width(),
faces[0].height(),
)
face_image = gray_image[y : y + h, x : x + w]
return face_image
@staticmethod
def get_face_texture(face_image: np.array) -> Tuple[np.array, float]:
radius = 1
n_points = 8 * radius
lbp = local_binary_pattern(face_image, n_points, radius, method="uniform")
hist, _ = np.histogram(
lbp.ravel(), bins=np.arange(0, n_points + 3), range=(0, n_points + 2)
)
variance = np.var(hist)
std = np.sqrt(variance)
return lbp, std
@staticmethod
def postprocess_image(lbp: np.array) -> PILImage:
lbp = (lbp * 255).astype(np.uint8)
return PILImage.fromarray(lbp)
def main(self, image_input) -> List[Union[PILImage.Image, PILImage.Image, dict]]:
image = get_image(image_input)
gray_image = self.preprocess_image(image)
face_image = self.get_face(gray_image)
lbp, std = self.get_face_texture(face_image)
face_texture_image = self.postprocess_image(lbp)
face_image = PILImage.fromarray(face_image)
face_image = resize_image_height(face_image, new_height=300)
face_texture_image = resize_image_height(face_texture_image, new_height=300)
return face_image, face_texture_image, {"texture_std": round(std, 2)}
if __name__ == "__main__":
image_path = "data/gigi_hadid.webp"
print(GetFaceTexture().main(image_path))