-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #33 from Face-Tagger/release
Release Face Tagger v1.0.0
- Loading branch information
Showing
26 changed files
with
584 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build" | |
|
||
[project] | ||
name = "face_tagger" | ||
version = "0.0.6" | ||
version = "1.0.0" | ||
authors = [ | ||
{ name="Bae SungJoon", email="[email protected]" }, | ||
{ name="Yoon JongBeom", email="[email protected]" }, | ||
|
@@ -13,7 +13,7 @@ authors = [ | |
] | ||
description = "A library for face recognition in multiple images and classification of photos containing each individual." | ||
readme = "README.md" | ||
requires-python = ">=3.7" | ||
requires-python = ">=3.11" | ||
classifiers = [ | ||
"Programming Language :: Python :: 3", | ||
"License :: OSI Approved :: MIT License", | ||
|
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from setuptools import setup, find_packages | ||
|
||
with open('requirements.txt') as f: | ||
required = f.read().splitlines() | ||
|
||
setup( | ||
name="face_tagger", | ||
version="1.0.0", | ||
description="Python library designed to classify photos containing specific individuals from a collection of " | ||
"images.", | ||
author="Sohn YoungJin", | ||
author_email="[email protected]", | ||
packages=find_packages(), | ||
install_requires=required, | ||
classifiers=[ | ||
"Programming Language :: Python :: 3.11", | ||
"License :: OSI Approved :: MIT License", | ||
"Operating System :: OS Independent", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from .face_tagger import FaceTagger | ||
from .classifier import Classifier | ||
from .detector import Detector | ||
from .embedder import Embedder | ||
from .utils import resize_image, convert_bgr_to_rgb, bytes_to_cvimage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import hdbscan | ||
import torch | ||
|
||
|
||
class Classifier: | ||
""" | ||
Class for face classification. | ||
""" | ||
|
||
def __init__(self, min_faces_to_be_group=3, min_similarity_face_count=2): | ||
""" | ||
Constructor of Classifier class. | ||
:param min_faces_to_be_group: Minimum number of faces required to be classified as a group. | ||
:param min_similarity_Face_count: Minimum number of similar faces required to be included in a group. | ||
""" | ||
|
||
self.min_faces_to_be_group = min_faces_to_be_group | ||
self.min_similarity_face_count = min_similarity_face_count | ||
|
||
def convert_to_numpy(self, face_embeddings): | ||
""" | ||
Convert embeddings to numpy format. | ||
:param face_embeddings: Embeddings to convert. | ||
:return: Numpy format embeddings. | ||
""" | ||
|
||
return torch.stack(face_embeddings).view(len(face_embeddings), -1).detach().numpy() | ||
|
||
def cluster_embeddings(self, embeddings_np): | ||
""" | ||
Cluster embeddings using HDBSCAN. | ||
:param embeddings_np: Numpy format embeddings to cluster. | ||
:return: Cluster labels. | ||
""" | ||
|
||
hdbscan_cluster = hdbscan.HDBSCAN(min_samples=self.min_similarity_face_count, | ||
min_cluster_size=self.min_faces_to_be_group).fit(embeddings_np) | ||
|
||
return hdbscan_cluster.labels_ | ||
|
||
def classify_faces(self, face_embeddings): | ||
""" | ||
Classify faces using clustering. | ||
:param face_embeddings: Embeddings to classify. | ||
:return: Cluster labels. | ||
""" | ||
|
||
embeddings_np = self.convert_to_numpy(face_embeddings) | ||
|
||
return self.cluster_embeddings(embeddings_np) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from mtcnn import MTCNN | ||
|
||
|
||
class Detector: | ||
""" | ||
Class for face detection. | ||
""" | ||
|
||
def __init__(self): | ||
""" | ||
Constructor of Detector class. | ||
""" | ||
|
||
self.face_detector = MTCNN() | ||
|
||
def detect_face(self, image): | ||
""" | ||
Detects faces in an image. | ||
:param image: Image to detect faces. | ||
:return: Detected faces with their bounding boxes. | ||
""" | ||
|
||
# Face detection using MTCNN. | ||
return self.face_detector.detect_faces(image) | ||
|
||
def crop(self, image, face): | ||
""" | ||
Crops the face area from the image. | ||
:param image: Image from which to crop the face. | ||
:param face: Detected face with bounding box. | ||
:return: Cropped face image. | ||
""" | ||
|
||
x, y, width, height = face['box'] | ||
|
||
return image[y:y + height, x:x + width] | ||
|
||
def detect_face_and_crop(self, image): | ||
""" | ||
Detects faces in an image and returns cropped face images. | ||
:param image: Image to detect faces. | ||
:return: List of cropped face images. | ||
""" | ||
|
||
faces = self.detect_face(image) | ||
|
||
return [self.crop(image, face) for face in faces] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import torch | ||
import torchvision.transforms as transforms | ||
from facenet_pytorch import InceptionResnetV1 | ||
from .utils import resize_image, convert_bgr_to_rgb | ||
|
||
|
||
class Embedder: | ||
""" | ||
Class for face embedding. | ||
""" | ||
|
||
def __init__(self, use_gpu=False): | ||
""" | ||
Constructor of Embedder class. | ||
:param use_gpu: Use GPU or not. | ||
""" | ||
|
||
self.device = torch.device('cuda' if use_gpu and torch.cuda.is_available() else 'cpu') | ||
self.resnet = InceptionResnetV1(pretrained='vggface2').eval().to(self.device) | ||
self.transform = transforms.ToTensor() | ||
|
||
def prepare_image_tensor(self, face_image): | ||
""" | ||
Convert the image to tensor format and add batch dimension. | ||
:param face_image: An image to process. | ||
:return: Processed image tensor. | ||
""" | ||
|
||
return self.transform(face_image).unsqueeze(0).to(self.device) | ||
|
||
def compute_embeddings(self, face_image): | ||
""" | ||
Compute embeddings of an image. | ||
:param face_image: An image to compute embeddings. | ||
:return: Embeddings of an image. | ||
""" | ||
|
||
face_image = resize_image(face_image, 160, 160) | ||
face_image = convert_bgr_to_rgb(face_image) | ||
img_tensor = self.prepare_image_tensor(face_image) | ||
|
||
# Compute embeddings. | ||
img_embedding = self.resnet(img_tensor) | ||
|
||
return img_embedding.cpu() |
Oops, something went wrong.