Documentation
¶
Overview ¶
Package face is a from-scratch, standard-library-only port of a useful subset of OpenCV's contrib face module: classic (non-neural) face recognition. It implements the three canonical recognizers — Eigenfaces, Fisherfaces and Local Binary Pattern Histograms — plus the underlying Local Binary Pattern operator, using only the Go standard library and the root github.com/malcolmston/opencv package. There is no cgo and there are no third-party dependencies.
Beyond recognition the package now also provides a self-contained, integral-image Haar face *detector* (GetFacesHAAR), a trainable facial *landmark* localiser in the FacemarkLBF spirit (FacemarkLBF), a biologically-inspired feature descriptor (BIF) and a Minimum Average Correlation Energy filter (MACE) — so a full pipeline (detect, align by landmarks, describe, verify or identify) can be built without leaving this package. The objdetect subpackage still hosts a general Haar cascade classifier for production detection.
The recognizer interface ¶
Every model implements FaceRecognizer:
Train(images []*cv.Mat, labels []int) Predict(img *cv.Mat) (label int, confidence float64)
Train fits the model to labelled faces; Predict returns the best-matching label and a confidence score. Following OpenCV, the confidence is a distance in the model's feature space, so lower is better and an exact match scores 0. Malformed input (no images, mismatched label count, a nil/empty image, or Predict before Train) panics rather than returning an error, matching the root package's convention for programmer error.
Recognizers ¶
EigenFaceRecognizer — Eigenfaces. Flattens each face, mean-centres the set, and runs a principal-component analysis (PCA); faces are projected onto the leading eigenvectors ("eigenfaces") and matched by nearest neighbour. The PCA is computed from scratch: the mean-centred data's Gram matrix is eigendecomposed with a cyclic Jacobi solver (see the internal linear-algebra kernels) and mapped back to covariance eigenvectors, the Turk–Pentland small-matrix trick. Keep the top K components with NewEigenFaceRecognizer; fewer components give a coarser, lower-rank reconstruction, which EigenFaceRecognizer.Reconstruct exposes directly.
FisherFaceRecognizer — Fisherfaces. Reduces dimensionality with PCA (to N−C dimensions for N images and C classes) and then applies a linear discriminant analysis that maximises between-class scatter over within-class scatter, yielding up to C−1 discriminant axes. The generalized eigenproblem is solved by whitening the within-class scatter and eigendecomposing the transformed between-class scatter. Fisherfaces models class structure explicitly and is more robust to illumination than Eigenfaces.
LBPHFaceRecognizer — Local Binary Pattern Histograms. Encodes each face as a grid of local texture histograms and matches with the chi-square histogram distance. Because LBP depends only on the ordering of neighbouring pixel intensities, LBPH is inherently robust to monotonic brightness changes and needs no common face geometry.
Local Binary Patterns ¶
LBP computes the basic 3×3, 8-neighbour LBP code image (codes 0–255) and LBPUniform computes the uniform-pattern variant (labels 0–58, collapsing the non-uniform codes). The neighbour weighting is the fixed Ojala et al. convention documented on those functions, so codes are reproducible and can be checked by hand. Both operators reduce colour input to luma and return a Mat two pixels smaller in each dimension, since the pattern is undefined on the border.
The extended family adds LBPCircular, which samples any number of neighbours (up to eight) on a circle of arbitrary radius with bilinear interpolation, and LBPUniformRotInvariant, the rotation-invariant uniform ("riu2") operator whose labels (0–9) are unchanged by in-plane rotation of the texture.
Persistence, thresholds and richer prediction ¶
Every recognizer can be serialised to and from an io.Writer/io.Reader with encoding/gob via its Save/Load methods; a round trip reproduces predictions exactly. SetThreshold/GetThreshold set a maximum acceptable match distance, beyond which the threshold-aware PredictThreshold methods return Unknown rather than a spurious label. PredictCollect exposes the full, distance-sorted ranking of training samples behind a plain Predict, for k-nearest-neighbour voting or confidence analysis. The Eigenfaces and Fisherfaces subspaces are exposed as vectors and as renderable images (EigenVectors, MeanFace, EigenFaceImage, DiscriminantAxes, FisherFaceImage).
Detection, landmarks, descriptors and correlation filters ¶
GetFacesHAAR detects upright, face-like regions with a fixed set of Haar-like features evaluated in O(1) over an integral image, across scales and positions, with non-maximum suppression.
FacemarkLBF localises facial landmarks inside a face rectangle using a Supervised Descent cascade of ridge regressors over shape-indexed local features, converging from a learned mean shape toward the true landmarks.
BIF computes Biologically Inspired Features: a Gabor filter bank pooled across scale bands and a spatial grid into a compact, contrast-normalised descriptor.
MACE synthesises a Minimum Average Correlation Energy filter from one subject's images and verifies a query by the peak-to-sidelobe ratio of its correlation output, using a from-scratch 2D discrete Fourier transform.
Determinism ¶
Nothing in this package uses randomness: training and prediction (including landmark fitting, detection, BIF and MACE) are fully deterministic functions of their inputs, so repeated runs produce identical results. The only global state is an internal side table that records each recognizer's optional recognition threshold, keyed by the recognizer, and it does not affect determinism.
Relationship to the root package ¶
All image input and output uses the root cv.Mat type; colour reduction reuses the root's BT.601 luma weights and resampling reuses cv.Resize. The package deliberately does not import the sibling cv/* subpackages.
Deferred ¶
The following members of OpenCV's face module remain out of scope: the active-appearance and Kazemi landmark models (FacemarkAAM, FacemarkKazemi; the FacemarkLBF-style regression cascade is provided by FacemarkLBF) and deep face embeddings / DNN-based recognition. The general trained Haar cascade classifier remains in objdetect; GetFacesHAAR here is a self-contained, model-free detector rather than a cascade loader.
Index ¶
- Constants
- Variables
- func GetFacesHAAR(img *cv.Mat, params *HaarParams) []cv.Rect
- func LBP(img *cv.Mat) *cv.Mat
- func LBPCircular(img *cv.Mat, radius, neighbours int) *cv.Mat
- func LBPUniform(img *cv.Mat) *cv.Mat
- func LBPUniformRotInvariant(img *cv.Mat) *cv.Mat
- type BIF
- type EigenFaceRecognizer
- func (r *EigenFaceRecognizer) Dims() (rows, cols int)
- func (r *EigenFaceRecognizer) EigenFaceImage(i int) *cv.Mat
- func (r *EigenFaceRecognizer) EigenValues() []float64
- func (r *EigenFaceRecognizer) EigenVector(i int) []float64
- func (r *EigenFaceRecognizer) EigenVectors() [][]float64
- func (r *EigenFaceRecognizer) GetThreshold() float64
- func (r *EigenFaceRecognizer) Load(rd io.Reader) error
- func (r *EigenFaceRecognizer) Mean() []float64
- func (r *EigenFaceRecognizer) MeanFace() *cv.Mat
- func (r *EigenFaceRecognizer) NumComponents() int
- func (r *EigenFaceRecognizer) Predict(img *cv.Mat) (int, float64)
- func (r *EigenFaceRecognizer) PredictCollect(img *cv.Mat) []PredictedFace
- func (r *EigenFaceRecognizer) PredictThreshold(img *cv.Mat) (int, float64)
- func (r *EigenFaceRecognizer) Project(img *cv.Mat) []float64
- func (r *EigenFaceRecognizer) Reconstruct(coeffs []float64) []float64
- func (r *EigenFaceRecognizer) ReconstructImage(coeffs []float64) *cv.Mat
- func (r *EigenFaceRecognizer) Save(w io.Writer) error
- func (r *EigenFaceRecognizer) SetThreshold(t float64)
- func (r *EigenFaceRecognizer) Train(images []*cv.Mat, labels []int)
- type FaceRecognizer
- type FacemarkLBF
- type FisherFaceRecognizer
- func (r *FisherFaceRecognizer) DiscriminantAxes() [][]float64
- func (r *FisherFaceRecognizer) FisherFaceImage(k int) *cv.Mat
- func (r *FisherFaceRecognizer) GetThreshold() float64
- func (r *FisherFaceRecognizer) Load(rd io.Reader) error
- func (r *FisherFaceRecognizer) NumComponents() int
- func (r *FisherFaceRecognizer) Predict(img *cv.Mat) (int, float64)
- func (r *FisherFaceRecognizer) PredictCollect(img *cv.Mat) []PredictedFace
- func (r *FisherFaceRecognizer) PredictThreshold(img *cv.Mat) (int, float64)
- func (r *FisherFaceRecognizer) Project(img *cv.Mat) []float64
- func (r *FisherFaceRecognizer) Save(w io.Writer) error
- func (r *FisherFaceRecognizer) SetThreshold(t float64)
- func (r *FisherFaceRecognizer) Train(images []*cv.Mat, labels []int)
- type HaarParams
- type LBPHFaceRecognizer
- func (r *LBPHFaceRecognizer) GetThreshold() float64
- func (r *LBPHFaceRecognizer) Load(rd io.Reader) error
- func (r *LBPHFaceRecognizer) Predict(img *cv.Mat) (int, float64)
- func (r *LBPHFaceRecognizer) PredictCollect(img *cv.Mat) []PredictedFace
- func (r *LBPHFaceRecognizer) PredictThreshold(img *cv.Mat) (int, float64)
- func (r *LBPHFaceRecognizer) Save(w io.Writer) error
- func (r *LBPHFaceRecognizer) SetThreshold(t float64)
- func (r *LBPHFaceRecognizer) Train(images []*cv.Mat, labels []int)
- type MACE
- type PredictedFace
Examples ¶
Constants ¶
const Unknown = -1
Unknown is the label returned by the threshold-aware prediction methods (EigenFaceRecognizer.PredictThreshold and friends) when the nearest match lies beyond the configured recognition threshold, indicating the query face was not confidently recognised as any known subject. It mirrors OpenCV's convention of returning -1 for a rejected prediction.
Variables ¶
var ErrVersion = errors.New("face: incompatible serialized model version")
ErrVersion is returned by the Load methods when the gob stream was written by an incompatible version of the serialisation format.
Functions ¶
func GetFacesHAAR ¶ added in v0.4.0
func GetFacesHAAR(img *cv.Mat, params *HaarParams) []cv.Rect
GetFacesHAAR detects upright, face-like regions in img and returns their bounding rectangles. img is reduced to luma and summarised by an integral image so each window's Haar features cost O(1) regardless of size. Windows are scanned over a range of scales and positions; those whose combined feature response exceeds the acceptance score are kept and then reduced by greedy non-maximum suppression so each face yields a single box. Pass params nil to use DefaultHaarParams. The returned rectangles are ordered by descending score. It panics on a nil or empty image.
Example ¶
ExampleGetFacesHAAR locates a planted face-like pattern with the integral-image detector.
package main
import (
"fmt"
cv "github.com/malcolmston/opencv"
"github.com/malcolmston/opencv/face"
)
func main() {
img := cv.NewMat(72, 72, 1)
img.SetTo(130)
// A dark eye band over a bright field inside a 32-pixel window.
for y := 24; y < 32; y++ {
for x := 20; x < 52; x++ {
img.Set(y, x, 0, 40)
}
}
for y := 32; y < 50; y++ {
for x := 20; x < 52; x++ {
img.Set(y, x, 0, 210)
}
}
p := face.DefaultHaarParams()
p.MinSize = 24
p.MaxSize = 48
fmt.Println(len(face.GetFacesHAAR(img, &p)) > 0)
}
Output: true
func LBP ¶
LBP computes the basic 3×3 Local Binary Pattern code image of img. The image is first reduced to luma; each interior pixel is compared against its eight neighbours (see the package-level weighting) to form an 8-bit code in [0,255]. Because the pattern is undefined on the outer border, the result is a single-channel Mat of size (Rows−2)×(Cols−2): output pixel (y,x) holds the code of input pixel (y+1,x+1). In particular the LBP of a 3×3 image is a 1×1 Mat containing that single code.
LBP is illumination-robust by construction: adding a constant to every pixel preserves the neighbour ordering and therefore leaves the codes unchanged. It panics if img is smaller than 3×3.
Example ¶
ExampleLBP computes the Local Binary Pattern code of a hand-built 3×3 patch.
package main
import (
"fmt"
cv "github.com/malcolmston/opencv"
"github.com/malcolmston/opencv/face"
)
func main() {
m := cv.NewMat(3, 3, 1)
copy(m.Data, []uint8{
10, 200, 10,
200, 100, 200,
10, 200, 10,
})
out := face.LBP(m)
fmt.Println(out.Rows, out.Cols, out.Data[0])
}
Output: 1 1 170
func LBPCircular ¶ added in v0.4.0
LBPCircular computes the extended, circular Local Binary Pattern code image of img with the given radius and neighbour count. The image is reduced to luma; for each interior pixel the neighbours are sampled at equal angles on a circle of the given radius (bilinearly interpolated between the four surrounding pixels, since sample points rarely land on the integer grid) and thresholded against the centre, most-significant bit first. neighbours must be between 1 and 8 so a code still fits in the uint8 output; radius must be at least 1.
The result is a single-channel Mat of size (Rows−2r)×(Cols−2r): the r-pixel border, where the circle would fall outside the image, is dropped. With radius 1 and 8 neighbours the sampling reduces to the classic 3×3 pattern, up to the interpolation of the four diagonal neighbours (which are exact at radius 1). It panics on out-of-range parameters or an image too small to hold a single sampling neighbourhood.
func LBPUniform ¶
LBPUniform computes the uniform-pattern LBP label image of img. It is identical to LBP except that each 8-bit code is mapped to a compact label: the 58 "uniform" patterns (those with at most two 0↔1 transitions in their circular bit string) receive distinct labels 0–57, and every non-uniform pattern collapses to label 58, for 59 labels total. Uniform patterns capture the fundamental local textures (edges, corners, spots) and yield much shorter histograms. The result is a single-channel Mat of size (Rows−2)×(Cols−2). It panics if img is smaller than 3×3.
func LBPUniformRotInvariant ¶ added in v0.4.0
LBPUniformRotInvariant computes the rotation-invariant uniform LBP (the "riu2" operator) of img on the classic radius-1, 8-neighbour circle. Each uniform pattern (at most two circular 0↔1 transitions) is labelled by its number of set bits, giving labels 0–8; every non-uniform pattern collapses to label 9, for 10 labels total. Because the label is the popcount of a uniform code it is invariant to rotation of the neighbourhood, so the descriptor is unaffected by in-plane rotation of the texture, unlike LBPUniform.
The result is a single-channel Mat of size (Rows−2)×(Cols−2). It panics if img is smaller than 3×3.
Example ¶
ExampleLBPUniformRotInvariant labels a small patch with the rotation-invariant uniform operator, and shows a 90° rotation gets the same label.
package main
import (
"fmt"
cv "github.com/malcolmston/opencv"
"github.com/malcolmston/opencv/face"
)
func main() {
right := cv.NewMat(3, 3, 1)
copy(right.Data, []uint8{
0, 0, 0,
0, 100, 255,
0, 0, 0,
})
down := cv.NewMat(3, 3, 1)
copy(down.Data, []uint8{
0, 0, 0,
0, 100, 0,
0, 255, 0,
})
fmt.Println(face.LBPUniformRotInvariant(right).Data[0], face.LBPUniformRotInvariant(down).Data[0])
}
Output: 1 1
Types ¶
type BIF ¶ added in v0.4.0
type BIF struct {
// contains filtered or unexported fields
}
BIF computes Biologically Inspired Features. Construct one with NewBIF; the zero value is not usable.
func NewBIF ¶ added in v0.4.0
NewBIF returns a BIF descriptor with the given number of scales and orientations and a grid×grid spatial pooling grid. Scales use geometrically increasing Gabor envelopes; adjacent scales are MAX-pooled into bands, so at least two scales are required. It panics on non-positive parameters or fewer than two scales.
func (*BIF) Compute ¶ added in v0.4.0
Compute reduces img to luma and returns its BIF descriptor. Each Gabor response magnitude image (S1) is computed, adjacent scales are combined by per-pixel MAX into bands (C1), and every band/orientation map is average- pooled over a grid×grid layout, concatenating the cell means in band-major, orientation, row-major cell order. The descriptor is L2-normalised so overall contrast does not dominate the distance between two faces. It panics on a nil or empty image.
func (*BIF) FeatureLength ¶ added in v0.4.0
FeatureLength returns the length of the vector BIF.Compute produces: one value per (band, orientation, grid cell), where the number of bands is one fewer than the number of scales.
type EigenFaceRecognizer ¶
type EigenFaceRecognizer struct {
// contains filtered or unexported fields
}
EigenFaceRecognizer implements the classic Eigenfaces method (Turk & Pentland, 1991). Training flattens every face into a vector, computes their mean, and performs a principal-component analysis on the mean-centred data; the leading principal axes are the "eigenfaces" spanning the face subspace. Each training face is projected onto that subspace and remembered. A query face is projected the same way and classified by nearest neighbour (Euclidean distance) among the stored projections.
Eigenfaces are holistic: every training and query image is reduced to luma and resampled to a common geometry (that of the first training image), so the method is sensitive to alignment and illumination. Construct with NewEigenFaceRecognizer; the zero value is not usable.
Example ¶
ExampleEigenFaceRecognizer trains an Eigenfaces model on two gradient classes and classifies a fresh horizontal gradient.
package main
import (
"fmt"
cv "github.com/malcolmston/opencv"
"github.com/malcolmston/opencv/face"
)
// gradient builds a deterministic 12×12 single-channel test image: a horizontal
// ramp for dir 0 and a vertical ramp for dir 1.
func gradient(dir int) *cv.Mat {
const n = 12
m := cv.NewMat(n, n, 1)
for y := 0; y < n; y++ {
for x := 0; x < n; x++ {
var v float64
if dir == 0 {
v = 20 + 200*float64(x)/float64(n-1)
} else {
v = 20 + 200*float64(y)/float64(n-1)
}
m.Data[y*n+x] = uint8(v)
}
}
return m
}
func main() {
imgs := []*cv.Mat{gradient(0), gradient(0), gradient(1), gradient(1)}
labels := []int{0, 0, 1, 1}
r := face.NewEigenFaceRecognizer(0)
r.Train(imgs, labels)
label, _ := r.Predict(gradient(0))
fmt.Println(label)
}
Output: 0
func NewEigenFaceRecognizer ¶
func NewEigenFaceRecognizer(numComponents int) *EigenFaceRecognizer
NewEigenFaceRecognizer returns an untrained recognizer that keeps at most numComponents eigenfaces. Pass numComponents <= 0 to keep every component with non-negligible variance (at most one fewer than the number of training images).
func (*EigenFaceRecognizer) Dims ¶ added in v0.4.0
func (r *EigenFaceRecognizer) Dims() (rows, cols int)
Dims returns the (rows, cols) geometry every face is resampled to before projection, i.e. the shape of the mean face and each eigenface. It returns (0,0) before training.
func (*EigenFaceRecognizer) EigenFaceImage ¶ added in v0.4.0
func (r *EigenFaceRecognizer) EigenFaceImage(i int) *cv.Mat
EigenFaceImage renders the i-th eigenface as a viewable single-channel image of size rows×cols. Eigenfaces contain signed coefficients, so the values are contrast-normalised to fill [0,255] (the minimum maps to 0 and the maximum to 255) purely for display. It panics if the recognizer is untrained or i is out of range.
func (*EigenFaceRecognizer) EigenValues ¶
func (r *EigenFaceRecognizer) EigenValues() []float64
EigenValues returns the variance associated with each retained eigenface, in descending order. The returned slice is a copy.
func (*EigenFaceRecognizer) EigenVector ¶ added in v0.4.0
func (r *EigenFaceRecognizer) EigenVector(i int) []float64
EigenVector returns a copy of the i-th eigenface as a flat vector of length rows*cols, ordered by descending variance. It panics if the recognizer is untrained or i is out of range.
func (*EigenFaceRecognizer) EigenVectors ¶ added in v0.4.0
func (r *EigenFaceRecognizer) EigenVectors() [][]float64
EigenVectors returns the retained eigenfaces as rows: a K×(rows*cols) matrix whose k-th row is the k-th unit-length principal axis in pixel space, ordered by descending variance. The result is a deep copy; it is nil before training.
func (*EigenFaceRecognizer) GetThreshold ¶ added in v0.4.0
func (r *EigenFaceRecognizer) GetThreshold() float64
GetThreshold returns the recognition threshold set by EigenFaceRecognizer.SetThreshold, or 0 (unbounded) if none was set.
func (*EigenFaceRecognizer) Load ¶ added in v0.4.0
func (r *EigenFaceRecognizer) Load(rd io.Reader) error
Load restores a recognizer previously written with EigenFaceRecognizer.Save, replacing the receiver's state. It returns a decoding error, including ErrVersion when the stream was produced by an incompatible version.
func (*EigenFaceRecognizer) Mean ¶
func (r *EigenFaceRecognizer) Mean() []float64
Mean returns the average face vector learned during training (length rows*cols) as a copy. It returns nil before training.
func (*EigenFaceRecognizer) MeanFace ¶ added in v0.4.0
func (r *EigenFaceRecognizer) MeanFace() *cv.Mat
MeanFace renders the learned mean face as a viewable single-channel image of size rows×cols, saturating each averaged sample into [0,255]. It panics if the recognizer is untrained.
func (*EigenFaceRecognizer) NumComponents ¶
func (r *EigenFaceRecognizer) NumComponents() int
NumComponents returns the number of eigenfaces retained after training (which may be fewer than requested if the data has lower rank). It returns 0 before training.
func (*EigenFaceRecognizer) Predict ¶
func (r *EigenFaceRecognizer) Predict(img *cv.Mat) (int, float64)
Predict projects the query face into the eigenspace and returns the label of the nearest training projection along with the Euclidean distance to it (lower is more confident). It panics if the recognizer is untrained.
func (*EigenFaceRecognizer) PredictCollect ¶ added in v0.4.0
func (r *EigenFaceRecognizer) PredictCollect(img *cv.Mat) []PredictedFace
PredictCollect returns every training sample scored against img, sorted by ascending distance in the eigenspace. When a threshold has been set with EigenFaceRecognizer.SetThreshold, samples beyond it are omitted. This is the analogue of OpenCV's predict_collect with a StandardCollector: it exposes the full ranking behind a plain Predict, which is useful for k-nearest-neighbour voting or confidence analysis. It panics if the recognizer is untrained.
func (*EigenFaceRecognizer) PredictThreshold ¶ added in v0.4.0
func (r *EigenFaceRecognizer) PredictThreshold(img *cv.Mat) (int, float64)
PredictThreshold behaves like Predict but honours the recognition threshold: if the nearest training distance exceeds the value set with EigenFaceRecognizer.SetThreshold, it returns (Unknown, distance) instead of a spurious label. With no threshold set it is equivalent to Predict.
func (*EigenFaceRecognizer) Project ¶
func (r *EigenFaceRecognizer) Project(img *cv.Mat) []float64
Project returns the coordinates of img in the trained eigenspace (one coefficient per retained eigenface). It panics if the recognizer is untrained.
func (*EigenFaceRecognizer) Reconstruct ¶
func (r *EigenFaceRecognizer) Reconstruct(coeffs []float64) []float64
Reconstruct rebuilds a face vector (length rows*cols) from projection coefficients, using the first len(coeffs) eigenfaces. Supplying fewer coefficients yields a lower-rank approximation; this is the knob behind eigenface reconstruction-quality experiments. It panics if the recognizer is untrained.
func (*EigenFaceRecognizer) ReconstructImage ¶ added in v0.4.0
func (r *EigenFaceRecognizer) ReconstructImage(coeffs []float64) *cv.Mat
ReconstructImage rebuilds a face from projection coefficients (see EigenFaceRecognizer.Reconstruct) and renders it as a viewable single-channel image of size rows×cols. It panics if the recognizer is untrained.
func (*EigenFaceRecognizer) Save ¶ added in v0.4.0
func (r *EigenFaceRecognizer) Save(w io.Writer) error
Save writes the trained recognizer to w using encoding/gob. It panics if the recognizer is untrained and returns any encoding error from w.
Example ¶
ExampleEigenFaceRecognizer_Save trains a model, serialises it with gob and reloads it into a fresh recognizer that reproduces the original prediction.
imgs := []*cv.Mat{gradient(0), gradient(0), gradient(1), gradient(1)}
labels := []int{0, 0, 1, 1}
orig := face.NewEigenFaceRecognizer(0)
orig.Train(imgs, labels)
var buf bytes.Buffer
if err := orig.Save(&buf); err != nil {
panic(err)
}
loaded := face.NewEigenFaceRecognizer(0)
if err := loaded.Load(&buf); err != nil {
panic(err)
}
label, _ := loaded.Predict(gradient(1))
fmt.Println(label)
Output: 1
func (*EigenFaceRecognizer) SetThreshold ¶ added in v0.4.0
func (r *EigenFaceRecognizer) SetThreshold(t float64)
SetThreshold sets the maximum acceptable prediction distance for this recognizer. Predictions whose nearest distance exceeds t are reported as "unknown" (label Unknown) by the threshold-aware prediction methods. A non-positive t clears the threshold, restoring the default unbounded behaviour.
func (*EigenFaceRecognizer) Train ¶
func (r *EigenFaceRecognizer) Train(images []*cv.Mat, labels []int)
Train fits the eigenspace to the labelled images. Every image is reduced to luma and resampled to the first image's dimensions before flattening. It panics on malformed input (see FaceRecognizer).
type FaceRecognizer ¶
type FaceRecognizer interface {
// Train fits the recognizer to the labelled images.
Train(images []*cv.Mat, labels []int)
// Predict returns the best-matching label and its distance-based
// confidence (lower is more confident).
Predict(img *cv.Mat) (label int, confidence float64)
}
FaceRecognizer is the common interface implemented by every recognizer in this package: EigenFaceRecognizer, FisherFaceRecognizer and LBPHFaceRecognizer. It mirrors the shape of OpenCV's cv::face::FaceRecognizer.
Train fits the model to a set of labelled face images. Every image is reduced to single-channel luma; the holistic recognizers (Eigen, Fisher) additionally resample each image to a common geometry taken from the first training image. labels are arbitrary non-negative integers identifying the subject of each image; the same label may (and should) appear more than once.
Predict classifies a query face and returns the predicted label together with a confidence score. Following OpenCV's convention the confidence is a distance in the recognizer's feature space, so smaller is better and a perfect match scores 0. The unit differs per recognizer (Euclidean distance in the eigen/fisher subspace, chi-square histogram distance for LBPH).
Both methods panic on malformed input (no images, a label/image count mismatch, a nil or empty image, or Predict before Train) rather than returning an error, matching the panic-on-programmer-error style of the root package's pixel accessors.
type FacemarkLBF ¶ added in v0.4.0
type FacemarkLBF struct {
// contains filtered or unexported fields
}
FacemarkLBF is a trainable facial-landmark localiser. Construct one with NewFacemarkLBF; the zero value is not usable. After FacemarkLBF.Train it places numLandmarks landmarks inside any supplied face rectangle via FacemarkLBF.Fit.
func NewFacemarkLBF ¶ added in v0.4.0
func NewFacemarkLBF(numLandmarks int) *FacemarkLBF
NewFacemarkLBF returns an untrained localiser for numLandmarks landmarks. It uses sensible defaults: a five-stage cascade and a 5×5 shape-indexed sampling patch per landmark. Tune these with NewFacemarkLBFParams. It panics if numLandmarks is not positive.
func NewFacemarkLBFParams ¶ added in v0.4.0
func NewFacemarkLBFParams(numLandmarks, stages, radius int) *FacemarkLBF
NewFacemarkLBFParams returns an untrained localiser with an explicit number of cascade stages and patch radius (the sampling grid is (2*radius+1) square). It panics on non-positive parameters.
func (*FacemarkLBF) Fit ¶ added in v0.4.0
Fit places the landmarks in img inside the face rectangle rect and returns them as image-coordinate points. It starts from the mean shape and runs the trained cascade. It panics if the localiser is untrained.
func (*FacemarkLBF) MeanShapeAt ¶ added in v0.4.0
func (f *FacemarkLBF) MeanShapeAt(rect cv.Rect) []cv.Point
MeanShapeAt returns the learned mean shape placed inside rect, as image- coordinate points. This is the localiser's starting guess before regression and a useful baseline. It panics if the localiser is untrained.
func (*FacemarkLBF) NumLandmarks ¶ added in v0.4.0
func (f *FacemarkLBF) NumLandmarks() int
NumLandmarks returns the number of landmarks the localiser predicts.
func (*FacemarkLBF) Train ¶ added in v0.4.0
Train fits the cascade to labelled faces. images[i] carries a face inside rects[i], and shapes[i] gives that face's numLandmarks ground-truth landmark points in image coordinates. Landmarks are stored relative to their face rectangle so the model generalises across face positions and sizes. It panics on mismatched slice lengths, an empty set, or a shape with the wrong landmark count.
type FisherFaceRecognizer ¶
type FisherFaceRecognizer struct {
// contains filtered or unexported fields
}
FisherFaceRecognizer implements the Fisherfaces method (Belhumeur, Hespanha & Kriegman, 1997): a principal-component analysis for dimensionality reduction followed by a linear discriminant analysis (LDA) that maximises between-class scatter relative to within-class scatter. The PCA step first reduces the data to N−C dimensions (N training images, C classes) so the within-class scatter matrix is non-singular; the LDA step then finds at most C−1 discriminant axes. Compared with EigenFaceRecognizer, Fisherfaces explicitly models class structure and is markedly more robust to illumination changes.
Faces are reduced to luma and resampled to the first training image's geometry, exactly as for Eigenfaces. A query is projected through both the PCA and LDA stages and classified by nearest neighbour (Euclidean distance) in the discriminant subspace. Construct with NewFisherFaceRecognizer; the zero value is not usable.
func NewFisherFaceRecognizer ¶
func NewFisherFaceRecognizer(numComponents int) *FisherFaceRecognizer
NewFisherFaceRecognizer returns an untrained recognizer. numComponents caps the number of retained discriminant axes; pass numComponents <= 0 to keep the full C−1 axes, which is the usual choice.
func (*FisherFaceRecognizer) DiscriminantAxes ¶ added in v0.4.0
func (r *FisherFaceRecognizer) DiscriminantAxes() [][]float64
DiscriminantAxes returns the retained Fisher discriminant directions mapped back into pixel space, as rows of a K×(rows*cols) matrix. Each axis is the composition of the PCA basis with one LDA direction, i.e. the pixel-space "Fisherface" along which that discriminant projects. The result is a deep copy; it is nil before training.
func (*FisherFaceRecognizer) FisherFaceImage ¶ added in v0.4.0
func (r *FisherFaceRecognizer) FisherFaceImage(k int) *cv.Mat
FisherFaceImage renders the k-th discriminant axis (see FisherFaceRecognizer.DiscriminantAxes) as a contrast-normalised, viewable single-channel image of size rows×cols. It panics if the recognizer is untrained or k is out of range.
func (*FisherFaceRecognizer) GetThreshold ¶ added in v0.4.0
func (r *FisherFaceRecognizer) GetThreshold() float64
GetThreshold returns the recognition threshold, or 0 if unset.
func (*FisherFaceRecognizer) Load ¶ added in v0.4.0
func (r *FisherFaceRecognizer) Load(rd io.Reader) error
Load restores a recognizer previously written with FisherFaceRecognizer.Save.
func (*FisherFaceRecognizer) NumComponents ¶
func (r *FisherFaceRecognizer) NumComponents() int
NumComponents returns the number of discriminant axes retained after training. It returns 0 before training.
func (*FisherFaceRecognizer) Predict ¶
func (r *FisherFaceRecognizer) Predict(img *cv.Mat) (int, float64)
Predict projects the query through the PCA and LDA stages and returns the nearest training label with its Euclidean distance (lower is more confident). It panics if the recognizer is untrained.
func (*FisherFaceRecognizer) PredictCollect ¶ added in v0.4.0
func (r *FisherFaceRecognizer) PredictCollect(img *cv.Mat) []PredictedFace
PredictCollect returns every training sample scored against img in the discriminant subspace, sorted by ascending distance and threshold-filtered when a threshold is set. It panics if the recognizer is untrained.
func (*FisherFaceRecognizer) PredictThreshold ¶ added in v0.4.0
func (r *FisherFaceRecognizer) PredictThreshold(img *cv.Mat) (int, float64)
PredictThreshold behaves like Predict but returns Unknown when the nearest match is beyond the configured threshold.
func (*FisherFaceRecognizer) Project ¶
func (r *FisherFaceRecognizer) Project(img *cv.Mat) []float64
Project returns the coordinates of img in the trained discriminant subspace. It panics if the recognizer is untrained.
func (*FisherFaceRecognizer) Save ¶ added in v0.4.0
func (r *FisherFaceRecognizer) Save(w io.Writer) error
Save writes the trained recognizer to w using encoding/gob. It panics if the recognizer is untrained.
func (*FisherFaceRecognizer) SetThreshold ¶ added in v0.4.0
func (r *FisherFaceRecognizer) SetThreshold(t float64)
SetThreshold sets the maximum acceptable prediction distance; see EigenFaceRecognizer.SetThreshold.
type HaarParams ¶ added in v0.4.0
type HaarParams struct {
// MinSize is the smallest square window side, in pixels, that is scanned.
MinSize int
// MaxSize caps the largest window side; 0 means the smaller image side.
MaxSize int
// ScaleStep multiplies the window side between scales (must be > 1);
// 0 selects the default 1.25.
ScaleStep float64
// StepRatio sets the sliding stride as a fraction of the window side
// (clamped to at least one pixel); 0 selects the default 0.1.
StepRatio float64
// MinScore is the minimum combined feature response, in mean grey levels,
// for a window to be accepted; 0 selects the default 18.
MinScore float64
}
HaarParams tunes the GetFacesHAAR sliding-window search.
func DefaultHaarParams ¶ added in v0.4.0
func DefaultHaarParams() HaarParams
DefaultHaarParams returns the parameters GetFacesHAAR uses when passed a nil configuration: a scan from 24-pixel windows up to the image size, a 1.25 scale step, a 10%-of-window stride and a moderate acceptance score.
type LBPHFaceRecognizer ¶
type LBPHFaceRecognizer struct {
// GridX and GridY are the number of cells the LBP image is divided into
// horizontally and vertically.
GridX, GridY int
// Uniform selects uniform LBP labels (59-bin cell histograms) over the
// full 256-bin histograms.
Uniform bool
// contains filtered or unexported fields
}
LBPHFaceRecognizer implements Local Binary Pattern Histograms face recognition (Ahonen, Hadid & Pietikäinen, 2004). Each face is turned into an LBP code image (see LBP/LBPUniform), split into a GridX×GridY grid of cells, and summarised by concatenating the per-cell code histograms into one spatially-aware feature vector. A query face is described the same way and classified by nearest neighbour under the chi-square histogram distance.
Unlike the holistic recognizers, LBPH is a local, texture-based method: it needs no common geometry (histograms are size-independent) and is inherently robust to monotonic illumination changes, because LBP codes depend only on the ordering of neighbouring intensities. Construct with NewLBPHFaceRecognizer or NewLBPHFaceRecognizerWithParams; the zero value is not usable.
The neighbourhood is fixed at the classic radius-1, 8-neighbour 3×3 sampling.
Example ¶
ExampleLBPHFaceRecognizer trains an LBPH model on two gradient classes and classifies a fresh vertical gradient.
package main
import (
"fmt"
cv "github.com/malcolmston/opencv"
"github.com/malcolmston/opencv/face"
)
// gradient builds a deterministic 12×12 single-channel test image: a horizontal
// ramp for dir 0 and a vertical ramp for dir 1.
func gradient(dir int) *cv.Mat {
const n = 12
m := cv.NewMat(n, n, 1)
for y := 0; y < n; y++ {
for x := 0; x < n; x++ {
var v float64
if dir == 0 {
v = 20 + 200*float64(x)/float64(n-1)
} else {
v = 20 + 200*float64(y)/float64(n-1)
}
m.Data[y*n+x] = uint8(v)
}
}
return m
}
func main() {
imgs := []*cv.Mat{gradient(0), gradient(1)}
labels := []int{0, 1}
r := face.NewLBPHFaceRecognizerWithParams(2, 2, false)
r.Train(imgs, labels)
label, _ := r.Predict(gradient(1))
fmt.Println(label)
}
Output: 1
func NewLBPHFaceRecognizer ¶
func NewLBPHFaceRecognizer() *LBPHFaceRecognizer
NewLBPHFaceRecognizer returns an untrained recognizer with the OpenCV default geometry: an 8×8 grid and full 256-bin (non-uniform) histograms.
func NewLBPHFaceRecognizerWithParams ¶
func NewLBPHFaceRecognizerWithParams(gridX, gridY int, uniform bool) *LBPHFaceRecognizer
NewLBPHFaceRecognizerWithParams returns an untrained recognizer with an explicit grid and histogram type. It panics if gridX or gridY is not positive.
func (*LBPHFaceRecognizer) GetThreshold ¶ added in v0.4.0
func (r *LBPHFaceRecognizer) GetThreshold() float64
GetThreshold returns the recognition threshold, or 0 if unset.
func (*LBPHFaceRecognizer) Load ¶ added in v0.4.0
func (r *LBPHFaceRecognizer) Load(rd io.Reader) error
Load restores a recognizer previously written with LBPHFaceRecognizer.Save.
func (*LBPHFaceRecognizer) Predict ¶
func (r *LBPHFaceRecognizer) Predict(img *cv.Mat) (int, float64)
Predict describes the query face and returns the label of the nearest stored histogram together with their chi-square distance (lower is more confident). It panics if the recognizer is untrained.
func (*LBPHFaceRecognizer) PredictCollect ¶ added in v0.4.0
func (r *LBPHFaceRecognizer) PredictCollect(img *cv.Mat) []PredictedFace
PredictCollect returns every stored histogram scored against img under the chi-square distance, sorted ascending and threshold-filtered when a threshold is set. It panics if the recognizer is untrained.
func (*LBPHFaceRecognizer) PredictThreshold ¶ added in v0.4.0
func (r *LBPHFaceRecognizer) PredictThreshold(img *cv.Mat) (int, float64)
PredictThreshold behaves like Predict but returns Unknown when the nearest match is beyond the configured threshold.
func (*LBPHFaceRecognizer) Save ¶ added in v0.4.0
func (r *LBPHFaceRecognizer) Save(w io.Writer) error
Save writes the trained recognizer to w using encoding/gob. It panics if the recognizer is untrained.
func (*LBPHFaceRecognizer) SetThreshold ¶ added in v0.4.0
func (r *LBPHFaceRecognizer) SetThreshold(t float64)
SetThreshold sets the maximum acceptable prediction distance; see EigenFaceRecognizer.SetThreshold.
Example ¶
ExampleLBPHFaceRecognizer_SetThreshold rejects a query that lies beyond the configured recognition distance, returning face.Unknown.
imgs := []*cv.Mat{gradient(0), gradient(1)}
labels := []int{0, 1}
r := face.NewLBPHFaceRecognizerWithParams(2, 2, false)
r.Train(imgs, labels)
r.SetThreshold(1e-9) // impossibly strict: nothing is close enough
// A flat grey image is unlike either gradient, so it is rejected.
flat := cv.NewMat(12, 12, 1)
flat.SetTo(128)
label, _ := r.PredictThreshold(flat)
fmt.Println(label == face.Unknown)
Output: true
func (*LBPHFaceRecognizer) Train ¶
func (r *LBPHFaceRecognizer) Train(images []*cv.Mat, labels []int)
Train computes and stores the spatial LBP histogram of every labelled image. It panics on malformed input (see FaceRecognizer). Grid defaults are filled in when the struct was created without a constructor.
type MACE ¶ added in v0.4.0
type MACE struct {
// contains filtered or unexported fields
}
MACE is a synthesised Minimum Average Correlation Energy correlation filter. Construct one with NewMACE and fit it with MACE.Train; the zero value is not usable.
Example ¶
ExampleMACE synthesises a correlation filter and checks that an authentic image scores a far higher peak-to-sidelobe ratio than an impostor.
package main
import (
"fmt"
cv "github.com/malcolmston/opencv"
"github.com/malcolmston/opencv/face"
)
func main() {
tile := func(v0, v1 uint8) *cv.Mat {
m := cv.NewMat(16, 16, 1)
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
if (x/2+y/2)%2 == 0 {
m.Set(y, x, 0, v0)
} else {
m.Set(y, x, 0, v1)
}
}
}
return m
}
authentic := []*cv.Mat{tile(40, 200), tile(45, 195), tile(35, 205)}
m := face.NewMACE(16)
m.Train(authentic)
gradientImg := cv.NewMat(16, 16, 1)
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
gradientImg.Set(y, x, 0, uint8(16*x))
}
}
fmt.Println(m.PSR(tile(40, 200)) > m.PSR(gradientImg))
}
Output: true
func NewMACE ¶ added in v0.4.0
NewMACE returns an untrained MACE filter that operates on size×size images (every training and query image is reduced to luma and resampled to this square geometry). size must be positive; powers of two are fastest but any size works. The default authenticity threshold is a PSR of 20, adjustable with MACE.SetThreshold.
func (*MACE) PSR ¶ added in v0.4.0
PSR correlates img with the trained filter and returns the peak-to-sidelobe ratio of the correlation plane: the correlation peak minus the mean of the surrounding sidelobe region, divided by that region's standard deviation. A high PSR indicates an authentic match. It panics if the filter is untrained.
func (*MACE) Same ¶ added in v0.4.0
Same reports whether img is authentic for this filter, i.e. its MACE.PSR exceeds the threshold set by MACE.SetThreshold (default 20).
func (*MACE) SetThreshold ¶ added in v0.4.0
SetThreshold sets the peak-to-sidelobe ratio above which MACE.Same reports a query as authentic.
func (*MACE) Train ¶ added in v0.4.0
Train synthesises the correlation filter from one subject's images. Each image is reduced to luma, resampled to size×size, DFT-transformed and used as a constraint that the correlation peak at the origin equals one while the average correlation energy is minimised. It panics if given no images.
type PredictedFace ¶ added in v0.4.0
type PredictedFace struct {
// Label is the subject label of the matched training sample.
Label int
// Distance is the query-to-sample distance; smaller is a better match.
Distance float64
}
PredictedFace is a single scored candidate produced by the PredictCollect family: the training-set Label and the Distance from the query to that sample in the recognizer's feature space (lower is more similar).