How to Setup

The rules are defined by a filtering strategy and the logic which can be configured based on your specific use case. The strategy ensures that only an identified person will pass the access barrier in the right time without stoppage or any further action.

Applying Filtering Strategies

SmartFace Access Controller supports wide range of configuration in order to fullfil range of requirements. In generally, configuration is done via configuration file or environment variables. The configuration method differs between the Microsoft Windows and the Docker versions.

Windows Application

Configuration of the AccessController running on Windows is located in config file appSettings.json is usually located at C:\Program Files\Innovatrics\Access Controller and has structure of a JSON. File is locked for write and requires administrator’s privilegs to be overwritten.

Docker on Linux

The AccessController running in Docker on Linux has by default configuration stored in .env.sfac file located allongside the docker-compose.yml file. The format used is such as the Docker environment variables.

Configurable Options

Each option can be configured separately, by using bool value true and false for the option’s enablement variable. For example to enable the Face order, use line as below. The example uses the Docker version of the configuration.

FilterConfiguration__FaceOrderConfiguration__Enabled=true

If you would like to keep it disabled, please use line as below:

FilterConfiguration__FaceOrderConfiguration__Enabled=false

To achieve the desired result a mixing combination of various options can be applied at the same time. Please see the description of the available options below.

Face Order

This filter is used for filtering out faces which are not detected closest to the camera. It ensures that Access Controller sends an access-granted notification only for a person who is the nearest to the access point. Access Controller sends an access-granted notification only if the detected face on the incoming video stream has the order (in terms of distance from the camera) equal to the configured value. The default value of the order is 1. Therefore, only to the closest detected face is granted the access.

Face Order

Environment Variable
FilterConfiguration__FaceOrderConfiguration__Enabled=false
FilterConfiguration__FaceOrderConfiguration__Order=1
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "FaceOrderConfiguration": {
            "Enabled": true,
            "Order": 1
        },
        ...
    }
    ...
}

Opening Debounce

This filter is used for filtering out multiple notifications which are sent for the same person for a predefined time period. Access Controller sends an access-granted notification only when a predefined interval has passed since the last granted access for the respective person. The default interval for the debounce time is 4000 ms. This filter prevents multiple openings for the same person in a short time interval.

Environment Variable
FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceEnabled=true
FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceMs=4000
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "OpeningDebounceConfiguration": {
            "OpeningDebounceEnabled": true,
            "OpeningDebounceMs": 4000
        },
        ...
    }
    ...
}

Blocking Debounce

This filter is similar to OpeningDebounceFilter but it filters block notifications. The default interval for the debounce time is 4000 ms. This filter prevents multiple block notifications being sent for the same person in a short time interval.

Environment Variable
FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceEnabled=true
FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceMs=4000
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "BlockingDebounceConfiguration": {
            "BlockingDebounceEnabled": true,
            "BlockingDebounceMs": 4000
        },
        ...
    }
    ...
}

Exclusive camera

After granting access to an identified person to a particular access point, Access Controller filters out notifications for opening of all other access points for this person for a predefined time period. The default value for blocking of other access points is 5000 ms. This filter ensures that a person who turned around after passing the access point isn’t detected again and the access point won’t open for this person in the opposite direction.

Environment Variable
FilterConfiguration__ExclusiveCameraConfiguration__Enabled=true
FilterConfiguration__ExclusiveCameraConfiguration__ExclusivityMs=5000
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "ExclusiveCameraConfiguration": {
            "Enabled": true,
            "ExclusivityMs": 5000
        },
        ...
    }
    ...
}

Not identified person configuration

This filter is used for filtering out incoming NoMatch notifications and for sending an access-denied notification, when a detected person is continuously unidentified for a predefined time period and when this person’s face was the nearest to the camera. NotIdentifiedPersonFilter is defined by the RoamingLimitTimeMs parameter with a default value of 3000 ms. This filter ensures that the user is notified only once per a defined time period about an unknown person and is not overwhelmed by NoMatch notifications.

Environment Variable
FilterConfiguration__NotIdentifiedPersonConfiguration__Enabled=true
FilterConfiguration__NotIdentifiedPersonConfiguration__RoamingLimitTimeMs=3000
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "NotIdentifiedPersonConfiguration": {
            "Enabled": true,
            "RoamingLimitTimeMs": 3000
        },
        ...
    }
    ...
}

Blacklist configuration

This filter sends an access-blocked notification when an identified person belongs to a watchlist specified as a blacklist. The filter ensures that the user is notified about a disapproved and restricted person detected in front of the access point. Watchlists specified as blacklists can be listed in the configuration. There is no default blacklist configured.

Environment Variable
FilterConfiguration__BlacklistsConfiguration__Enabled=true
FilterConfiguration__BlacklistsConfiguration__Blacklists__0=first_black_list_id
FilterConfiguration__BlacklistsConfiguration__Blacklists__1=second_black_list_id
FilterConfiguration__BlacklistsConfiguration__Blacklists__2=third_black_list_id
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "BlacklistsConfiguration": {
            "Enabled": true,
            "Blacklists": [ "first_black_list_id", "second_black_list_id", "third_black_list_id" ]
        },
        ...
    }
    ...
}

Face mask configuration

Ensures that the access is denied to an identified person who is trying to access the premises but doesn’t wear a face mask. The access-denied notification is sent every 4000 ms which is configurable by the DenyingDebounceMs parameter. This filter allows you to enforce rules on wearing face masks due to epidemics or pandemics.

Environment Variable
FilterConfiguration__FaceMaskConfiguration__Enabled=false
FilterConfiguration__FaceMaskConfiguration__DenyingDebounceMs=4000
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "FaceMaskConfiguration": {
            "Enabled": true,
            "DenyingDebounceMs": 4000
        },
        ...
    }
    ...
}

Intentional access configuration

Grants access to persons that have an intention to enter the premises. Currently, this is done by estimating how fast they approach the camera or how close they are to the camera. If this speed is greater than the RequiredFaceApproachingRatePercent parameter or the person has face area larger than the AlwaysOpenForFaceAreaPercentLargerThan parameter, access is granted.

Under the hood, RequiredFaceApproachingRatePercent is based on FaceAreaChange attribute sent in SmartFace notifications. FaceAreaChange is a ratio between FaceArea of two consequentive faces of a person. When FaceAreaChange is less than 1, person is moving towards the camera. When larger than 1, person is moving backwards and distance to camera is increasing.

How to get FaceAreaChange

When configuring AccessController for particular gate, door or turnistille, it is always necessary to have configuration taylored for the usecase. The value of RequiredFaceApproachingRatePercent works for good for one gate but will not work for another because people are approaching under an angle, for example. To get the best value for RequiredFaceApproachingRatePercent do a several testing attempts and record FaceAreaChange for tracklets.

FaceAreaChange can be observed via SmartFace Station in detail of tracklet or in AccessController log. AccessController needs to be switched to debug mode:

Environment Variable
Serilog__MinimumLevel__Default=Debug
AppSettings.json
{
    ...    
    
    "Serilog": {
        "MinimumLevel": {
        "Default": "Debug",
        ...
        }
    },
    ...
}

After that the you will have in the log files live values as faceApproachingRate for particular usecase:

[09:21:07 Debug] Match received for Tracklet "e337672c-ffec-4403-9b8b-17ec927799ef" {}
[09:21:07 Information] Received "Match" notification from stream "3f6bf57e-bd65-4b64-98f9-3e742734ae8d". {} 
[09:21:07 Debug] No openings in the given time interval (4000 milliseconds), allow opening. {}
[09:21:07 Debug] Watchlist member with Id "1" has faceApproachingRate: 0.013180462643504143. {}
[09:21:07 Debug] Watchlist member with Id "1" has intention to enter. {}

Stream group configuration

When one camera in a group signals to open, then all cameras from the same group will not signal an open for 3000 ms configurable by the GroupOpeningDebounceMs parameter. This is introduced to support a use case when one gate is accessible from both directions (in and out) and two people simultaneously try to enter and exit. In such a case only the first person opens the gate and the second one will have to wait for the configurable time. This is done so that the gate does not try to open in both directions simultaneously.

Environment Variable
FilterConfiguration__StreamGroupsConfiguration__Enabled=true
FilterConfiguration__StreamGroupsConfiguration__GroupOpeningDebounceMs=3000
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "StreamGroupsConfiguration": {
            "Enabled": true,
            "GroupOpeningDebounceMs": 3000
        },
        ...
    }
    ...
}

Liveness / spoofcheck configuration

Ensures that the access is denied to a person who is trying to enter as another person (e.g. by aiming tablet display with a photo to the camera). The access-blocked notification is sent every 4000 ms which is configurable by the DenyingDebounceMs parameter. There is also possibility to enable more sophisticated option - spoof rate limiting strategy by enabling SpoofRateLimitingConfiguration.

Environment Variable
FilterConfiguration__SpoofCheckConfiguration__Enabled=false
FilterConfiguration__SpoofCheckConfiguration__DenyingDebounceMs=4000
FilterConfiguration__SpoofCheckConfiguration__SpoofRateLimitingConfiguration__Enabled=false
FilterConfiguration__SpoofCheckConfiguration__SpoofRateLimitingConfiguration__SpoofAttemptsCount=2
FilterConfiguration__SpoofCheckConfiguration__SpoofRateLimitingConfiguration__SpoofAttemptsWindowMs=120000
FilterConfiguration__SpoofCheckConfiguration__SpoofRateLimitingConfiguration__BlockingTimeIncrementCooldownMs=10000
FilterConfiguration__SpoofCheckConfiguration__SpoofRateLimitingConfiguration__BlockingTimeIncrementMs=30000
FilterConfiguration__SpoofCheckConfiguration__SpoofRateLimitingConfiguration__MaxBlockingTimeMs=300000
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "SpoofCheckConfiguration": {
            "Enabled": false,
            "DenyingDebounceMs": 4000,
            "SpoofRateLimitingConfiguration": {
                "Enabled": false,
                "SpoofAttemptsCount": 2,
                "SpoofAttemptsWindowMs": 120000,
                "BlockingTimeIncrementCooldownMs": 10000,
                "BlockingTimeIncrementMs": 30000,
                "MaxBlockingTimeMs": 300000
            }
        },
        ...
    }
    ...
}

Expression configuration

The expression configuration feature is available since version 5.4.19.

You are able to detect and evaluate expression - angles between your face and the camera (the pitch and yaw angles) and the face size being detected. By enabling this configuration the access will be granted only to the person who’s expression fits within the set constrains.

Environment Variable
FilterConfiguration__ExpressionConfiguration__Enabled=false
FilterConfiguration__ExpressionConfiguration__Expression="props.YawAngle >= -20 && props.YawAngle <= 20 && props.PitchAngle >= -20 && props.PitchAngle <= 20 && props.FaceSize >= 60"
AppSettings.json
{
    ...    
    "FilterConfiguration": {
        ...
        "ExpressionConfiguration" : {     
            "Enabled" : false,
            "Expression" : "props.YawAngle >= -20 && props.YawAngle <= 20 && props.PitchAngle >= -20 && props.PitchAngle <= 20 && props.FaceSize >= 60"
        }
    }
}

Expression Configuration explained

Currently is supported filtering by following attributes:

FaceArea, FaceSize,Sharpness,Brightness,TintedGlasses,
HeavyFrame, GlassStatus, YawAngle, PitchAngle, RollAngle, Age, Gender

These attributes are nullable, therefore they can be empty and have null value.

Any of these attributes can be combined together and compared with these operators, expressions also follow standard C# rules for operators precedence, therefore parentheses can be used normally.

CategoryOperators
Relational and type testing< > <= >= is as
Equality== !=
Logical AND&
Logical OR|
Logical XOR^
Conditional AND&&
Conditional OR
Examples:

Allow passage if YawAngle of face is in range (-10,10):

props.YawAngle > -10 && props.YawAngle < 10

Allow passage if YawAngle and PitchAngle of face is in range (-10,10):

props.YawAngle > -10 && props.YawAngle < 10 && props.PitchAngle > -10 && props.PitchAngle < 10
</span>

Allow passage if Brightness equals 100:

props.Brightness == 100

Require input with Brightness more or equal than 100 and Sharpness needs to be more than 50 and FaceSize needs to be larger than 25px and confidence of HeavyFrame and TintedGlasses needs to be under certain level (100 and 50):

props.Brightness >= 100 && props.Sharpness > 50 && props.FaceSize > 25 && props.HeavyFrame < 100 && props.TintedGlasses < 50

Require Age 18 or above and Female gender

props.Age >= 18 && props.Gender < 0

Require Age 18 or above or Age 18 or less and Male gender

props.Age >= 18 || (props.Age <= 18 && props.Gender > 0)

Configure settings for all cameras/specific camera(s)

If the settings are under the FilterConfiguration then it is applied to all cameras. You can apply camera specific settings that will be applied to a selected camera, overwriting the general settings by using the StreamFilterConfigurations section. Within the StreamFilterConfigurations you need to define a camera stream id that will be used for all the camera specific setup.

Environment Variable
StreamFilterConfigurations__<camera-stream-id1>__SpoofCheckConfiguration__Enabled=true
StreamFilterConfigurations__<camera-stream-id1>__SpoofCheckConfiguration__DenyingDebounceMs=4000
StreamFilterConfigurations__<camera-stream-id2>__SpoofCheckConfiguration__Enabled=true
StreamFilterConfigurations__<camera-stream-id2>__SpoofCheckConfiguration__DenyingDebounceMs=4000
AppSettings.json
{
    ...    
    "StreamFilterConfigurations": {
        "camera-stream-id1" : {
            "SpoofCheckConfiguration": {
                "Enabled": true,
                "DenyingDebounceMs": 4000
            }
        },
        "camera-stream-id2" : {
            "SpoofCheckConfiguration": {
                "Enabled": true,
                "DenyingDebounceMs": 4000
            }
        }
    }
}

Jaeger tracing

These are settings related to tracing for development purposes.

# Set true when a Jaeger tracing is required
AppSettings__USE_JAEGER_APP_SETTINGS=false
AppSettings__JAEGER_SAMPLER_TYPE = const
AppSettings__JAEGER_SAMPLER_PARAM = 1
AppSettings__Log_RollingFile_Enabled = true
AppSettings__Log_JsonConsole_Enabled = false

# Jaeger tracing endpoint. 'jaeger' is the name of included docker container.
# If targeting outside SmartFace docker, change to remote URL
AppSettings__JAEGER_AGENT_HOST = jaeger

API

The Access Controller exposes the gRPC service that is streaming access notifications. GRPC service is hosted inside ASP .NET Core Web Server (Kestrel) and therefore can be configured by modifying Kestrel configuration section in appsettings.json file.

Default Kestrel port is set to 5050 and running as HTTP with localhost (127.0.0.1).

You can write your own application using the access notifications provided. For a sample of code please read about the Relay Connector .

GRPC AccessNotificationService.proto file:

syntax = "proto3";
package innovatrics.smartface;
import "google/protobuf/timestamp.proto";

enum AccessNotificationType
{
	UNSPECIFIED_GRANTED = 0;
	GRANTED = 0x01;
	DENIED = 0x02;
	BLOCKED = 0x04;
	PING = 0x08;
}

enum MaskStatus
{
	UNKNOWN = 0;
	MASK = 1;
	NO_MASK = 2;
}

enum DenyReason
{
	NOT_IDENTIFIED = 0;
	IDENTIFIED_WITH_NO_MASK = 1;
}

enum BlockReason
{
	IDENTIFIED_IN_BLOCK_LIST = 0;
	SPOOF_DETECTED = 1;
	OPENING_TEMPORARILY_BLOCKED = 2;
}

message AccessNotificationRequest
{
	bool send_image_data = 1;
	uint32 type_of_access_notification = 2;
}

message AccessNotification
{
	AccessNotificationGranted access_notification_granted = 1;
	string stream_id = 2;
	string face_id = 3;
	google.protobuf.Timestamp face_detected_at = 4;
	google.protobuf.Timestamp sent_at = 5;
	map<string,string> headers = 6;
	AccessNotificationDenied access_notification_denied = 7;
	uint32 type_of_access_notification = 8;
	//this response type cannot be both GRANTED and DENIED (or BLACKLIST) at the same time
	AccessNotificationBlocked access_notification_blocked = 9;
	string tracklet_id = 10;
	MaskStatus mask_status = 11;
	double face_mask_confidence = 12;
	int64 frame_timestamp_us = 13;
	EyeCoordinates eye_coordinates = 14;
}

message AccessNotificationGranted
{
	string watchlist_member_external_id = 1;
	string watchlist_external_id = 2;
	string watchlist_member_full_name = 3;
	string watchlist_member_id = 4;
	string watchlist_id = 5;
	string watchlist_full_name = 6;
	int64 match_result_score = 7;
	bytes crop_image = 8;
}

message AccessNotificationDenied
{
	bytes crop_image = 1;
	DenyReason reason = 2;
	string watchlist_member_full_name = 3;
	string watchlist_member_id = 4;
	string watchlist_id = 5;
	string watchlist_full_name = 6;
	int64 match_result_score = 7;
}

message AccessNotificationBlocked
{
	string watchlist_member_full_name = 1;
	string watchlist_member_id = 2;
	string watchlist_id = 3;
	string watchlist_full_name = 4;
	int64 match_result_score = 5;
	bytes crop_image = 6;
	BlockReason reason = 7;
	google.protobuf.Timestamp blocked_until = 8;
}

message EyeCoordinates
{
	double left_eye_x = 1;
	double left_eye_y = 2;
	double right_eye_x = 3;
	double right_eye_y = 4;
}

service AccessNotificationService
{
	rpc GetAccessNotifications(AccessNotificationRequest) returns (stream AccessNotification);
}