211142 (3) [Avatar] Offline
#1
I downloaded the faceDetection-js.zip file from the book. Then I modified dstBucket and outputDomain appropriately and uploaded the new zip to AWS Lambda. Finally I added a policy to allow PUTting S3 objects in my bucket and connected the policy to a Lambda rule for my faceDetection function.

I ran:
aws lambda invoke --function-name faceDetection --payload '{"imageUrl":"http://weknowyourdreams.com/images/people/people-06.jpg"}' output.txt

I got this result:
{
    "FunctionError": "Unhandled", 
    "StatusCode": 200
}

This was in the output.txt file:
{
  "errorMessage": "Cannot find module '/var/task/node_modules/opencv/build/opencv/v5.0.0/Release/node-v46-linux-x64/opencv.node'",
  "errorType": "Error",
  "stackTrace": [
    "Function.Module._load (module.js:276:25)",
    "Module.require (module.js:353:17)",
    "require (internal/module.js:12:17)",
    "Object.<anonymous> (/var/task/node_modules/opencv/lib/bindings.js:4:15)",
    "Module._compile (module.js:409:26)",
    "Object.Module._extensions..js (module.js:416:10)",
    "Module.load (module.js:343:32)",
    "Function.Module._load (module.js:300:12)",
    "Module.require (module.js:353:17)"
  ]
}


There isn't a node-v46-linux-x64/opencv.node file in node_modules. Instead there's a node-v11-linux-x64/opencv.node file. How I can get this to work?
211142 (3) [Avatar] Offline
#2
Changing {node_abi} to node-v11 in package.json's binary:module_path value led to this error:
{
  "errorMessage": "Module did not self-register.",
  "errorType": "Error",
  "stackTrace": [
    "Object.Module._extensions..node (module.js:434:18)",
    "Module.load (module.js:343:32)",
    "Function.Module._load (module.js:300:12)",
    "Module.require (module.js:353:17)",
    "require (internal/module.js:12:17)",
    "Object.<anonymous> (/var/task/node_modules/opencv/lib/bindings.js:4:15)",
    "Module._compile (module.js:409:26)",
    "Object.Module._extensions..js (module.js:416:10)",
    "Module.load (module.js:343:32)"
  ]
}
211142 (3) [Avatar] Offline
#3
Anybody else able to get opencv to work?
475381 (1) [Avatar] Offline
#4
Hi, I have same problem.Beside that the book in this exercise is not well described, but i get:

"errorMessage": "Cannot find module '/var/task/node_modules/opencv/build/opencv/v5.0.0/Release/node-v48-linux-x64/opencv.node'"

any hints?
481543 (1) [Avatar] Offline
#5
I had the same problem. It looks like the opencv that was delivered with the node.js is not right (not sure why) because the directly that the log is complaining about doesn't exist. I uploaded the python version. I had to change the invoke method for python and I was able to get this to work.
512702 (1) [Avatar] Offline
#6
I had the same problems with opencv face-detection example for nodejs.

I tried the faceDetection several hours before I understood, that I have to compile the opencv for the node-version I selected in lambda (6.10).
And than use that binaries for the lambda package to get the face detection running in lambda.

I googled around and sampled steps mainly from two pages and the book itself to get it running.
Hope posting my steps help you.

WARNING:
If you are not experienced in setting up and using a AWS EC2 Linux instance and Linux (via ssh/commandline/scp/zip ...), the description of my steps will not help you.

What I did:
1. Start a new AWS EC2 instance from the Amazon Linux-Image.
2. Connect to this instance via ssh.
3. Install the nvm ( node version manager)
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.0/install.sh | bash
. ~/.nvm/nvm.sh

4. Install the node Version I selected in the lambda-Function (6.10)
nvm install 6.10
5. Install the compiler and tools
sudo yum update -y
sudo yum install –y gcc44 gcc-c++ libgcc44 cmake

6. make a Directory for compiling opencv and changed to it
mkdir compile_opencv && cd compile_opencv
7. Download opencv version 2.4. linux unix-source-code
wget https://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.4.11/opencv-2.4.11.zip/download -O opencv-2.4.11.zip

8. make folder for the source files
mkdir opencv-source
9. change to soure folder
cd opencv-source
10. unzip opencv-zip to souce-folder
unzip ../opencv-2.4.11.zip
11. prepare compiling
cmake -D CMAKE_BUILD_TYPE=RELEASE -D BUILD_SHARED_LIBS=NO -D CMAKE_INSTALL_PREFIX=~/opencv opencv-2.4.11/
12. compile and install opencv locally (takes a while or long depending on your ec2 instance)
make && make install
13. correct the library parameters for the image-formats (as explained in the book) in the file:
~/opencv/lib/pkgconfig/opencv.pc
change:
-ljasper -ltiff -lpng -ljpeg
to:
-llibjasper -llibtiff -llibpng -llibjpeg
14. make a node project folder
cd ~
mkdir opencv_lambda_template

15. install opencv in the project folder
PKG_CONFIG_PATH=~/opencv/lib/pkgconfig/ npm install --prefix=~/opencv_lambda_template opencv

16. (optional) test opencv in project folder (copied from step 6: https://aws.amazon.com/de/blogs/compute/nodejs-packages-in-lambda/)

cd ~/opencv_lambda_template
cd node_modules/opencv/examples/
mkdir tmp
node face-detection.js # Image saved to ./tmp/face-detection.png
ls tmp # face-detection.png
rm -r tmp



You may then zip the project folder and copy (scp ...) the zip to your local machine.
There you can extract and use it as template for the project. You fill with your code file and install the appropriate packages.

Or you may edit the project on the ec2 instance.
Finally you zip it and push it to S3 (you have to install the needed credentials on the ec2 instance if you do it from there).

From S3 you can load the zip to lambda.

Pages that helped me beside the book itself:
http://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html
https://aws.amazon.com/de/blogs/compute/nodejs-packages-in-lambda/


Hope that helps

Maslek
DeMoehn (10) [Avatar] Offline
#7
Thanks for the detailed introductions.
I had the same problems with Node.js as you guys.

As it is a but cumbersome to create an EC2 instance, build the opencv library, install all the needed npms, etc. I have the opencv and the finished node.js lambda application hosted on my S3 if anyone is intertested, feel free:

- OpenCV: https://s3.eu-central-1.amazonaws.com/demoehn-public/opencv.zip
- App: https://s3.eu-central-1.amazonaws.com/demoehn-public/ImageAppFaceDetection-v1.0.zip

504344 (14) [Avatar] Offline
#8
Thanks for sharing unfortunately I am not able to solve it with your provided files. What I have done:

1) downloaded app provided by DeMoehn

2) unzipped file

3) modified index.js to include my buckets (input and output to same xx-faces)

4) deleted package.json and output.txt

5) zipped index + node_modules

6) created new policy and role for face detection same like in previous example (thumbs) - read and put in S3 bucket

7) created lambda function with S3 trigger

smilie checked logs and here we are

Unable to import module 'index': Error
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)


Seems for me index is not liked but I do not get why

@DeMoehn maybe you can help out. Some insights are really appreciated.
DeMoehn (10) [Avatar] Offline
#9
Hmm...
I just did the same as you

- Downloaded my Code
- unpacked
- Deleted packe.json and output.txt
- Opened the index.js file (didn't change the bucket)
- Zipped everything
- Uploaded it again

Worked out great for me...

Did you somehow forget to add the index.js to the .zip file, is index.js not in the root directory or maybe somehow currupt?
504344 (14) [Avatar] Offline
#10
You were right I had mixed up zipping process shame on me. Now at least I have some errors.



2018-01-04T10:41:05.847Z 9f085fb5-f13b-11e7-a561-573ee1a9c4a8 Error: options.uri is a required argument
at Request.init (/var/task/node_modules/request/request.js:232:31)
at new Request (/var/task/node_modules/request/request.js:128:8)
at request (/var/task/node_modules/request/index.js:53:10)
at /var/task/node_modules/request/index.js:61:12
at Function.get (/var/task/node_modules/request/index.js:100:12)
at exports.handler (/var/task/index.js:23:11)
2018-01-04T10:41:05.964Z 9f085fb5-f13b-11e7-a561-573ee1a9c4a8
{
    "errorMessage": "options.uri is a required argument",
    "errorType": "Error",
    "stackTrace": [
        "Request.init (/var/task/node_modules/request/request.js:232:31)",
        "new Request (/var/task/node_modules/request/request.js:128:8)",
        "request (/var/task/node_modules/request/index.js:53:10)",
        "/var/task/node_modules/request/index.js:61:12",
        "Function.get (/var/task/node_modules/request/index.js:100:12)",
        "exports.handler (/var/task/index.js:23:11)"
    ]
}
OpenCV Error: Bad flag (parameter or structure field) (Unrecognized or unsupported array type) in cvGetMat, file /home/ec2-user/compile_opencv/opencv-source/opencv-2.4.11/modules/core/src/array.cpp, line 2482
...
DeMoehn (10) [Avatar] Offline
#11
Are you using Node 6.10? Or 4.3?
504344 (14) [Avatar] Offline
#12
6.10
DeMoehn (10) [Avatar] Offline
#13
Seems like there is a problem with the original image URL.
Where is it stored?
Is it public accessible?
504344 (14) [Avatar] Offline
#14
I rechecked by uploading a new one, bucket and image permissions are set to public.

Storage in S3 same folder like output jr-faces.
DeMoehn (10) [Avatar] Offline
#15
I see, just try using a public Picture you found on Google or something like this with public URL, not AWS
504344 (14) [Avatar] Offline
#16
thx for help, i will try later
150034 (6) [Avatar] Offline
#17
AWS Lambda recently released support for Node 8.10.0, which for the first time means Lambda supports async/await, so I wanted to see if I could modify this project to utilize the latest available versions of Node and OpenCV as of April 2018.

I was able to get the last release on the OpenCV 2.x line to work, which is (as I write) version 2.4.13.6, but I was unable to get the latest 3.x release to work with Node.

Here are reproducible steps to build a binary OpenCV Node module from 2.4.13.6 under Node 8.10.0:

1. Spin up an Amazon Linux EC2 instance (ami-1853ac65), bring it up to date, install build tools, and reboot into the updated kernel:
$ sudo yum update -y
$ sudo yum install -y gcc gcc-c++ libgcc cmake
$ sudo reboot


2. Install NVM and use it to install Node 8.10.0
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.9/install.sh | bash
[... relog to get nvm env...]
$ nvm install 8.10.0


3. Download and build OpenCV 2.4.13.6
$ cd
$ curl -L -O https://github.com/opencv/opencv/archive/2.4.13.6.zip
$ mkdir opencv-build
$ unzip 2.4.13.6.zip -d opencv-build/
$ cd opencv-build/
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D BUILD_SHARED_LIBS=NO -D CMAKE_INSTALL_PREFIX=~/opencv opencv-2.4.13.6/
$ make && make install


4. The problems in the file ~/opencv/lib/pkgconfig/opencv.pc from version 2.4.11 has been fixed, however in between 2.4.11 and 2.4.13.6 another problem was introduced.

Edit the file ~/opencv/lib/pkgconfig/opencv.pc and in the Libs: line, insert the flag (anywhere in the line):
-L${exec_prefix}/share/OpenCV/3rdparty/lib

That is, the line should ultimately read like this:
Libs: -L${exec_prefix}/share/OpenCV/3rdparty/lib -L${exec_prefix}/lib -lopencv_contrib -lopencv_stitching -lopencv_nonfree -lopencv_superres -lopencv_ocl -lopencv_ts -lopencv_videostab -lopencv_gpu -lopencv_photo -lopencv_objdetect -lopencv_legacy -lopencv_video -lopencv_ml -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lIlmImf -llibjasper -llibtiff -llibpng -llibjpeg -lopencv_imgproc -lopencv_flann -lopencv_core -lzlib -lrt -lpthread -lm -ldl -lstdc++


5. Build the binary node module, installing it in the package root of your Lambda function, which I named faceDetection to match the name of the Lambda:
$ cd
$ mkdir ~/faceDetection
$ PKG_CONFIG_PATH=~/opencv/lib/pkgconfig/ npm install --prefix=~/faceDetection/ opencv


6. Test the module:
$ cd ~/faceDetection/node_modules/opencv/examples
$ mkdir tmp
$ node face-detection
Image saved to ./tmp/face-detection.png


Have a look at that ./tmp/face-detection.png to see that it's working.

Copy the book's index.js to that package root, edit it with your S3 bucket information, install the other required Node packages (util, request, node-uuid), ZIP it up and it should work as your Lambda function using Node 8.10.0.

Since the whole point of this exercise was to take advantage of the features of Node 8.10.0, I rewrote the handler function to use promises with async/await, which I've copied below.

'use strict';

const cv = require('opencv');
const util = require('util');
const request = require('request').defaults({encoding: null});

const uuid = require('node-uuid');
const AWS = require('aws-sdk');

const s3 = new AWS.S3();

const dstBucket = 'YOUR-BUCKET';
const dstPrefix = 'tmp/';
const outputDomain = 'YOUR-BUCKET.s3.amazonaws.com';

function getFormattedDate() {
  const now = new Date().toISOString(); // YYYY-MM-DDTHH:mm:ss.sssZ
  const formattedNow = `${now.substr(0, 4)}${now.substr(5, 2)}${now.substr(8, 2)}${now.substr(11, 2)}${now.substr(14, 2)}${now.substr(17, 2)}`;
  return formattedNow;
}

exports.handler = async event => {
  console.log('Reading options from event:\n', util.inspect(event, {depth: 5}));

  const {imageUrl} = event;

  const body = await new Promise((resolve, reject) => {
    request.get(imageUrl, (error, _, body) => error ? reject(error) : resolve(body));
  });

  const image = await new Promise((resolve, reject) => {
    cv.readImage(body, (error, image) => error ? reject(error) : resolve(image));
  });

  if (image.width() < 1 || image.height() < 1) {
    throw new Error('Image has no size');
  }

  const faces = await new Promise((resolve, reject) => {
    image.detectObject('node_modules/opencv/data/haarcascade_frontalface_alt.xml', {}, (error, faces) => {
      return error ? reject(error) : resolve(faces);
    });
  });

  if (faces.length === 0) {
    return {
      faces: 0,
      outputURL: imageUrl,
    };
  }

  for (const face of faces) {
    image.rectangle([face.x, face.y], [face.width, face.height], [255, 255, 255], 2);
  }

  const dstKey = dstPrefix + getFormattedDate() + '-' + uuid.v4() + '.jpg';
  const contentType = 'image/jpeg';

  await s3.putObject({
    Bucket: dstBucket,
    Key: dstKey,
    Body: image.toBuffer(),
    ContentType: contentType,
  }).promise();

  return {
    faces: faces.length,
    outputURL: `https://${outputDomain}/${dstKey}`,
  };
};