docs: examples

This commit is contained in:
kweijack
2024-07-09 02:29:20 +00:00
parent 2b438a7b20
commit 8b6d769350
10 changed files with 308 additions and 13 deletions

View File

@@ -1,4 +1,9 @@
# face
[![GoDoc](https://pkg.go.dev/badge/github.com/dev6699/face)](https://pkg.go.dev/github.com/dev6699/face)
[![Go Report Card](https://goreportcard.com/badge/github.com/dev6699/face)](https://goreportcard.com/report/github.com/dev6699/face)
[![License](https://img.shields.io/github/license/dev6699/face)](LICENSE)
A comprehensive collection of face AI models with integrated pre and post-processing steps, utilizing NVIDIA Triton Inference Server for seamless inference. This repository aims to provide easy-to-use face detection, recognition, and analysis tools.
## Table of Contents
@@ -21,28 +26,34 @@ This repository contains a suite of face AI models designed for various applicat
- <b>Easy-to-Use Interface:</b> Simple API for quick integration into various applications.
## Installation
1. Clone the Repository:
- ### Use `go get` to install this package:
```bash
go get github.com/dev6699/face
```
- ### Clone the Repository:
```bash
git clone https://github.com/dev6699/face.git
cd face
```
2. Open the repository in vscode devcontainer.
### Download and Prepare Models:
- Navigate to the [Available Models](#available-models) section to find the download links for each model.
- Download each model and rename the file to `model.onnx`.
- Place each `model.onnx` file into its respective directory within the model_repository folder.
- Example: Setting up the YOLOFace model:
3. Download and Prepare Models:
- Navigate to the [Available Models](#available-models) section to find the download links for each model.
- Download each model and rename the file to `model.onnx`.
- Place each `model.onnx` file into its respective directory within the model_repository folder.
- Example: Setting up the YOLOFace model:
```bash
mkdir -p model_repository/yoloface/1
wget -O model_repository/yoloface/1/model.onnx <model_url>
```
Ensure to replace <model_url> with the actual URL provided in the [Available Models](#available-models) section.
```bash
mkdir -p model_repository/yoloface/1
wget -O model_repository/yoloface/1/model.onnx <model_url>
```
Ensure to replace <model_url> with the actual URL provided in the [Available Models](#available-models) section.
## Usage
Please refer to the [examples](examples) folder for more information on how to use the models and run various tasks.
1. Start Triton Inference Server:
```bash

View File

@@ -15,3 +15,7 @@ services:
reservations:
devices:
- capabilities: [gpu]
networks:
default:
name: face_devcontainer_default

46
examples/2dfan4/main.go Normal file
View File

@@ -0,0 +1,46 @@
package main
import (
"log"
"github.com/dev6699/face/client"
"github.com/dev6699/face/examples"
"github.com/dev6699/face/model"
_2dfan4 "github.com/dev6699/face/model/2dfan4"
"github.com/dev6699/face/model/yoloface"
"gocv.io/x/gocv"
)
func main() {
faceDetectorScore := float32(0.5)
iouThreshold := 0.4
yolofaceFactory := yoloface.NewFactory(faceDetectorScore, iouThreshold)
_2dfan4Factory := _2dfan4.NewFactory()
err := client.Init(
"tritonserver:8001",
[]model.ModelMeta{
yolofaceFactory(),
_2dfan4Factory(),
},
)
if err != nil {
log.Fatal(err)
}
img := gocv.IMRead("../image.jpg", gocv.IMReadColor)
yoloFaceOutput, err := client.Infer(yolofaceFactory, &yoloface.Input{Img: img})
if err != nil {
log.Fatal(err)
}
for _, d := range yoloFaceOutput.Detections {
fanOutput, err := client.Infer(_2dfan4Factory, &_2dfan4.Input{Img: img, BoundingBox: d.BoundingBox})
if err != nil {
log.Fatal(err)
}
examples.DrawPoints(&img, fanOutput.FaceLandmark68.Data, examples.Red, 2)
}
gocv.IMWrite("output.jpg", img)
}

52
examples/arcface/main.go Normal file
View File

@@ -0,0 +1,52 @@
package main
import (
"fmt"
"log"
"github.com/dev6699/face/client"
"github.com/dev6699/face/model"
"github.com/dev6699/face/model/arcface"
"github.com/dev6699/face/model/yoloface"
"gocv.io/x/gocv"
)
func main() {
faceDetectorScore := float32(0.5)
iouThreshold := 0.4
yolofaceFactory := yoloface.NewFactory(faceDetectorScore, iouThreshold)
arcfaceFactory := arcface.NewFactory()
err := client.Init(
"tritonserver:8001",
[]model.ModelMeta{
yolofaceFactory(),
arcfaceFactory(),
},
)
if err != nil {
log.Fatal(err)
}
img := gocv.IMRead("../image.jpg", gocv.IMReadColor)
yoloFaceOutput, err := client.Infer(yolofaceFactory, &yoloface.Input{Img: img})
if err != nil {
log.Fatal(err)
}
faceEmbeddings := [][]float32{}
for _, d := range yoloFaceOutput.Detections {
arcfaceOutput, err := client.Infer(arcfaceFactory, &arcface.Input{Img: img, FaceLandmark5: d.FaceLandmark5})
if err != nil {
log.Fatal(err)
}
faceEmbeddings = append(faceEmbeddings, arcfaceOutput.NormedEmbedding)
}
similarDistance := 0.6
for i, f1 := range faceEmbeddings {
for j, f2 := range faceEmbeddings {
faceDistance := model.CalcFaceDistance(f1, f2)
isSimilar := faceDistance < similarDistance
fmt.Printf("Face %d & %d: %.2f %v\n", i, j, faceDistance, isSimilar)
}
}
}

View File

@@ -0,0 +1,51 @@
package main
import (
"fmt"
"log"
"github.com/dev6699/face/client"
"github.com/dev6699/face/examples"
"github.com/dev6699/face/model"
"github.com/dev6699/face/model/genderage"
"github.com/dev6699/face/model/yoloface"
"gocv.io/x/gocv"
)
func main() {
faceDetectorScore := float32(0.5)
iouThreshold := 0.4
yolofaceFactory := yoloface.NewFactory(faceDetectorScore, iouThreshold)
genderAgeFactory := genderage.NewFactory()
err := client.Init(
"tritonserver:8001",
[]model.ModelMeta{
yolofaceFactory(),
genderAgeFactory(),
},
)
if err != nil {
log.Fatal(err)
}
img := gocv.IMRead("../image.jpg", gocv.IMReadColor)
yoloFaceOutput, err := client.Infer(yolofaceFactory, &yoloface.Input{Img: img})
if err != nil {
log.Fatal(err)
}
for _, d := range yoloFaceOutput.Detections {
genderAgeOutput, err := client.Infer(genderAgeFactory, &genderage.Input{Img: img, BoundingBox: d.BoundingBox})
if err != nil {
log.Fatal(err)
}
genderString := "M"
if genderAgeOutput.Gender == 0 {
genderString = "F"
}
examples.DrawBoundingBoxes(&img, d.BoundingBox, fmt.Sprintf("%s %d", genderString, genderAgeOutput.Age), examples.Green, examples.Red)
}
gocv.IMWrite("output.jpg", img)
}

43
examples/gfpgan/main.go Normal file
View File

@@ -0,0 +1,43 @@
package main
import (
"fmt"
"log"
"github.com/dev6699/face/client"
"github.com/dev6699/face/model"
"github.com/dev6699/face/model/gfpgan"
"github.com/dev6699/face/model/yoloface"
"gocv.io/x/gocv"
)
func main() {
faceDetectorScore := float32(0.5)
iouThreshold := 0.4
yolofaceFactory := yoloface.NewFactory(faceDetectorScore, iouThreshold)
gfpganFactory := gfpgan.NewFactory(80.0)
err := client.Init(
"tritonserver:8001",
[]model.ModelMeta{
yolofaceFactory(),
gfpganFactory(),
},
)
if err != nil {
log.Fatal(err)
}
img := gocv.IMRead("../image.jpg", gocv.IMReadColor)
yoloFaceOutput, err := client.Infer(yolofaceFactory, &yoloface.Input{Img: img})
if err != nil {
log.Fatal(err)
}
for i, d := range yoloFaceOutput.Detections {
gfpganOutput, err := client.Infer(gfpganFactory, &gfpgan.Input{Img: img, FaceLandmark5: d.FaceLandmark5})
if err != nil {
log.Fatal(err)
}
gocv.IMWrite(fmt.Sprintf("output%d.jpg", i+1), gfpganOutput.OutFrame)
}
}

BIN
examples/image.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

26
examples/util.go Normal file
View File

@@ -0,0 +1,26 @@
package examples
import (
"image"
"image/color"
"github.com/dev6699/face/model"
"gocv.io/x/gocv"
)
var (
Red = color.RGBA{R: 255, G: 0, B: 0, A: 255}
Green = color.RGBA{R: 0, G: 255, B: 0, A: 255}
Blue = color.RGBA{R: 0, G: 0, B: 255, A: 255}
)
func DrawBoundingBoxes(img *gocv.Mat, box model.BoundingBox, text string, boxColor, textColor color.RGBA) {
gocv.Rectangle(img, image.Rectangle{Min: image.Point{X: int(box.X1), Y: int(box.Y1)}, Max: image.Point{X: int(box.X2), Y: int(box.Y2)}}, boxColor, 2)
gocv.PutText(img, text, image.Point{X: int(box.X1), Y: int(box.Y1) - 5}, gocv.FontHersheySimplex, 0.5, textColor, 2)
}
func DrawPoints(img *gocv.Mat, points []gocv.Point2f, col color.RGBA, radius int) {
for _, pt := range points {
gocv.Circle(img, image.Pt(int(pt.X), int(pt.Y)), radius, col, -1)
}
}

40
examples/yoloface/main.go Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"fmt"
"log"
"github.com/dev6699/face/client"
"github.com/dev6699/face/examples"
"github.com/dev6699/face/model"
"github.com/dev6699/face/model/yoloface"
"gocv.io/x/gocv"
)
func main() {
faceDetectorScore := float32(0.5)
iouThreshold := 0.4
yolofaceFactory := yoloface.NewFactory(faceDetectorScore, iouThreshold)
err := client.Init(
"tritonserver:8001",
[]model.ModelMeta{
yolofaceFactory(),
},
)
if err != nil {
log.Fatal(err)
}
img := gocv.IMRead("../image.jpg", gocv.IMReadColor)
yoloFaceOutput, err := client.Infer(yolofaceFactory, &yoloface.Input{Img: img})
if err != nil {
log.Fatal(err)
}
for _, d := range yoloFaceOutput.Detections {
examples.DrawBoundingBoxes(&img, d.BoundingBox, fmt.Sprintf("Score: %.2f", d.Confidence), examples.Green, examples.Green)
examples.DrawPoints(&img, d.FaceLandmark5, examples.Red, 3)
}
gocv.IMWrite("output.jpg", img)
}

View File

@@ -287,3 +287,25 @@ func getInverseVisionFrame(cropVisionFrame gocv.Mat, inverseMatrix gocv.Mat, tem
inverseVisionFrame.ConvertTo(&inverseVisionFrame, gocv.MatTypeCV64F)
return inverseVisionFrame
}
// CalcFaceDistance to calculate the distance between two face embeddings
func CalcFaceDistance(faceEmbedding, referenceFaceEmbedding []float32) float64 {
if len(faceEmbedding) == 0 || len(referenceFaceEmbedding) == 0 || len(faceEmbedding) != len(referenceFaceEmbedding) {
return 0
}
dotProduct := dotProduct(faceEmbedding, referenceFaceEmbedding)
return 1.0 - float64(dotProduct)
}
func dotProduct(v1, v2 []float32) float32 {
if len(v1) != len(v2) {
return 0
}
var result float32
for i := 0; i < len(v1); i++ {
result += v1[i] * v2[i]
}
return result
}