2
votes

Is it possible to send image byte through Lambda using Boto3? The byte will be sent to Lambda function which will then forward the image to Rekognition. I've tried this but it didn't work:

with open(image_name) as image_source:
    image_bytes = image_source.read()

context = base64.b64encode(b'{"custom":{ \
    "image_name":"'+imagename+'", \
    "image_bytes" : "'+image_bytes+'"}}').decode('utf-8')

response = lambda_fn.invoke(
    ClientContext=context,
    FunctionName='recognize-face-in-image'
)

And this is the Lambda function code:

import boto3  
import base64  
import json  

def lambda_handler(event, context):
 print("Lambda triggered...")
 rek = boto3.client('rekognition')

 context_dict = context.client_context.custom
 image_bytes = context_dict["image_bytes"]
 rekresp = rek.detect_faces(Image={'Bytes': image_bytes},Attributes=['ALL'])
 if not rekresp['FaceDetails']:
     print "No face"
 else:
     print "Got face"  

When I run it, this is the Lambda function error shown in Cloudwatch:

An error occurred (ValidationException) when calling the DetectFaces operation: 1 validation error detected: Value 'java.nio.HeapByteBuffer[pos=0 lim=0 cap=0]' at 'image.bytes' failed to satisfy constraint: Member must have length greater than or equal to 1: ClientError Traceback (most recent call last): File "/var/task/lambda_function.py", line 17, in lambda_handler rekresp = rek.detect_faces(Image={'Bytes': image_bytes},Attributes=['ALL']) File "/var/runtime/botocore/client.py", line 314, in _api_call return self._make_api_call(operation_name, kwargs) File "/var/runtime/botocore/client.py", line 612, in _make_api_call raise error_class(parsed_response, operation_name) ClientError: An error occurred (ValidationException) when calling the DetectFaces operation: 1 validation error detected: Value 'java.nio.HeapByteBuffer[pos=0 lim=0 cap=0]' at 'image.bytes' failed to satisfy constraint: Member must have length greater than or equal to 1

2

2 Answers

1
votes

ClientContext isn't the right way to send bulk data to Lambda function. Instead, Payload should be used.

Additionally, the image is going to be binary data, which needs to be opened in rb mode and can't be carried in JSON.

import base64
import json
import boto3

with open(image_name, 'rb') as image_source:
    image_bytes = image_source.read()

response = boto3.client('lambda').invoke(
    FunctionName='recognize-face-in-image',
    Payload=json.dumps({
        'image_name': image_name,
        'image_bytes': base64.b85encode(image_bytes).decode('utf-8'),
    }),
)

And the Lambda function should look something like this:

import base64

def handler(event, context):
    image_bytes = base64.b85decode(event['image_bytes'])
    ...
0
votes

From Lambda.invoke() doesn't send client context · Issue #1388 · aws/aws-sdk-js:

var ctx = {
    custom: { foo: 'bar' },
    client: { snap: ['crackle', 'pop']},
    env: { fizz: 'buzz' },
};
la.invoke({
    FunctionName: 'contextPrinter',
    ClientContext: AWS.util.base64.encode(JSON.stringify(ctx)),
    InvocationType: 'RequestResponse',
    Payload: JSON.stringify({ baz: 'quux' })
}, function (err, data) { return console.log(err, data); });

While this is JavaScript rather than Python, it should give a general idea of how to encode context.