Search
Our search API allows you to search for registered persons by using an image.
Given an image of a person, search answers the following two questions:
- Are they a registered person?
- Which registered person are they?
This facilitates a wide variety of use-cases ranging from Attendance Tracking, Building Security, etc.
Sending a search request
The following snippet shows the process of creating a search request:
from opencv.fr.search.schemas import SearchRequest, SearchMode
from pathlib import Path
# As before, you can also use OpenCV or Pillow images
image_base_path = Path("sample_images")
image_path = image_base_path / "varun.jpg"
search_request = SearchRequest([image_path], min_score=0.7,
collection_id=None,
search_mode=SearchMode.FAST)
In addition to supplying up to 3 images in a list, you can optionally specify a collection_id
, min_score
, and SearchMode
.
The collection_id
if not None
, will restrict the search to only persons who belong to the specified collection.
The min_score
is a similarity threshold ranging between 0 and 1. When specified (as in this example), the API will return only persons with a similarity score above 0.7.
The SearchMode
when using SearchMode.ACCURATE
performs double the computation (and hence is slower) but can give a better score.
Usually omitting these parameters and letting the system use the defaults is good enough for most purposes.
from opencv.fr.search.schemas import SearchRequest, SearchMode
from pathlib import Path
# As before, you can also use OpenCV or Pillow images
image_base_path = Path("sample_images")
image_path = image_base_path / "varun.jpg"
search_request = SearchRequest([image_path])
If you want to recognize persons with masks, you can try a min_score
of 0.66
Now that we have created a search_request
, let's send it to the server:
result = sdk.search.search(search_request)
The result is simply a list of PersonSearchResult with each object containing a person
attribute and a score
attribute.
As an example, we can print the person and score attributes from the first item in the result:
print(result[0].person)
print(result[0].score)
A search can return more than one matched person, thus we use the first item from the result in the example above.
Sending a multi-face detection and search request
The search API we used before assumes that there is only one prominent face in an image. But what if we wanted to recognize all the people in an image?
This would mean we first need to detect all faces, and then search for each detected face, and each detected face could match with more than one persons.
To make this easy for you, we combined the search and detect functionalities in one API call.
As a user, you can choose to only detect faces, or to detect faces, and also search for them:
from opencv.fr.search.schemas import DetectionRequest, SearchOptions
from pathlib import Path
image_base_path = Path("sample_images")
image_path = image_base_path / "varun.jpg"
options = SearchOptions(
min_score = 0.6,
search_mode = "FAST"
)
detect_request_without_search = DetectionRequest(image_path)
detect_request_with_search = DetectionRequest(image_path, options)
In the example above, we construct two different detection requests.
For detect_request_without_search
we do not specify any search options in the constructor.
For detect_request_with_search
we specify search options.
When we call the API with detect_request_without_search
, it will not search for the detected faces and return only the bounding boxes, landmarks, and thumbnails for all the detected faces:
print(sdk.search.detect(detect_object_without_search))
The following result shows one face was detected and gives us the position of the left (x ordinate), top (y ordinate), right (x ordinate), and the bottom (y ordinate) that specifies the bounding box of detection.
Then, it includes the position of Facial Landmarks (left_eye, right_eye, etc.) as [x, y] coordinates.
It further includes a thumbnail for the cropped face from the detection.
Finally, it includes a detection score, and a list of PersonSearchResult items that match the detection.
Had there been more detections, the top level list would have more such DetectionResponseItem objects.
Since we did not specify any SearchOptions, the list of person items will always be empty.
[
{
'box': {'left': 178, 'top': 139, 'right': 319, 'bottom': 314},
'landmarks': {
'left_eye': [214, 201],
'right_eye': [277, 203],
'nose': [242, 237],
'left_mouth': [211, 257],
'right_mouth': [276, 259]
},
'thumbnail': <PIL.Image.Image image mode=RGB size=112x112 at 0x7F9AB7E2BD30>,
'detection_score': 0.78,
'persons': []
}
]
Now we can try our request where we did specify SearchOptions
print(sdk.search.detect(detect_request_with_search))
[
{
'box': {'left': 178, 'top': 139, 'right': 319, 'bottom': 314},
'landmarks': {
'left_eye': [214, 201],
'right_eye': [277, 203],
'nose': [242, 237],
'left_mouth': [211, 257],
'right_mouth': [276, 259]
},
'thumbnail': <PIL.Image.Image image mode=RGB size=112x112 at 0x7FE5E817B580>,
'detection_score': 0.78,
'persons': [
{
'person': {
'id': 'bb106660-85cd-44d0-8b80-2dc288503890',
'name': 'Varun Chatterji',
'images': [<PIL.Image.Image image mode=RGB size=112x112 at 0x7FE577712B80>],
'gender': None,
'collections': [],
'date_of_birth': None,
'nationality': None,
'notes': None,
'create_date': '2022-07-13 13:33:17.133421',
'modified_date': '2022-07-13 13:33:39.689646'
},
'score': 0.9973
}
]
}
]
It is to be noted that more than one person can be associated with each detection.
Structure of the detection response
The detection response is a list of DetectionResponseItem objects. Each DetectionResponseItem contains:
box
- a box object of type Box, with object attributesleft
,top
,right
,left
of type intlandmarks
- a landmarks object of type Landmarks, with attributesleft_eye
,right_eye
, etc. each of type Coordinate.- A Coordinate object has attributes
x
andy
.
- A Coordinate object has attributes
thumbnail
- a thumbnail of the detected face of type PIL.Image.Imagedetection_score
- a detection score of type floatpersons
- a list of persons matching the detection thumbnail of type PersonSearchResult
Verifying a specific Person
If you know the id
of a specific person, and you would just like to know if a given image matches the person with the specified id
, then this API is best suited to your needs.
As usual, we first create a VerificationRequest
from opencv.fr.search.schemas import VerificationRequest
from pathlib import Path
image_base_path = Path("sample_images")
image_path = image_base_path / "varun.jpg"
person_id = "bb106660-85cd-44d0-8b80-2dc288503890"
verification_request = VerificationRequest(person_id, [image_path])
Then we call the API:
print(sdk.search.verify(verification_request))
The response is an object of type PersonSearchResult and contains a person
attribute of type Person and a score
attribute of type float.
If the image doesn't match the id
, then person
will be None, and the score
shall be 0.