Exemple #1
0
    def compare_faces(self, target_image, similarity):
        """
        Compares faces in the image with the largest face in the target image.

        :param target_image: The target image to compare against.
        :param similarity: Faces in the image must have a similarity value greater
                           than this value to be included in the results.
        :return: A tuple. The first element is the list of faces that match the
                 reference image. The second element is the list of faces that have
                 a similarity value below the specified threshold.
        """
        try:
            response = self.rekognition_client.compare_faces(
                SourceImage=self.image,
                TargetImage=target_image.image,
                SimilarityThreshold=similarity)
            matches = [
                RekognitionFace(match['Face'])
                for match in response['FaceMatches']
            ]
            unmatches = [
                RekognitionFace(face) for face in response['UnmatchedFaces']
            ]
            logger.info("Found %s matched faces and %s unmatched faces.",
                        len(matches), len(unmatches))
        except ClientError:
            logger.exception("Couldn't match faces from %s to %s.",
                             self.image_name, target_image.image_name)
            raise
        else:
            return matches, unmatches
Exemple #2
0
    def search_faces_by_image(self, image, threshold, max_faces):
        """
        Searches for faces in the collection that match the largest face in the
        reference image.

        :param image: The image that contains the reference face to search for.
        :param threshold: The match confidence must be greater than this value
                          for a face to be included in the results.
        :param max_faces: The maximum number of faces to return.
        :return: A tuple. The first element is the face found in the reference image.
                 The second element is the list of matching faces found in the
                 collection.
        """
        try:
            response = self.rekognition_client.search_faces_by_image(
                CollectionId=self.collection_id, Image=image.image,
                FaceMatchThreshold=threshold, MaxFaces=max_faces)
            image_face = RekognitionFace({
                'BoundingBox': response['SearchedFaceBoundingBox'],
                'Confidence': response['SearchedFaceConfidence']
            })
            collection_faces = [
                RekognitionFace(face['Face']) for face in response['FaceMatches']]
            logger.info("Found %s faces in the collection that match the largest "
                        "face in %s.", len(collection_faces), image.image_name)
        except ClientError:
            logger.exception(
                "Couldn't search for faces in %s that match %s.", self.collection_id,
                image.image_name)
            raise
        else:
            return image_face, collection_faces
def test_compare_faces(make_stubber, make_faces, error_code):
    rekognition_client = boto3.client('rekognition')
    rekognition_stubber = make_stubber(rekognition_client)
    source_image = RekognitionImage(TEST_IMAGE, 'source-image',
                                    rekognition_client)
    target_image = RekognitionImage(TEST_IMAGE, 'target-image',
                                    rekognition_client)
    matches = [RekognitionFace(face) for face in make_faces(1)]
    unmatches = [RekognitionFace(face) for face in make_faces(2)]
    similarity = 80

    rekognition_stubber.stub_compare_faces(source_image.image,
                                           target_image.image,
                                           similarity,
                                           matches,
                                           unmatches,
                                           error_code=error_code)

    if error_code is None:
        got_matches, got_unmatches = source_image.compare_faces(
            target_image, similarity)
        assert ([face.to_dict() for face in matches
                 ] == [face.to_dict() for face in got_matches])
        assert ([face.to_dict() for face in unmatches
                 ] == [face.to_dict() for face in got_unmatches])
    else:
        with pytest.raises(ClientError) as exc_info:
            source_image.compare_faces(target_image, similarity)
        assert exc_info.value.response['Error']['Code'] == error_code
Exemple #4
0
    def index_faces(self, image, max_faces):
        """
        Finds faces in the specified image, indexes them, and stores them in the
        collection.

        :param image: The image to index.
        :param max_faces: The maximum number of faces to index.
        :return: A tuple. The first element is a list of indexed faces.
                 The second element is a list of faces that couldn't be indexed.
        """
        try:
            response = self.rekognition_client.index_faces(
                CollectionId=self.collection_id, Image=image.image,
                ExternalImageId=image.image_name, MaxFaces=max_faces,
                DetectionAttributes=['ALL'])
            indexed_faces = [
                RekognitionFace({**face['Face'], **face['FaceDetail']})
                for face in response['FaceRecords']]
            unindexed_faces = [
                RekognitionFace(face['FaceDetail'])
                for face in response['UnindexedFaces']]
            logger.info(
                "Indexed %s faces in %s. Could not index %s faces.", len(indexed_faces),
                image.image_name, len(unindexed_faces))
        except ClientError:
            logger.exception("Couldn't index faces in image %s.", image.image_name)
            raise
        else:
            return indexed_faces, unindexed_faces
def test_index_faces(make_stubber, make_faces, error_code):
    rekognition_client = boto3.client('rekognition')
    rekognition_stubber = make_stubber(rekognition_client)
    image = RekognitionImage(TEST_IMAGE, 'test-image', rekognition_client)
    max_faces = 3
    indexed_faces = [
        RekognitionFace(face)
        for face in make_faces(3, has_details=True, is_index=True)
    ]
    unindexed_faces = [RekognitionFace(face) for face in make_faces(4)]
    collection = make_collection(rekognition_client)

    rekognition_stubber.stub_index_faces(collection.collection_id,
                                         image,
                                         max_faces,
                                         indexed_faces,
                                         unindexed_faces,
                                         error_code=error_code)

    if error_code is None:
        got_indexed_faces, got_unindexed_faces = collection.index_faces(
            image, max_faces)
        assert ([face.to_dict() for face in indexed_faces
                 ] == [face.to_dict() for face in got_indexed_faces])
        assert ([face.to_dict() for face in unindexed_faces
                 ] == [face.to_dict() for face in got_unindexed_faces])
    else:
        with pytest.raises(ClientError) as exc_info:
            collection.index_faces(image, max_faces)
        assert exc_info.value.response['Error']['Code'] == error_code
def test_search_face_by_image(make_stubber, make_faces, error_code):
    rekognition_client = boto3.client('rekognition')
    rekognition_stubber = make_stubber(rekognition_client)
    collection = make_collection(rekognition_client)
    image = RekognitionImage(TEST_IMAGE, 'test-image', rekognition_client)
    threshold = 80
    max_faces = 3
    image_face = RekognitionFace(make_faces(1)[0])
    faces = [
        RekognitionFace({
            'FaceIndex': f'face-{index}',
            'ImageIndex': f'image-{index}'
        }) for index in range(0, 3)
    ]

    rekognition_stubber.stub_search_faces_by_image(collection.collection_id,
                                                   image,
                                                   threshold,
                                                   max_faces,
                                                   image_face,
                                                   faces,
                                                   error_code=error_code)

    if error_code is None:
        got_image_face, got_faces = collection.search_faces_by_image(
            image, threshold, max_faces)
        assert image_face.to_dict() == got_image_face.to_dict()
        assert ([face.to_dict()
                 for face in faces] == [face.to_dict() for face in got_faces])
    else:
        with pytest.raises(ClientError) as exc_info:
            collection.search_faces_by_image(image, threshold, max_faces)
        assert exc_info.value.response['Error']['Code'] == error_code
def test_search_faces(make_stubber, make_faces, error_code):
    rekognition_client = boto3.client('rekognition')
    rekognition_stubber = make_stubber(rekognition_client)
    collection = make_collection(rekognition_client)
    face_id = 'test-face-id'
    threshold = 80
    max_faces = 3
    faces = [
        RekognitionFace({
            'FaceIndex': f'face-{index}',
            'ImageIndex': f'image-{index}'
        }) for index in range(0, 3)
    ]

    rekognition_stubber.stub_search_faces(collection.collection_id,
                                          face_id,
                                          threshold,
                                          max_faces,
                                          faces,
                                          error_code=error_code)

    if error_code is None:
        got_faces = collection.search_faces(face_id, threshold, max_faces)
        assert ([face.to_dict()
                 for face in faces] == [face.to_dict() for face in got_faces])
    else:
        with pytest.raises(ClientError) as exc_info:
            collection.search_faces(face_id, threshold, max_faces)
        assert exc_info.value.response['Error']['Code'] == error_code
Exemple #8
0
    def search_faces(self, face_id, threshold, max_faces):
        """
        Searches for faces in the collection that match another face from the
        collection.

        :param face_id: The ID of the face in the collection to search for.
        :param threshold: The match confidence must be greater than this value
                          for a face to be included in the results.
        :param max_faces: The maximum number of faces to return.
        :return: The list of matching faces found in the collection. This list does
                 not contain the face specified by `face_id`.
        """
        try:
            response = self.rekognition_client.search_faces(
                CollectionId=self.collection_id,
                FaceId=face_id,
                FaceMatchThreshold=threshold,
                MaxFaces=max_faces)
            faces = [
                RekognitionFace(face['Face'])
                for face in response['FaceMatches']
            ]
            logger.info("Found %s faces in %s that match %s.", len(faces),
                        self.collection_id, face_id)
        except ClientError:
            logger.exception("Couldn't search for faces in %s that match %s.",
                             self.collection_id, face_id)
            raise
        else:
            return faces
Exemple #9
0
    def recognize_celebrities(self):
        """
        Detects celebrities in the image.

        :return: A tuple. The first element is the list of celebrities found in
                 the image. The second element is the list of faces that were
                 detected but did not match any known celebrities.
        """
        try:
            response = self.rekognition_client.recognize_celebrities(
                Image=self.image)
            celebrities = [
                RekognitionCelebrity(celeb)
                for celeb in response['CelebrityFaces']
            ]
            other_faces = [
                RekognitionFace(face) for face in response['UnrecognizedFaces']
            ]
            logger.info("Found %s celebrities and %s other faces in %s.",
                        len(celebrities), len(other_faces), self.image_name)
        except ClientError:
            logger.exception("Couldn't detect celebrities in %s.",
                             self.image_name)
            raise
        else:
            return celebrities, other_faces
Exemple #10
0
 def detect_faces(self):
     try:
         response = self.rekognition_client.detect_faces(Image=self.image,
                                                         Attributes=['ALL'])
         faces = [RekognitionFace(face) for face in response['FaceDetails']]
         logger.info("Detected %s faces.", len(faces))
     except ClientError:
         logger.exception("Couldn't detect faces in %s.", self.image_name)
         raise
     else:
         return faces
Exemple #11
0
 def compare_faces(self, target_image, similarity):
     try:
         response = self.rekognition_client.compare_faces(
             SourceImage=self.image,
             TargetImage=target_image.image,
             SimilarityThreshold=similarity)
         matches = [
             RekognitionFace(match['Face'])
             for match in response['FaceMatches']
         ]
         unmatches = [
             RekognitionFace(face) for face in response['UnmatchedFaces']
         ]
         logger.info("Found %s matched faces and %s unmatched faces.",
                     len(matches), len(unmatches))
     except ClientError:
         logger.exception("Couldn't match faces from %s to %s.",
                          self.image_name, target_image.image_name)
         raise
     else:
         return matches, unmatches
Exemple #12
0
    def do_face_detection(self):
        """
        Performs face detection on the video.

        :return: The list of faces found in the video.
        """
        return self._do_rekognition_job(
            "face detection",
            self.rekognition_client.start_face_detection,
            self.rekognition_client.get_face_detection,
            lambda response: [
                RekognitionFace(face['Face'], face['Timestamp']) for face in
                response['Faces']])
def test_detect_faces(make_stubber, make_faces, error_code):
    rekognition_client = boto3.client('rekognition')
    rekognition_stubber = make_stubber(rekognition_client)
    image = RekognitionImage(TEST_IMAGE, 'test-image', rekognition_client)
    faces = [RekognitionFace(face) for face in make_faces(3, True)]

    rekognition_stubber.stub_detect_faces(image.image,
                                          faces,
                                          error_code=error_code)

    if error_code is None:
        got_faces = image.detect_faces()
        assert ([face.to_dict()
                 for face in faces] == [face.to_dict() for face in got_faces])
    else:
        with pytest.raises(ClientError) as exc_info:
            image.detect_faces()
        assert exc_info.value.response['Error']['Code'] == error_code
Exemple #14
0
    def list_faces(self, max_results):
        """
        Lists the faces currently indexed in the collection.

        :param max_results: The maximum number of faces to return.
        :return: The list of faces in the collection.
        """
        try:
            response = self.rekognition_client.list_faces(
                CollectionId=self.collection_id, MaxResults=max_results)
            faces = [RekognitionFace(face) for face in response['Faces']]
            logger.info("Found %s faces in collection %s.", len(faces),
                        self.collection_id)
        except ClientError:
            logger.exception("Couldn't list faces in collection %s.",
                             self.collection_id)
            raise
        else:
            return faces
Exemple #15
0
 def recognize_celebrities(self):
     try:
         response = self.rekognition_client.recognize_celebrities(
             Image=self.image)
         celebrities = [
             RekognitionCelebrity(celeb)
             for celeb in response['CelebrityFaces']
         ]
         other_faces = [
             RekognitionFace(face) for face in response['UnrecognizedFaces']
         ]
         logger.info("Found %s celebrities and %s other faces in %s.",
                     len(celebrities), len(other_faces), self.image_name)
     except ClientError:
         logger.exception("Couldn't detect celebrities in %s.",
                          self.image_name)
         raise
     else:
         return celebrities, other_faces
Exemple #16
0
def test_do_face_detection(make_stubber, stub_runner, make_faces, monkeypatch,
                           error_code, stop_on_method):
    rekognition_client = boto3.client('rekognition')
    rekognition_stubber = make_stubber(rekognition_client)
    job_id = 'test-job-id'
    job_status = 'TESTING'
    video = mock_video(monkeypatch, 'SUCCEEDED', rekognition_client)
    faces = [RekognitionFace(face, time.time_ns()) for face in make_faces(3)]

    with stub_runner(error_code, stop_on_method) as runner:
        runner.add(rekognition_stubber.stub_start_detection,
                   'start_face_detection', video.video,
                   video.get_notification_channel(), job_id)
        runner.add(rekognition_stubber.stub_get_face_detection, job_id,
                   job_status, faces)

    if error_code is None:
        got_faces = video.do_face_detection()
        assert ([face.to_dict()
                 for face in faces] == [face.to_dict() for face in got_faces])
    else:
        with pytest.raises(ClientError) as exc_info:
            video.do_face_detection()
        assert exc_info.value.response['Error']['Code'] == error_code
def test_recognize_celebrities(make_stubber, make_faces, error_code):
    rekognition_client = boto3.client('rekognition')
    rekognition_stubber = make_stubber(rekognition_client)
    image = RekognitionImage(TEST_IMAGE, 'test-image', rekognition_client)
    celebrities = [
        RekognitionCelebrity(face) for face in make_faces(3, is_celebrity=True)
    ]
    normals = [RekognitionFace(face) for face in make_faces(2)]

    rekognition_stubber.stub_recognize_celebrities(image.image,
                                                   celebrities,
                                                   normals,
                                                   error_code=error_code)

    if error_code is None:
        got_celebrities, got_normals = image.recognize_celebrities()
        assert ([celeb.to_dict() for celeb in celebrities
                 ] == [celeb.to_dict() for celeb in got_celebrities])
        assert ([normal.to_dict() for normal in normals
                 ] == [normal.to_dict() for normal in got_normals])
    else:
        with pytest.raises(ClientError) as exc_info:
            image.recognize_celebrities()
        assert exc_info.value.response['Error']['Code'] == error_code