Performs a liveness detection on one or two live images. Depending on the number of live images and the tags provided in the call, different versions of our liveness detection will be executed:
One image: only a passive liveness detection will be performed. Due to the limitation to a single image, only the texture based liveness detection can be used to make a decision.
Two images: a passive and an active liveness detection will be performed. Beside of the texture based liveness detection on each of the provided images a motion based 3D detection on each two consecutive images is executed. All decisions must indicate a live person to finally declare the entire call as live.
Two images with tagged second image: a passive and an active liveness detection will be performed. Additionally a challenge-response mechanism is applied: as we have a motion direction calculated for the face found in the second image, we can check whether this is the same direction as demanded by the tags, i.e. whether the head moved up, down, left or right as requested. Also refer to the Liveness Detection Modes.
The LivenessDetection
API is defined as a unary RPC:
rpc LivenessDetection (LivenessDetectionRequest) returns (LivenessDetectionResponse);
message LivenessDetectionRequest {
repeated ImageData live_images = 1;
}
message LivenessDetectionResponse {
JobStatus status = 1;
repeated JobError errors = 2;
repeated ImageProperties image_properties = 3;
bool live = 4;
double liveness_score = 5;
}
The LivenessDetectionRequest
message has a single field:
live_images
This API requires a valid JWT in the Authorization request header and accepts an optional reference number.
On success the API returns a LivenessDetectionResponse
message with the fields as follows:
status
errors
image_properties
live
true
, the provided images are supposed to be recorded from a live person. No errors are reported in this case.
When this field is set to false
, there will be at least one error reported that explains, why the provided images are not supposed to be recorded from a live person.
liveness_score
In case that the live
field is set to false
, at least one of the following errors will be reported in the errors
field:
FullyVisibleFace
quality check results.Beside of the success return status code OK (0), this call might also return one of the following gRPC error status codes to indicate an error:
All successful BWS gRPC calls return a response header and a response trailer containing additional information about the request:
Response Trailer | |
jobid | The Job-ID (a GUID) that has been assigned to this BWS call. |
bws-version | The version of the BWS gRPC service. |
response-time-ms | The timespan im milliseconds the request spent at the BWS service. |
reference-number | An optional reference number as provided in the request header. |
Response Header | |
date | The timestamp when the request has been received at the server. |
... | Other headers that might have been added by the server (NGINX, Kestrel, ...) that was handling the request. |
Here is a short example of how to call into the LivenessDetection gRPC API using live images loaded from files.
Please refer to BWS API Authentication for a description of the methods CreateAuthenticatedChannel and GenerateToken.
The tooling package Grpc.Tools
can be used to generate the C# assets from the bws.proto
file.
Refer to overview for gRPC on .NET to learn more about how to call into a gRPC service with a .NET client.
try
{
using GrpcChannel channel = CreateAuthenticatedChannel(new Uri(options.Host), GenerateToken(options.ClientId, options.Key));
var client = new BioIDWebService.BioIDWebServiceClient(channel);
var request = new LivenessDetectionRequest();
foreach (string file in options.Files)
{
request.LiveImages.Add(new ImageData { Image = ByteString.CopyFrom(File.ReadAllBytes(file)) });
}
var call = client.LivenessDetectionAsync(request);
LivenessDetectionResponse response = await call.ResponseAsync.ConfigureAwait(false);
// ...
Console.WriteLine($"This was live: {response.Live} (confidence: {response.LivenessScore:F2})");
}
catch (RpcException ex)
{
Console.Error.WriteLine($"gRPC error from calling service: {ex.Status.StatusCode} - '{ex.Status.Detail}'");
}
TODO: how to create the Java code from the protobuf file ...
import bioid.services.v1.ImageData;
import bioid.services.v1.LivenessDetectionRequest;
import bioid.services.v1.LivenessDetectionResponse;
import io.grpc.StatusRuntimeException;
import bioid.services.v1.BioIDWebServiceGrpc.BioIDWebServiceBlockingStub;
private void useActiveLivenessDetection(BioIDWebServiceBlockingStub client,
ImageData.Builder liveImage1, ImageData.Builder liveImage2) {
LivenessDetectionRequest livenessDetectionRequest =
LivenessDetectionRequest.getDefaultInstance();
livenessDetectionRequest = livenessDetectionRequest.toBuilder()
.addLiveImages(0, liveImage1)
.addLiveImages(1, liveImage2)
.build();
LivenessDetectionResponse livenessDetectionResponse;
try {
livenessDetectionResponse =
client.livenessDetection(livenessDetectionRequest);
System.out.printf("This was live: %s - Confidence: %.2f",
livenessDetectionResponse.getLive(),
livenessDetectionResponse.getLivenessScore());
} catch (StatusRuntimeException ex) {
System.err.printf("gRPC error from calling service: %s - '%s'",
ex.getStatus(), ex.getStatus().getDescription());
}
}
Using the protocol buffer compiler protoc (install: python -m pip install grpcio-tools
)
from the Phython gRPC tools
you can create the Phyton client code from the .proto service definition:
python -m grpc_tools.protoc --proto_path=. --python_out=. --grpc_python_out=. bws.proto
import grpc
import bws_pb2_grpc
import bws_pb2
token = GenerateToken(args.clientid, args.key, 10)
with CreateAuthenticatedChannel(args.host, token) as channel:
stub = bws_pb2_grpc.BioIDWebServiceStub(channel)
request = bws_pb2.LivenessDetectionRequest()
for img_file in args.images:
with open(img_file, 'rb') as f:
request.live_images.add(image=f.read())
try:
response = stub.LivenessDetection(request)
except grpc.RpcError as rpc_error:
print("Received error: ", rpc_error)
print response