mirror of
https://github.com/dev6699/face.git
synced 2026-04-22 23:17:27 +08:00
feat: added arcface
This commit is contained in:
@@ -57,6 +57,18 @@ This repository contains a suite of face AI models designed for various applicat
|
||||
|
||||
<img src="docs/2dfan4.jpg" height=200>
|
||||
|
||||
### ArcFace for Feature Embedding
|
||||
- Model Name: [arcface](model/arcface/arcface.go)
|
||||
- Description: Generates feature embeddings for faces, useful for identity verification and facial recognition tasks.
|
||||
- Download Link: [Download ArcFace Model](https://github.com/facefusion/facefusion-assets/releases/download/models/arcface_w600k_r50.onnx)
|
||||
|
||||
*Cosine distance of arcface embedding*
|
||||
| Source\Target | <img src="docs/arcface_1.jpg" height=80 align=right> | <img src="docs/arcface_2.jpg" height=80 align=right> | <img src="docs/arcface_3.jpg" height=80 align=right> |
|
||||
| :-----: | :-: | :---: | :-----: |
|
||||
| <img src="docs/arcface_1.jpg" height=80 align=right> | 0.00 | 0.29 | 0.48 |
|
||||
| <img src="docs/arcface_2.jpg" height=80 align=right> | 0.29 | 0.00 | 0.45 |
|
||||
| <img src="docs/arcface_3.jpg" height=80 align=right> | 0.48 | 0.45 | 0.00 |
|
||||
|
||||
### Gender and Age Estimation
|
||||
- Model Name: [gender_age](model/genderage/genderage.go)
|
||||
- Description: Detects gender and estimates the age of detected faces.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,40 @@
|
||||
package arcface
|
||||
|
||||
import (
|
||||
"github.com/dev6699/face/model"
|
||||
"gocv.io/x/gocv"
|
||||
)
|
||||
|
||||
type Model struct{}
|
||||
|
||||
type Input struct {
|
||||
Img gocv.Mat
|
||||
FaceLandmark5 []gocv.Point2f
|
||||
}
|
||||
|
||||
type Output struct {
|
||||
Embedding []float32
|
||||
NormedEmbedding []float32
|
||||
}
|
||||
|
||||
type TModel = model.Model[*Input, *Output]
|
||||
|
||||
var _ TModel = &Model{}
|
||||
|
||||
func NewFactory() func() TModel {
|
||||
return func() TModel {
|
||||
return New()
|
||||
}
|
||||
}
|
||||
|
||||
func New() *Model {
|
||||
return &Model{}
|
||||
}
|
||||
|
||||
func (m *Model) ModelName() string {
|
||||
return "arcface_w600k_r50"
|
||||
}
|
||||
|
||||
func (m *Model) ModelVersion() string {
|
||||
return "1"
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package arcface
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/dev6699/face/model"
|
||||
)
|
||||
|
||||
func (m *Model) PostProcess(rawOutputContents [][]byte) (*Output, error) {
|
||||
// "outputs": [
|
||||
// {
|
||||
// "name": "683",
|
||||
// "datatype": "FP32",
|
||||
// "shape": [
|
||||
// 1,
|
||||
// 512
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
embedding, err := model.BytesToFloat32Slice(rawOutputContents[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
normedEmbedding := normalizeEmbedding(embedding)
|
||||
|
||||
return &Output{
|
||||
Embedding: embedding,
|
||||
NormedEmbedding: normedEmbedding,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Normalize the embedding
|
||||
func normalizeEmbedding(embedding []float32) []float32 {
|
||||
normalizeEmbedding := make([]float32, len(embedding))
|
||||
norm := float32(l2Norm(embedding))
|
||||
if norm == 0 {
|
||||
normalizeEmbedding = append(normalizeEmbedding, embedding...)
|
||||
return normalizeEmbedding // Avoid division by zero
|
||||
}
|
||||
|
||||
for i, val := range embedding {
|
||||
normalizeEmbedding[i] = (val / norm)
|
||||
}
|
||||
return normalizeEmbedding
|
||||
}
|
||||
|
||||
// Compute the L2 norm of a vector
|
||||
func l2Norm(vector []float32) float64 {
|
||||
var sum float64
|
||||
for _, val := range vector {
|
||||
sum += float64(val * val)
|
||||
}
|
||||
return math.Sqrt(sum)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package arcface
|
||||
|
||||
import (
|
||||
"github.com/dev6699/face/model"
|
||||
"github.com/dev6699/face/protobuf"
|
||||
"gocv.io/x/gocv"
|
||||
)
|
||||
|
||||
func (m *Model) PreProcess(i *Input) ([]*protobuf.InferTensorContents, error) {
|
||||
cropVisionFrame, affineMatrix := model.WarpFaceByFaceLandmark5(
|
||||
i.Img,
|
||||
i.FaceLandmark5,
|
||||
arcface_112_v2,
|
||||
model.Size{Width: 112, Height: 112},
|
||||
)
|
||||
defer cropVisionFrame.Close()
|
||||
defer affineMatrix.Close()
|
||||
|
||||
d := []float32{}
|
||||
cropVisionFrame.ConvertTo(&cropVisionFrame, gocv.MatTypeCV32F)
|
||||
cropVisionFrame.DivideFloat(127.5)
|
||||
model.MatSubtract(cropVisionFrame, 1.0)
|
||||
|
||||
rgbChannels := gocv.Split(cropVisionFrame)
|
||||
b := rgbChannels[2]
|
||||
defer b.Close()
|
||||
bd, _ := b.DataPtrFloat32()
|
||||
d = append(d, bd...)
|
||||
|
||||
g := rgbChannels[1]
|
||||
defer g.Close()
|
||||
gd, _ := g.DataPtrFloat32()
|
||||
d = append(d, gd...)
|
||||
|
||||
r := rgbChannels[0]
|
||||
defer r.Close()
|
||||
rd, _ := r.DataPtrFloat32()
|
||||
d = append(d, rd...)
|
||||
|
||||
contents := &protobuf.InferTensorContents{
|
||||
Fp32Contents: d,
|
||||
}
|
||||
return []*protobuf.InferTensorContents{contents}, nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package arcface
|
||||
|
||||
import "gocv.io/x/gocv"
|
||||
|
||||
var arcface_112_v2 = []gocv.Point2f{
|
||||
{X: 0.34191607, Y: 0.46157411},
|
||||
{X: 0.65653393, Y: 0.45983393},
|
||||
{X: 0.50022500, Y: 0.64050536},
|
||||
{X: 0.37097589, Y: 0.82469196},
|
||||
{X: 0.63151696, Y: 0.82325089},
|
||||
}
|
||||
Reference in New Issue
Block a user