Subject: [PR] Adding Rekognition compare_faces, detect_labels and detect_text, Textract detect_document_text (#7161)
This commit is contained in:
parent
ba73f64e08
commit
ba27f02225
@ -46,6 +46,30 @@ class RekognitionBackend(BaseBackend):
|
||||
self._text_model_version(),
|
||||
)
|
||||
|
||||
def compare_faces(
|
||||
self,
|
||||
) -> Tuple[List[Dict[str, Any]], str, str, List[Dict[str, Any]], Dict[str, Any],]:
|
||||
return (
|
||||
self._face_matches(),
|
||||
"ROTATE_90",
|
||||
"ROTATE_90",
|
||||
self._unmatched_faces(),
|
||||
self.source_image_face(),
|
||||
)
|
||||
|
||||
def detect_labels(self) -> Tuple[List[Dict[str, Any]], Dict[str, Any], str]:
|
||||
return (
|
||||
self._mobile_phone_label(),
|
||||
self._image_properties(),
|
||||
"3.0",
|
||||
)
|
||||
|
||||
def detect_text(self) -> Tuple[List[Dict[str, Any]], str]:
|
||||
return (
|
||||
self._detect_text_text_detections(),
|
||||
"3.0",
|
||||
)
|
||||
|
||||
# private
|
||||
|
||||
def _job_id(self) -> str:
|
||||
@ -339,5 +363,391 @@ class RekognitionBackend(BaseBackend):
|
||||
},
|
||||
]
|
||||
|
||||
def _face_matches(self) -> List[Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
"Face": {
|
||||
"BoundingBox": {
|
||||
"Width": 0.5521978139877319,
|
||||
"Top": 0.1203877404332161,
|
||||
"Left": 0.23626373708248138,
|
||||
"Height": 0.3126954436302185,
|
||||
},
|
||||
"Confidence": 99.98751068115234,
|
||||
"Pose": {
|
||||
"Yaw": -82.36799621582031,
|
||||
"Roll": -62.13221740722656,
|
||||
"Pitch": 0.8652129173278809,
|
||||
},
|
||||
"Quality": {
|
||||
"Sharpness": 99.99880981445312,
|
||||
"Brightness": 54.49755096435547,
|
||||
},
|
||||
"Landmarks": [
|
||||
{
|
||||
"Y": 0.2996366024017334,
|
||||
"X": 0.41685718297958374,
|
||||
"Type": "eyeLeft",
|
||||
},
|
||||
{
|
||||
"Y": 0.2658946216106415,
|
||||
"X": 0.4414493441581726,
|
||||
"Type": "eyeRight",
|
||||
},
|
||||
{
|
||||
"Y": 0.3465650677680969,
|
||||
"X": 0.48636093735694885,
|
||||
"Type": "nose",
|
||||
},
|
||||
{
|
||||
"Y": 0.30935320258140564,
|
||||
"X": 0.6251809000968933,
|
||||
"Type": "mouthLeft",
|
||||
},
|
||||
{
|
||||
"Y": 0.26942989230155945,
|
||||
"X": 0.6454493403434753,
|
||||
"Type": "mouthRight",
|
||||
},
|
||||
],
|
||||
},
|
||||
"Similarity": 100.0,
|
||||
}
|
||||
]
|
||||
|
||||
def _unmatched_faces(self) -> List[Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
"BoundingBox": {
|
||||
"Width": 0.4890109896659851,
|
||||
"Top": 0.6566604375839233,
|
||||
"Left": 0.10989011079072952,
|
||||
"Height": 0.278298944234848,
|
||||
},
|
||||
"Confidence": 99.99992370605469,
|
||||
"Pose": {
|
||||
"Yaw": 51.51519012451172,
|
||||
"Roll": -110.32493591308594,
|
||||
"Pitch": -2.322134017944336,
|
||||
},
|
||||
"Quality": {
|
||||
"Sharpness": 99.99671173095703,
|
||||
"Brightness": 57.23163986206055,
|
||||
},
|
||||
"Landmarks": [
|
||||
{
|
||||
"Y": 0.8288310766220093,
|
||||
"X": 0.3133862614631653,
|
||||
"Type": "eyeLeft",
|
||||
},
|
||||
{
|
||||
"Y": 0.7632885575294495,
|
||||
"X": 0.28091415762901306,
|
||||
"Type": "eyeRight",
|
||||
},
|
||||
{"Y": 0.7417283654212952, "X": 0.3631140887737274, "Type": "nose"},
|
||||
{
|
||||
"Y": 0.8081989884376526,
|
||||
"X": 0.48565614223480225,
|
||||
"Type": "mouthLeft",
|
||||
},
|
||||
{
|
||||
"Y": 0.7548204660415649,
|
||||
"X": 0.46090251207351685,
|
||||
"Type": "mouthRight",
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
def source_image_face(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"BoundingBox": {
|
||||
"Width": 0.5521978139877319,
|
||||
"Top": 0.1203877404332161,
|
||||
"Left": 0.23626373708248138,
|
||||
"Height": 0.3126954436302185,
|
||||
},
|
||||
"Confidence": 99.98751068115234,
|
||||
}
|
||||
|
||||
def _mobile_phone_label(self) -> List[Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
"Name": "Mobile Phone",
|
||||
"Parents": [{"Name": "Phone"}],
|
||||
"Aliases": [{"Name": "Cell Phone"}],
|
||||
"Categories": [{"Name": "Technology and Computing"}],
|
||||
"Confidence": 99.9364013671875,
|
||||
"Instances": [
|
||||
{
|
||||
"BoundingBox": {
|
||||
"Width": 0.26779675483703613,
|
||||
"Height": 0.8562285900115967,
|
||||
"Left": 0.3604024350643158,
|
||||
"Top": 0.09245597571134567,
|
||||
},
|
||||
"Confidence": 99.9364013671875,
|
||||
"DominantColors": [
|
||||
{
|
||||
"Red": 120,
|
||||
"Green": 137,
|
||||
"Blue": 132,
|
||||
"HexCode": "3A7432",
|
||||
"SimplifiedColor": "red",
|
||||
"CssColor": "fuscia",
|
||||
"PixelPercentage": 40.10,
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
def _image_properties(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"ImageProperties": {
|
||||
"Quality": {
|
||||
"Brightness": 40,
|
||||
"Sharpness": 40,
|
||||
"Contrast": 24,
|
||||
},
|
||||
"DominantColors": [
|
||||
{
|
||||
"Red": 120,
|
||||
"Green": 137,
|
||||
"Blue": 132,
|
||||
"HexCode": "3A7432",
|
||||
"SimplifiedColor": "red",
|
||||
"CssColor": "fuscia",
|
||||
"PixelPercentage": 40.10,
|
||||
}
|
||||
],
|
||||
"Foreground": {
|
||||
"Quality": {
|
||||
"Brightness": 40,
|
||||
"Sharpness": 40,
|
||||
},
|
||||
"DominantColors": [
|
||||
{
|
||||
"Red": 200,
|
||||
"Green": 137,
|
||||
"Blue": 132,
|
||||
"HexCode": "3A7432",
|
||||
"CSSColor": "",
|
||||
"SimplifiedColor": "red",
|
||||
"PixelPercentage": 30.70,
|
||||
}
|
||||
],
|
||||
},
|
||||
"Background": {
|
||||
"Quality": {
|
||||
"Brightness": 40,
|
||||
"Sharpness": 40,
|
||||
},
|
||||
"DominantColors": [
|
||||
{
|
||||
"Red": 200,
|
||||
"Green": 137,
|
||||
"Blue": 132,
|
||||
"HexCode": "3A7432",
|
||||
"CSSColor": "",
|
||||
"SimplifiedColor": "Red",
|
||||
"PixelPercentage": 10.20,
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
def _detect_text_text_detections(self) -> List[Dict[str, Any]]:
|
||||
return [
|
||||
{
|
||||
"Confidence": 99.35693359375,
|
||||
"DetectedText": "IT'S",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.09988046437501907,
|
||||
"Left": 0.6684935688972473,
|
||||
"Top": 0.18226495385169983,
|
||||
"Width": 0.1461552083492279,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.6684935688972473, "Y": 0.1838926374912262},
|
||||
{"X": 0.8141663074493408, "Y": 0.18226495385169983},
|
||||
{"X": 0.8146487474441528, "Y": 0.28051772713661194},
|
||||
{"X": 0.6689760088920593, "Y": 0.2821454107761383},
|
||||
],
|
||||
},
|
||||
"Id": 0,
|
||||
"Type": "LINE",
|
||||
},
|
||||
{
|
||||
"Confidence": 99.6207275390625,
|
||||
"DetectedText": "MONDAY",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.11442459374666214,
|
||||
"Left": 0.5566731691360474,
|
||||
"Top": 0.3525116443634033,
|
||||
"Width": 0.39574965834617615,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.5566731691360474, "Y": 0.353712260723114},
|
||||
{"X": 0.9522717595100403, "Y": 0.3525116443634033},
|
||||
{"X": 0.9524227976799011, "Y": 0.4657355844974518},
|
||||
{"X": 0.5568241477012634, "Y": 0.46693623065948486},
|
||||
],
|
||||
},
|
||||
"Id": 1,
|
||||
"Type": "LINE",
|
||||
},
|
||||
{
|
||||
"Confidence": 99.6160888671875,
|
||||
"DetectedText": "but keep",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.08314694464206696,
|
||||
"Left": 0.6398131847381592,
|
||||
"Top": 0.5267938375473022,
|
||||
"Width": 0.2021435648202896,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.640289306640625, "Y": 0.5267938375473022},
|
||||
{"X": 0.8419567942619324, "Y": 0.5295097827911377},
|
||||
{"X": 0.8414806723594666, "Y": 0.609940767288208},
|
||||
{"X": 0.6398131847381592, "Y": 0.6072247624397278},
|
||||
],
|
||||
},
|
||||
"Id": 2,
|
||||
"Type": "LINE",
|
||||
},
|
||||
{
|
||||
"Confidence": 88.95134735107422,
|
||||
"DetectedText": "Smiling",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.4326171875,
|
||||
"Left": 0.46289217472076416,
|
||||
"Top": 0.5634765625,
|
||||
"Width": 0.5371078252792358,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.46289217472076416, "Y": 0.5634765625},
|
||||
{"X": 1.0, "Y": 0.5634765625},
|
||||
{"X": 1.0, "Y": 0.99609375},
|
||||
{"X": 0.46289217472076416, "Y": 0.99609375},
|
||||
],
|
||||
},
|
||||
"Id": 3,
|
||||
"Type": "LINE",
|
||||
},
|
||||
{
|
||||
"Confidence": 99.35693359375,
|
||||
"DetectedText": "IT'S",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.09988046437501907,
|
||||
"Left": 0.6684935688972473,
|
||||
"Top": 0.18226495385169983,
|
||||
"Width": 0.1461552083492279,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.6684935688972473, "Y": 0.1838926374912262},
|
||||
{"X": 0.8141663074493408, "Y": 0.18226495385169983},
|
||||
{"X": 0.8146487474441528, "Y": 0.28051772713661194},
|
||||
{"X": 0.6689760088920593, "Y": 0.2821454107761383},
|
||||
],
|
||||
},
|
||||
"Id": 4,
|
||||
"ParentId": 0,
|
||||
"Type": "WORD",
|
||||
},
|
||||
{
|
||||
"Confidence": 99.6207275390625,
|
||||
"DetectedText": "MONDAY",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.11442466825246811,
|
||||
"Left": 0.5566731691360474,
|
||||
"Top": 0.35251158475875854,
|
||||
"Width": 0.39574965834617615,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.5566731691360474, "Y": 0.3537122905254364},
|
||||
{"X": 0.9522718787193298, "Y": 0.35251158475875854},
|
||||
{"X": 0.9524227976799011, "Y": 0.4657355546951294},
|
||||
{"X": 0.5568241477012634, "Y": 0.46693626046180725},
|
||||
],
|
||||
},
|
||||
"Id": 5,
|
||||
"ParentId": 1,
|
||||
"Type": "WORD",
|
||||
},
|
||||
{
|
||||
"Confidence": 99.96778869628906,
|
||||
"DetectedText": "but",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.0625,
|
||||
"Left": 0.6402802467346191,
|
||||
"Top": 0.5283203125,
|
||||
"Width": 0.08027780801057816,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.6402802467346191, "Y": 0.5283203125},
|
||||
{"X": 0.7205580472946167, "Y": 0.5283203125},
|
||||
{"X": 0.7205580472946167, "Y": 0.5908203125},
|
||||
{"X": 0.6402802467346191, "Y": 0.5908203125},
|
||||
],
|
||||
},
|
||||
"Id": 6,
|
||||
"ParentId": 2,
|
||||
"Type": "WORD",
|
||||
},
|
||||
{
|
||||
"Confidence": 99.26438903808594,
|
||||
"DetectedText": "keep",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.0818721204996109,
|
||||
"Left": 0.7344760298728943,
|
||||
"Top": 0.5280686020851135,
|
||||
"Width": 0.10748066753149033,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.7349520921707153, "Y": 0.5280686020851135},
|
||||
{"X": 0.8419566750526428, "Y": 0.5295097827911377},
|
||||
{"X": 0.8414806127548218, "Y": 0.6099407076835632},
|
||||
{"X": 0.7344760298728943, "Y": 0.6084995269775391},
|
||||
],
|
||||
},
|
||||
"Id": 7,
|
||||
"ParentId": 2,
|
||||
"Type": "WORD",
|
||||
},
|
||||
{
|
||||
"Confidence": 88.95134735107422,
|
||||
"DetectedText": "Smiling",
|
||||
"Geometry": {
|
||||
"BoundingBox": {
|
||||
"Height": 0.4326171875,
|
||||
"Left": 0.46289217472076416,
|
||||
"Top": 0.5634765625,
|
||||
"Width": 0.5371078252792358,
|
||||
},
|
||||
"Polygon": [
|
||||
{"X": 0.46289217472076416, "Y": 0.5634765625},
|
||||
{"X": 1.0, "Y": 0.5634765625},
|
||||
{"X": 1.0, "Y": 0.99609375},
|
||||
{"X": 0.46289217472076416, "Y": 0.99609375},
|
||||
],
|
||||
},
|
||||
"Id": 8,
|
||||
"ParentId": 3,
|
||||
"Type": "WORD",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
rekognition_backends = BackendDict(RekognitionBackend, "rekognition")
|
||||
|
@ -58,6 +58,51 @@ class RekognitionResponse(BaseResponse):
|
||||
)
|
||||
)
|
||||
|
||||
def compare_faces(self) -> str:
|
||||
(
|
||||
face_matches,
|
||||
source_image_orientation_correction,
|
||||
target_image_orientation_correction,
|
||||
unmatched_faces,
|
||||
source_image_face,
|
||||
) = self.rekognition_backend.compare_faces()
|
||||
|
||||
return json.dumps(
|
||||
dict(
|
||||
FaceMatches=face_matches,
|
||||
SourceImageOrientationCorrection=source_image_orientation_correction,
|
||||
TargetImageOrientationCorrection=target_image_orientation_correction,
|
||||
UnmatchedFaces=unmatched_faces,
|
||||
SourceImageFace=source_image_face,
|
||||
)
|
||||
)
|
||||
|
||||
def detect_labels(self) -> str:
|
||||
(
|
||||
labels,
|
||||
image_properties,
|
||||
label_model_version,
|
||||
) = self.rekognition_backend.detect_labels()
|
||||
return json.dumps(
|
||||
dict(
|
||||
Labels=labels,
|
||||
ImageProperties=image_properties,
|
||||
LabelModelVersion=label_model_version,
|
||||
)
|
||||
)
|
||||
|
||||
def detect_text(self) -> str:
|
||||
(
|
||||
text_detections,
|
||||
text_model_version,
|
||||
) = self.rekognition_backend.detect_text()
|
||||
return json.dumps(
|
||||
dict(
|
||||
TextDetections=text_detections,
|
||||
TextModelVersion=text_model_version,
|
||||
)
|
||||
)
|
||||
|
||||
def start_face_search(self) -> TYPE_RESPONSE:
|
||||
headers = {"Content-Type": "application/x-amz-json-1.1"}
|
||||
job_id = self.rekognition_backend.start_face_search()
|
||||
|
@ -42,6 +42,13 @@ class TextractBackend(BaseBackend):
|
||||
raise InvalidJobIdException()
|
||||
return job
|
||||
|
||||
def detect_document_text(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"Blocks": TextractBackend.BLOCKS,
|
||||
"DetectDocumentTextModelVersion": "1.0",
|
||||
"DocumentMetadata": {"Pages": TextractBackend.PAGES},
|
||||
}
|
||||
|
||||
def start_document_text_detection(self, document_location: str) -> str:
|
||||
"""
|
||||
The following parameters have not yet been implemented: ClientRequestToken, JobTag, NotificationChannel, OutputConfig, KmsKeyID
|
||||
|
@ -23,6 +23,10 @@ class TextractResponse(BaseResponse):
|
||||
job = self.textract_backend.get_document_text_detection(job_id=job_id).to_dict()
|
||||
return json.dumps(job)
|
||||
|
||||
def detect_document_text(self) -> str:
|
||||
result = self.textract_backend.detect_document_text()
|
||||
return json.dumps(result)
|
||||
|
||||
def start_document_text_detection(self) -> str:
|
||||
params = json.loads(self.body)
|
||||
document_location = params.get("DocumentLocation")
|
||||
|
@ -43,6 +43,48 @@ def test_start_text_detection():
|
||||
assert "JobId" in resp
|
||||
|
||||
|
||||
@mock_rekognition
|
||||
def test_compare_faces():
|
||||
client = boto3.client("rekognition", region_name="ap-southeast-1")
|
||||
sourceimage = {
|
||||
"S3Object": {"Bucket": "string", "Name": "string", "Version": "string"}
|
||||
}
|
||||
targetimage = {
|
||||
"S3Object": {"Bucket": "string", "Name": "string", "Version": "string"}
|
||||
}
|
||||
|
||||
resp = client.compare_faces(
|
||||
SimilarityThreshold=80, SourceImage=sourceimage, TargetImage=targetimage
|
||||
)
|
||||
|
||||
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||
assert "FaceMatches" in resp
|
||||
|
||||
|
||||
@mock_rekognition
|
||||
def test_detect_labels():
|
||||
client = boto3.client("rekognition", region_name="ap-southeast-1")
|
||||
|
||||
resp = client.detect_labels(
|
||||
Image={"S3Object": {"Bucket": "string", "Name": "name.jpg"}}, MaxLabels=10
|
||||
)
|
||||
|
||||
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||
assert "Labels" in resp
|
||||
|
||||
|
||||
@mock_rekognition
|
||||
def test_detect_text():
|
||||
client = boto3.client("rekognition", region_name="ap-southeast-1")
|
||||
|
||||
resp = client.detect_text(
|
||||
Image={"S3Object": {"Bucket": "string", "Name": "name.jpg"}}
|
||||
)
|
||||
|
||||
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||
assert "TextDetections" in resp
|
||||
|
||||
|
||||
@mock_rekognition
|
||||
def test_get_face_search():
|
||||
client = boto3.client("rekognition", region_name="us-east-2")
|
||||
|
@ -23,6 +23,22 @@ def test_textract_start_text_detection():
|
||||
assert isinstance(data["JobId"], str)
|
||||
|
||||
|
||||
@mock_textract
|
||||
def test_detect_document_text():
|
||||
backend = server.create_backend_app("textract")
|
||||
test_client = backend.test_client()
|
||||
headers = {"X-Amz-Target": "X-Amz-Target=Textract.DetectDocumentText"}
|
||||
request_body = {
|
||||
"DocumentLocation": {
|
||||
"S3Object": {"Bucket": "bucket", "Name": "name", "Version": "version"}
|
||||
}
|
||||
}
|
||||
resp = test_client.post("/", headers=headers, json=request_body)
|
||||
data = json.loads(resp.data.decode("utf-8"))
|
||||
assert resp.status_code == 200
|
||||
assert isinstance(data["Blocks"], list)
|
||||
|
||||
|
||||
@mock_textract
|
||||
def test_textract_start_text_detection_without_document_location():
|
||||
backend = server.create_backend_app("textract")
|
||||
|
@ -84,3 +84,18 @@ def test_get_document_text_detection_without_document_location():
|
||||
'Parameter validation failed:\nMissing required parameter in input: "DocumentLocation"'
|
||||
in e.value.args
|
||||
)
|
||||
|
||||
|
||||
@mock_textract
|
||||
def test_detect_document_text():
|
||||
client = boto3.client("textract", region_name="us-east-1")
|
||||
result = client.detect_document_text(
|
||||
Document={
|
||||
"S3Object": {
|
||||
"Bucket": "bucket",
|
||||
"Name": "name.jpg",
|
||||
}
|
||||
}
|
||||
)
|
||||
assert isinstance(result["Blocks"], list)
|
||||
assert result["DetectDocumentTextModelVersion"] == "1.0"
|
||||
|
Loading…
Reference in New Issue
Block a user