POST /photoverify?accuracy={accuracy}
POST /photoverify2?accuracy={accuracy}
Performs a liveness detection on the uploaded samples to verify whether they are recorded from a live person. Then performs a one-to-one comparison with the ID photo submitted in order to verify whether the live images and ID photo belong to the same person.
PhotoVerify is a BWS service, which uses one 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. Periocular biometrics is used as it gives better results than face (and allows for close-view recordings). No classes are created, no templates or patterns are stored. It fulfills all requirements for an anonymous ID proofing service.
To perform a photo verification, three images have to be provided:
A decision about the similarity of the photo and the live images is made according to an accuracy level. The higher the accuracy level, the better the faces on the images must match. Higher accuracy levels are recommended, but 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.
Five accuracy settings are defined from 1 to 5 with accuracy lower or equal to 1 being the worst (with a false acceptance rate of about 0.5%), and greater or equal to 5 being the best (with a false acceptance rate of about 0.0001%). The default is 4, with a false acceptance rate of 0.001%.
liveimage2
) is optional. If it is omitted,
no liveness detection will be performed! Everything else remains unchanged.
PhotoVerify2 API
is available, which does not return a single boolean but a result object
that also includes the calculated actual level of accuracy!
App-ID:App-Secret
. To receive the necessary BWS WebAPI access data (App-ID
and App-Secret
) you have
to register your application on the BWS Portal first. This requires a valid BWS subscription.
accuracy
optional integer containing the desired accuracy level:
state
The body contains the two or three images encoded into a Data-URL using the data URI scheme as described in RFC 2397 (see also at Wikipedia), e.g. using the application/json media type:
{ "liveimage1": "data:image/...", "liveimage2": "data:image/...", "idphoto": "data:image/..." }
or using the application/x-www-form-urlencoded media type:
liveimage1=data:image/...&liveimage2=data:image/...&idphoto=data:image/...
If all provided images could be processed successfully, this API returns the OK HTTP status code (200) with either
a single boolean value in the body content (PhotoVerify
) or a PhotoVerifyResult
object (PhotoVerify2
).
The boolean value indicates whether the live image(s) match the ID photo or not with regard to the applied accuracy level.
The result object has the members as follows:
Success
AccuracyLevel
JobID
State
Errors
Samples
Errors
EyeCenters
An example result object might look as follows:
{
"Success": true,
"JobID": "3e4ed0e8-5eb4-4684-930a-bdae875b854e",
"AccuracyLevel": 5,
"Samples": [{
"Errors": [{
"Code": "ImageTooSmall",
"Message": "The part of the image containing the found face is too small.",
"Details": "The found face (with an eye-distance of 55 pixels) does not have the required eye-distance of at least 60 pixels."
}
],
"EyeCenters": {
"RightEyeX": 290.188,
"RightEyeY": 251.479,
"LeftEyeX": 345.9,
"LeftEyeY": 251.182
}
}, {
"Errors": [{
"Code": "ImageTooBlurry",
"Message": "The image is too blurry, i.e. it is not sharp enough.",
"Details": "An image blurring of 10.45% was calculated, where up to 9.00% is allowed. Note that compression artifacts might be the reason for this fuzziness as they reduce the objective sharpness more than the subjective sharpness."
}
],
"EyeCenters": {
"RightEyeX": 280.599,
"RightEyeY": 242.184,
"LeftEyeX": 333.96,
"LeftEyeY": 241.687
}
}
]
}
In case something goes wrong, an error HTTP status code is returned together with some additional information if available.
The call returns one of the standard HTTP status codes:
PhotoVerify
) or contains
the PhotoVerifyResult
object (in case of PhotoVerify2
).
Invalid samples have been uploaded or they could not be processed successfully, e.g. no face found or live detection failed, etc. The response body typically has a Message field containing the error code:
Message
and an ExceptionMessage
.
private static async Task<bool> PhotoVerifyAsync(int accuracy, string dataUrlLiveImage1, string dataUrlLiveImage2, string dataUrlIdPhoto)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{APP_IDENTIFIER}:{APP_SECRET}")));
string mediaType, images;
// using the application/json media type
mediaType = "application/json";
images = $@"{{""liveimage1"":""{dataUrlLiveImage1}"""
+ $@",""liveimage2"":""{dataUrlLiveImage2}"""
+ $@",""idphoto"":""{dataUrlIdPhoto}""}}";
// or using application/x-www-form-urlencoded
/*
mediaType = "application/x-www-form-urlencoded";
images = string.Format("liveimage1={0}&liveimage2={1}&idphoto={2}", HttpUtility.UrlEncode(dataUrlLiveImage1), HttpUtility.UrlEncode(dataUrlLiveImage2), HttpUtility.UrlEncode(dataUrlIdPhoto));
*/
using (var content = new StringContent(images, Encoding.ASCII, mediaType))
using (var response = await client.PostAsync(ENDPOINT + $"photoverify?accuracy={accuracy}", content))
{
Console.Write("PhotoVerify Response... ");
string result = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
if (bool.TryParse(result, out var match))
{
Console.WriteLine(match);
return match;
}
}
Console.WriteLine(response.StatusCode.ToString());
Console.WriteLine(result);
return false;
}
}
}
// using org.json.JSONObject from JSON-java library
JSONObject requestBody = new JSONObject();
requestBody.put("liveimage1", "data:image/png;base64," + Base64.getEncoder().encodeToString(png1AsByteArray));
requestBody.put("liveimage2", "data:image/png;base64," + Base64.getEncoder().encodeToString(png2AsByteArray));
requestBody.put("idphoto", "data:image/png;base64," + Base64.getEncoder().encodeToString(photoIdPngAsByteArray));
// using OkHttpClient from the OkHttp library
Request request = new Request.Builder()
.url("https://bws.bioid.com/extension/photoverify")
.addHeader("Authorization", Credentials.basic(APP_IDENTIFIER, APP_SECRET))
.post(RequestBody.create(MediaType.parse("application/json"), requestBody.toString()))
.build();
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
if (response.code() == 200) {
if (response.body().string().equals("true")) {
System.out.println("live images do match the ID photo");
} else {
System.out.println("live images do not match the ID photo");
}
}