face

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2025 License: GPL-3.0 Imports: 22 Imported by: 0

README

Go Face Recognizer

A high-performance face recognition library for Go, combining Pigo (fast detection) and GoCV (feature extraction), with support for multiple deep learning models and multi-sample recognition.

Features

Fast Detection: Efficient face detection using Pigo
Multiple Models: Support for OpenFace, FaceNet, ArcFace, Dlib, and custom models
Flexible Configuration: Options pattern for easy customization
Multi-Sample Training: Register multiple photos per person for improved accuracy
Persistent Storage: Save/load face database in JSON format
Thread-Safe: Built-in concurrency control for multi-threaded environments
Easy to Use: Clean and intuitive API design

Dependencies

Go Packages
go get -u gocv.io/x/gocv
go get -u github.com/esimov/pigo/core
System Dependencies

OpenCV (required for GoCV):

# macOS
brew install opencv

# Ubuntu/Debian
sudo apt-get install libopencv-dev

# For detailed installation, see GoCV documentation
# https://gocv.io/getting-started/

Model Files

Use the built-in model downloader:

# Download required models (Pigo + OpenFace)
go run cmd/download-models/main.go

# List available models
go run cmd/download-models/main.go -list

# Download specific model
go run cmd/download-models/main.go -model=openface

# Download all available models
go run cmd/download-models/main.go -all

# Custom output directory
go run cmd/download-models/main.go -output=/path/to/models

Or use the downloader in your code:

import fr "github.com/lib-x/face"

// Download required models
downloader := fr.NewModelDownloader("./models")
if err := downloader.DownloadRequired(); err != nil {
    log.Fatal(err)
}

// Download specific model
if err := downloader.Download("openface"); err != nil {
    log.Fatal(err)
}
Toolchains
Arch User
paru -S  hdf5 vtk opencv opencv-samples base-devel pkgconf
Manual Download

If you prefer manual download:

  1. Pigo Face Detector
mkdir -p models
wget https://raw.githubusercontent.com/esimov/pigo/master/cascade/facefinder -O models/facefinder
  1. OpenFace Model (96x96 input, 128-dim, fastest)
# Primary mirror
wget https://storage.cmusatyalab.org/openface-models/nn4.small2.v1.t7 -O models/nn4.small2.v1.t7

# Alternative mirrors if primary fails
wget https://raw.githubusercontent.com/pyannote/pyannote-data/master/openface.nn4.small2.v1.t7 -O models/nn4.small2.v1.t7
# OR
wget https://files.kde.org/digikam/facesengine/dnnface/openface_nn4.small2.v1.t7 -O models/nn4.small2.v1.t7
  1. Other Models (optional):

FaceNet (160x160 input, 128-dim, balanced)

# Download from TensorFlow models repository
# See: https://github.com/davidsandberg/facenet

ArcFace (112x112 input, 512-dim, most accurate)

# Download ONNX model
# See: https://github.com/onnx/models/tree/main/vision/body_analysis/arcface
Available Models
Model Auto-Download Size MD5 Checksum
Pigo facefinder ~50KB N/A
OpenFace nn4.small2.v1 ~30MB c95bfd8cc1adf05210e979ff623013b6
FaceNet Variable Manual
ArcFace Variable Manual

Quick Start

1. Basic Usage with Default Model
package main

import (
    "fmt"
    fr "github.com/lib-x/face"
    "gocv.io/x/gocv"
)

func main() {
    // Initialize with default OpenFace model
    recognizer, err := fr.NewFaceRecognizer(
        fr.Config{
            PigoCascadeFile:  "./models/facefinder",
            FaceEncoderModel: "./models/nn4.small2.v1.t7",
        },
    )
    if err != nil {
        panic(err)
    }
    defer recognizer.Close()
    
    // Add a person
    recognizer.AddPerson("001", "Alice")
    
    // Add face samples
    img := gocv.IMRead("alice.jpg", gocv.IMReadColor)
    recognizer.AddFaceSample("001", img)
    img.Close()
    
    // Recognize faces
    testImg := gocv.IMRead("test.jpg", gocv.IMReadColor)
    results, _ := recognizer.Recognize(testImg)
    
    for _, r := range results {
        fmt.Printf("Found: %s (%.2f%%)\n", r.PersonName, r.Confidence*100)
    }
}
2. Using Different Models
// OpenFace (fastest, good accuracy)
recognizer, _ := fr.NewFaceRecognizer(
    fr.Config{
        PigoCascadeFile:  "./models/facefinder",
        FaceEncoderModel: "./models/nn4.small2.v1.t7",
    },
    fr.WithModelType(fr.ModelOpenFace),
    fr.WithSimilarityThreshold(0.6),
)

// FaceNet (balanced)
recognizer, _ := fr.NewFaceRecognizer(
    fr.Config{
        PigoCascadeFile:   "./models/facefinder",
        FaceEncoderModel:  "./models/facenet.pb",
        FaceEncoderConfig: "./models/facenet.pbtxt",
    },
    fr.WithModelType(fr.ModelFaceNet),
    fr.WithSimilarityThreshold(0.65),
)

// ArcFace (most accurate)
recognizer, _ := fr.NewFaceRecognizer(
    fr.Config{
        PigoCascadeFile:  "./models/facefinder",
        FaceEncoderModel: "./models/arcface.onnx",
    },
    fr.WithModelType(fr.ModelArcFace),
    fr.WithSimilarityThreshold(0.7),
)
3. Custom Configuration
recognizer, _ := fr.NewFaceRecognizer(
    fr.Config{
        PigoCascadeFile:  "./models/facefinder",
        FaceEncoderModel: "./models/nn4.small2.v1.t7",
    },
    // Set model type
    fr.WithModelType(fr.ModelOpenFace),
    // Set similarity threshold
    fr.WithSimilarityThreshold(0.65),
    // Set face detection parameters
    fr.WithMinFaceSize(80),
    fr.WithMaxFaceSize(800),
    // Or set all Pigo parameters at once
    fr.WithPigoParams(fr.PigoParams{
        MinSize:          80,
        MaxSize:          800,
        ShiftFactor:      0.1,
        ScaleFactor:      1.1,
        QualityThreshold: 6.0,
    }),
)
4. Custom Model Configuration
customModel := fr.ModelConfig{
    InputSize:   image.Pt(128, 128),
    FeatureDim:  256,
    MeanValues:  gocv.NewScalar(127.5, 127.5, 127.5, 0),
    ScaleFactor: 1.0 / 127.5,
    SwapRB:      true,
    Crop:        false,
}

recognizer, _ := fr.NewFaceRecognizer(
    fr.Config{
        PigoCascadeFile:  "./models/facefinder",
        FaceEncoderModel: "./models/custom.onnx",
    },
    fr.WithCustomModel(customModel),
)

Supported Model Types

Model Input Size Features Speed Accuracy Threshold
OpenFace 96x96 128-dim ⚡⚡⚡ ⭐⭐⭐ 0.6
FaceNet 160x160 128-dim ⚡⚡ ⭐⭐⭐⭐ 0.65
ArcFace 112x112 512-dim ⭐⭐⭐⭐⭐ 0.7
Dlib 150x150 128-dim ⚡⚡ ⭐⭐⭐⭐ 0.6
Custom Variable Variable - - Adjust

API Documentation

Initialization Options
// WithModelType sets predefined model configuration
func WithModelType(modelType ModelType) Option

// WithCustomModel sets custom model configuration
func WithCustomModel(config ModelConfig) Option

// WithSimilarityThreshold sets recognition threshold (0.0-1.0)
func WithSimilarityThreshold(threshold float32) Option

// WithPigoParams sets Pigo detector parameters
func WithPigoParams(params PigoParams) Option

// WithMinFaceSize sets minimum face size for detection
func WithMinFaceSize(size int) Option

// WithMaxFaceSize sets maximum face size for detection
func WithMaxFaceSize(size int) Option
Person Management
// Add a new person
func (fr *FaceRecognizer) AddPerson(id, name string) error

// Remove a person
func (fr *FaceRecognizer) RemovePerson(id string) error

// Get person information
func (fr *FaceRecognizer) GetPerson(id string) (*Person, error)

// List all persons
func (fr *FaceRecognizer) ListPersons() []*Person

// Get sample count for a person
func (fr *FaceRecognizer) GetSampleCount(personID string) (int, error)
Face Recognition
// Add a face sample for a person
func (fr *FaceRecognizer) AddFaceSample(personID string, img gocv.Mat) error

// Recognize faces in an image
func (fr *FaceRecognizer) Recognize(img gocv.Mat) ([]RecognizeResult, error)

// Detect faces (detection only, no recognition)
func (fr *FaceRecognizer) DetectFaces(img image.Image) []image.Rectangle

// Extract feature vector from face image
func (fr *FaceRecognizer) ExtractFeature(faceImg gocv.Mat) ([]float32, error)
Database Operations
// Save database to JSON file
func (fr *FaceRecognizer) SaveDatabase(filepath string) error

// Load database from JSON file
func (fr *FaceRecognizer) LoadDatabase(filepath string) error
Configuration
// Set similarity threshold
func (fr *FaceRecognizer) SetThreshold(threshold float32)

// Get current threshold
func (fr *FaceRecognizer) GetThreshold() float32

// Get model configuration
func (fr *FaceRecognizer) GetModelConfig() ModelConfig

Model Configuration Structure

type ModelConfig struct {
    Type        ModelType    // Model type identifier
    InputSize   image.Point  // Model input size (width, height)
    FeatureDim  int          // Feature vector dimension
    MeanValues  gocv.Scalar  // Mean values for normalization
    ScaleFactor float64      // Scale factor for normalization
    SwapRB      bool         // Swap Red and Blue channels
    Crop        bool         // Center crop input image
}

Recognition Result

type RecognizeResult struct {
    PersonID    string          // Person identifier
    PersonName  string          // Person name
    Confidence  float32         // Confidence score (0.0-1.0)
    BoundingBox image.Rectangle // Face bounding box
}

Best Practices

1. Sample Collection
  • Quantity: 3-5 photos per person
  • Variety: Different angles (front, left, right)
  • Expressions: Neutral, smiling, different expressions
  • Lighting: Various lighting conditions
  • Quality: Clear, high-resolution images
2. Threshold Selection

Strict Mode (0.7-0.8):

  • High precision, may miss some matches
  • Use when false positives are costly

Balanced Mode (0.6-0.7):

  • Recommended for most applications
  • Good balance between precision and recall

Relaxed Mode (0.5-0.6):

  • High recall, may have false positives
  • Use when missing matches is more costly
3. Model Selection

Use OpenFace when:

  • Speed is critical
  • Running on limited hardware
  • Good accuracy is sufficient

Use FaceNet when:

  • Need balanced performance
  • Moderate hardware available
  • Better accuracy required

Use ArcFace when:

  • Maximum accuracy needed
  • GPU available
  • Speed is less critical
4. Image Quality Requirements
  • Resolution: Minimum 640x480
  • Face Size: At least 100x100 pixels
  • Lighting: Avoid overexposure or underexposure
  • Clarity: Avoid motion blur
  • Angle: Frontal or near-frontal faces work best
5. Performance Optimization
// Concurrent processing
var wg sync.WaitGroup
results := make(chan []fr.RecognizeResult, len(images))

for _, imgPath := range images {
    wg.Add(1)
    go func(path string) {
        defer wg.Done()
        img := gocv.IMRead(path, gocv.IMReadColor)
        defer img.Close()
        
        res, _ := recognizer.Recognize(img)
        results <- res
    }(imgPath)
}

wg.Wait()
close(results)

Project Structure

your-project/
├── models/
│   ├── facefinder              # Pigo detector
│   ├── nn4.small2.v1.t7        # OpenFace model
│   ├── facenet.pb              # FaceNet model (optional)
│   └── arcface.onnx            # ArcFace model (optional)
├── images/
│   ├── person1_sample1.jpg
│   ├── person1_sample2.jpg
│   └── ...
├── test_images/
│   └── test.jpg
├── output/
│   └── results/
├── face_database.json          # Face database
└── main.go

Troubleshooting

Q: Low recognition accuracy?

A:

  1. Add more samples per person (3-5 recommended)
  2. Ensure sample quality (clear, well-lit, frontal)
  3. Adjust similarity threshold
  4. Try a different model (FaceNet or ArcFace)
  5. Verify model files are loaded correctly
Q: Face not detected?

A:

  1. Ensure face size is at least 100x100 pixels
  2. Check image quality and lighting
  3. Adjust Pigo's MinSize and MaxSize parameters
  4. Verify face is frontal or near-frontal
Q: What image formats are supported?

A: All formats supported by GoCV: JPG, PNG, BMP, TIFF, etc.

Q: Can this work with real-time video?

A: Yes, but consider:

  • Reduce frame rate (e.g., process every 5th frame)
  • Use faster model (OpenFace)
  • Detect faces first, then recognize only when needed
  • Consider GPU acceleration
Q: How to improve processing speed?

A:

  1. Use OpenFace model (fastest)
  2. Reduce image resolution
  3. Adjust Pigo's ShiftFactor and ScaleFactor
  4. Use batch processing with goroutines
  5. Enable GPU acceleration in OpenCV (if available)
Q: Different models give different results?

A: Yes, each model has different:

  • Training data
  • Architecture
  • Feature dimensions
  • Optimal thresholds

Test with your specific use case to find the best model.

Model Comparison

Speed Benchmark (on Intel i7, single core)
  • OpenFace: ~15ms per face
  • FaceNet: ~25ms per face
  • ArcFace: ~30ms per face
Accuracy (LFW dataset)
  • OpenFace: ~92%
  • FaceNet: ~99.63%
  • ArcFace: ~99.82%

Note: Actual performance varies based on hardware, image quality, and use case.

Advanced Usage

Batch Processing with Progress Tracking
type ProgressTracker struct {
    total     int
    processed int
    mu        sync.Mutex
}

func (pt *ProgressTracker) Update() {
    pt.mu.Lock()
    pt.processed++
    progress := float64(pt.processed) / float64(pt.total) * 100
    pt.mu.Unlock()
    fmt.Printf("\rProgress: %.1f%%", progress)
}

tracker := &ProgressTracker{total: len(images)}
// Use in concurrent processing...
Custom Distance Metrics
// The library uses cosine similarity by default
// You can implement custom metrics:

func customSimilarity(a, b []float32) float32 {
    // Your custom similarity calculation
    // Example: Euclidean distance
    var sum float32
    for i := range a {
        diff := a[i] - b[i]
        sum += diff * diff
    }
    return 1.0 / (1.0 + float32(math.Sqrt(float64(sum))))
}

License

MIT License

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  • Pigo - Fast face detection
  • GoCV - Go bindings for OpenCV
  • OpenFace - Face recognition toolkit
  • InsightFace - State-of-the-art face recognition

Acknowledgments

This library builds upon the excellent work of:

  • Pigo face detector by Endre Simo
  • GoCV by the Hybridgroup team
  • OpenFace, FaceNet, and ArcFace research teams

Documentation

Overview

Example

Example demonstrates basic face recognition workflow

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	// Initialize recognizer
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	recognizer, err := face.NewFaceRecognizer(config)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	// Register a person
	err = recognizer.AddPerson("001", "Alice")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Face recognition system initialized")
	fmt.Println("Person registered: Alice (ID: 001)")

}
Output:

Face recognition system initialized
Person registered: Alice (ID: 001)
Example (BatchRegistration)

Example_batchRegistration demonstrates registering multiple persons with multiple photos

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	storage, _ := face.NewFileStorage("./testdata/face_db")
	defer storage.Close()

	recognizer, err := face.NewFaceRecognizer(
		config,
		face.WithStorage(storage),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	// Batch registration data
	persons := map[string]struct {
		name   string
		photos []string
	}{
		"001": {name: "Alice", photos: []string{"alice1.jpg", "alice2.jpg"}},
		"002": {name: "Bob", photos: []string{"bob1.jpg", "bob2.jpg"}},
	}

	// Register each person
	for id, data := range persons {
		recognizer.AddPerson(id, data.name)
		fmt.Printf("Registered: %s (ID: %s)\n", data.name, id)

		// In real scenario, would load and add photos here
		// For example purposes, we just show the structure
		for i := range data.photos {
			fmt.Printf("  - Sample %d would be added\n", i+1)
		}
	}

	// List all registered persons
	persons_list := recognizer.ListPersons()
	fmt.Printf("\nTotal registered: %d persons\n", len(persons_list))

}
Output:

Registered: Alice (ID: 001)
  - Sample 1 would be added
  - Sample 2 would be added
Registered: Bob (ID: 002)
  - Sample 1 would be added
  - Sample 2 would be added

Total registered: 2 persons
Example (WorkflowComplete)

Example_workflowComplete demonstrates a complete workflow

package main

import (
	"fmt"
)

func main() {
	fmt.Println("Complete Face Recognition Workflow:")
	fmt.Println("")
	fmt.Println("Step 1: Initialize recognizer with file storage")
	fmt.Println("Step 2: Register persons and add face samples")
	fmt.Println("Step 3: Save data (automatic with file storage)")
	fmt.Println("Step 4: Load test image")
	fmt.Println("Step 5: Detect and recognize faces")
	fmt.Println("Step 6: Process recognition results")
	fmt.Println("")
	fmt.Println("API Usage:")
	fmt.Println("  storage, _ := face.NewFileStorage(\"./face_db\")")
	fmt.Println("  recognizer, _ := face.NewFaceRecognizer(config, face.WithStorage(storage))")
	fmt.Println("  recognizer.AddPerson(\"001\", \"Alice\")")
	fmt.Println("  recognizer.AddFaceSample(\"001\", img)")
	fmt.Println("  results, _ := recognizer.Recognize(testImg)")

}
Output:

Complete Face Recognition Workflow:

Step 1: Initialize recognizer with file storage
Step 2: Register persons and add face samples
Step 3: Save data (automatic with file storage)
Step 4: Load test image
Step 5: Detect and recognize faces
Step 6: Process recognition results

API Usage:
  storage, _ := face.NewFileStorage("./face_db")
  recognizer, _ := face.NewFaceRecognizer(config, face.WithStorage(storage))
  recognizer.AddPerson("001", "Alice")
  recognizer.AddFaceSample("001", img)
  results, _ := recognizer.Recognize(testImg)

Index

Examples

Constants

This section is empty.

Variables

View Source
var AvailableModels = map[string]ModelInfo{
	"pigo-facefinder": {
		Name:        "Pigo Face Detector",
		URL:         "https://raw.githubusercontent.com/esimov/pigo/master/cascade/facefinder",
		Filename:    "facefinder",
		Size:        51764,
		Description: "Pigo cascade classifier for face detection",
	},
	"openface": {
		Name:        "OpenFace nn4.small2.v1",
		URL:         "https://storage.cmusatyalab.org/openface-models/nn4.small2.v1.t7",
		Filename:    "nn4.small2.v1.t7",
		MD5:         "c95bfd8cc1adf05210e979ff623013b6",
		Size:        31510785,
		Description: "OpenFace face recognition model (96x96, 128-dim)",
		ModelType:   ModelOpenFace,
	},
	"openface-alternative": {
		Name:        "OpenFace nn4.small2.v1 (Mirror)",
		URL:         "https://raw.githubusercontent.com/pyannote/pyannote-data/master/openface.nn4.small2.v1.t7",
		Filename:    "nn4.small2.v1.t7",
		Size:        31510785,
		Description: "OpenFace model from alternative mirror",
		ModelType:   ModelOpenFace,
	},
	"openface-kde": {
		Name:        "OpenFace nn4.small2.v1 (KDE Mirror)",
		URL:         "https://files.kde.org/digikam/facesengine/dnnface/openface_nn4.small2.v1.t7",
		Filename:    "nn4.small2.v1.t7",
		Size:        31510785,
		Description: "OpenFace model from KDE mirror",
		ModelType:   ModelOpenFace,
	},
}

AvailableModels Available models for download

View Source
var SupportedImageFormats = []string{
	".jpg", ".jpeg",
	".png",
	".bmp",
	".tif", ".tiff",
	".webp",
	".gif",
}

SupportedImageFormats lists all supported image formats

Functions

func GetImageInfo

func GetImageInfo(filepath string) (width, height, channels int, err error)

GetImageInfo returns information about an image file

func GetModelPath

func GetModelPath(outputDir, modelKey string) (string, error)

GetModelPath returns the expected path for a downloaded model

func IsSupportedImageFormat

func IsSupportedImageFormat(filename string) bool

IsSupportedImageFormat checks if the file extension is supported

Example

ExampleIsSupportedImageFormat demonstrates format checking

package main

import (
	"fmt"

	"github.com/lib-x/face"
)

func main() {
	formats := []string{
		"photo.jpg",
		"image.png",
		"picture.gif",
		"document.pdf", // Not supported
	}

	for _, filename := range formats {
		if face.IsSupportedImageFormat(filename) {
			fmt.Printf("%s: supported\n", filename)
		} else {
			fmt.Printf("%s: not supported\n", filename)
		}
	}

}
Output:

photo.jpg: supported
image.png: supported
picture.gif: supported
document.pdf: not supported

func ListAvailableModels

func ListAvailableModels()

ListAvailableModels lists all available models

func LoadImage

func LoadImage(filepath string) (gocv.Mat, error)

LoadImage loads an image from file path Supports: JPG, PNG, BMP, TIFF, WebP, GIF

Example

ExampleLoadImage demonstrates how to load images in different formats

package main

import (
	"fmt"

	"github.com/lib-x/face"
)

func main() {
	// Check if image format is supported
	if face.IsSupportedImageFormat("photo.jpg") {
		fmt.Println("JPEG format is supported")
	}

	// Load image from file
	img, err := face.LoadImage("./testdata/sample.jpg")
	if err != nil {
		// Handle error - image file might not exist in example
		fmt.Println("Image loading example (file may not exist)")
		return
	}
	defer img.Close()

	fmt.Println("Image loaded successfully")

}
Output:

JPEG format is supported

func LoadImageFromBytes

func LoadImageFromBytes(data []byte) (gocv.Mat, error)

LoadImageFromBytes loads an image from byte slice

func LoadImageFromStdImage

func LoadImageFromStdImage(img image.Image) (gocv.Mat, error)

LoadImageFromStdImage converts standard Go image.Image to gocv.Mat

func SaveImage

func SaveImage(filepath string, img gocv.Mat) error

SaveImage saves a Mat to file

Types

type Config

type Config struct {
	PigoCascadeFile   string
	FaceEncoderModel  string
	FaceEncoderConfig string // Optional config file for some models
}

Config holds the basic configuration for FaceRecognizer

type DownloadProgress

type DownloadProgress struct {
	Total      int64
	Downloaded int64
	Percentage float64
	Speed      float64 // bytes per second
	Elapsed    time.Duration
}

DownloadProgress represents download progress

type FaceFeature

type FaceFeature struct {
	PersonID string    `json:"person_id"`
	Feature  []float32 `json:"feature"`
}

FaceFeature represents a face feature vector

type FaceRecognizer

type FaceRecognizer struct {
	// contains filtered or unexported fields
}

FaceRecognizer is the main face recognition engine

func NewFaceRecognizer

func NewFaceRecognizer(config Config, opts ...Option) (*FaceRecognizer, error)

NewFaceRecognizer creates a new FaceRecognizer instance

func (*FaceRecognizer) AddFaceSample

func (fr *FaceRecognizer) AddFaceSample(personID string, img gocv.Mat) error

AddFaceSample adds a face sample for a specific person

Example

ExampleFaceRecognizer_AddFaceSample demonstrates adding face samples

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	recognizer, err := face.NewFaceRecognizer(config)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	// Register person first
	recognizer.AddPerson("001", "Alice")

	// Load image (example - file may not exist)
	img, err := face.LoadImage("./testdata/alice.jpg")
	if err != nil {
		fmt.Println("Adding face sample example")
		fmt.Println("Note: Sample image file not found")
		return
	}
	defer img.Close()

	// Add face sample
	err = recognizer.AddFaceSample("001", img)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Face sample added for Alice")

}
Output:

Adding face sample example
Note: Sample image file not found

func (*FaceRecognizer) AddPerson

func (fr *FaceRecognizer) AddPerson(id, name string) error

AddPerson adds a new person to the recognition database

Example

ExampleFaceRecognizer_AddPerson demonstrates person registration

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	recognizer, err := face.NewFaceRecognizer(config)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	// Add a person
	err = recognizer.AddPerson("001", "Alice")
	if err != nil {
		log.Fatal(err)
	}

	// Add another person
	err = recognizer.AddPerson("002", "Bob")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Registered: Alice")
	fmt.Println("Registered: Bob")

}
Output:

Registered: Alice
Registered: Bob

func (*FaceRecognizer) Close

func (fr *FaceRecognizer) Close() error

Close releases all resources

func (*FaceRecognizer) DetectFaces

func (fr *FaceRecognizer) DetectFaces(img image.Image) []image.Rectangle

DetectFaces detects faces in an image using Pigo

func (*FaceRecognizer) ExtractFeature

func (fr *FaceRecognizer) ExtractFeature(faceImg gocv.Mat) ([]float32, error)

ExtractFeature extracts face feature vector using the configured model

func (*FaceRecognizer) GetModelConfig

func (fr *FaceRecognizer) GetModelConfig() ModelConfig

GetModelConfig returns the current model configuration

func (*FaceRecognizer) GetPerson

func (fr *FaceRecognizer) GetPerson(id string) (*Person, error)

GetPerson retrieves a person by ID

func (*FaceRecognizer) GetSampleCount

func (fr *FaceRecognizer) GetSampleCount(personID string) (int, error)

GetSampleCount returns the number of samples for a person

func (*FaceRecognizer) GetStorage

func (fr *FaceRecognizer) GetStorage() FaceStorage

GetStorage returns the storage backend

func (*FaceRecognizer) GetThreshold

func (fr *FaceRecognizer) GetThreshold() float32

GetThreshold returns the current similarity threshold

func (*FaceRecognizer) ListPersons

func (fr *FaceRecognizer) ListPersons() []*Person

ListPersons returns all registered persons

Example

ExampleFaceRecognizer_ListPersons demonstrates listing registered persons

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	recognizer, err := face.NewFaceRecognizer(config)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	// Add some persons
	recognizer.AddPerson("001", "Alice")
	recognizer.AddPerson("002", "Bob")
	recognizer.AddPerson("003", "Charlie")

	// List all persons
	persons := recognizer.ListPersons()

	fmt.Printf("Total registered persons: %d\n", len(persons))
	for _, person := range persons {
		fmt.Printf("ID: %s, Name: %s\n", person.ID, person.Name)
	}

}
Output:

Total registered persons: 3
ID: 001, Name: Alice
ID: 002, Name: Bob
ID: 003, Name: Charlie

func (*FaceRecognizer) LoadDatabase

func (fr *FaceRecognizer) LoadDatabase(filepath string) error

LoadDatabase loads the face database from a JSON file

func (*FaceRecognizer) Recognize

func (fr *FaceRecognizer) Recognize(img gocv.Mat) ([]RecognizeResult, error)

Recognize recognizes faces in an image

Example

ExampleFaceRecognizer_Recognize demonstrates face recognition

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	recognizer, err := face.NewFaceRecognizer(config)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	// This would normally recognize faces in an image
	// For this example, we just show the API usage
	fmt.Println("Face recognition API example:")
	fmt.Println("1. Load image with LoadImage()")
	fmt.Println("2. Call Recognize(img) to detect and identify faces")
	fmt.Println("3. Process RecognizeResult for each detected face")

}
Output:

Face recognition API example:
1. Load image with LoadImage()
2. Call Recognize(img) to detect and identify faces
3. Process RecognizeResult for each detected face

func (*FaceRecognizer) RemovePerson

func (fr *FaceRecognizer) RemovePerson(id string) error

RemovePerson removes a person from the database

func (*FaceRecognizer) SaveDatabase

func (fr *FaceRecognizer) SaveDatabase(filepath string) error

SaveDatabase saves the face database to a JSON file

func (*FaceRecognizer) SetThreshold

func (fr *FaceRecognizer) SetThreshold(threshold float32)

SetThreshold sets the similarity threshold

type FaceStorage

type FaceStorage interface {
	// SavePerson saves a person and their features
	SavePerson(person *Person) error

	// LoadPerson loads a person by ID
	LoadPerson(id string) (*Person, error)

	// LoadAllPersons loads all persons
	LoadAllPersons() ([]*Person, error)

	// DeletePerson deletes a person by ID
	DeletePerson(id string) error

	// PersonExists checks if a person exists
	PersonExists(id string) (bool, error)

	// Close closes the storage connection
	Close() error
}

FaceStorage defines the interface for face feature storage Implementations can use database, filesystem, or memory storage

type FileStorage

type FileStorage struct {
	// contains filtered or unexported fields
}

FileStorage implements filesystem-based storage (persistent)

func NewFileStorage

func NewFileStorage(baseDir string) (*FileStorage, error)

NewFileStorage creates a new filesystem storage

Example

ExampleNewFileStorage demonstrates persistent file storage

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	// Create file storage
	storage, err := face.NewFileStorage("./testdata/face_db")
	if err != nil {
		log.Fatal(err)
	}
	defer storage.Close()

	// Use with recognizer
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	recognizer, err := face.NewFaceRecognizer(
		config,
		face.WithStorage(storage),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	fmt.Println("File storage initialized")
	fmt.Println("Data will be persisted to: ./testdata/face_db")

}
Output:

File storage initialized
Data will be persisted to: ./testdata/face_db

func (*FileStorage) Close

func (s *FileStorage) Close() error

func (*FileStorage) DeletePerson

func (s *FileStorage) DeletePerson(id string) error

func (*FileStorage) LoadAllPersons

func (s *FileStorage) LoadAllPersons() ([]*Person, error)

func (*FileStorage) LoadPerson

func (s *FileStorage) LoadPerson(id string) (*Person, error)

func (*FileStorage) PersonExists

func (s *FileStorage) PersonExists(id string) (bool, error)

func (*FileStorage) SavePerson

func (s *FileStorage) SavePerson(person *Person) error

type JSONStorage

type JSONStorage struct {
	// contains filtered or unexported fields
}

JSONStorage implements a single JSON file storage (for small datasets)

func NewJSONStorage

func NewJSONStorage(filepath string) (*JSONStorage, error)

NewJSONStorage creates a new JSON file storage

Example

ExampleNewJSONStorage demonstrates single JSON file storage

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	// Create JSON storage
	storage, err := face.NewJSONStorage("./testdata/faces.json")
	if err != nil {
		log.Fatal(err)
	}
	defer storage.Close()

	fmt.Println("JSON storage initialized")
	fmt.Println("Data file: ./testdata/faces.json")

}
Output:

JSON storage initialized
Data file: ./testdata/faces.json

func (*JSONStorage) Close

func (s *JSONStorage) Close() error

func (*JSONStorage) DeletePerson

func (s *JSONStorage) DeletePerson(id string) error

func (*JSONStorage) LoadAllPersons

func (s *JSONStorage) LoadAllPersons() ([]*Person, error)

func (*JSONStorage) LoadPerson

func (s *JSONStorage) LoadPerson(id string) (*Person, error)

func (*JSONStorage) PersonExists

func (s *JSONStorage) PersonExists(id string) (bool, error)

func (*JSONStorage) SavePerson

func (s *JSONStorage) SavePerson(person *Person) error

type MemoryStorage

type MemoryStorage struct {
	// contains filtered or unexported fields
}

MemoryStorage implements in-memory storage (default, fast but volatile)

func NewMemoryStorage

func NewMemoryStorage() *MemoryStorage

NewMemoryStorage creates a new in-memory storage

Example

ExampleNewMemoryStorage demonstrates in-memory storage

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	// Create in-memory storage
	storage := face.NewMemoryStorage()

	// Use with recognizer
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	recognizer, err := face.NewFaceRecognizer(
		config,
		face.WithStorage(storage),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	fmt.Println("Memory storage initialized")

}
Output:

Memory storage initialized

func (*MemoryStorage) Close

func (s *MemoryStorage) Close() error

func (*MemoryStorage) DeletePerson

func (s *MemoryStorage) DeletePerson(id string) error

func (*MemoryStorage) LoadAllPersons

func (s *MemoryStorage) LoadAllPersons() ([]*Person, error)

func (*MemoryStorage) LoadPerson

func (s *MemoryStorage) LoadPerson(id string) (*Person, error)

func (*MemoryStorage) PersonExists

func (s *MemoryStorage) PersonExists(id string) (bool, error)

func (*MemoryStorage) SavePerson

func (s *MemoryStorage) SavePerson(person *Person) error

type ModelConfig

type ModelConfig struct {
	Type        ModelType
	InputSize   image.Point // Input image size for the model
	FeatureDim  int         // Feature vector dimension
	MeanValues  gocv.Scalar // Mean values for normalization
	ScaleFactor float64     // Scale factor for normalization
	SwapRB      bool        // Swap Red and Blue channels
	Crop        bool        // Center crop
}

ModelConfig holds model-specific configuration

type ModelDownloader

type ModelDownloader struct {
	OutputDir        string
	OnProgress       ProgressCallback
	Timeout          time.Duration
	SkipVerification bool
	ProxyURL         string // SOCKS5 or HTTP proxy URL (e.g., "socks5://127.0.0.1:10808")
}

ModelDownloader handles model file downloads

func NewModelDownloader

func NewModelDownloader(outputDir string) *ModelDownloader

NewModelDownloader creates a new model downloader

func (*ModelDownloader) Download

func (md *ModelDownloader) Download(modelKey string) error

Download downloads a model by its key

func (*ModelDownloader) DownloadAll

func (md *ModelDownloader) DownloadAll() error

DownloadAll downloads all available models

func (*ModelDownloader) DownloadModel

func (md *ModelDownloader) DownloadModel(model ModelInfo) error

DownloadModel downloads a specific model

func (*ModelDownloader) DownloadRequired

func (md *ModelDownloader) DownloadRequired() error

DownloadRequired downloads only the required models for basic functionality

type ModelInfo

type ModelInfo struct {
	Name        string
	URL         string
	Filename    string
	MD5         string // Optional checksum
	Size        int64  // Expected size in bytes
	Description string
	ModelType   ModelType
}

ModelInfo contains information about a downloadable model

type ModelType

type ModelType string

ModelType defines the face encoding model type

const (
	// ModelOpenFace is the OpenFace nn4.small2.v1 model (128-dim, 96x96 input)
	ModelOpenFace ModelType = "openface"
	// ModelFaceNet is the FaceNet model (128-dim, 160x160 input)
	ModelFaceNet ModelType = "facenet"
	// ModelArcFace is the ArcFace model (512-dim, 112x112 input)
	ModelArcFace ModelType = "arcface"
	// ModelDlib is the Dlib ResNet model (128-dim, 150x150 input)
	ModelDlib ModelType = "dlib"
	// ModelCustom allows custom model configuration
	ModelCustom ModelType = "custom"
)

type Option

type Option func(*FaceRecognizer)

Option is a function that configures FaceRecognizer

func WithCustomModel

func WithCustomModel(config ModelConfig) Option

WithCustomModel sets a custom model configuration

func WithMaxFaceSize

func WithMaxFaceSize(size int) Option

WithMaxFaceSize sets the maximum face size for detection

func WithMinFaceSize

func WithMinFaceSize(size int) Option

WithMinFaceSize sets the minimum face size for detection

func WithModelType

func WithModelType(modelType ModelType) Option

WithModelType sets the model type (uses predefined configuration)

Example

ExampleWithModelType demonstrates using different model types

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	// Use OpenFace model (default)
	recognizer, err := face.NewFaceRecognizer(
		config,
		face.WithModelType(face.ModelOpenFace),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	modelConfig := recognizer.GetModelConfig()
	fmt.Printf("Model type: %s\n", modelConfig.Type)
	fmt.Printf("Feature dimension: %d\n", modelConfig.FeatureDim)
	fmt.Printf("Input size: %dx%d\n", modelConfig.InputSize.X, modelConfig.InputSize.Y)

}
Output:

Model type: openface
Feature dimension: 128
Input size: 96x96

func WithPigoParams

func WithPigoParams(params PigoParams) Option

WithPigoParams sets custom Pigo detector parameters

func WithSimilarityThreshold

func WithSimilarityThreshold(threshold float32) Option

WithSimilarityThreshold sets the similarity threshold for recognition

Example

ExampleWithSimilarityThreshold demonstrates setting similarity threshold

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	config := face.Config{
		PigoCascadeFile:  "./testdata/facefinder",
		FaceEncoderModel: "./testdata/nn4.small2.v1.t7",
	}

	// Create recognizer with custom threshold
	recognizer, err := face.NewFaceRecognizer(
		config,
		face.WithSimilarityThreshold(0.7), // Higher threshold = stricter matching
	)
	if err != nil {
		log.Fatal(err)
	}
	defer recognizer.Close()

	threshold := recognizer.GetThreshold()
	fmt.Printf("Similarity threshold set to: %.2f\n", threshold)

}
Output:

Similarity threshold set to: 0.70

func WithStorage

func WithStorage(storage FaceStorage) Option

WithStorage sets a custom storage backend

type Person

type Person struct {
	ID       string        `json:"id"`
	Name     string        `json:"name"`
	Features []FaceFeature `json:"features"`
	// contains filtered or unexported fields
}

Person represents a person with multiple face samples

type PigoParams

type PigoParams struct {
	MinSize          int     // Minimum face size
	MaxSize          int     // Maximum face size
	ShiftFactor      float64 // Shift factor
	ScaleFactor      float64 // Scale factor
	QualityThreshold float32 // Detection quality threshold
}

PigoParams holds Pigo face detector parameters

type ProgressCallback

type ProgressCallback func(progress DownloadProgress)

ProgressCallback is called during download to report progress

type RecognizeResult

type RecognizeResult struct {
	PersonID    string          `json:"person_id"`
	PersonName  string          `json:"person_name"`
	Confidence  float32         `json:"confidence"`
	BoundingBox image.Rectangle `json:"bounding_box"`
}

RecognizeResult represents a face recognition result

type StorageMetadata

type StorageMetadata struct {
	TotalPersons  int       `json:"total_persons"`
	TotalFeatures int       `json:"total_features"`
	LastUpdated   time.Time `json:"last_updated"`
}

StorageMetadata contains metadata about stored persons

func GetStorageMetadata

func GetStorageMetadata(storage FaceStorage) (*StorageMetadata, error)

GetMetadata returns metadata about the storage

Example

ExampleGetStorageMetadata demonstrates getting storage statistics

package main

import (
	"fmt"
	"log"

	"github.com/lib-x/face"
)

func main() {
	storage := face.NewMemoryStorage()

	// Create person data for example
	person := &face.Person{
		ID:   "001",
		Name: "Alice",
		Features: []face.FaceFeature{
			{PersonID: "001", Feature: make([]float32, 128)},
			{PersonID: "001", Feature: make([]float32, 128)},
		},
	}
	storage.SavePerson(person)

	// Get metadata
	metadata, err := face.GetStorageMetadata(storage)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Total persons: %d\n", metadata.TotalPersons)
	fmt.Printf("Total features: %d\n", metadata.TotalFeatures)

}
Output:

Total persons: 1
Total features: 2

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL