Playground biometrics demo BioID home page

gRPC Method PhotoVerify

Performs a one-to-one comparison of the submitted live images with the submitted ID photo in order to verify whether the live images and ID photo belong to the same person.

Additionally, if not explicitely denied, a liveness detection is performed on the provided live images. This is done by internally calling into the LivenessDetection API.

PhotoVerify is a service, which uses one photo, e.g. a passport image from an ID document, and compares that to one or two "live" images of a person, to find out whether the persons shown are the same. No classes are created, no templates or patterns are stored. It fulfills all requirements for an anonymous ID proofing service.

To make a decision about the similarity of the photo and the live images, an accuracy level is calculated (returned in the verification_level field). The higher the accuracy level, the better the faces on the images match. We highly recommend to use high accuracy levels, at least level 4, for your decision. Anyway, lower accuracy levels can be used with low quality ID photos (e.g. scanned passport images), where a higher accuracy cannot be reached any more.

Service method definition

The PhotoVerify API is defined as a unary RPC:

rpc PhotoVerify (PhotoVerifyRequest) returns (PhotoVerifyResponse);

message PhotoVerifyRequest {
    repeated ImageData live_images = 1;
    bytes photo = 2;
    bool disable_liveness_detection = 3;
}
message PhotoVerifyResponse {
    JobStatus status = 1;
    repeated JobError errors = 2;
    repeated ImageProperties image_properties = 3;
    ImageProperties photo_properties = 4;
    AccuracyLevel verification_level = 5;
    double verification_score = 6;
    bool live = 7;
    double liveness_score = 8;
    enum AccuracyLevel {
        NOT_RECOGNIZED = 0;
        LEVEL_1 = 1;
        LEVEL_2 = 2;
        LEVEL_3 = 3;
        LEVEL_4 = 4;
        LEVEL_5 = 5;
    }
}

Request

The PhotoVerify message has the fields as follows:

live_images
A list of one or two ImageData messages containing the live images. If two images are provided and liveness detection is not disabled, the tags of the second image can optionally be used for challenge-response.
photo
The ID-photo image. Refer to ImageData for a list of supported formats and image recommendations.
disable_liveness_detection
By default this API automatically calls into the LivenessDetection API with the provided live_images. If you do not want to perform a liveness detection at all, simply set this flag to true.

Request Headers

This API requires a valid JWT in the Authorization request header and accepts an optional reference number.

Authorization
Required Bearer authentication. Please refer to BWS API Authentication for a description of how to provide a valid JWT here.
Reference-Number
Optional, client specific reference number, which will be added to the BWS bookkeeping as well as to the response trailer. You typically use this reference to link the resulting BWS bookkeeping entries with your logs.

Response

On success the API returns a PhotoVerifyResponse message with the fields as follows:

status
The status of the BWS job that processed the request.
errors
A list of errors that might have occurred while the request has been processed. Note that errors are reported independently from the status (i.e. even if status is not set to faulted).
image_properties
The calculated image properties for each of the provided live images in the given order.
photo_properties
The calculated image properties of the provided ID photo.
verification_level

The actual level of accuracy the specified photo complies with. A decision about the similarity of the photo and the live images should be made on this response field. We recommend to at least only accept accuracy level 4 or higher.

The calculated accuracy level correlates with a false accepted rate (FAR) as follows:

Level 5FAR of 0.001%very high propability that the persons on the images are the same - the identity can be seen as approved
Level 4FAR of 0.01%good propability that the persons on the images are the same - recommended as minimum accepted level
Level 3FAR of 0.1%moderate accuracy level
Level 2FAR of 0.25%a relatively high false acceptance rate, should be the lowest acceptable level when using photo scans
Level 1FAR of 0.5%we do not recommend to use this level, which is intended for really bad ID photos only
Not recognizedNot recognized at all.when reported with no additional error, the photo simply does not match with the live image(s)
verification_score

An informative verification score (a value between 0.0 and 1.0) that reflects the verification level. The higher the score, the more likely the live images and ID photo belong to the same person. If this score is exactly 0.0, it has not been calculated.

As this score relates to the model currently used by PhotoVerify, we advise you not to use this score for your decision. It is intended for informational purposes only.
live
The liveness decision mabe by BWS in case liveness detection is not disabled. If this field is set to true, the provided images are supposed to be recorded from a live person. When this field is set to false and disable_liveness_detection was not set to true in the request, 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
An informative liveness score (a value between 0.0 and 1.0) that reflects the confidence level of the live decision. The higher the score, the more likely the person is a live person. If this score is exactly 0.0, it has not been calculated.

BWS Errors

In case that the liveness detection or the photo verification could not be performed, at least one of the following errors will be reported in the errors field:

FaceNotFound
No suitable face was found in at least one of the provided images.
MultipleFacesFound
More than one face has been found in at least one of the provided images.
ThumbnailExtractionFailed
None of the found faces could be extracted, typically because they are too close to the edge. There should have been reported one or more FullyVisibleFace quality check results.
RejectedByPassiveLiveDetection
At least one of the live images seem not to be recorded from a live person.
RejectedByActiveLiveDetection
The 3D detector observed some unnatural motion.
RejectedByChallengeResponse
At least one of the head-movement challenge-response criteria (as provided in the tags of the second image) was not fulfilled.

gRPC Errors

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:

Cancelled (1)
Client application cancelled the request.
Unknown (2)
Server experienced some unexpected behaviour.
InvalidArgument (3)
Client specified an invalid argument:
  • No live images have been provided.
  • Too many images have been provided. Only one or two images are supported.
  • No photo has been provided for photo verification.
  • The service cannot decode the provided input data, e.g. because the format cannot be detected or the image is too big.
DeadlineExceeded (4)
Deadline expired before operation could complete.
Internal (13)
Internal errors. Means some invariants expected by underlying system has been broken. If you see one of these errors, something is very broken. Can happen if the configuration of the service ins invalid, an authenticated client cannot be found any more or any other unexpected exception occurs.
Unavailable (14)
The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff.
Unauthenticated (16)
The request does not have valid authentication credentials for the operation.

Response Headers/Trailers

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.

Example:

Here is a short example of how to call into the PhotoVerify gRPC API using a photo ID image and 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 PhotoVerifyRequest
    {
        Photo = ByteString.CopyFrom(File.ReadAllBytes(options.Photo))
    };
    foreach (string file in options.Files)
    {
        request.LiveImages.Add(new ImageData { Image = ByteString.CopyFrom(File.ReadAllBytes(file)) });
    }
    var call = client.PhotoVerifyAsync(request);
    PhotoVerifyResponse response = await call.ResponseAsync.ConfigureAwait(false);
    // ...
    Console.WriteLine($"VerificationLevel: {response.VerificationLevel} ({response.VerificationScore})");
}
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.BioIDWebServiceGrpc.BioIDWebServiceBlockingStub;
import bioid.services.v1.PhotoVerifyRequest;
import bioid.services.v1.PhotoVerifyResponse;
import io.grpc.StatusRuntimeException;

private void usePhotoVerify(BioIDWebServiceBlockingStub client, 
    ImageData.Builder liveImage, ImageData.Builder passportImage) {
    PhotoVerifyRequest request = PhotoVerifyRequest.newBuilder()
        .setPhoto(passportImage.getImage())
        .addLiveImages(liveImage)
        .setDisableLivenessDetection(false)
        .build();
    try {
        PhotoVerifyResponse response = client.photoVerify(request);
        System.out.printf("VerificationLevel: %s (%s)%n", 
            response.getVerificationLevel(), response.getVerificationScore());
    } catch (StatusRuntimeException e) {
        System.err.printf("gRPC error from calling service: %s - '%s'%n", 
            e.getStatus().getCode(), e.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())
    with open(args.photo, 'rb') as f:
        request.photo = f.read()
    request.disable_liveness_detection = args.disablelive

    try:
        response = stub.PhotoVerify(request)
    except grpc.RpcError as rpc_error:
        print("Received error: ", rpc_error)

    print response