Skip to content

Commit

Permalink
Merge pull request exadel-inc#919 from exadel-inc/1.1.x
Browse files Browse the repository at this point in the history
1.1.x
  • Loading branch information
pospielov authored Oct 21, 2022
2 parents 79d4411 + 46d4404 commit d4bfa0b
Show file tree
Hide file tree
Showing 120 changed files with 1,475 additions and 988 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</a>
<br>
<i>Exadel CompreFace is a free and open-source face recognition service that can be easily integrated into any system without prior machine learning skills.
CompreFace provides REST API for face recognition, face verification, face detection, landmark detection, age, and gender recognition and is easily deployed with docker.
CompreFace provides REST API for face recognition, face verification, face detection, landmark detection, mask detection, head pose detection, age, and gender recognition and is easily deployed with docker.
</i>
<br>
</p>
Expand Down Expand Up @@ -72,7 +72,7 @@ Exadel CompreFace is a free and open-source face recognition GitHub project.
Essentially, it is a docker-based application that can be used as a standalone server or deployed in the cloud.
You don’t need prior machine learning skills to set up and use CompreFace.

The system provides REST API for face recognition, face verification, face detection, landmark detection, age, and gender recognition.
The system provides REST API for face recognition, face verification, face detection, landmark detection, mask detection, head pose detection, age, and gender recognition.
The solution also features a role management system that allows you to easily control who has access to your Face Recognition Services.

CompreFace is delivered as a docker-compose config and supports different models that work on CPU and GPU.
Expand Down Expand Up @@ -116,6 +116,7 @@ The system can accurately identify people even when it has only “seen” their
- [age recognition plugin](/docs/Face-services-and-plugins.md#face-plugins)
- [gender recognition plugin](/docs/Face-services-and-plugins.md#face-plugins)
- [face mask detection plugin](/docs/Face-services-and-plugins.md#face-plugins)
- [head pose plugin](/docs/Face-services-and-plugins.md#face-plugins)
- Use the CompreFace UI panel for convenient user roles and access management

# Getting Started with CompreFace
Expand Down
10 changes: 10 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ through them and set up CompreFace accordingly

- `registry` - this is the docker hub registry. For release and
pre-build images, it should be set to `exadel/` value
- `postgres_username` - username for Postgres database
- `postgres_password` - password for Postgres database. It should be
changed for production systems from the default value.
- `postgres_db` - name for Postgres database
- `postgres_domain` - the domain where Postgres database is run
- `postgres_port` - Postgres database port
- `enable_email_server` - if true, it enables email verification for
Expand All @@ -31,7 +33,15 @@ through them and set up CompreFace accordingly
container
- `compreface_admin_java_options` - java options of compreface-admin
container
- `max_file_size` - maximum image size acceptable to CompreFace. It must be less than or equal to `max_request_size`
- `max_request_size` - maximum request size for a multipart/form-data acceptable to CompreFace. It must be greater than or equal to
`max_file_size`
- `uwsgi_processes` - the number of uWSGI processes
- `uwsgi_threads` - the number of uWSGI threads
- `connection_timeout` - request connection timeout. It is used to set the connection timeout for the Nginx proxy and the Feign client
- `read_timeout` - request read timeout. It is used to set the read timeout for the Nginx proxy and the Feign client
- `ADMIN_VERSION` - docker image tag of the compreface-admin container
- `API_VERSION` - docker image tag of the compreface-api container
- `FE_VERSION` - docker image tag of the compreface-fe container
- `CORE_VERSION` - docker image tag of the compreface-core container
- `POSTGRES_VERSION` - docker image tag of the compreface-postgres-db container
2 changes: 1 addition & 1 deletion docs/Custom-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ compreface-core:
args:
- FACE_DETECTION_PLUGIN=insightface.FaceDetector@retinaface_r50_v1
- CALCULATION_PLUGIN=insightface.Calculator@arcface_r100_v1
- EXTRA_PLUGINS=insightface.LandmarksDetector,insightface.GenderDetector,insightface.AgeDetector,insightface.facemask.MaskDetector
- EXTRA_PLUGINS=insightface.LandmarksDetector,insightface.GenderDetector,insightface.AgeDetector,insightface.facemask.MaskDetector,insightface.PoseEstimator
- BASE_IMAGE=compreface-core-base:base-cuda100-py37
- GPU_IDX=0
environment:
Expand Down
7 changes: 5 additions & 2 deletions docs/Face-services-and-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ CompreFace supports these face services and plugins:
* Gender detection plugin
* Landmarks detection plugin
* Calculator plugin
* Face mask detection plugin
* Head pose plugin

# Services

Expand Down Expand Up @@ -119,19 +121,20 @@ comma-separated needed plugins in the query `face_plugins` parameter. This param
Example:

```shell
curl -X POST "http://localhost:8000/api/v1/recognition/recognize?face_plugins=age,gender,landmarks,mask" \
curl -X POST "http://localhost:8000/api/v1/recognition/recognize?face_plugins=age,gender,landmarks,mask,pose" \
-H "Content-Type: multipart/form-data" \
-H "x-api-key: <faces_recognition_api_key>" \
-F file=<local_file>
```

This request will recognize faces on the image and return additional information about age, gender, face mask, and landmarks.
This request will recognize faces on the image and return additional information about age, gender, head pose, face mask, and landmarks.

The list of possible plugins:
* age - returns the supposed range of a person’s age in format [min, max]
* gender - returns the supposed person’s gender
* landmarks - returns face landmarks. This plugin is supported by all configurations and returns 5 points of eyes, nose, and mouth
* calculator - returns face embeddings.
* pose - returns head pose in format: `{"pitch": 0.0,"roll": 0.0,"yaw": 0.0}`
* mask - returns if the person wears a mask. Possible results: `without_mask`, `mask_worn_incorrectly`, `mask_worn_correctly`. Learn more about [mask plugin](Mask-detection-plugin.md)
* landmarks2d106 - returns face landmarks. This plugin is supported only by the configuration that uses insightface library. It’s not
available by default. More information about landmarks [here](https://github.com/deepinsight/insightface/tree/ce3600a74209808017deaf73c036759b96a44ccb/alignment/coordinate_reg#visualization).
4 changes: 4 additions & 0 deletions docs/Rest-API-description.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ Response body on success:
|----------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| age | object | detected age range. Return only if [age plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| gender | object | detected gender. Return only if [gender plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| pose | object | detected head pose. Return only if [pose plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| mask | object | detected mask. Return only if [face mask plugin](Face-services-and-plugins.md#face-plugins) is enabled. |
| embedding | array | face embeddings. Return only if [calculator plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| box | object | list of parameters of the bounding box for this face |
Expand Down Expand Up @@ -559,6 +560,7 @@ Response body on success:
|----------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| age | object | detected age range. Return only if [age plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| gender | object | detected gender. Return only if [gender plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| pose | object | detected head pose. Return only if [pose plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| mask | object | detected mask. Return only if [face mask plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| embedding | array | face embeddings. Return only if [calculator plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| box | object | list of parameters of the bounding box for this face |
Expand Down Expand Up @@ -639,6 +641,7 @@ Response body on success:
|----------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| age | object | detected age range. Return only if [age plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| gender | object | detected gender. Return only if [gender plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| pose | object | detected head pose. Return only if [pose plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| mask | object | detected mask. Return only if [face mask plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| embedding | array | face embeddings. Return only if [calculator plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| box | object | list of parameters of the bounding box for this face (on processedImage) |
Expand Down Expand Up @@ -757,6 +760,7 @@ Response body on success:
| face_matches | array | result of face verification |
| age | object | detected age range. Return only if [age plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| gender | object | detected gender. Return only if [gender plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| pose | object | detected head pose. Return only if [pose plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| mask | object | detected mask. Return only if [face mask plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| embedding | array | face embeddings. Return only if [calculator plugin](Face-services-and-plugins.md#face-plugins) is enabled |
| box | object | list of parameters of the bounding box for this face |
Expand Down
2 changes: 1 addition & 1 deletion embedding-calculator/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ARG GPU_IDX=-1
ENV GPU_IDX=$GPU_IDX INTEL_OPTIMIZATION=$INTEL_OPTIMIZATION
ARG FACE_DETECTION_PLUGIN="facenet.FaceDetector"
ARG CALCULATION_PLUGIN="facenet.Calculator"
ARG EXTRA_PLUGINS="facenet.LandmarksDetector,agegender.AgeDetector,agegender.GenderDetector,facenet.facemask.MaskDetector"
ARG EXTRA_PLUGINS="facenet.LandmarksDetector,agegender.AgeDetector,agegender.GenderDetector,facenet.facemask.MaskDetector,facenet.PoseEstimator"
ENV FACE_DETECTION_PLUGIN=$FACE_DETECTION_PLUGIN CALCULATION_PLUGIN=$CALCULATION_PLUGIN \
EXTRA_PLUGINS=$EXTRA_PLUGINS
COPY src src
Expand Down
1 change: 0 additions & 1 deletion embedding-calculator/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ SHELL := /bin/bash
.DEFAULT_GOAL := default
.PHONY := default up build-images build-cuda

VERSION := 1.0.1
IMAGE := ${DOCKER_REGISTRY}compreface-core
CUDA_IMAGE = $(IMAGE)-base:base-cuda112-py37
APPERY_ARG := --build-arg APPERY_API_KEY=${APPERY_API_KEY}
Expand Down
18 changes: 10 additions & 8 deletions embedding-calculator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,15 @@ Pass to `EXTRA_PLUGINS` comma-separated names of plugins.
|------------------------------------|----------------|-------------|------------|-------------|
| agegender.AgeDetector | age | agegender | Tensorflow | |
| agegender.GenderDetector | gender | agegender | Tensorflow | |
| insightface.AgeDetector | age | insightface | MXNet | + |
| insightface.GenderDetector | gender | insightface | MXNet | + |
| facenet.LandmarksDetector | landmarks | Facenet | Tensorflow | + |
| insightface.LandmarksDetector | landmarks | insightface | MXNet | + |
| insightface.Landmarks2d106Detector | landmarks2d106 | insightface | MXNet | + |
| facenet.facemask.MaskDetector | mask | facemask | Tensorflow | + |
| insightface.facemask.MaskDetector | mask | facemask | MXNet | + |
| insightface.AgeDetector | age | insightface | MXNet | + |
| insightface.GenderDetector | gender | insightface | MXNet | + |
| facenet.LandmarksDetector | landmarks | Facenet | Tensorflow | + |
| insightface.LandmarksDetector | landmarks | insightface | MXNet | + |
| insightface.Landmarks2d106Detector | landmarks2d106 | insightface | MXNet | + |
| facenet.facemask.MaskDetector | mask | facemask | Tensorflow | + |
| insightface.facemask.MaskDetector | mask | facemask | MXNet | + |
| facenet.PoseEstimator | pose | Facenet | Tensorflow | + |
| insightface.PoseEstimator | pose | insightface | MXNet | + |

Notes:
* `facenet.LandmarksDetector` and `insightface.LandmarksDetector` extract landmarks
Expand All @@ -116,7 +118,7 @@ Notes:
```
FACE_DETECTION_PLUGIN=facenet.FaceDetector
CALCULATION_PLUGIN=facenet.Calculator
EXTRA_PLUGINS=agegender.AgeDetector,agegender.GenderDetector,facenet.facemask.MaskDetector
EXTRA_PLUGINS=facenet.LandmarksDetector,agegender.GenderDetector,agegender.AgeDetector,facenet.facemask.MaskDetector,facenet.PoseEstimator
```

#### Pre-trained models
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,9 @@ public UserAppRole updateUserAppRole(final UserRoleUpdateDto userRoleUpdateDto,
authManager.verifyWritePrivilegesToApp(admin, app, true);

val userToUpdate = userService.getUserByGuid(userRoleUpdateDto.getUserId());
if (userToUpdate.getId().equals(adminId)) {
throw new SelfRoleChangeException();
}

val userToUpdateAppRole = app.getUserAppRole(userToUpdate.getId()).orElseThrow();
val newAppRole = AppRole.valueOf(userRoleUpdateDto.getRole());


if (userToUpdateAppRole.getRole().equals(OWNER)) {
throw new InsufficientPrivilegesException();
}
Expand Down
28 changes: 0 additions & 28 deletions java/admin/src/test/java/com/exadel/frs/AppServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -239,34 +239,6 @@ void failUpdateUserAppSelfRoleOwnerChange() {
verifyNoMoreInteractions(appRepositoryMock);
}

@Test
void failUpdateAppSelfRoleChange() {
val userRoleUpdateDto = UserRoleUpdateDto.builder()
.userId("userGuid")
.role(AppRole.USER.toString())
.build();
val user = user(USER_ID, USER);

val app = App.builder()
.name("name")
.guid(APPLICATION_GUID)
.build();

when(appRepositoryMock.findByGuid(APPLICATION_GUID)).thenReturn(Optional.of(app));
when(userServiceMock.getUserByGuid(any())).thenReturn(user);
when(userServiceMock.getUser(USER_ID)).thenReturn(user);

assertThatThrownBy(() -> appService.updateUserAppRole(
userRoleUpdateDto,
APPLICATION_GUID,
USER_ID
)).isInstanceOf(SelfRoleChangeException.class);

verify(authManagerMock).verifyWritePrivilegesToApp(user, app, true);
verify(authManagerMock).verifyReadPrivilegesToApp(user, app);
verifyNoMoreInteractions(authManagerMock);
}

@Test
void failUpdateAppNameIsNotUnique() {
val appUpdateDto = AppUpdateDto.builder()
Expand Down
4 changes: 3 additions & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
"@angular/platform-browser": "~11.0.5",
"@angular/platform-browser-dynamic": "~11.0.5",
"@angular/router": "~11.0.5",
"@ng-web-apis/common": "^2.0.1",
"@ng-web-apis/intersection-observer": "^2.1.0",
"@ngrx/data": "^10.0.1",
"@ngrx/effects": "^10.0.1",
"@ngrx/entity": "^10.0.1",
Expand All @@ -36,8 +38,8 @@
"@ngrx/store-devtools": "^10.0.1",
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"jasmine-marbles": "^0.6.0",
"chart.js": "^2.9.3",
"jasmine-marbles": "^0.6.0",
"ng2-charts": "^2.4.3",
"ngx-infinite-scroll": "^10.0.1",
"rxjs": "~6.6.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
<mat-icon svgIcon="search" class="search"></mat-icon>
</div>
<ng-container *ngIf="!hideContent && currentRole as userRole">
<button class="app-search--btn_user_list" *ngIf="userRole !== requiredRole" (click)="onOpenUserList()">
<mat-icon svgIcon="user-icon"></mat-icon>
<button class="app-search--btn_user_list" (click)="onOpenUserList()">
<mat-icon svgIcon="user-icon" matTooltip="{{ 'users.manage.manage_users_title' | translate }}" matTooltipClass="top-arrow"></mat-icon>
</button>
</ng-container>
<ng-container *ngIf="currentRole as userRole">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
@import 'media.scss';

.app-search {
padding: 30px 0;
padding-bottom: 20px;
display: flex;
align-items: center;
border-bottom: 1px solid $lighter-gray;
Expand All @@ -31,7 +31,7 @@
}

&--title {
font-size: 35px;
font-size: $text-lg;
line-height: 53px;
color: $dark-blue;
margin: 0 16px 0 0;
Expand Down Expand Up @@ -62,13 +62,13 @@
border: none;
border-bottom: 1px solid $light-gray;
background: none;
font-size: 14px;
font-size: $text-sm;
box-sizing: border-box;
outline: none;

&::placeholder {
color: $gray;
font-size: 15px;
font-size: $text-sm;
}
}

Expand All @@ -86,6 +86,7 @@
padding: 0;

&_user_list {
cursor: pointer;
display: flex;
align-items: center;
border: none;
Expand All @@ -96,14 +97,7 @@
}

button {
background: $light-blue;
border-radius: 15px;
width: 193px;
height: 51px;
color: $white;
font-size: 14px;
font-weight: 600;
line-height: 21px;
@include action-btns(193px, $white, $light-blue);
border: none;

span {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
</ng-container>

<ng-container *ngIf="applicationCollection.length < 1 && !isLoading && totalApplications">
<div class="create-new-message">
<div class="no-data-message">
<mat-icon svgIcon="info_new" inline="true"></mat-icon>
<p class="mat-caption">
<p class="caption">
{{ 'users.search.no_results' | translate }}
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,14 @@
justify-content: center;
}
}
.no-data-message {
display: flex;
align-items: center;
p {
@include no-data-msg;
}
.mat-icon {
@include sm-icon-size(14px);
margin-right: 10px;
}
}
Loading

0 comments on commit d4bfa0b

Please sign in to comment.