Discussed in #144
Originally posted by Tunahanyrd July 13, 2026
I traced the anti-spoof model selection in 1.4.1 and found that the selected MiniFAS model type is lost before inference.
-
minifas-v2 is registered as a selectable anti-spoof model:
|
KnownModel { |
|
slug: "mobilenetv3-antispoof", |
|
filename: "mobilenetv3_antispoof.onnx", |
|
display_name: "MobileNetV3 Anti-Spoof", |
|
model_type: "anti_spoofing", |
|
}, |
|
KnownModel { |
|
slug: "minifas-v2", |
|
filename: "minifas_v2.onnx", |
|
display_name: "MiniFASNet V2", |
|
model_type: "anti_spoofing", |
|
}, |
-
The inference caller resolves the selected model path, but constructs FaceAntiSpoofing with only the path, image size and threshold:
|
bool checkAntiSpoofByAIModel(const FaceMethodConfig& faceCfg, const std::string& username, |
|
const ImageRGB& face, const AuthConfig& authCfg, |
|
const ModelRegistry& model_registry) { |
|
const std::string modelPath = |
|
model_registry.resolveModelPath(faceCfg.anti_spoofing.model.model_id).value_or(""); |
|
if (modelPath.empty() || !std::ifstream(modelPath).good()) { |
|
spdlog::error("FaceAuth: Anti-spoofing model file not found: {}", modelPath); |
|
return false; |
|
} |
|
|
|
try { |
|
FaceAntiSpoofing face_as(modelPath, 128, faceCfg.anti_spoofing.model.threshold); |
|
const SpoofResult result = face_as.inference(face); |
-
The omitted fourth argument defaults to mobilenetv3:
|
// model_type: "minifasv2" or "mobilenetv3" (default) |
|
class FaceAntiSpoofing { |
|
public: |
|
FaceAntiSpoofing(const std::string& ckpt, int imgsz = 128, const float threshold = 0.8, |
|
const std::string& model_type = "mobilenetv3"); |
-
Filename inference only runs when model_type is neither mobilenetv3 nor minifasv2. Since the default is already mobilenetv3, the MiniFAS filename is never inspected:
|
FaceAntiSpoofing::FaceAntiSpoofing(const std::string& ckpt, int imgsz, const float threshold, |
|
const std::string& model_type) |
|
: threshold(threshold), |
|
imgsz(imgsz), |
|
model_type(model_type), |
|
session(ckpt, "FaceAntiSpoofing") { |
|
// Unrecognized model_type: infer from the checkpoint filename. |
|
if (this->model_type != "minifasv2" && this->model_type != "mobilenetv3") { |
|
this->model_type = |
|
(ckpt.find("mobilenetv3") != std::string::npos) ? "mobilenetv3" : "minifasv2"; |
|
} |
The loaded file can therefore be minifas_v2.onnx while preprocessing and output handling still follow the MobileNetV3 branch.
I would like to send a small PR that passes the selected built-in model type explicitly and adds a regression test. The scoring policy and other anti-spoof behavior would remain unchanged.
Discussed in #144
Originally posted by Tunahanyrd July 13, 2026
I traced the anti-spoof model selection in 1.4.1 and found that the selected MiniFAS model type is lost before inference.
minifas-v2is registered as a selectable anti-spoof model:biopass/app/src-tauri/src/db.rs
Lines 48 to 59 in aa8c3e2
The inference caller resolves the selected model path, but constructs
FaceAntiSpoofingwith only the path, image size and threshold:biopass/auth/face/antispoofing/antispoof_check.cc
Lines 30 to 42 in aa8c3e2
The omitted fourth argument defaults to
mobilenetv3:biopass/auth/face/antispoofing/face_as.h
Lines 19 to 23 in aa8c3e2
Filename inference only runs when
model_typeis neithermobilenetv3norminifasv2. Since the default is alreadymobilenetv3, the MiniFAS filename is never inspected:biopass/auth/face/antispoofing/face_as.cc
Lines 24 to 34 in aa8c3e2
The loaded file can therefore be
minifas_v2.onnxwhile preprocessing and output handling still follow the MobileNetV3 branch.I would like to send a small PR that passes the selected built-in model type explicitly and adds a regression test. The scoring policy and other anti-spoof behavior would remain unchanged.