Comparar commits
162 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| e3b20082ab | |||
| fbb030e571 | |||
| 1c96622c67 | |||
| 77a6d19c3b | |||
| e00f24b3e4 | |||
| d75f437b73 | |||
| a6d6be2d7d | |||
| 52e03bb7f3 | |||
| 9e0367e9f9 | |||
| 22c86364c7 | |||
| 5a3cc35d25 | |||
| 73c47177e2 | |||
| fc518a1459 | |||
| db3322ebcd | |||
| c7ae7140ea | |||
| 1d9072aefb | |||
| 6f9f38112b | |||
| f66364f1bb | |||
| 0d53c15058 | |||
| bbf36e72b1 | |||
| b79c30069f | |||
| fddd01a3d1 | |||
| dd5961cfe2 | |||
| 2c5324df41 | |||
| 0520e6dcea | |||
| 612d0f1c21 | |||
| 65d9e3ea99 | |||
| 824ffceeb2 | |||
| 5daf9c0f4d | |||
| 187b6d073a | |||
| 146925ee6d | |||
| e7300b1cfc | |||
| e0c4d42503 | |||
| b2ed603a2a | |||
| 3105e14f25 | |||
| 276e42bffc | |||
| ce742ecce2 | |||
| 6bdaa3a24f | |||
| cceea7b498 | |||
| d60e3d11d5 | |||
| 363b950f1e | |||
| 813e5ee55f | |||
| 852de17b47 | |||
| a190298eaf | |||
| 4ce14beb96 | |||
| b8ec62e5f8 | |||
| 03a00c062f | |||
| d9f0b16f16 | |||
| 7ea1435491 | |||
| 13488fa94b | |||
| 85e1ce2448 | |||
| 3b4c361f5c | |||
| 5eb7e836c3 | |||
| abb20798c3 | |||
| 7548d39616 | |||
| 762ac42f3b | |||
| 45846cd3b2 | |||
| 27f722e6aa | |||
| 1e5a0f2a23 | |||
| 4cc5eff25b | |||
| ca87972037 | |||
| bae7a1bfd9 | |||
| c93cfb782b | |||
| bce9d95c29 | |||
| 25bec10b28 | |||
| f5df8f6599 | |||
| f6ff1e58b5 | |||
| e507377a80 | |||
| aa7b3317fe | |||
| 769d6ebf77 | |||
| 21917f3f17 | |||
| 7b3835bbf5 | |||
| c3d1379cd5 | |||
| c4a20bb279 | |||
| cca52ad691 | |||
| 67abbf4c24 | |||
| d364f64b84 | |||
| 440a72c38e | |||
| 865962c845 | |||
| a347ab682e | |||
| f1d629bfb3 | |||
| 507ecbf832 | |||
| f0461db126 | |||
| 3c6028e0e3 | |||
| 95b2585838 | |||
| 289c519362 | |||
| 1d542bc056 | |||
| 76f3847321 | |||
| 8e55b380cd | |||
| 0efbd11d0c | |||
| b8ce5d0def | |||
| 053a693c9a | |||
| 64f933f2a9 | |||
| b17fceca72 | |||
| e5be89c813 | |||
| fd25b58e43 | |||
| ebd1f6e4e8 | |||
| e88d2d6b8a | |||
| daca1a14cb | |||
| 11db468dcf | |||
| 55cbf0a37f | |||
| 77279a33c0 | |||
| 6225a3c0f0 | |||
| f2ec2cd3ed | |||
| c3d3f0f4b4 | |||
| 0840e0b2e2 | |||
| 4ca165635e | |||
| a8e5ac4b6b | |||
| 24f255a161 | |||
| 0bb7fe9918 | |||
| 0cb436e930 | |||
| 3a7469fe52 | |||
| e1e1267bc3 | |||
| 32a1b76852 | |||
| a320ff9af0 | |||
| 521139a76e | |||
| 454fd1188a | |||
| 0de039956e | |||
| bb1fa037f3 | |||
| 84e5f255df | |||
| 4f7968e567 | |||
| a197586673 | |||
| e64b558bbd | |||
| c057d411a5 | |||
| fb55cec501 | |||
| be92fe5e65 | |||
| 642f111f9d | |||
| 8d6180bcaf | |||
| 63891ae4fa | |||
| 22bdf646b1 | |||
| 3b3c591517 | |||
| abf5e9948c | |||
| d2e8b1969f | |||
| e3280ddc1e | |||
| a94bc32d5f | |||
| 7be98efacf | |||
| b73ccb67fa | |||
| 3efe469ea0 | |||
| 8b899d073a | |||
| 2d0e747a4d | |||
| 644f6797d3 | |||
| f90cea5ffd | |||
| 4f56834420 | |||
| ab686c5445 | |||
| dcf7462b13 | |||
| 7d43360b72 | |||
| 20fa7a1c51 | |||
| 0ab26f913c | |||
| c4aac1d201 | |||
| 6df8bbbb9b | |||
| 33146b15e0 | |||
| c50cdf35a4 | |||
| fa6e6b4da1 | |||
| b6468cff4e | |||
| e33afd97ef | |||
| a9717c7dc0 | |||
| b5fe027703 | |||
| 3a1477c527 | |||
| e4c0ddd4e4 | |||
| d71b0ae7b3 | |||
| ac6c685b56 | |||
| 56fd1824d3 |
@@ -3,4 +3,6 @@ build
|
||||
.DS_Store
|
||||
node_modules
|
||||
npm-debug.log
|
||||
out.jpg
|
||||
out*.jpg
|
||||
out*.png
|
||||
examples/*.avi
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
- "0.6"
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install libcv-dev
|
||||
- sudo apt-get install libopencv-dev
|
||||
- sudo apt-get install libhighgui-dev
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# This file describes how to build node-opencv into a runnable linux container with all dependencies installed
|
||||
# To build:
|
||||
# 1) Install docker (http://docker.io)
|
||||
# 2) Build: wget https://raw.github.com/dotcloud/docker/v0.1.6/contrib/docker-build/docker-build && python docker-build $USER/node-opencv < Dockerfile
|
||||
# 3) Test: docker run $USER/node-opencv node -e "console.log(require('opencv').version)"
|
||||
#
|
||||
# VERSION 0.1
|
||||
# DOCKER-VERSION 0.1.6
|
||||
|
||||
from ubuntu:12.04
|
||||
run echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
run apt-get install -q -y libcv-dev
|
||||
run apt-get install -q -y libopencv-dev
|
||||
run apt-get install -q -y libhighgui-dev
|
||||
run apt-get install wget
|
||||
run wget -O - http://nodejs.org/dist/v0.8.23/node-v0.8.23-linux-x64.tar.gz | tar -C /usr/local/ --strip-components=1 -zxv
|
||||
run npm install opencv
|
||||
@@ -13,31 +13,31 @@ You'll need OpenCV 2.3.1 installed.
|
||||
|
||||
Then:
|
||||
|
||||
|
||||
npm install opencv
|
||||
|
||||
```bash
|
||||
$ npm install opencv
|
||||
```
|
||||
|
||||
Or to build the repo:
|
||||
|
||||
|
||||
node-gyp rebuild
|
||||
|
||||
```bash
|
||||
$ node-gyp rebuild
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Face Detection
|
||||
|
||||
|
||||
cv.readImage("./examples/test.jpg", function(err, im){
|
||||
im.detectObject("./data/haarcascade_frontalface_alt.xml", {}, function(err, faces){
|
||||
for (var i=0;i<faces.length; i++){
|
||||
var x = faces[i]
|
||||
im.ellipse(x.x + x.width/2, x.y + x.height/2, x.width/2, x.height/2);
|
||||
}
|
||||
im.save('./out.jpg');
|
||||
});
|
||||
})
|
||||
|
||||
```javascript
|
||||
cv.readImage("./examples/test.jpg", function(err, im){
|
||||
im.detectObject(cv.FACE_CASCADE, {}, function(err, faces){
|
||||
for (var i=0;i<faces.length; i++){
|
||||
var x = faces[i]
|
||||
im.ellipse(x.x + x.width/2, x.y + x.height/2, x.width/2, x.height/2);
|
||||
}
|
||||
im.save('./out.jpg');
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
## API Documentation
|
||||
@@ -49,60 +49,95 @@ base datastructure in OpenCV. Things like images are just matrices of pixels.
|
||||
|
||||
#### Creation
|
||||
|
||||
new Matrix(width, height)
|
||||
```javascript
|
||||
new Matrix(rows, cols)
|
||||
```
|
||||
|
||||
Or if you're thinking of a Matrix as an image:
|
||||
|
||||
```javascript
|
||||
new Matrix(height, width)
|
||||
```
|
||||
|
||||
Or you can use opencv to read in image files. Supported formats are in the OpenCV docs, but jpgs etc are supported.
|
||||
|
||||
cv.readImage(filename, function(mat){
|
||||
...
|
||||
})
|
||||
```javascript
|
||||
cv.readImage(filename, function(mat){
|
||||
...
|
||||
})
|
||||
|
||||
cv.readImage(buffer, function(mat){
|
||||
...
|
||||
})
|
||||
cv.readImage(buffer, function(mat){
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
If you need to pipe data into an image, you can use an imagestream:
|
||||
If you need to pipe data into an image, you can use an ImageDataStream:
|
||||
|
||||
var s = new cv.ImageStream()
|
||||
```javascript
|
||||
var s = new cv.ImageDataStream()
|
||||
|
||||
s.on('load', function(matrix){
|
||||
...
|
||||
})
|
||||
|
||||
fs.createReadStream('./examples/test.jpg').pipe(s);
|
||||
```
|
||||
|
||||
If however, you have a series of images, and you wish to stream them into a
|
||||
stream of Matrices, you can use an ImageStream. Thus:
|
||||
|
||||
```javascript
|
||||
var s = new cv.ImageStream()
|
||||
|
||||
s.on('data', function(matrix){
|
||||
...
|
||||
})
|
||||
|
||||
ardrone.createPngStream().pipe(s);
|
||||
```
|
||||
|
||||
Note: Each 'data' event into the ImageStream should be a complete image buffer.
|
||||
|
||||
s.on('load', function(matrix){
|
||||
...
|
||||
})
|
||||
|
||||
fs.createReadStream('./examples/test.jpg').pipe(s);
|
||||
|
||||
#### Accessing Data
|
||||
|
||||
var mat = new cv.Matrix.Eye(4,4); // Create identity matrix
|
||||
```javascript
|
||||
var mat = new cv.Matrix.Eye(4,4); // Create identity matrix
|
||||
|
||||
mat.get(0,0) // 1
|
||||
|
||||
mat.row(0) // [1,0,0,0]
|
||||
mat.col(4) // [0,0,0,1]
|
||||
mat.get(0,0) // 1
|
||||
|
||||
mat.row(0) // [1,0,0,0]
|
||||
mat.col(4) // [0,0,0,1]
|
||||
```
|
||||
|
||||
##### Save
|
||||
|
||||
mat.save('./pic.jpg')
|
||||
```javascript
|
||||
mat.save('./pic.jpg')
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
var buff = mat.toBuffer()
|
||||
|
||||
```javascript
|
||||
var buff = mat.toBuffer()
|
||||
```
|
||||
|
||||
#### Image Processing
|
||||
|
||||
im.convertGrayscale()
|
||||
im.canny(5, 300)
|
||||
im.houghLinesP()
|
||||
|
||||
```javascript
|
||||
im.convertGrayscale()
|
||||
im.canny(5, 300)
|
||||
im.houghLinesP()
|
||||
```
|
||||
|
||||
|
||||
#### Simple Drawing
|
||||
|
||||
im.ellipse(x, y)
|
||||
im.line([x1,y1], [x2, y2])
|
||||
|
||||
```javascript
|
||||
im.ellipse(x, y)
|
||||
im.line([x1,y1], [x2, y2])
|
||||
```
|
||||
|
||||
#### Object Detection
|
||||
|
||||
@@ -110,22 +145,98 @@ There is a shortcut method for
|
||||
[Viola-Jones Haar Cascade](http://www.cognotics.com/opencv/servo_2007_series/part_2/sidebar.html) object
|
||||
detection. This can be used for face detection etc.
|
||||
|
||||
```javascript
|
||||
mat.detectObject(haar_cascade_xml, opts, function(err, matches){})
|
||||
```
|
||||
|
||||
mat.detectObject(haar_cascade_xml, opts, function(err, matches){})
|
||||
|
||||
For convenience in face recognition, cv.FACE_CASCADE is a cascade that can be used for frontal face recognition.
|
||||
|
||||
Also:
|
||||
|
||||
mat.goodFeaturesToTrack
|
||||
|
||||
```javascript
|
||||
mat.goodFeaturesToTrack
|
||||
```
|
||||
|
||||
#### Contours
|
||||
|
||||
mat.findCountours
|
||||
mat.drawContour
|
||||
mat.drawAllContours
|
||||
```javascript
|
||||
mat.findCountours
|
||||
mat.drawContour
|
||||
mat.drawAllContours
|
||||
```
|
||||
|
||||
### Using Contours
|
||||
|
||||
`findContours` returns a `Contours` collection object, not a native array. This object provides
|
||||
functions for accessing, computing with, and altering the contours contained in it.
|
||||
See [relevant source code](src/Contours.cc) and [examples](examples/)
|
||||
|
||||
```javascript
|
||||
var contours = im.findContours;
|
||||
|
||||
# Count of contours in the Contours object
|
||||
contours.size();
|
||||
|
||||
# Count of corners(verticies) of contour `index`
|
||||
contours.cornerCount(index);
|
||||
|
||||
# Access vertex data of contours
|
||||
for(var c = 0; c < contours.size(); ++c) {
|
||||
console.log("Contour " + c);
|
||||
for(var i = 0; i < contours.cornerCount(c); ++i) {
|
||||
var point = contours.point(c, i);
|
||||
console.log("(" + point.x + "," + point.y + ")");"
|
||||
}
|
||||
}
|
||||
|
||||
# Computations of contour `index`
|
||||
contours.area(index);
|
||||
contours.arcLength(index, isClosed);
|
||||
contours.boundingRect(index);
|
||||
contours.minAreaRect(index);
|
||||
contours.isConvex(index);
|
||||
|
||||
# Destructively alter contour `index`
|
||||
contours.approxPolyDP(index, epsilon, isClosed);
|
||||
contours.convexHull(index, clockwise);
|
||||
```
|
||||
|
||||
## MIT License
|
||||
The library is distributed under the MIT License - if for some reason that
|
||||
doesn't work for you please get in touch.
|
||||
|
||||
## Changelog
|
||||
|
||||
#### 0.0.13
|
||||
|
||||
- V Early support for face recognition - API is _likely_ to change. Have fun!
|
||||
- *API Change*: VideoCapture.read now calls callback(err, im) instead of callback(im)
|
||||
|
||||
#### 0.0.12
|
||||
- Matrix clone()
|
||||
- NamedWindow Support
|
||||
|
||||
#### 0.0.11
|
||||
|
||||
- Bug Fixes
|
||||
- ImageStream becomes ImageDataStream, and new ImageStream allows multiple images to be
|
||||
streamed as matrices, for example, with an object detection stream.
|
||||
- @ryansouza improved documentation
|
||||
- Correcting matrix constructor (thanks @gluxon)
|
||||
- @Michael Smith expanded Contours functionality.
|
||||
|
||||
Thanks all!
|
||||
|
||||
#### 0.0.10
|
||||
|
||||
- Bug Fixes
|
||||
- @Contra added code that allows thickness and color args for ellipse
|
||||
- Camshift Support
|
||||
- @jtlebi added bindings for erode, gaussianBlur, arcLength, approxPolyDP, isConvex, cornerCount
|
||||
- @gluxon added bindings for inRange
|
||||
|
||||
Thanks everyone!
|
||||
|
||||
#### 0.0.9
|
||||
|
||||
- toBuffer can now take a callback and be run async (re #21)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
im.calcHistograms(function(err, hist){})
|
||||
|
||||
im.calcHistograms(mask, function(err, hist){})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Face recognition TODO
|
||||
|
||||
|
||||
// Load Database
|
||||
// TODO<
|
||||
|
||||
|
||||
|
||||
cv.loadImage('test.jpg', function(err, im){
|
||||
im.detectObject("front-face.xml", {}, function(err, faces){
|
||||
_.each(faces, function(v){
|
||||
|
||||
// TODO {
|
||||
|
||||
var section = im.slice(v.x, v.y, v.x + v.width, v.y + v.height);
|
||||
section.convertGrayscale()
|
||||
section.resize(WID, HEIGHT);
|
||||
section.equaliseHistogram();
|
||||
|
||||
// } TODO
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----
|
||||
|
||||
|
||||
http://www.athile.net/library/wiki/index.php?title=Library/V8/Tutorial#Wrapping_a_Javascript_function_as_a_std::function.3C.3E
|
||||
|
||||
https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/
|
||||
@@ -9,12 +9,21 @@
|
||||
, "src/Contours.cc"
|
||||
, "src/Point.cc"
|
||||
, "src/VideoCaptureWrap.cc"
|
||||
, "src/CamShift.cc"
|
||||
, "src/HighGUI.cc"
|
||||
, "src/FaceRecognizer.cc"
|
||||
]
|
||||
, 'libraries': [
|
||||
'<!@(pkg-config --libs opencv)'
|
||||
]
|
||||
|
||||
# For windows
|
||||
,'include_dirs': [
|
||||
'<!@(pkg-config --cflags opencv)'
|
||||
]
|
||||
|
||||
, 'cflags': [
|
||||
'<!@(pkg-config --cflags --libs opencv)'
|
||||
'<!@(pkg-config --cflags "opencv >= 2.3.1" )'
|
||||
, '-Wall'
|
||||
]
|
||||
, 'cflags!' : [ '-fno-exceptions']
|
||||
@@ -24,6 +33,9 @@
|
||||
# cflags on OS X are stupid and have to be defined like this
|
||||
'xcode_settings': {
|
||||
'OTHER_CFLAGS': [
|
||||
"-mmacosx-version-min=10.7",
|
||||
"-std=c++11",
|
||||
"-stdlib=libc++",
|
||||
'<!@(pkg-config --cflags opencv)'
|
||||
]
|
||||
, "GCC_ENABLE_CPP_RTTI": "YES"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
node-gyp rebuild &&
|
||||
cd examples &&
|
||||
#node face_detection.js
|
||||
node $1
|
||||
@@ -5,7 +5,7 @@ var camera = new cv.VideoCapture(0);
|
||||
|
||||
setInterval(function() {
|
||||
|
||||
camera.read(function(im) {
|
||||
camera.read(function(err, im) {
|
||||
|
||||
im.save('/tmp/cam.png');
|
||||
});
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
cv = require 'opencv'
|
||||
|
||||
# we create a function helper to display the images.
|
||||
displayImage = (windowName, img) ->
|
||||
namedWindow = new cv.NamedWindow(windowName)
|
||||
namedWindow.show(img)
|
||||
namedWindow.blockingWaitKey(0, 5000)
|
||||
|
||||
# Load both sources to be blended
|
||||
cv.readImage("./images/windows-logo.png", (err, src1) ->
|
||||
|
||||
# Display Source 1
|
||||
displayImage('Source 1', src1)
|
||||
|
||||
# Load source #2
|
||||
cv.readImage("./images/linux-logo.png", (err, src2) ->
|
||||
|
||||
# Display Source 2
|
||||
displayImage('Source 2', src2)
|
||||
|
||||
# We use the addWeighted opencv wrapper to blend the images.
|
||||
# we need to use a different image object, since src1 and src2
|
||||
# will be manipulated.
|
||||
result = new cv.Matrix(src1.width(), src2.height())
|
||||
result.addWeighted(src1, 0.7, src2, 0.9)
|
||||
result.save("./tmp/blended.png")
|
||||
|
||||
# Display Blended result 2
|
||||
displayImage('Blended', result)
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,56 @@
|
||||
cv = require 'opencv'
|
||||
|
||||
# First we create a new VideoCapture object to get
|
||||
# video from the camera (0 for default camera)
|
||||
camera = new cv.VideoCapture(1)
|
||||
|
||||
# we create a window to display the Video frames
|
||||
namedWindow = new cv.NamedWindow('Video', 0)
|
||||
color = [255,0,0]
|
||||
|
||||
frameRead = () ->
|
||||
# camera.read allows us to retrieve the current
|
||||
# frame to be displayed in the video window.
|
||||
camera.read((err, im) ->
|
||||
# We can check for errors and even break the
|
||||
# program execution if an error is detected here.
|
||||
console.log "The err ==>#{ err }" if err
|
||||
|
||||
# There is no need to display the image width or Height
|
||||
# but I leave this here in case anyone needs to check them.
|
||||
#console.log("Width: #{im.width()}")
|
||||
#console.log("height: #{im.height()}")
|
||||
|
||||
# Before working with the frame we need to check the image
|
||||
# is already available and has a width and height greater than 0,
|
||||
# otherwise it will fail when trying to do namedWindow.show()
|
||||
# and the image has width or height equal or less than 0.
|
||||
if im.width() > 0 and im.height() > 0
|
||||
#console.log("Interval ID => #{ intervalId }")
|
||||
#console.log(intervalId)
|
||||
clearInterval(intervalId) if intervalId?
|
||||
im.detectObject('./haarcascades/haarcascade_frontalface_alt.xml', {}, (err, faces) ->
|
||||
for face in faces
|
||||
im.rectangle([face.x, face.y], [face.x + face.width, face.y + face.height], [0,255,0], 2)
|
||||
|
||||
# We use the previously created namedWindow to display the
|
||||
# video frame to wich we applied the blur and filter.
|
||||
namedWindow.show(im)
|
||||
|
||||
# Finally we get the key pressed on the window to terminate
|
||||
# execution of the program.
|
||||
res = namedWindow.blockingWaitKey(0, 20)
|
||||
|
||||
# In this case we terminate the program if any key is pressed.
|
||||
#if res >= 0 then do not set a new timeout to get a new frame.
|
||||
setTimeout(frameRead, 5) if res < 0
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
# We set an interval to retrieve frames from the
|
||||
# video source and we get the intervalId so we can
|
||||
# stop the program by pressing any key on the video feed window.
|
||||
intervalId = setInterval(() ->
|
||||
frameRead(intervalId)
|
||||
, 100)
|
||||
@@ -0,0 +1,49 @@
|
||||
cv = require 'opencv'
|
||||
|
||||
# First we create a new VideoCapture object to get
|
||||
# video from the camera (0 for default camera)
|
||||
camera = new cv.VideoCapture(1)
|
||||
|
||||
# we create a window to display the Video frames
|
||||
namedWindow = new cv.NamedWindow('Video',1)
|
||||
color = [255,0,0]
|
||||
|
||||
# We set an interval to retrieve frames from the
|
||||
# video source and we get the intervalId so we can
|
||||
# stop the program from the video feed window.
|
||||
intervalId = setInterval(()->
|
||||
|
||||
# camera.read allows us to retrieve the current
|
||||
# frame to be displayed in the video window.
|
||||
camera.read((err, im) ->
|
||||
# We can check for errors and even break the
|
||||
# program execution if an error is detected here.
|
||||
console.log "The err ==>#{ err }" if err
|
||||
|
||||
# There is no need to display the image width or Height
|
||||
# but I leave this here in case anyone needs to check them.
|
||||
#console.log("Width: #{im.width()}")
|
||||
#console.log("height: #{im.height()}")
|
||||
|
||||
# Before working with the frame we need to check the image
|
||||
# is already available and has a width and height greater than 0,
|
||||
# otherwise it will fail when trying to do namedWindow.show()
|
||||
# and the image has width or height equal or less than 0.
|
||||
if im.width() > 0 and im.height() > 0
|
||||
im.detectObject('./haarcascades/haarcascade_frontalface_alt.xml', {}, (err, faces) ->
|
||||
for face in faces
|
||||
im.rectangle([face.x, face.y], [face.x + face.width, face.y + face.height], [0,255,0], 2)
|
||||
|
||||
# We use the previously created namedWindow to display the
|
||||
# video frame to wich we applied the blur and filter.
|
||||
namedWindow.show(im)
|
||||
)
|
||||
|
||||
# Finally we get the key pressed on the window to terminate
|
||||
# execution of the program.
|
||||
res = namedWindow.blockingWaitKey(0, 50)
|
||||
|
||||
# In this case I terminate the program if any key is pressed.
|
||||
if res >= 0 then clearInterval(intervalId)
|
||||
)
|
||||
, 150)
|
||||
@@ -0,0 +1,58 @@
|
||||
cv = require 'opencv'
|
||||
|
||||
# First we create a new VideoCapture object to get
|
||||
# video from the camera (0 for default camera)
|
||||
camera = new cv.VideoCapture(1)
|
||||
|
||||
# we create a window to display the Video frames
|
||||
namedWindow = new cv.NamedWindow('Video',1)
|
||||
|
||||
# We set an interval to retrieve frames from the
|
||||
# video source and we get the intervalId so we can
|
||||
# stop the program from the video feed window.
|
||||
intervalId = setInterval(()->
|
||||
|
||||
# camera.read allows us to retrieve the current
|
||||
# frame to be displayed in the video window.
|
||||
camera.read((err, im) ->
|
||||
# We can check for errors and even break the
|
||||
# program execution if an error is detected here.
|
||||
console.log "The err ==>#{ err }" if err
|
||||
|
||||
# There is no need to display the image width or Height
|
||||
# but I leave this here in case anyone needs to check them.
|
||||
#console.log("Width: #{im.width()}")
|
||||
#console.log("height: #{im.height()}")
|
||||
|
||||
# Before working with the frame we need to check the image
|
||||
# is already available and has a width and height greater than 0,
|
||||
# otherwise it will fail when trying to do namedWindow.show()
|
||||
# and the image has width or height equal or less than 0.
|
||||
if im.width() > 0 and im.height() > 0
|
||||
# We apply filters and effects to the frame we got from the
|
||||
# camera to manipulate the video that we'll display.
|
||||
# First we convert to grayscale.
|
||||
im.convertGrayscale()
|
||||
# We then apply GaussianBlur.
|
||||
# It takes an array of type double and size 2
|
||||
# that indicates how strong the gaussian blur should be.
|
||||
im.gaussianBlur([7,7])
|
||||
# We then apply canny edge filtering.
|
||||
# Params are lower and higher threshold and aperture size,
|
||||
# although nodejs-opencv overwrite the aperture size param
|
||||
# with 0. An update to consider it is needed.
|
||||
im.canny(0, 30, 3)
|
||||
|
||||
# We use the previously created namedWindow to display the
|
||||
# video frame to wich we applied the blur and filter.
|
||||
namedWindow.show(im)
|
||||
|
||||
# Finally we get the key pressed on the window to terminate
|
||||
# execution of the program.
|
||||
res = namedWindow.blockingWaitKey(0, 20)
|
||||
console.log("KEYPRESSED => #{ res } ")
|
||||
|
||||
# In this case I terminate the program if any key is pressed.
|
||||
if res >= 0 then clearInterval(intervalId)
|
||||
)
|
||||
, 50)
|
||||
@@ -0,0 +1,57 @@
|
||||
cv = require 'opencv'
|
||||
|
||||
# First we create a new VideoCapture object to get
|
||||
# video from the camera (0 for default camera)
|
||||
camera = new cv.VideoCapture(1)
|
||||
|
||||
# we create a window to display the Video frames
|
||||
namedWindow = new cv.NamedWindow('Video',1)
|
||||
|
||||
# We set an interval to retrieve frames from the
|
||||
# video source and we get the intervalId so we can
|
||||
# stop the program from the video feed window.
|
||||
intervalId = setInterval(()->
|
||||
|
||||
# camera.read allows us to retrieve the current
|
||||
# frame to be displayed in the video window.
|
||||
camera.read((err, im) ->
|
||||
# We can check for errors and even break the
|
||||
# program execution if an error is detected here.
|
||||
console.log "The err ==>#{ err }" if err
|
||||
|
||||
# There is no need to display the image width or Height
|
||||
# but I leave this here in case anyone needs to check them.
|
||||
#console.log("Width: #{im.width()}")
|
||||
#console.log("height: #{im.height()}")
|
||||
|
||||
# Before working with the frame we need to check the image
|
||||
# is already available and has a width and height greater than 0,
|
||||
# otherwise it will fail when trying to do namedWindow.show()
|
||||
# and the image has width or height equal or less than 0.
|
||||
if im.width() > 0 and im.height() > 0
|
||||
# We apply filters and effects to the frame we got from the
|
||||
# camera to manipulate the video that we'll display.
|
||||
# First we convert to grayscale.
|
||||
im.convertGrayscale()
|
||||
# We then apply GaussianBlur.
|
||||
# It takes an array of type double and size 2
|
||||
# that indicates how strong the gaussian blur should be.
|
||||
im.gaussianBlur([7,7])
|
||||
# We then apply canny edge filtering.
|
||||
# Params are lower and higher threshold and aperture size,
|
||||
# although nodejs-opencv overwrite the aperture size param
|
||||
# with 0. An update to consider it is needed.
|
||||
im.canny(0, 30, 3)
|
||||
|
||||
# We use the previously created namedWindow to display the
|
||||
# video frame to wich we applied the blur and filter.
|
||||
namedWindow.show(im)
|
||||
|
||||
# Finally we get the key pressed on the window to terminate
|
||||
# execution of the program.
|
||||
res = namedWindow.blockingWaitKey(0, 20)
|
||||
|
||||
# In this case I terminate the program if any key is pressed.
|
||||
if res >= 0 then clearInterval(intervalId)
|
||||
)
|
||||
, 50)
|
||||
@@ -0,0 +1,41 @@
|
||||
cv = require 'opencv'
|
||||
|
||||
# First we create a new VideoCapture object to get
|
||||
# video from the camera (0 for default camera)
|
||||
camera = new cv.VideoCapture(1)
|
||||
|
||||
# we create a window to display the Video frames
|
||||
namedWindow = new cv.NamedWindow('Video',1)
|
||||
|
||||
# We set an interval to retrieve frames from the
|
||||
# video source and we get the intervalId so we can
|
||||
# stop the program from the video feed window.
|
||||
intervalId = setInterval(()->
|
||||
|
||||
# camera.read allows us to retrieve the current
|
||||
# frame to be displayed in the video window.
|
||||
camera.read((err, im) ->
|
||||
# We can check for errors and even break the
|
||||
# program execution if an error is detected here.
|
||||
console.log "The err ==>#{ err }" if err
|
||||
|
||||
# There is no need to display the image width or Height
|
||||
# but I leave this here in case anyone needs to check them.
|
||||
#console.log("Width: #{im.width()}")
|
||||
#console.log("height: #{im.height()}")
|
||||
|
||||
# We use the previously created namedWindow to display the
|
||||
# video feed frame, we need to check the image is already
|
||||
# available and has a width and height greater than 0,
|
||||
# otherwise namedWindow.show() will fail if any of those is 0.
|
||||
namedWindow.show(im) if im.width() > 0 and im.height() > 0
|
||||
|
||||
# Finally we get the key pressed on the window to terminate
|
||||
# execution of the program.
|
||||
res = namedWindow.blockingWaitKey(0, 20)
|
||||
console.log("KEYPRESSED => #{ res } ")
|
||||
|
||||
# In this case I terminate the program if any key is pressed.
|
||||
if res >= 0 then clearInterval(intervalId)
|
||||
)
|
||||
, 500)
|
||||
@@ -0,0 +1,29 @@
|
||||
cv = require('opencv')
|
||||
|
||||
|
||||
cv.readImage("./images/mona.png", (err, im) ->
|
||||
# Create new NamedWindow object to hold the image
|
||||
# NamedWindow takes two arguments String WindowName and String windowSize
|
||||
namedWindow = new cv.NamedWindow('Display Window', '400x400')
|
||||
|
||||
# We add a couple of basic shapes to the image, just to show how
|
||||
# to create basic shapes.
|
||||
# im.rectangle([startX, StartY], [width, height], color(array of RGB)
|
||||
im.rectangle([50, 50], [200, 200], [0, 255, 0], 2)
|
||||
# im.ellipse(centerX, centerY, width, height, color(array of RGB)
|
||||
im.ellipse(150, 150, 50, 50, [255, 255, 0], 2)
|
||||
|
||||
# We then tell the image to show the image we loaded.
|
||||
namedWindow.show(im)
|
||||
|
||||
console.log("Image should be displayed inside a window.")
|
||||
# Finally we tell the NamedWindow to wait for any key being pressed to close
|
||||
# itself (by passing a 0 as the first param, or wait a defined amount of time
|
||||
# by passing the time as a second argument (in milliseconds)
|
||||
#
|
||||
# If we do not tell the window to wait it will just load and show the image
|
||||
# and close so fast that it will appear nothing happened.
|
||||
namedWindow.blockingWaitKey(0, 5000)
|
||||
|
||||
console.log("And the window should close automatically or by pressing any key on it.")
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
cv = require('opencv')
|
||||
|
||||
|
||||
cv.readImage("./images/mona.png", (err, im) ->
|
||||
# Create new NamedWindow object to hold the image
|
||||
# NamedWindow takes two arguments String WindowName and String windowSize
|
||||
namedWindow = new cv.NamedWindow('Display Window', '400x400')
|
||||
|
||||
# We then tell the image to show the image we loaded.
|
||||
namedWindow.show(im)
|
||||
|
||||
console.log("Image should be displayed inside a window.")
|
||||
# Finally we tell the NamedWindow to wait for any key being pressed to close
|
||||
# itself (by passing a 0 as the first param, or wait a defined amount of time
|
||||
# by passing the time as a second argument (in milliseconds)
|
||||
#
|
||||
# If we do not tell the window to wait it will just load and show the image
|
||||
# and close so fast that it will appear nothing happened.
|
||||
namedWindow.blockingWaitKey(0, 5000)
|
||||
|
||||
console.log("And the window should close automatically or by pressing any key on it.")
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
cv = require('opencv')
|
||||
|
||||
|
||||
cv.readImage("./images/windows-logo.png", (err, im) ->
|
||||
|
||||
# The nodejs-opencv has some shortcodes for image manipulation.
|
||||
# We modify the image using the handy function im.convertGrayscale()
|
||||
# This will overwrite the current image with a grayscaled version.
|
||||
im.convertGrayscale()
|
||||
|
||||
# Create new NamedWindow object to hold the image
|
||||
# NamedWindow takes two arguments String WindowName and String windowSize
|
||||
namedWindow = new cv.NamedWindow('Display Window', '400x400')
|
||||
|
||||
# We then tell the image to show the image we loaded.
|
||||
namedWindow.show(im)
|
||||
|
||||
console.log("Image should be displayed inside a window.")
|
||||
# Finally we tell the NamedWindow to wait for any key being pressed to close
|
||||
# itself (by passing a 0 as the first param, or wait a defined amount of time
|
||||
# by passing the time as a second argument (in milliseconds)
|
||||
#
|
||||
# If we do not tell the window to wait it will just load and show the image
|
||||
# and close so fast that it will appear nothing happened.
|
||||
namedWindow.blockingWaitKey(0, 5000)
|
||||
|
||||
console.log("And the window should close automatically or by pressing any key on it.")
|
||||
)
|
||||
|
Depois Largura: | Altura: | Tamanho: 17 KiB |
|
Depois Largura: | Altura: | Tamanho: 518 KiB |
|
Depois Largura: | Altura: | Tamanho: 50 KiB |
|
Depois Largura: | Altura: | Tamanho: 9.4 KiB |
|
Depois Largura: | Altura: | Tamanho: 13 KiB |
@@ -0,0 +1,12 @@
|
||||
var cv = require('../lib/opencv');
|
||||
|
||||
// (B)lue, (G)reen, (R)ed
|
||||
var lower_threshold = [46, 57, 83];
|
||||
var upper_threshold = [80, 96, 115];
|
||||
|
||||
cv.readImage('./coin1.jpg', function(err, im) {
|
||||
|
||||
im.inRange(lower_threshold, upper_threshold);
|
||||
im.save('./coin_detected.jpg');
|
||||
|
||||
});
|
||||
@@ -7,7 +7,7 @@ var maxArea = 2500;
|
||||
|
||||
var GREEN = [0, 255, 0]; //B, G, R
|
||||
var WHITE = [255, 255, 255]; //B, G, R
|
||||
|
||||
var RED = [0, 0, 255]; //B, G, R
|
||||
|
||||
cv.readImage('./stuff.png', function(err, im) {
|
||||
|
||||
@@ -24,7 +24,12 @@ cv.readImage('./stuff.png', function(err, im) {
|
||||
|
||||
for(i = 0; i < contours.size(); i++) {
|
||||
if(contours.area(i) > maxArea) {
|
||||
var moments = contours.moments(i);
|
||||
var cgx = Math.round(moments.m10/moments.m00);
|
||||
var cgy = Math.round(moments.m01/moments.m00);
|
||||
big.drawContour(contours, i, GREEN);
|
||||
big.line([cgx - 5, cgy], [cgx + 5, cgy], RED);
|
||||
big.line([cgx, cgy - 5], [cgx, cgy + 5], RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
//
|
||||
// Detects triangles and quadrilaterals
|
||||
//
|
||||
|
||||
var cv = require('../lib/opencv');
|
||||
|
||||
var lowThresh = 0;
|
||||
var highThresh = 100;
|
||||
var nIters = 2;
|
||||
var minArea = 2000;
|
||||
|
||||
var BLUE = [0, 255, 0]; //B, G, R
|
||||
var RED = [0, 0, 255]; //B, G, R
|
||||
var GREEN = [0, 255, 0]; //B, G, R
|
||||
var WHITE = [255, 255, 255]; //B, G, R
|
||||
|
||||
|
||||
cv.readImage('./shapes.jpg', function(err, im) {
|
||||
|
||||
var out = new cv.Matrix(im.height(), im.width());
|
||||
|
||||
im.convertGrayscale();
|
||||
im_canny = im.copy();
|
||||
|
||||
im_canny.canny(lowThresh, highThresh);
|
||||
im_canny.dilate(nIters);
|
||||
|
||||
contours = im_canny.findContours();
|
||||
|
||||
for(i = 0; i < contours.size(); i++) {
|
||||
|
||||
if(contours.area(i) < minArea) continue;
|
||||
|
||||
var arcLength = contours.arcLength(i, true);
|
||||
contours.approxPolyDP(i, 0.01 * arcLength, true);
|
||||
|
||||
switch(contours.cornerCount(i)) {
|
||||
case 3:
|
||||
out.drawContour(contours, i, GREEN);
|
||||
break;
|
||||
case 4:
|
||||
out.drawContour(contours, i, RED);
|
||||
break;
|
||||
default:
|
||||
out.drawContour(contours, i, WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
out.save('./out.png');
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
mencoder examples/motion.mov -ovc raw -vf format=i420 -nosound -o examples/motion.avi
|
||||
@@ -0,0 +1,25 @@
|
||||
var path = require('path'),
|
||||
cv = require('../lib/opencv');
|
||||
|
||||
// When opening a file, the full path must be passed to opencv
|
||||
var vid = new cv.VideoCapture(path.join(__dirname, "motion.mov"));
|
||||
|
||||
vid.read(function(err, mat){
|
||||
var track = new cv.TrackedObject(mat, [420, 110, 490, 170], {channel: "value"});
|
||||
var x = 0;
|
||||
var iter = function(){
|
||||
vid.read(function(err, m2){
|
||||
x++;
|
||||
var rec = track.track(m2)
|
||||
console.log(">>", x, ":" , rec)
|
||||
if (x % 10 == 0){
|
||||
m2.rectangle([rec[0], rec[1]], [rec[2], rec[3]])
|
||||
// m2.save('./out-motiontrack-' + x + '.jpg')
|
||||
}
|
||||
if (x<100)
|
||||
iter();
|
||||
})
|
||||
}
|
||||
iter();
|
||||
})
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
//
|
||||
// Finds quadrilaterals and fills them with an X
|
||||
//
|
||||
|
||||
var cv = require('../lib/opencv');
|
||||
|
||||
var lowThresh = 0;
|
||||
var highThresh = 100;
|
||||
var nIters = 2;
|
||||
var minArea = 2000;
|
||||
var maxArea = 100000;
|
||||
|
||||
var BLUE = [0, 255, 0]; //B, G, R
|
||||
var RED = [0, 0, 255]; //B, G, R
|
||||
var GREEN = [0, 255, 0]; //B, G, R
|
||||
var WHITE = [255, 255, 255]; //B, G, R
|
||||
|
||||
|
||||
cv.readImage('./quads.jpg', function(err, im) {
|
||||
|
||||
var out = im.copy();
|
||||
|
||||
im.convertGrayscale();
|
||||
im_canny = im.copy();
|
||||
|
||||
im_canny.canny(lowThresh, highThresh);
|
||||
im_canny.dilate(nIters);
|
||||
|
||||
contours = im_canny.findContours();
|
||||
|
||||
for(i = 0; i < contours.size(); i++) {
|
||||
|
||||
var area = contours.area(i);
|
||||
if(area < minArea || area > maxArea) continue;
|
||||
|
||||
var arcLength = contours.arcLength(i, true);
|
||||
contours.approxPolyDP(i, 0.01 * arcLength, true);
|
||||
|
||||
if(contours.cornerCount(i) != 4) continue;
|
||||
|
||||
var points = [
|
||||
contours.point(i, 0),
|
||||
contours.point(i, 1),
|
||||
contours.point(i, 2),
|
||||
contours.point(i, 3)
|
||||
]
|
||||
|
||||
out.line([points[0].x,points[0].y], [points[2].x, points[2].y], RED);
|
||||
out.line([points[1].x,points[1].y], [points[3].x, points[3].y], RED);
|
||||
}
|
||||
|
||||
out.save('./out.png');
|
||||
});
|
||||
|
Depois Largura: | Altura: | Tamanho: 111 KiB |
|
Depois Largura: | Altura: | Tamanho: 116 KiB |
@@ -0,0 +1,31 @@
|
||||
var cv = require('../lib/opencv')
|
||||
|
||||
var vid = new cv.VideoCapture(0)
|
||||
|
||||
|
||||
var snap = function(){
|
||||
vid.read(function(err, im){
|
||||
im.detectObject(cv.FACE_CASCADE, {}, function(err, faces){
|
||||
|
||||
if (!faces){
|
||||
console.log("No Faces")
|
||||
return;
|
||||
}
|
||||
var face = faces[0]
|
||||
, ims = im.size()
|
||||
|
||||
var im2 = im.roi(face.x, face.y, face.width, face.height)
|
||||
/*
|
||||
im.adjustROI(
|
||||
-face.y
|
||||
, (face.y + face.height) - ims[0]
|
||||
, -face.x
|
||||
, (face.x + face.width) - ims[1])
|
||||
*/
|
||||
im2.save('out.jpg')
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
snap()
|
||||
@@ -1,6 +1,7 @@
|
||||
var Stream = require('stream').Stream
|
||||
, Buffers = require('buffer')
|
||||
, util = require('util');
|
||||
, Buffers = require('buffers')
|
||||
, util = require('util')
|
||||
, path = require('path')
|
||||
|
||||
var bindings = require('./bindings')
|
||||
|
||||
@@ -20,7 +21,15 @@ var matrix = cv.Matrix.prototype;
|
||||
matrix.detectObject = function(classifier, opts, cb){
|
||||
opts = opts || {}
|
||||
|
||||
var face_cascade = new cv.CascadeClassifier(classifier);
|
||||
cv._detectObjectClassifiers = cv._detectObjectClassifiers || {}
|
||||
|
||||
if (cv._detectObjectClassifiers[classifier]){
|
||||
var face_cascade = cv._detectObjectClassifiers[classifier];
|
||||
} else{
|
||||
var face_cascade = new cv.CascadeClassifier(classifier);
|
||||
cv._detectObjectClassifiers[classifier] = face_cascade;
|
||||
}
|
||||
|
||||
face_cascade.detectMultiScale(this, cb, opts.scale, opts.neighbors
|
||||
, opts.min && opts.min[0], opts.min && opts.min[1]);
|
||||
}
|
||||
@@ -32,23 +41,23 @@ matrix.inspect = function(){
|
||||
|
||||
}
|
||||
|
||||
cv.ImageStream = function(){
|
||||
cv.ImageDataStream = function(){
|
||||
this.data = Buffers([])
|
||||
this.writable = true
|
||||
}
|
||||
|
||||
util.inherits(cv.ImageStream, Stream);
|
||||
var imagestream = cv.ImageStream.prototype;
|
||||
util.inherits(cv.ImageDataStream, Stream);
|
||||
var imagedatastream = cv.ImageDataStream.prototype;
|
||||
|
||||
imagestream.write = function(buf){
|
||||
this.data.push(buf)
|
||||
imagedatastream.write = function(buf){
|
||||
this.data.push(buf)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
imagestream.end = function(b){
|
||||
imagedatastream.end = function(b){
|
||||
var self = this;
|
||||
|
||||
|
||||
if (b)
|
||||
imagestream.write.call(this,b);
|
||||
|
||||
@@ -59,3 +68,90 @@ imagestream.end = function(b){
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
cv.ImageStream = function(){
|
||||
this.writable = true
|
||||
}
|
||||
|
||||
util.inherits(cv.ImageStream, Stream);
|
||||
var imagestream = cv.ImageStream.prototype;
|
||||
|
||||
imagestream.write = function(buf){
|
||||
var self = this;
|
||||
cv.readImage(buf, function(err, matrix){
|
||||
self.emit('data', matrix);
|
||||
});
|
||||
}
|
||||
|
||||
// Object detect stream
|
||||
cv.ObjectDetectionStream = function(cascade, opts){
|
||||
this.classifier = new cv.CascadeClassifier(cascade);
|
||||
this.opts = opts || {}
|
||||
this.readable = true;
|
||||
this.writable = true;
|
||||
}
|
||||
|
||||
util.inherits(cv.ObjectDetectionStream, Stream);
|
||||
var ods = cv.ObjectDetectionStream.prototype;
|
||||
|
||||
ods.write = function(m){
|
||||
var self = this;
|
||||
|
||||
this.classifier.detectMultiScale(m,
|
||||
function(e, objs){
|
||||
if (e) { throw e }
|
||||
self.emit('data', objs, m);
|
||||
}
|
||||
, this.opts.scale, this.opts.neighbors
|
||||
, this.opts.min && this.opts.min[0], this.opts.min && this.opts.min[1]);
|
||||
}
|
||||
|
||||
// == Video Stream ==
|
||||
cv.VideoStream = function(src){
|
||||
if (src instanceof cv.VideoCapture){
|
||||
this.video = src
|
||||
} else {
|
||||
this.video = new cv.VideoCapture(src);
|
||||
}
|
||||
this.readable = true;
|
||||
this.paused = false;
|
||||
}
|
||||
|
||||
util.inherits(cv.VideoStream, Stream);
|
||||
var videostream = cv.VideoStream.prototype;
|
||||
cv.VideoCapture.prototype.toStream = function(){
|
||||
return new cv.VideoStream(this);
|
||||
}
|
||||
|
||||
videostream.read = function(){
|
||||
var self = this;
|
||||
|
||||
var frame = function(){
|
||||
self.video.read(function(err, mat){
|
||||
self.emit('data', mat)
|
||||
if (!self.paused){
|
||||
process.nextTick(frame)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
frame();
|
||||
}
|
||||
|
||||
videostream.pause = function(){
|
||||
this.paused = true
|
||||
}
|
||||
|
||||
videostream.resume = function(){
|
||||
this.paused = false
|
||||
this.read()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Provide cascade data for faces etc.
|
||||
cv.FACE_CASCADE = path.resolve(__dirname, '../data/haarcascade_frontalface_alt.xml')
|
||||
|
||||
|
||||
|
||||
@@ -5,14 +5,27 @@
|
||||
"dependencies": {
|
||||
"buffers": "0.1.1"
|
||||
},
|
||||
"version": "0.0.8",
|
||||
"version": "0.4.0",
|
||||
"devDependencies": {
|
||||
"vows": "*"
|
||||
},
|
||||
"engine": "node >= 0.4.1",
|
||||
"engines": {
|
||||
"node": ">=0.4.1"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"preinstall": "node-gyp clean rebuild",
|
||||
"test": "vows test/unit.js"
|
||||
},
|
||||
"main": "./lib/opencv"
|
||||
"keywords": [
|
||||
"opencv",
|
||||
"computer",
|
||||
"vision",
|
||||
"quadrocopter"
|
||||
],
|
||||
"main": "./lib/opencv",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/peterbraden/node-opencv.git"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
#!/bin/bash
|
||||
node-gyp rebuild && echo '-- Compiled OK --
|
||||
|
||||
if [ ! -f smoke/smoketest.js ]; then
|
||||
echo "Please run smoke test from the top-level folder of the repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
node-gyp build && echo '-- Compiled OK --
|
||||
|
||||
' && node smoke/smoketest.js && echo '-- Smoke Done, running tests --
|
||||
|
||||
' && npm test
|
||||
' && npm test # && echo '-- Tests Run, runnning examples --
|
||||
#(building example data)
|
||||
#' && ./examples/make-example-files.sh && node examples/motion-track.js
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
var cv = require('../lib/opencv')
|
||||
|
||||
var trainingData = []
|
||||
/*
|
||||
new cv.VideoCapture(0).read(function(mat){
|
||||
for (var i = 1; i< 41; i++){
|
||||
for (var j = 1; j<10; j++){
|
||||
trainingData.push([i,"/Users/peterbraden/Downloads/orl_faces/s" + i + "/" + j + ".pgm" ])
|
||||
}
|
||||
}
|
||||
|
||||
mat.resize(200,100)
|
||||
mat.save('./out.jpg')
|
||||
cv.readImage("/Users/peterbraden/Downloads/orl_faces/s6/10.pgm", function(e, im){
|
||||
|
||||
var facerec = cv.FaceRecognizer.createEigenFaceRecognizer();
|
||||
//facerec.trainSync(trainingData);
|
||||
facerec.loadSync("/Users/peterbraden/Desktop/ORL")
|
||||
|
||||
console.log(facerec.predictSync(im));
|
||||
|
||||
mat.detectObject("./data/haarcascade_frontalface_alt.xml", {min : [30,30]}, function(err, faces){
|
||||
for (var i=0;i<faces.length; i++){
|
||||
var x = faces[i]
|
||||
mat.ellipse(x.x + x.width/2, x.y + x.height/2, x.width/2, x.height/2);
|
||||
}
|
||||
console.log(faces.length ? (faces.length + " faces found") : "No faces")
|
||||
mat.save('./out.jpg');
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
*/
|
||||
cv.readImage("examples/mona.png", function(e, mat){
|
||||
var th = mat.threshold(200, 200, "Threshold to Zero Inverted");
|
||||
th.save('out.png')
|
||||
|
||||
})
|
||||
|
||||
cv.readImage("./examples/stuff.png", function(err, im){
|
||||
var i2 = im.copy()
|
||||
i2.convertGrayscale()
|
||||
i2.canny(5, 300)
|
||||
var features = i2.houghLinesP();
|
||||
for (var i=0;i<features.length; i++){
|
||||
var x = features[i]
|
||||
im.line([x[0], x[1]], [x[2], x[3]]);
|
||||
im.ellipse(x[0], x[1]);
|
||||
im.ellipse(x[2], x[3]);
|
||||
}
|
||||
console.log(features)
|
||||
im.save('./out.jpg');
|
||||
});
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
#include "CamShift.h"
|
||||
#include "OpenCV.h"
|
||||
#include "Matrix.h"
|
||||
|
||||
|
||||
#define CHANNEL_HUE 0
|
||||
#define CHANNEL_SATURATION 1
|
||||
#define CHANNEL_VALUE 2
|
||||
|
||||
|
||||
Persistent<FunctionTemplate> TrackedObject::constructor;
|
||||
|
||||
void
|
||||
TrackedObject::Init(Handle<Object> target) {
|
||||
HandleScope scope;
|
||||
|
||||
// Constructor
|
||||
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(TrackedObject::New));
|
||||
constructor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
constructor->SetClassName(String::NewSymbol("TrackedObject"));
|
||||
|
||||
// Prototype
|
||||
//Local<ObjectTemplate> proto = constructor->PrototypeTemplate();
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "track", Track);
|
||||
target->Set(String::NewSymbol("TrackedObject"), constructor->GetFunction());
|
||||
};
|
||||
|
||||
|
||||
Handle<Value>
|
||||
TrackedObject::New(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
if (args.This()->InternalFieldCount() == 0){
|
||||
JSTHROW_TYPE("Cannot Instantiate without new")
|
||||
}
|
||||
|
||||
Matrix* m = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
|
||||
cv::Rect r;
|
||||
int channel = CHANNEL_HUE;
|
||||
|
||||
if (args[1]->IsArray()){
|
||||
Local<Object> v8rec = args[1]->ToObject();
|
||||
r = cv::Rect(
|
||||
v8rec->Get(0)->IntegerValue(),
|
||||
v8rec->Get(1)->IntegerValue(),
|
||||
v8rec->Get(2)->IntegerValue() - v8rec->Get(0)->IntegerValue(),
|
||||
v8rec->Get(3)->IntegerValue() - v8rec->Get(1)->IntegerValue());
|
||||
} else {
|
||||
JSTHROW_TYPE("Must pass rectangle to track")
|
||||
}
|
||||
|
||||
if (args[2]->IsObject()){
|
||||
Local<Object> opts = args[2]->ToObject();
|
||||
|
||||
if (opts->Get(String::New("channel"))->IsString()){
|
||||
v8::String::Utf8Value c(opts->Get(String::New("channel"))->ToString());
|
||||
std::string cc = std::string(*c);
|
||||
|
||||
if (cc == "hue" || cc == "h"){
|
||||
channel = CHANNEL_HUE;
|
||||
}
|
||||
|
||||
if (cc == "saturation" || cc == "s"){
|
||||
channel = CHANNEL_SATURATION;
|
||||
}
|
||||
|
||||
if (cc == "value" || cc == "v"){
|
||||
channel = CHANNEL_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrackedObject *to = new TrackedObject(m->mat, r, channel);
|
||||
|
||||
|
||||
to->Wrap(args.This());
|
||||
return args.This();
|
||||
}
|
||||
|
||||
|
||||
void update_chann_image(TrackedObject* t, cv::Mat image){
|
||||
// Store HSV Hue Image
|
||||
cv::cvtColor(image, t->hsv, CV_BGR2HSV); // convert to HSV space
|
||||
//mask out-of-range values
|
||||
int vmin = 65, vmax = 256, smin = 55;
|
||||
cv::inRange(t->hsv, //source
|
||||
cv::Scalar(0, smin, MIN(vmin, vmax), 0), //lower bound
|
||||
cv::Scalar(180, 256, MAX(vmin, vmax) ,0), //upper bound
|
||||
t->mask); //destination
|
||||
|
||||
//extract the hue channel, split: src, dest channels
|
||||
std::vector<cv::Mat> hsvplanes;
|
||||
cv::split(t->hsv, hsvplanes);
|
||||
t->hue = hsvplanes[t->channel];
|
||||
|
||||
|
||||
}
|
||||
|
||||
TrackedObject::TrackedObject(cv::Mat image, cv::Rect rect, int chan){
|
||||
channel = chan;
|
||||
update_chann_image(this, image);
|
||||
prev_rect = rect;
|
||||
|
||||
// Calculate Histogram
|
||||
int hbins = 30, sbins = 32;
|
||||
int histSizes[] = {hbins, sbins};
|
||||
//float hranges[] = { 0, 180 };
|
||||
// saturation varies from 0 (black-gray-white) to
|
||||
// 255 (pure spectrum color)
|
||||
float sranges[] = { 0, 256 };
|
||||
const float* ranges[] = { sranges };
|
||||
|
||||
cv::Mat hue_roi = hue(rect);
|
||||
cv::Mat mask_roi = mask(rect);
|
||||
|
||||
cv::calcHist(&hue_roi, 1, 0, mask_roi, hist, 1, histSizes, ranges, true, false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Handle<Value>
|
||||
TrackedObject::Track(const v8::Arguments& args){
|
||||
SETUP_FUNCTION(TrackedObject)
|
||||
|
||||
if (args.Length() != 1){
|
||||
v8::ThrowException(v8::Exception::TypeError(v8::String::New("track takes an image param")));
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
|
||||
Matrix *im = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
|
||||
cv::RotatedRect r;
|
||||
|
||||
if (self->prev_rect.x <0 ||
|
||||
self->prev_rect.y <0 ||
|
||||
self->prev_rect.width <= 1 ||
|
||||
self->prev_rect.height <= 1){
|
||||
return v8::ThrowException(v8::Exception::TypeError(v8::String::New("OPENCV ERROR: prev rectangle is illogical")));
|
||||
}
|
||||
|
||||
update_chann_image(self, im->mat);
|
||||
|
||||
cv::Rect backup_prev_rect = cv::Rect(
|
||||
self->prev_rect.x,
|
||||
self->prev_rect.y,
|
||||
self->prev_rect.width,
|
||||
self->prev_rect.height);
|
||||
|
||||
float sranges[] = { 0, 256 };
|
||||
const float* ranges[] = { sranges };
|
||||
int channel = 0;
|
||||
cv::calcBackProject(&self->hue, 1, &channel, self->hist, self->prob, ranges);
|
||||
|
||||
r = cv::CamShift(self->prob, self->prev_rect,
|
||||
cv::TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1));
|
||||
|
||||
cv::Rect bounds = r.boundingRect();
|
||||
if (bounds.x >=0 && bounds.y >=0 && bounds.width > 1 && bounds.height > 1){
|
||||
self->prev_rect = bounds;
|
||||
} else {
|
||||
//printf("CRAP> %i %i %i %i ;", self->prev_rect.x, self->prev_rect.y, self->prev_rect.width, self->prev_rect.height);
|
||||
|
||||
// We have encountered a bug in opencv. Somehow the prev_rect has got mangled, so we
|
||||
// must reset it to a good value.
|
||||
self->prev_rect = backup_prev_rect;
|
||||
}
|
||||
|
||||
|
||||
v8::Local<v8::Array> arr = v8::Array::New(4);
|
||||
|
||||
|
||||
arr->Set(0, Number::New(bounds.x));
|
||||
arr->Set(1, Number::New(bounds.y));
|
||||
arr->Set(2, Number::New(bounds.x + bounds.width));
|
||||
arr->Set(3, Number::New(bounds.y + bounds.height));
|
||||
|
||||
/*
|
||||
cv::Point2f pts[4];
|
||||
r.points(pts);
|
||||
|
||||
for (int i=0; i<8; i+=2){
|
||||
arr->Set(i, Number::New(pts[i].x));
|
||||
arr->Set(i+1, Number::New(pts[i].y));
|
||||
}
|
||||
*/
|
||||
|
||||
return scope.Close(arr);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "OpenCV.h"
|
||||
|
||||
|
||||
class TrackedObject: public node::ObjectWrap {
|
||||
public:
|
||||
int channel;
|
||||
cv::Mat hsv;
|
||||
cv::Mat hue;
|
||||
cv::Mat mask;
|
||||
cv::Mat prob;
|
||||
|
||||
cv::Mat hist;
|
||||
cv::Rect prev_rect;
|
||||
|
||||
static Persistent<FunctionTemplate> constructor;
|
||||
static void Init(Handle<Object> target);
|
||||
static Handle<Value> New(const Arguments &args);
|
||||
|
||||
TrackedObject(cv::Mat image, cv::Rect rect, int channel);
|
||||
|
||||
JSFUNC(Track);
|
||||
|
||||
};
|
||||
@@ -112,7 +112,7 @@ CascadeClassifierWrap::DetectMultiScale(const v8::Arguments& args){
|
||||
// eio_custom(EIO_DetectMultiScale, EIO_PRI_DEFAULT, EIO_AfterDetectMultiScale, baton);
|
||||
// ev_ref(EV_DEFAULT_UC);
|
||||
|
||||
uv_queue_work(uv_default_loop(), &baton->request, AsyncDetectMultiScale, AfterAsyncDetectMultiScale);
|
||||
uv_queue_work(uv_default_loop(), &baton->request, AsyncDetectMultiScale, (uv_after_work_cb)AfterAsyncDetectMultiScale);
|
||||
|
||||
return Undefined();
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class CascadeClassifierWrap: public node::ObjectWrap {
|
||||
//static Handle<Value> LoadHaarClassifierCascade(const v8::Arguments&);
|
||||
|
||||
static Handle<Value> DetectMultiScale(const v8::Arguments&);
|
||||
static void EIO_DetectMultiScale(eio_req *req);
|
||||
static int EIO_AfterDetectMultiScale(eio_req *req);
|
||||
static void EIO_DetectMultiScale(uv_work_t *req);
|
||||
static int EIO_AfterDetectMultiScale(uv_work_t *req);
|
||||
|
||||
};
|
||||
|
||||
@@ -23,8 +23,17 @@ Contour::Init(Handle<Object> target) {
|
||||
//Local<ObjectTemplate> proto = constructor->PrototypeTemplate();
|
||||
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "point", Point);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "size", Size);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "cornerCount", CornerCount);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "area", Area);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "arcLength", ArcLength);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "approxPolyDP", ApproxPolyDP);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "convexHull", ConvexHull);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "boundingRect", BoundingRect);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "minAreaRect", BoundingRect);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "isConvex", IsConvex);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "moments", Moments);
|
||||
target->Set(String::NewSymbol("Contours"), m->GetFunction());
|
||||
};
|
||||
|
||||
@@ -48,6 +57,26 @@ Contour::Contour(): ObjectWrap() {
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
Contour::Point(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
int index = args[1]->NumberValue();
|
||||
|
||||
cv::Point point = self->contours[pos][index];
|
||||
|
||||
Local<Object> data = Object::New();
|
||||
data->Set(String::NewSymbol("x"), Number::New(point.x));
|
||||
data->Set(String::NewSymbol("y"), Number::New(point.y));
|
||||
|
||||
return scope.Close(data);
|
||||
}
|
||||
|
||||
// FIXME: this sould better be called "Length" as ``Contours`` is an Array like structure
|
||||
// also, this would allow to use ``Size`` for the function returning the number of corners
|
||||
// in the contour for better consistency with OpenCV.
|
||||
Handle<Value>
|
||||
Contour::Size(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
@@ -55,9 +84,17 @@ Contour::Size(const Arguments &args) {
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
|
||||
return scope.Close(Number::New(self->contours.size()));
|
||||
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
Contour::CornerCount(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
|
||||
return scope.Close(Number::New(self->contours[pos].size()));
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
Contour::Area(const Arguments &args) {
|
||||
@@ -68,6 +105,140 @@ Contour::Area(const Arguments &args) {
|
||||
|
||||
//return scope.Close(Number::New(contourArea(self->contours)));
|
||||
return scope.Close(Number::New(contourArea(cv::Mat(self->contours[pos]))));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
Contour::ArcLength(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
bool isClosed = args[1]->BooleanValue();
|
||||
|
||||
return scope.Close(Number::New(arcLength(cv::Mat(self->contours[pos]), isClosed)));
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
Contour::ApproxPolyDP(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
double epsilon = args[1]->NumberValue();
|
||||
bool isClosed = args[2]->BooleanValue();
|
||||
|
||||
cv::Mat approxed;
|
||||
approxPolyDP(cv::Mat(self->contours[pos]), approxed, epsilon, isClosed);
|
||||
approxed.copyTo(self->contours[pos]);
|
||||
|
||||
return scope.Close(v8::Null());
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
Contour::ConvexHull(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
|
||||
int pos = args[0]->NumberValue();
|
||||
bool clockwise = args[1]->BooleanValue();
|
||||
|
||||
cv::Mat hull;
|
||||
cv::convexHull(cv::Mat(self->contours[pos]), hull, clockwise);
|
||||
hull.copyTo(self->contours[pos]);
|
||||
|
||||
return scope.Close(v8::Null());
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
Contour::BoundingRect(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
|
||||
cv::Rect bounding = cv::boundingRect(cv::Mat(self->contours[pos]));
|
||||
Local<Object> rect = Object::New();
|
||||
|
||||
rect->Set(String::NewSymbol("x"), Number::New(bounding.x));
|
||||
rect->Set(String::NewSymbol("y"), Number::New(bounding.y));
|
||||
rect->Set(String::NewSymbol("width"), Number::New(bounding.width));
|
||||
rect->Set(String::NewSymbol("height"), Number::New(bounding.height));
|
||||
|
||||
return scope.Close(rect);
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
Contour::MinAreaRect(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
|
||||
cv::RotatedRect minimum = cv::minAreaRect(cv::Mat(self->contours[pos]));
|
||||
|
||||
Local<Object> rect = Object::New();
|
||||
rect->Set(String::NewSymbol("angle"), Number::New(minimum.angle));
|
||||
|
||||
Local<Object> size = Object::New();
|
||||
size->Set(String::NewSymbol("height"), Number::New(minimum.size.height));
|
||||
size->Set(String::NewSymbol("width"), Number::New(minimum.size.width));
|
||||
rect->Set(String::NewSymbol("size"), size);
|
||||
|
||||
Local<Object> center = Object::New();
|
||||
center->Set(String::NewSymbol("x"), Number::New(minimum.center.x));
|
||||
center->Set(String::NewSymbol("y"), Number::New(minimum.center.y));
|
||||
|
||||
v8::Local<v8::Array> points = v8::Array::New(4);
|
||||
|
||||
cv::Point2f rect_points[4];
|
||||
minimum.points(rect_points);
|
||||
|
||||
for (unsigned int i=0; i<4; i++){
|
||||
Local<Object> point = Object::New();
|
||||
point->Set(String::NewSymbol("x"), Number::New(rect_points[i].x));
|
||||
point->Set(String::NewSymbol("y"), Number::New(rect_points[i].y));
|
||||
points->Set(i, point);
|
||||
}
|
||||
|
||||
rect->Set(String::NewSymbol("points"), points);
|
||||
|
||||
return scope.Close(rect);
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
Contour::IsConvex(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
|
||||
return scope.Close(Boolean::New(isContourConvex(cv::Mat(self->contours[pos]))));
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
Contour::Moments(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
Contour *self = ObjectWrap::Unwrap<Contour>(args.This());
|
||||
int pos = args[0]->NumberValue();
|
||||
|
||||
/// Get the moments
|
||||
cv::Moments mu = moments( self->contours[pos], false );
|
||||
|
||||
Local<Object> res = Object::New();
|
||||
|
||||
res->Set(String::NewSymbol("m00"), Number::New(mu.m00));
|
||||
res->Set(String::NewSymbol("m10"), Number::New(mu.m10));
|
||||
res->Set(String::NewSymbol("m01"), Number::New(mu.m01));
|
||||
res->Set(String::NewSymbol("m11"), Number::New(mu.m11));
|
||||
|
||||
return scope.Close(res);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,19 @@ class Contour: public node::ObjectWrap {
|
||||
static void Init(Handle<Object> target);
|
||||
static Handle<Value> New(const Arguments &args);
|
||||
|
||||
Contour();
|
||||
Contour();
|
||||
|
||||
//JSFUNC(Size)
|
||||
static Handle<Value> Point(const v8::Arguments&);
|
||||
static Handle<Value> Size(const v8::Arguments&);
|
||||
static Handle<Value> CornerCount(const v8::Arguments&);
|
||||
static Handle<Value> Area(const v8::Arguments&);
|
||||
static Handle<Value> ArcLength(const v8::Arguments&);
|
||||
static Handle<Value> ApproxPolyDP(const v8::Arguments&);
|
||||
static Handle<Value> ConvexHull(const v8::Arguments&);
|
||||
static Handle<Value> BoundingRect(const v8::Arguments&);
|
||||
static Handle<Value> MinAreaRect(const v8::Arguments&);
|
||||
static Handle<Value> IsConvex(const v8::Arguments&);
|
||||
static Handle<Value> Moments(const v8::Arguments&);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
#include "FaceRecognizer.h"
|
||||
#include "OpenCV.h"
|
||||
|
||||
#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4
|
||||
|
||||
#include "Matrix.h"
|
||||
|
||||
#define EIGEN 0
|
||||
#define LBPH 1
|
||||
#define FISHER 2
|
||||
|
||||
// Todo, move somewhere useful
|
||||
cv::Mat fromMatrixOrFilename(Local<Value> v){
|
||||
cv::Mat im;
|
||||
if (v->IsString()){
|
||||
std::string filename = std::string(*v8::String::AsciiValue(v->ToString()));
|
||||
im = cv::imread(filename);
|
||||
//std::cout<< im.size();
|
||||
} else {
|
||||
Matrix *img = ObjectWrap::Unwrap<Matrix>(v->ToObject());
|
||||
im = img->mat;
|
||||
}
|
||||
return im;
|
||||
}
|
||||
|
||||
|
||||
void AsyncPredict(uv_work_t *req);
|
||||
void AfterAsyncPredict(uv_work_t *req);
|
||||
|
||||
Persistent<FunctionTemplate> FaceRecognizerWrap::constructor;
|
||||
|
||||
void
|
||||
FaceRecognizerWrap::Init(Handle<Object> target) {
|
||||
HandleScope scope;
|
||||
|
||||
// Constructor
|
||||
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(FaceRecognizerWrap::New));
|
||||
constructor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
constructor->SetClassName(String::NewSymbol("FaceRecognizer"));
|
||||
|
||||
NODE_SET_METHOD(constructor, "createLBPHFaceRecognizer", CreateLBPH);
|
||||
NODE_SET_METHOD(constructor, "createEigenFaceRecognizer", CreateEigen);
|
||||
NODE_SET_METHOD(constructor, "createFisherFaceRecognizer", CreateFisher);
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "trainSync", TrainSync);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "updateSync", UpdateSync);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "predictSync", PredictSync);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "saveSync", SaveSync);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "loadSync", LoadSync);
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "getMat", GetMat);
|
||||
|
||||
target->Set(String::NewSymbol("FaceRecognizer"), constructor->GetFunction());
|
||||
};
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::New(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
if (args.This()->InternalFieldCount() == 0)
|
||||
JSTHROW_TYPE("Cannot Instantiate without new")
|
||||
|
||||
// By default initialize LBPH
|
||||
cv::Ptr<cv::FaceRecognizer> f = cv::createLBPHFaceRecognizer(1, 8, 8, 8, 80.0);
|
||||
FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, LBPH);
|
||||
|
||||
pt->Wrap(args.This());
|
||||
return args.This();
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::CreateLBPH(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
int radius = 1;
|
||||
int neighbors = 8;
|
||||
int grid_x = 8;
|
||||
int grid_y = 8;
|
||||
double threshold = 80;
|
||||
|
||||
INT_FROM_ARGS(radius, 0)
|
||||
INT_FROM_ARGS(neighbors, 1)
|
||||
INT_FROM_ARGS(grid_x, 2)
|
||||
INT_FROM_ARGS(grid_y, 3)
|
||||
DOUBLE_FROM_ARGS(threshold, 4)
|
||||
|
||||
Local<Object> n = FaceRecognizerWrap::constructor->GetFunction()->NewInstance();
|
||||
|
||||
cv::Ptr<cv::FaceRecognizer> f = cv::createLBPHFaceRecognizer(
|
||||
radius, neighbors, grid_x, grid_y, threshold
|
||||
);
|
||||
FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, LBPH);
|
||||
|
||||
pt->Wrap(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::CreateEigen(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
int components = 0;
|
||||
double threshold = DBL_MAX;
|
||||
|
||||
INT_FROM_ARGS(components, 0)
|
||||
DOUBLE_FROM_ARGS(threshold, 1)
|
||||
|
||||
Local<Object> n = FaceRecognizerWrap::constructor->GetFunction()->NewInstance();
|
||||
|
||||
cv::Ptr<cv::FaceRecognizer> f = cv::createEigenFaceRecognizer(
|
||||
components, threshold
|
||||
);
|
||||
FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, EIGEN);
|
||||
|
||||
pt->Wrap(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::CreateFisher(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
int components = 0;
|
||||
double threshold = DBL_MAX;
|
||||
|
||||
INT_FROM_ARGS(components, 0)
|
||||
DOUBLE_FROM_ARGS(threshold, 1)
|
||||
|
||||
Local<Object> n = FaceRecognizerWrap::constructor->GetFunction()->NewInstance();
|
||||
|
||||
cv::Ptr<cv::FaceRecognizer> f = cv::createFisherFaceRecognizer(
|
||||
components, threshold
|
||||
);
|
||||
FaceRecognizerWrap *pt = new FaceRecognizerWrap(f, FISHER);
|
||||
|
||||
pt->Wrap(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
FaceRecognizerWrap::FaceRecognizerWrap(cv::Ptr<cv::FaceRecognizer> f, int type){
|
||||
rec = f;
|
||||
typ = type;
|
||||
}
|
||||
|
||||
|
||||
Handle<Value> UnwrapTrainingData(const Arguments& args, cv::vector<cv::Mat>* images, cv::vector<int>* labels){
|
||||
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsArray()){
|
||||
JSTHROW("FaceRecognizer.train takes a list of [<int> label, image] tuples")
|
||||
}
|
||||
|
||||
// Iterate through [[label, image], ...] etc, and add matrix / label to vectors
|
||||
const Local<Array> tuples = v8::Array::Cast(*args[0]);
|
||||
const uint32_t length = tuples->Length();
|
||||
for (uint32_t i=0 ; i<length ; ++i){
|
||||
const Local<Value> val = tuples->Get(i);
|
||||
|
||||
if (!val->IsArray()){
|
||||
JSTHROW("train takes a list of [label, image] tuples")
|
||||
}
|
||||
|
||||
Local<Array> valarr = v8::Array::Cast(*val);
|
||||
|
||||
if (valarr->Length() != 2 || !valarr->Get(0)->IsInt32()){
|
||||
JSTHROW("train takes a list of [label, image] tuples")
|
||||
}
|
||||
|
||||
int label = valarr->Get(0)->Uint32Value();
|
||||
cv::Mat im = fromMatrixOrFilename(valarr->Get(1));
|
||||
im = im.clone();
|
||||
cv::cvtColor(im, im, CV_RGB2GRAY);
|
||||
labels->push_back(label);
|
||||
images->push_back(im);
|
||||
}
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::TrainSync(const Arguments& args){
|
||||
SETUP_FUNCTION(FaceRecognizerWrap)
|
||||
|
||||
cv::vector<cv::Mat> images;
|
||||
cv::vector<int> labels;
|
||||
|
||||
Handle<Value> exception = UnwrapTrainingData(args, &images, &labels);
|
||||
if (!exception->IsUndefined()){
|
||||
return exception;
|
||||
}
|
||||
|
||||
self->rec->train(images, labels);
|
||||
|
||||
return scope.Close(v8::Undefined());
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::UpdateSync(const Arguments& args){
|
||||
SETUP_FUNCTION(FaceRecognizerWrap)
|
||||
|
||||
|
||||
if (self->typ == EIGEN){
|
||||
JSTHROW("Eigen Recognizer does not support update")
|
||||
}
|
||||
if (self->typ == FISHER){
|
||||
JSTHROW("Fisher Recognizer does not support update")
|
||||
}
|
||||
|
||||
cv::vector<cv::Mat> images;
|
||||
cv::vector<int> labels;
|
||||
|
||||
|
||||
Handle<Value> exception = UnwrapTrainingData(args, &images, &labels);
|
||||
if (!exception->IsUndefined()){
|
||||
return exception;
|
||||
}
|
||||
|
||||
self->rec->update(images, labels);
|
||||
|
||||
return scope.Close(v8::Undefined());
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::PredictSync(const Arguments& args){
|
||||
SETUP_FUNCTION(FaceRecognizerWrap)
|
||||
|
||||
cv::Mat im = fromMatrixOrFilename(args[0]);//TODO CHECK!
|
||||
cv::cvtColor(im, im, CV_RGB2GRAY);
|
||||
// int predictedLabel = self->rec->predict(im);
|
||||
|
||||
int predictedLabel = -1;
|
||||
double confidence = 0.0;
|
||||
self->rec->predict(im, predictedLabel, confidence);
|
||||
|
||||
v8::Local<v8::Object> res = v8::Object::New();
|
||||
res->Set(v8::String::New("id"), v8::Number::New(predictedLabel));
|
||||
res->Set(v8::String::New("confidence"), v8::Number::New(confidence));
|
||||
|
||||
return scope.Close(res);
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::SaveSync(const Arguments& args){
|
||||
SETUP_FUNCTION(FaceRecognizerWrap)
|
||||
if (!args[0]->IsString()){
|
||||
JSTHROW("Save takes a filename")
|
||||
}
|
||||
std::string filename = std::string(*v8::String::AsciiValue(args[0]->ToString()));
|
||||
self->rec->save(filename);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::LoadSync(const Arguments& args){
|
||||
SETUP_FUNCTION(FaceRecognizerWrap)
|
||||
if (!args[0]->IsString()){
|
||||
JSTHROW("Load takes a filename")
|
||||
}
|
||||
std::string filename = std::string(*v8::String::AsciiValue(args[0]->ToString()));
|
||||
self->rec->load(filename);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
FaceRecognizerWrap::GetMat(const Arguments& args){
|
||||
SETUP_FUNCTION(FaceRecognizerWrap)
|
||||
if (!args[0]->IsString()){
|
||||
JSTHROW("getMat takes a key")
|
||||
}
|
||||
std::string key = std::string(*v8::String::AsciiValue(args[0]->ToString()));
|
||||
cv::Mat m = self->rec->getMat(key);
|
||||
|
||||
Local<Object> im = Matrix::constructor->GetFunction()->NewInstance();
|
||||
Matrix *img = ObjectWrap::Unwrap<Matrix>(im);
|
||||
img->mat = m;
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
|
||||
#endif // End version > 2.4
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "OpenCV.h"
|
||||
|
||||
#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4
|
||||
|
||||
#include "opencv2/contrib/contrib.hpp"
|
||||
|
||||
class FaceRecognizerWrap: public node::ObjectWrap {
|
||||
public:
|
||||
cv::Ptr<cv::FaceRecognizer> rec;
|
||||
int typ;
|
||||
|
||||
static Persistent<FunctionTemplate> constructor;
|
||||
static void Init(Handle<Object> target);
|
||||
static Handle<Value> New(const Arguments &args);
|
||||
|
||||
FaceRecognizerWrap(cv::Ptr<cv::FaceRecognizer> f, int type);
|
||||
|
||||
JSFUNC(CreateLBPH)
|
||||
JSFUNC(CreateEigen)
|
||||
JSFUNC(CreateFisher)
|
||||
|
||||
JSFUNC(TrainSync)
|
||||
//JSFUNC(Train)
|
||||
JSFUNC(UpdateSync)
|
||||
//JSFUNC(Update)
|
||||
|
||||
JSFUNC(PredictSync)
|
||||
// JSFUNC(Predict)
|
||||
//static void EIO_Predict(eio_req *req);
|
||||
//static int EIO_AfterPredict(eio_req *req);
|
||||
|
||||
|
||||
JSFUNC(SaveSync)
|
||||
JSFUNC(LoadSync)
|
||||
|
||||
JSFUNC(GetMat)
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "HighGUI.h"
|
||||
#include "OpenCV.h"
|
||||
#include "Matrix.h"
|
||||
|
||||
|
||||
Persistent<FunctionTemplate> NamedWindow::constructor;
|
||||
|
||||
void
|
||||
NamedWindow::Init(Handle<Object> target) {
|
||||
HandleScope scope;
|
||||
|
||||
// Constructor
|
||||
constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(NamedWindow::New));
|
||||
constructor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
constructor->SetClassName(String::NewSymbol("NamedWindow"));
|
||||
|
||||
// Prototype
|
||||
//Local<ObjectTemplate> proto = constructor->PrototypeTemplate();
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "show", Show);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "destroy", Destroy);
|
||||
NODE_SET_PROTOTYPE_METHOD(constructor, "blockingWaitKey", BlockingWaitKey);
|
||||
target->Set(String::NewSymbol("NamedWindow"), constructor->GetFunction());
|
||||
};
|
||||
|
||||
|
||||
Handle<Value>
|
||||
NamedWindow::New(const Arguments &args) {
|
||||
HandleScope scope;
|
||||
|
||||
if (args.This()->InternalFieldCount() == 0){
|
||||
JSTHROW_TYPE("Cannot Instantiate without new")
|
||||
}
|
||||
|
||||
NamedWindow* win;
|
||||
if (args.Length() == 1){
|
||||
win = new NamedWindow(std::string(*v8::String::AsciiValue(args[0]->ToString())), 0);
|
||||
} else if (args.Length() == 2){
|
||||
win = new NamedWindow(std::string(*v8::String::AsciiValue(args[0]->ToString())), 0);
|
||||
}
|
||||
|
||||
win->Wrap(args.Holder());
|
||||
return scope.Close(args.Holder());
|
||||
}
|
||||
|
||||
|
||||
NamedWindow::NamedWindow(const std::string& name, int f){
|
||||
winname = std::string(name);
|
||||
flags = f;
|
||||
cv::namedWindow(winname, flags);
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
NamedWindow::Show(const v8::Arguments& args){
|
||||
SETUP_FUNCTION(NamedWindow)
|
||||
Matrix *im = ObjectWrap::Unwrap<Matrix>(args[0]->ToObject());
|
||||
cv::imshow(self->winname, im->mat);
|
||||
|
||||
return scope.Close(args.Holder());
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
NamedWindow::Destroy(const v8::Arguments& args){
|
||||
SETUP_FUNCTION(NamedWindow)
|
||||
cv::destroyWindow(self->winname);
|
||||
return scope.Close(args.Holder());
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
NamedWindow::BlockingWaitKey(const v8::Arguments& args){
|
||||
HandleScope scope;
|
||||
//SETUP_FUNCTION(NamedWindow)
|
||||
int time = 0;
|
||||
|
||||
if (args.Length() > 1){
|
||||
time = args[1]->IntegerValue();
|
||||
}else{
|
||||
if (args.Length() > 0){
|
||||
time = args[0]->IntegerValue();
|
||||
}
|
||||
}
|
||||
|
||||
int res = cv::waitKey(time);
|
||||
|
||||
return scope.Close(Number::New(res));
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "OpenCV.h"
|
||||
|
||||
|
||||
class NamedWindow: public node::ObjectWrap {
|
||||
public:
|
||||
std::string winname;
|
||||
int flags;
|
||||
|
||||
|
||||
static Persistent<FunctionTemplate> constructor;
|
||||
static void Init(Handle<Object> target);
|
||||
static Handle<Value> New(const Arguments &args);
|
||||
|
||||
NamedWindow(const std::string& winname, int flags);
|
||||
|
||||
JSFUNC(Show);
|
||||
JSFUNC(Destroy);
|
||||
JSFUNC(BlockingWaitKey);
|
||||
|
||||
};
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
class Matrix: public node::ObjectWrap {
|
||||
public:
|
||||
|
||||
|
||||
cv::Mat mat;
|
||||
static Persistent<FunctionTemplate> constructor;
|
||||
static void Init(Handle<Object> target);
|
||||
static Handle<Value> New(const Arguments &args);
|
||||
Matrix();
|
||||
Matrix();
|
||||
Matrix(cv::Mat other, cv::Rect roi);
|
||||
Matrix(int rows, int cols);
|
||||
Matrix(int rows, int cols, int typ);
|
||||
@@ -28,25 +28,38 @@ class Matrix: public node::ObjectWrap {
|
||||
JSFUNC(Width)
|
||||
JSFUNC(Height)
|
||||
JSFUNC(Channels)
|
||||
|
||||
JSFUNC(Clone)
|
||||
JSFUNC(Ellipse)
|
||||
JSFUNC(Rectangle)
|
||||
JSFUNC(Line)
|
||||
JSFUNC(Empty)
|
||||
|
||||
JSFUNC(Save)
|
||||
JSFUNC(SaveAsync)
|
||||
|
||||
JSFUNC(ToBuffer)
|
||||
JSFUNC(ToBufferAsync)
|
||||
|
||||
JSFUNC(Resize)
|
||||
JSFUNC(Rotate)
|
||||
JSFUNC(PyrDown)
|
||||
JSFUNC(PyrUp)
|
||||
|
||||
JSFUNC(ConvertGrayscale)
|
||||
JSFUNC(ConvertHSVscale)
|
||||
JSFUNC(GaussianBlur)
|
||||
JSFUNC(Copy)
|
||||
JSFUNC(Flip)
|
||||
JSFUNC(ROI)
|
||||
JSFUNC(Ptr)
|
||||
JSFUNC(AbsDiff)
|
||||
JSFUNC(AddWeighted)
|
||||
JSFUNC(Split)
|
||||
JSFUNC(BitwiseXor)
|
||||
JSFUNC(CountNonZero)
|
||||
//JSFUNC(Split)
|
||||
JSFUNC(Canny)
|
||||
JSFUNC(Dilate)
|
||||
JSFUNC(Erode)
|
||||
|
||||
JSFUNC(FindContours)
|
||||
JSFUNC(DrawContour)
|
||||
@@ -56,6 +69,21 @@ class Matrix: public node::ObjectWrap {
|
||||
JSFUNC(GoodFeaturesToTrack)
|
||||
JSFUNC(HoughLinesP)
|
||||
|
||||
JSFUNC(inRange)
|
||||
|
||||
JSFUNC(LocateROI)
|
||||
JSFUNC(AdjustROI)
|
||||
|
||||
JSFUNC(Threshold)
|
||||
JSFUNC(MeanStdDev)
|
||||
|
||||
JSFUNC(CopyTo)
|
||||
JSFUNC(CvtColor)
|
||||
JSFUNC(Split)
|
||||
JSFUNC(Merge)
|
||||
JSFUNC(EqualizeHist)
|
||||
JSFUNC(Pixel)
|
||||
JSFUNC(FloodFill)
|
||||
/*
|
||||
static Handle<Value> Val(const Arguments& args);
|
||||
static Handle<Value> RowRange(const Arguments& args);
|
||||
@@ -77,16 +105,14 @@ class Matrix: public node::ObjectWrap {
|
||||
// create, increment, release
|
||||
static Handle<Value> PushBack(const Arguments& args);
|
||||
static Handle<Value> PopBack(const Arguments& args);
|
||||
static Handle<Value> LocateROI(const Arguments& args);
|
||||
static Handle<Value> AdjustROI(const Arguments& args);
|
||||
static Handle<Value> Total(const Arguments& args);
|
||||
static Handle<Value> IsContinous(const Arguments& args);
|
||||
static Handle<Value> Type(const Arguments& args);
|
||||
static Handle<Value> Depth(const Arguments& args);
|
||||
static Handle<Value> Channels(const Arguments& args);
|
||||
static Handle<Value> StepOne(const Arguments& args);
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
@@ -27,7 +27,22 @@ using namespace node;
|
||||
#define JSFUNC(NAME) \
|
||||
static Handle<Value> NAME(const Arguments& args);
|
||||
|
||||
#define JSTHROW_TYPE(ERR) \
|
||||
return v8::ThrowException(v8::Exception::TypeError(v8::String::New(ERR)));
|
||||
|
||||
#define JSTHROW(ERR) \
|
||||
return v8::ThrowException(v8::Exception::Error(v8::String::New(ERR)));
|
||||
|
||||
|
||||
#define INT_FROM_ARGS(NAME, IND) \
|
||||
if (args[IND]->IsInt32()){ \
|
||||
NAME = args[IND]->Uint32Value(); \
|
||||
}
|
||||
|
||||
#define DOUBLE_FROM_ARGS(NAME, IND) \
|
||||
if (args[IND]->IsInt32()){ \
|
||||
NAME = args[IND]->NumberValue(); \
|
||||
}
|
||||
|
||||
class OpenCV: public node::ObjectWrap{
|
||||
public:
|
||||
|
||||
@@ -46,7 +46,10 @@ VideoCaptureWrap::New(const Arguments &args) {
|
||||
|
||||
if (args[0]->IsNumber()){
|
||||
v = new VideoCaptureWrap(args[0]->NumberValue());
|
||||
} else {}
|
||||
} else {
|
||||
//TODO - assumes that we have string, verify
|
||||
v = new VideoCaptureWrap(std::string(*v8::String::AsciiValue(args[0]->ToString())));
|
||||
}
|
||||
|
||||
|
||||
v->Wrap(args.This());
|
||||
@@ -64,6 +67,16 @@ VideoCaptureWrap::VideoCaptureWrap(int device){
|
||||
}
|
||||
}
|
||||
|
||||
VideoCaptureWrap::VideoCaptureWrap(const std::string& filename){
|
||||
HandleScope scope;
|
||||
cap.open(filename);
|
||||
// TODO! At the moment this only takes a full path - do relative too.
|
||||
if(!cap.isOpened()){
|
||||
v8::ThrowException(v8::Exception::Error(String::New("Video file could not be opened (opencv reqs. non relative paths)")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Handle<Value>
|
||||
VideoCaptureWrap::Read(const Arguments &args) {
|
||||
@@ -79,7 +92,7 @@ VideoCaptureWrap::Read(const Arguments &args) {
|
||||
baton->im = new Matrix();
|
||||
baton->request.data = baton;
|
||||
|
||||
uv_queue_work(uv_default_loop(), &baton->request, AsyncRead, AfterAsyncRead);
|
||||
uv_queue_work(uv_default_loop(), &baton->request, AsyncRead, (uv_after_work_cb)AfterAsyncRead);
|
||||
return Undefined();
|
||||
|
||||
}
|
||||
@@ -103,11 +116,12 @@ void AfterAsyncRead(uv_work_t *req) {
|
||||
mat = baton->im->mat;
|
||||
|
||||
img->mat = mat;
|
||||
Local<Value> argv[1];
|
||||
Local<Value> argv[2];
|
||||
|
||||
argv[0] = im_to_return;
|
||||
argv[0] = Local<Value>::New(Null());
|
||||
argv[1] = im_to_return;
|
||||
|
||||
baton->cb->Call(Context::GetCurrent()->Global(), 1, argv);
|
||||
baton->cb->Call(Context::GetCurrent()->Global(), 2, argv);
|
||||
baton->cb.Dispose();
|
||||
|
||||
delete baton;
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "CascadeClassifierWrap.h"
|
||||
#include "VideoCaptureWrap.h"
|
||||
#include "Contours.h"
|
||||
#include "CamShift.h"
|
||||
#include "HighGUI.h"
|
||||
#include "FaceRecognizer.h"
|
||||
|
||||
|
||||
extern "C" void
|
||||
@@ -14,7 +17,14 @@ init(Handle<Object> target) {
|
||||
Matrix::Init(target);
|
||||
CascadeClassifierWrap::Init(target);
|
||||
VideoCaptureWrap::Init(target);
|
||||
Contour::Init(target);
|
||||
Contour::Init(target);
|
||||
TrackedObject::Init(target);
|
||||
NamedWindow::Init(target);
|
||||
|
||||
#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >=4
|
||||
FaceRecognizerWrap::Init(target);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
NODE_MODULE(opencv, init)
|
||||
|
||||
@@ -9,6 +9,16 @@ assertDeepSimilar = function(res, exp){
|
||||
assert.deepEqual(res, exp)
|
||||
}
|
||||
|
||||
assertWithinRange = function(res, exp, range){
|
||||
assert.ok((res - exp) < range || (res - exp) > -range, "Not within range:" + res + " (" + exp + "+- " + range + ")")
|
||||
}
|
||||
|
||||
assertWithinRanges = function(res, exp, range){
|
||||
for (var i =0; i<res.length; i++){
|
||||
assertWithinRange(res[i], exp[i], range);
|
||||
}
|
||||
}
|
||||
|
||||
vows.describe('Smoke Tests OpenCV').addBatch({
|
||||
"Importing": {
|
||||
|
||||
@@ -29,6 +39,13 @@ vows.describe('Smoke Tests OpenCV').addBatch({
|
||||
, '.Matrix imports': function(topic){
|
||||
assert.ok(!!topic.Matrix)
|
||||
}
|
||||
|
||||
, 'importing library multiple times is ok' : function(){
|
||||
var cv1 = require('../lib/opencv')
|
||||
, cv2 = require('../lib/opencv')
|
||||
cv1.readImage('./examples/mona.png', function(){});
|
||||
cv2.readImage('./examples/mona.png', function(){});
|
||||
}
|
||||
}
|
||||
|
||||
, "Point" : {
|
||||
@@ -137,6 +154,23 @@ vows.describe('Smoke Tests OpenCV').addBatch({
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
, "toBuffer Async": {
|
||||
topic: function(cv){
|
||||
var buf = fs.readFileSync('./examples/mona.png')
|
||||
, cb = this.callback
|
||||
cv.readImage(buf.slice(0), function(err, mat){
|
||||
var buff = mat.toBuffer(function(){
|
||||
cb.apply(this, arguments)
|
||||
})
|
||||
})
|
||||
}
|
||||
, 'gives a buffer' : function(e, res){
|
||||
assert.ok(!e)
|
||||
assert.ok(res);
|
||||
assert.ok(res.length > 100);
|
||||
}
|
||||
}
|
||||
|
||||
, "detectObject": {
|
||||
|
||||
@@ -145,7 +179,7 @@ vows.describe('Smoke Tests OpenCV').addBatch({
|
||||
, cb = this.callback
|
||||
|
||||
cv.readImage("./examples/mona.png", function(err, im){
|
||||
im.detectObject("./data/haarcascade_frontalface_alt.xml", {}, cb)
|
||||
im.detectObject(cv.FACE_CASCADE, {}, cb)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -156,7 +190,34 @@ vows.describe('Smoke Tests OpenCV').addBatch({
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
, ".absDiff and .countNonZero" : function(cv) {
|
||||
cv.readImage("./examples/mona.png", function(err, im) {
|
||||
cv.readImage("./examples/mona.png", function(err, im2){
|
||||
assert.ok(im);
|
||||
assert.ok(im2);
|
||||
|
||||
var diff = new cv.Matrix(im.width(), im.height());
|
||||
diff.absDiff(im, im2);
|
||||
|
||||
diff.convertGrayscale();
|
||||
assert.equal(diff.countNonZero(), 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
, ".bitwiseXor" : function(cv) {
|
||||
var mat1 = new cv.Matrix(1,1);
|
||||
mat1.set(0,0, 1);
|
||||
|
||||
var mat2 = new cv.Matrix(1,1);
|
||||
mat2.set(0,0, 1);
|
||||
|
||||
var xored = new cv.Matrix(1,1);
|
||||
xored.bitwiseXor(mat1, mat2);
|
||||
|
||||
assert.equal(xored.get(0,0), 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -216,12 +277,12 @@ vows.describe('Smoke Tests OpenCV').addBatch({
|
||||
}
|
||||
|
||||
|
||||
, "ImageStream" : {
|
||||
, "ImageDataStream" : {
|
||||
topic : require('../lib/opencv')
|
||||
|
||||
, "pipe" : {
|
||||
topic : function(cv){
|
||||
var s = new cv.ImageStream()
|
||||
var s = new cv.ImageDataStream()
|
||||
, self = this
|
||||
s.on('load', function(im){
|
||||
assert.ok(im)
|
||||
@@ -239,6 +300,56 @@ vows.describe('Smoke Tests OpenCV').addBatch({
|
||||
|
||||
|
||||
}
|
||||
, "ImageStream" :{
|
||||
topic : require('../lib/opencv')
|
||||
, "write" : {
|
||||
topic: function(cv){
|
||||
var s = new cv.ImageStream()
|
||||
, im = fs.readFileSync('./examples/mona.png')
|
||||
, self = this;
|
||||
|
||||
s.on('data', function(m){
|
||||
self.callback(null, m)
|
||||
})
|
||||
s.write(im);
|
||||
}
|
||||
, "receives data" : function(mat){
|
||||
assert.deepEqual(mat.size(), [756,500])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
, "ObjectDetectionStream" :{
|
||||
topic : require('../lib/opencv')
|
||||
|
||||
}
|
||||
|
||||
, "CamShift" : {
|
||||
|
||||
"Can Create and Track" : {
|
||||
topic : function(){
|
||||
var cv = require('../lib/opencv')
|
||||
, self = this
|
||||
|
||||
cv.readImage('./examples/coin1.jpg', function(e, im){
|
||||
cv.readImage('./examples/coin2.jpg', function(e, im2){
|
||||
self.callback(im, im2, cv)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
, "create TrackedObject" : function(im, im2, cv){
|
||||
var tracked = new cv.TrackedObject(im, [420, 110, 490, 170]);
|
||||
assert.ok(tracked);
|
||||
}
|
||||
|
||||
, "use TrackedObject.track" : function(im, im2, cv){
|
||||
var tracked = new cv.TrackedObject(im, [420, 110, 490, 170], {channel: 'v'});
|
||||
assertWithinRanges(tracked.track(im2), [386, 112, 459, 166], 10);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
im.calcHistograms(function(err, hist){})
|
||||
|
||||
im.calcHistograms(mask, function(err, hist){})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Face recognition TODO
|
||||
|
||||
|
||||
// Load Database
|
||||
// TODO<
|
||||
|
||||
|
||||
|
||||
cv.loadImage('test.jpg', function(err, im){
|
||||
im.detectObject("front-face.xml", {}, function(err, faces){
|
||||
_.each(faces, function(v){
|
||||
|
||||
// TODO {
|
||||
|
||||
var section = im.slice(v.x, v.y, v.x + v.width, v.y + v.height);
|
||||
section.convertGrayscale()
|
||||
section.resize(WID, HEIGHT);
|
||||
section.equaliseHistogram();
|
||||
|
||||
// } TODO
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----
|
||||
|
||||
|
||||
http://www.athile.net/library/wiki/index.php?title=Library/V8/Tutorial#Wrapping_a_Javascript_function_as_a_std::function.3C.3E
|
||||
|
||||
https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/
|
||||