mirror of
https://github.com/peterbraden/node-opencv.git
synced 2025-12-08 19:45:55 +00:00
merge compare with piercus's master branch
This commit is contained in:
commit
6de971d0e8
@ -20,7 +20,8 @@
|
|||||||
"src/Calib3D.cc",
|
"src/Calib3D.cc",
|
||||||
"src/ImgProc.cc",
|
"src/ImgProc.cc",
|
||||||
"src/Stereo.cc",
|
"src/Stereo.cc",
|
||||||
"src/LDAWrap.cc"
|
"src/LDAWrap.cc",
|
||||||
|
"src/Histogram.cc",
|
||||||
],
|
],
|
||||||
|
|
||||||
"libraries": [
|
"libraries": [
|
||||||
|
|||||||
67
examples/calc-hist.js
Normal file
67
examples/calc-hist.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
var cv = require('../lib/opencv');
|
||||||
|
|
||||||
|
// (B)lue, (G)reen, (R)ed
|
||||||
|
var histSize = 256;
|
||||||
|
|
||||||
|
cv.readImage('./files/car1.jpg', function(err, im) {
|
||||||
|
if (err) throw err;
|
||||||
|
if (im.width() < 1 || im.height() < 1) throw new Error('Image has no size');
|
||||||
|
|
||||||
|
var bgrPlanes = im.split();
|
||||||
|
|
||||||
|
var size = 256,
|
||||||
|
range = [0, 256],
|
||||||
|
uniform = true,
|
||||||
|
histFile = 'files/chart2.png';
|
||||||
|
|
||||||
|
|
||||||
|
/// Compute a 3 dimension histogram
|
||||||
|
var hist64 = cv.histogram.calcHist( im, [0, 1, 2], [4, 4, 4], [[0, 256], [0, 256], [0, 256]], uniform);
|
||||||
|
|
||||||
|
/// Compute 3 histograms
|
||||||
|
var bHist = cv.histogram.calcHist( im, [0], [size], [range], uniform);
|
||||||
|
var gHist = cv.histogram.calcHist( im, [1], [size], [range], uniform);
|
||||||
|
var rHist = cv.histogram.calcHist( im, [2], [size], [range], uniform);
|
||||||
|
|
||||||
|
//////
|
||||||
|
// Uncommentand run `npm install chartjs-node` to draw the histogram !
|
||||||
|
///
|
||||||
|
/*
|
||||||
|
var ChartjsNode = require('chartjs-node');
|
||||||
|
var chartNode = new ChartjsNode(1200, 1200);
|
||||||
|
chartNode.drawChart({
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: bHist.map(function(a,i){return i.toString()}),
|
||||||
|
datasets : [{
|
||||||
|
data : bHist,
|
||||||
|
backgroundColor : "#4183c4",
|
||||||
|
borderColor : "#0c4b8a",
|
||||||
|
label : 'Blue'
|
||||||
|
},{
|
||||||
|
data : gHist,
|
||||||
|
backgroundColor : "#83c441",
|
||||||
|
borderColor : "#0c4b8a",
|
||||||
|
label : 'Green'
|
||||||
|
},{
|
||||||
|
data : rHist,
|
||||||
|
backgroundColor : "#c44183",
|
||||||
|
borderColor : "#0c4b8a",
|
||||||
|
label : 'Red'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'RGB Histograms'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).then(function(){
|
||||||
|
return chartNode.writeImageToFile('image/png', histFile);
|
||||||
|
}).then(function(){
|
||||||
|
console.log("result has been written in "+histFile)
|
||||||
|
}).catch(function(e){
|
||||||
|
console.log("error",e)
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
});
|
||||||
161
examples/emd.js
Normal file
161
examples/emd.js
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
var cv = require('../lib/opencv');
|
||||||
|
|
||||||
|
//
|
||||||
|
// Example of use of EMD distance using histograms
|
||||||
|
// 1. Build 2 histograms from images using calcHist
|
||||||
|
// 2. Transform each histogram to a 64 x 4 (hist, b, g, r) x 1 normalized signatures in BGR space
|
||||||
|
// 3. Compute the cost matrix (64 x 64 x 1), calculating the cost in LUV space
|
||||||
|
// 4. Run EMD algorithm
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Useful flatten function for step 2
|
||||||
|
|
||||||
|
function flatten(array, accu) {
|
||||||
|
if(!accu){
|
||||||
|
accu = [];
|
||||||
|
}
|
||||||
|
array.forEach(function(a){
|
||||||
|
if(Array.isArray(a)) {
|
||||||
|
flatten(a, accu)
|
||||||
|
} else {
|
||||||
|
accu.push(a)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return accu
|
||||||
|
};
|
||||||
|
|
||||||
|
cv.readImage('./files/car1.jpg', function(err, im1) {
|
||||||
|
if (err) throw err;
|
||||||
|
if (im1.width() < 1 || im1.height() < 1) throw new Error('Image has no size');
|
||||||
|
cv.readImage('./files/car2.jpg', function(err, im2) {
|
||||||
|
if (err) throw err;
|
||||||
|
if (im2.width() < 1 || im2.height() < 1) throw new Error('Image has no size');
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// 1. Build 2 histograms from images using calcHist
|
||||||
|
//////////////////
|
||||||
|
|
||||||
|
var size = [4, 4, 4],
|
||||||
|
channels = [0, 1, 2],
|
||||||
|
range = [[0, 256], [0, 256], [0, 256]],
|
||||||
|
uniform = true,
|
||||||
|
accumulate = true,
|
||||||
|
histFile = 'files/chart2.png';
|
||||||
|
|
||||||
|
/// Compute 64 (=4^3) histograms:
|
||||||
|
var firstImageHist64 = cv.histogram.calcHist(im1, channels, size, range, uniform);
|
||||||
|
var secondImageHist64 = cv.histogram.calcHist(im2, channels, size, range, uniform);
|
||||||
|
|
||||||
|
//////////////
|
||||||
|
// 2. Transform each histogram to a 64 x 4 (hist, b, g, r) x 1 normalized signatures in BGR space
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
var step = 256/4;
|
||||||
|
var halfStep = Math.round(step/2);
|
||||||
|
|
||||||
|
var sum1 = 0;
|
||||||
|
var sum2 = 0;
|
||||||
|
|
||||||
|
firstImageHist64.map(function(bHist, bIndex){
|
||||||
|
return bHist.map(function(bgHist, gIndex){
|
||||||
|
return bgHist.map(function(bgrHist, rIndex){
|
||||||
|
sum1 += bgrHist;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var sig1 = flatten(firstImageHist64.map(function(bHist, bIndex){
|
||||||
|
return bHist.map(function(bgHist, gIndex){
|
||||||
|
return bgHist.map(function(bgrHist, rIndex){
|
||||||
|
return {
|
||||||
|
data :[
|
||||||
|
[bgrHist/sum1],
|
||||||
|
[bIndex*step + halfStep],
|
||||||
|
[gIndex*step + halfStep],
|
||||||
|
[rIndex*step + halfStep]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})).map(function(a){
|
||||||
|
// trick to avoid flattening and get a 64 x 4 x 1 image as needed
|
||||||
|
return a.data;
|
||||||
|
});
|
||||||
|
|
||||||
|
secondImageHist64.map(function(bHist, bIndex){
|
||||||
|
return bHist.map(function(bgHist, gIndex){
|
||||||
|
return bgHist.map(function(bgrHist, rIndex){
|
||||||
|
sum2 += bgrHist;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var sig2 = flatten(secondImageHist64.map(function(bHist, bIndex){
|
||||||
|
return bHist.map(function(bgHist, gIndex){
|
||||||
|
return bgHist.map(function(bgrHist, rIndex){
|
||||||
|
return {
|
||||||
|
data : [
|
||||||
|
[bgrHist/sum2],
|
||||||
|
[bIndex*step + halfStep],
|
||||||
|
[gIndex*step + halfStep],
|
||||||
|
[rIndex*step + halfStep]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})).map(function(a){
|
||||||
|
// trick to avoid flattening and get a 64 x 4 x 1 image as needed
|
||||||
|
return a.data;
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// 3. Compute the cost matrix (64 x 64 x 1), calculating the cost in LUV space
|
||||||
|
/////////////
|
||||||
|
|
||||||
|
//middles is a 1 x 64 x 3 array of the middles positions in RGB used to change to LUV
|
||||||
|
var middles = [flatten(firstImageHist64.map(function(bHist, bIndex){
|
||||||
|
return bHist.map(function(bgHist, gIndex){
|
||||||
|
return bgHist.map(function(bgrHist, rIndex){
|
||||||
|
return {
|
||||||
|
data : [
|
||||||
|
bIndex*step + halfStep,
|
||||||
|
gIndex*step + halfStep,
|
||||||
|
rIndex*step + halfStep
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})).map(function(a){
|
||||||
|
// trick to avoid flattening and get a 1 x 64 x 3 image as needed
|
||||||
|
return a.data;
|
||||||
|
})];
|
||||||
|
|
||||||
|
var mat = cv.Matrix.fromArray(middles, cv.Constants.CV_8UC3);
|
||||||
|
mat.cvtColor("CV_BGR2Luv");
|
||||||
|
|
||||||
|
//luvValues is a 1 x 64 x 3 array of the middles positions in LUV
|
||||||
|
var luvMiddles = mat.toArray();
|
||||||
|
|
||||||
|
var distance = function(luv1, luv2){
|
||||||
|
return Math.sqrt((luv1[0]-luv2[0])*(luv1[0]-luv2[0]) + (luv1[1]-luv2[1])*(luv1[1]-luv2[1]) + (luv1[2]-luv2[2])*(luv1[2]-luv2[2]));
|
||||||
|
};
|
||||||
|
|
||||||
|
var costs = luvMiddles[0].map(function(luvMiddle1){
|
||||||
|
return luvMiddles[0].map(function(luvMiddle2){
|
||||||
|
return [distance(luvMiddle1, luvMiddle2)];
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
//////
|
||||||
|
// 4. Run EMD algorithm
|
||||||
|
/////
|
||||||
|
|
||||||
|
var matCosts = cv.Matrix.fromArray(costs, cv.Constants.CV_32FC1);
|
||||||
|
var matSig1 = cv.Matrix.fromArray(sig1, cv.Constants.CV_32FC1);
|
||||||
|
var matSig2 = cv.Matrix.fromArray(sig2, cv.Constants.CV_32FC1);
|
||||||
|
|
||||||
|
var dist = cv.Constants.CV_DIST_L2;
|
||||||
|
var emd = cv.histogram.emd(matSig1, matSig2, dist);//, matCosts);
|
||||||
|
console.log("EMD is ", emd)
|
||||||
|
});
|
||||||
|
});
|
||||||
20
examples/mat-array-conversion.js
Normal file
20
examples/mat-array-conversion.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
var cv = require('../lib/opencv');
|
||||||
|
|
||||||
|
cv.readImage("./files/mona.png", function(err, orig) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
var a = orig.toArray();
|
||||||
|
var type = orig.type();
|
||||||
|
var doubleConversion = cv.Matrix.fromArray(a, type).toArray();
|
||||||
|
|
||||||
|
for(var i = 0 ; i < a.length; i++){
|
||||||
|
for(var j = 0 ; j < a[i].length; j++){
|
||||||
|
for(var k = 0 ; k < a[i][j].length; k++){
|
||||||
|
if(a[i][j][k] !== doubleConversion[i][j][k]){
|
||||||
|
throw(new Error("double conversion is not equal to original"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
120
lib/opencv.js
120
lib/opencv.js
@ -1,7 +1,8 @@
|
|||||||
var Stream = require('stream').Stream
|
var Stream = require('stream').Stream
|
||||||
, Buffers = require('buffers')
|
, Buffers = require('buffers')
|
||||||
, util = require('util')
|
, util = require('util')
|
||||||
, path = require('path');
|
, path = require('path')
|
||||||
|
, os = require('os');
|
||||||
|
|
||||||
var cv = module.exports = require('./bindings');
|
var cv = module.exports = require('./bindings');
|
||||||
|
|
||||||
@ -33,6 +34,120 @@ Matrix.prototype.inspect = function(){
|
|||||||
return "[ Matrix " + size + " ]";
|
return "[ Matrix " + size + " ]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we use the Opencv constants naming convention to extract the number of bytes (8, 16, 32, 64), and the number of channels from constants names
|
||||||
|
var getNumberOfBytesAndChannelsPerType = function(type){
|
||||||
|
var regExp = /CV_([0-9]+)([A-Z]+)([0-9]+)/;
|
||||||
|
for(var k in cv.Constants) if(cv.Constants.hasOwnProperty(k) && k.match(regExp) && cv.Constants[k] === type){
|
||||||
|
var bytes, channels, dataType;
|
||||||
|
k.replace(regExp, function(all, b, l, c){
|
||||||
|
bytes = b;
|
||||||
|
channels = c;
|
||||||
|
dataType = l[0]
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
bytes : parseInt(bytes),
|
||||||
|
channels : !isNaN(parseInt(channels)) && parseInt(channels),
|
||||||
|
dataType : dataType,
|
||||||
|
label : k
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var getBufferMethodName = function(bytes, dataType, endianness, read){
|
||||||
|
var fnName;
|
||||||
|
|
||||||
|
if(read){
|
||||||
|
fnName = "read";
|
||||||
|
} else {
|
||||||
|
fnName = "write";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes === 32 && (dataType === "F" || dataType === "S")){
|
||||||
|
if(dataType === "F"){
|
||||||
|
fnName += "Float"+endianness;
|
||||||
|
} else {//dataType === "S"
|
||||||
|
fnName += "Int32"+endianness;
|
||||||
|
}
|
||||||
|
} else if(bytes === 8){
|
||||||
|
fnName += (dataType === "U" ? "U" : "")+"Int8";
|
||||||
|
} else if(bytes === 16){
|
||||||
|
fnName += (dataType === "U" ? "U" : "")+"Int16"+endianness;
|
||||||
|
} else {
|
||||||
|
throw("This matrix type (CV_"+bytes+dataType+") is not compatible with fromArray/toArray")
|
||||||
|
}
|
||||||
|
return fnName;
|
||||||
|
};
|
||||||
|
|
||||||
|
Matrix.fromArray = function(arr, type){
|
||||||
|
var n_bytes;
|
||||||
|
|
||||||
|
var bytesAndChannels = getNumberOfBytesAndChannelsPerType(type);
|
||||||
|
var bytes = bytesAndChannels.bytes;
|
||||||
|
var channels = bytesAndChannels.channels;
|
||||||
|
var dataType = bytesAndChannels.dataType;
|
||||||
|
var label = bytesAndChannels.label;
|
||||||
|
|
||||||
|
if(!Array.isArray(arr) ||!Array.isArray(arr[0]) || !Array.isArray(arr[0][0]) || (channels && arr[0][0].length !== channels)) {
|
||||||
|
throw(new Error("Input array must be a 3-level array/matrix with size rows x cols x channels corresponding to dataType ("+label+")"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!channels){
|
||||||
|
channels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows = arr.length;
|
||||||
|
var cols = arr[0].length;
|
||||||
|
|
||||||
|
var mat = new cv.Matrix(rows, cols, type);
|
||||||
|
|
||||||
|
var n_bytes = bytes/8;
|
||||||
|
var buf = new Buffer(rows * cols * channels * n_bytes);
|
||||||
|
|
||||||
|
buf.fill(0);
|
||||||
|
|
||||||
|
var fnName = getBufferMethodName(bytes, dataType, os.endianness(), false)
|
||||||
|
|
||||||
|
for(var i=0;i<rows * cols * channels;i++){
|
||||||
|
var c = i%channels;
|
||||||
|
var r = Math.floor(i/channels);
|
||||||
|
var y = r%cols;
|
||||||
|
var x = Math.floor(r/cols);
|
||||||
|
buf[fnName](arr[x][y][c], i*n_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat.put(buf);
|
||||||
|
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix.prototype.toArray = function(){
|
||||||
|
var size = this.size();
|
||||||
|
var buf = this.getData();
|
||||||
|
var type = this.type();
|
||||||
|
var bytesAndChannels = getNumberOfBytesAndChannelsPerType(type);
|
||||||
|
var bytes = bytesAndChannels.bytes;
|
||||||
|
var channels = bytesAndChannels.channels || this.channels();
|
||||||
|
var dataType = bytesAndChannels.dataType;
|
||||||
|
|
||||||
|
var n_bytes = bytes/8;
|
||||||
|
var fnName = getBufferMethodName(bytes, dataType, os.endianness(), true)
|
||||||
|
|
||||||
|
var res = []
|
||||||
|
for(var i = 0; i < size[0]; i++){
|
||||||
|
var row = [];
|
||||||
|
for(var j = 0; j < size[1]; j++){
|
||||||
|
var channelsValues = [];
|
||||||
|
for(var k = 0; k < channels; k++){
|
||||||
|
var index = (i*size[1]+j)*channels+k;
|
||||||
|
channelsValues.push(buf[fnName](index*n_bytes));
|
||||||
|
}
|
||||||
|
row.push(channelsValues);
|
||||||
|
}
|
||||||
|
res.push(row);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
ImageStream = cv.ImageStream = function(){
|
ImageStream = cv.ImageStream = function(){
|
||||||
this.writable = true;
|
this.writable = true;
|
||||||
@ -148,6 +263,3 @@ var CASCADES = {
|
|||||||
Object.keys(CASCADES).forEach(function(k){
|
Object.keys(CASCADES).forEach(function(k){
|
||||||
cv[k] = path.resolve(__dirname, '../data', CASCADES[k])
|
cv[k] = path.resolve(__dirname, '../data', CASCADES[k])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -96,6 +96,7 @@ void Constants::Init(Local<Object> target) {
|
|||||||
CONST_INT(CV_DIST_C);
|
CONST_INT(CV_DIST_C);
|
||||||
CONST_INT(CV_DIST_L1);
|
CONST_INT(CV_DIST_L1);
|
||||||
CONST_INT(CV_DIST_L2);
|
CONST_INT(CV_DIST_L2);
|
||||||
|
CONST_INT(CV_DIST_USER);
|
||||||
|
|
||||||
CONST_INT(CV_DIST_MASK_3);
|
CONST_INT(CV_DIST_MASK_3);
|
||||||
CONST_INT(CV_DIST_MASK_5);
|
CONST_INT(CV_DIST_MASK_5);
|
||||||
|
|||||||
135
src/Histogram.cc
Normal file
135
src/Histogram.cc
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include "Histogram.h"
|
||||||
|
#include "Matrix.h"
|
||||||
|
|
||||||
|
void Histogram::Init(Local<Object> target) {
|
||||||
|
Nan::Persistent<Object> inner;
|
||||||
|
Local<Object> obj = Nan::New<Object>();
|
||||||
|
inner.Reset(obj);
|
||||||
|
|
||||||
|
Nan::SetMethod(obj, "calcHist", CalcHist);
|
||||||
|
Nan::SetMethod(obj, "emd", Emd);
|
||||||
|
|
||||||
|
target->Set(Nan::New("histogram").ToLocalChecked(), obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
NAN_METHOD(Histogram::CalcHist) {
|
||||||
|
Nan::EscapableHandleScope scope;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Arg 0 is the image
|
||||||
|
Matrix* m0 = Nan::ObjectWrap::Unwrap<Matrix>(info[0]->ToObject());
|
||||||
|
cv::Mat inputImage = m0->mat;
|
||||||
|
|
||||||
|
// Arg 1 is the channel
|
||||||
|
Local<Array> nodeChannels = Local<Array>::Cast(info[1]->ToObject());
|
||||||
|
const unsigned int dims = nodeChannels->Length();
|
||||||
|
int channels[dims];
|
||||||
|
for (unsigned int i = 0; i < dims; i++) {
|
||||||
|
channels[i] = nodeChannels->Get(i)->IntegerValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arg 2 is histogram sizes in each dimension
|
||||||
|
Local<Array> nodeHistSizes = Local<Array>::Cast(info[2]->ToObject());
|
||||||
|
int histSize[dims];
|
||||||
|
for (unsigned int i = 0; i < dims; i++) {
|
||||||
|
histSize[i] = nodeHistSizes->Get(i)->IntegerValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arg 3 is array of the histogram bin boundaries in each dimension
|
||||||
|
Local<Array> nodeRanges = Local<Array>::Cast(info[3]->ToObject());
|
||||||
|
/// Set the ranges ( for B,G,R) )
|
||||||
|
float histRanges[dims][2];
|
||||||
|
const float* ranges[dims];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < dims; i++) {
|
||||||
|
Local<Array> nodeRange = Local<Array>::Cast(nodeRanges->Get(i)->ToObject());
|
||||||
|
float lower = nodeRange->Get(0)->NumberValue();
|
||||||
|
float higher = nodeRange->Get(1)->NumberValue();
|
||||||
|
histRanges[i][0] = lower;
|
||||||
|
histRanges[i][1] = higher;
|
||||||
|
ranges[i] = histRanges[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arg 4 is uniform flag
|
||||||
|
bool uniform = info[4]->BooleanValue();
|
||||||
|
|
||||||
|
// Make a mat to hold the result image
|
||||||
|
cv::Mat outputHist;
|
||||||
|
|
||||||
|
// Perform calcHist
|
||||||
|
cv::calcHist(&inputImage, 1, channels, cv::Mat(), outputHist, dims, histSize, ranges, uniform);
|
||||||
|
|
||||||
|
v8::Local<v8::Array> arr = Nan::New<Array>(histSize[0]);
|
||||||
|
|
||||||
|
if(dims < 1 || dims > 3){
|
||||||
|
return Nan::ThrowTypeError("OPENCV nodejs binding error : only dimensions from 1 to 3 are allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i=0; i < (unsigned int) histSize[0]; i++) {
|
||||||
|
if(dims <= 1){
|
||||||
|
arr->Set(i, Nan::New<Number>(outputHist.at<float>(i)));
|
||||||
|
} else {
|
||||||
|
v8::Local<v8::Array> arr2 = Nan::New<Array>(dims);
|
||||||
|
for (unsigned int j=0; j < (unsigned int) histSize[1]; j++) {
|
||||||
|
if(dims <= 2){
|
||||||
|
arr2->Set(j, Nan::New<Number>(outputHist.at<float>(i,j)));
|
||||||
|
} else {
|
||||||
|
v8::Local<v8::Array> arr3 = Nan::New<Array>(dims);
|
||||||
|
for (unsigned int k=0; k < (unsigned int) histSize[1]; k++) {
|
||||||
|
arr3->Set(k, Nan::New<Number>(outputHist.at<float>(i,j,k)));
|
||||||
|
}
|
||||||
|
arr2->Set(j, arr3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr->Set(i, arr2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(arr);
|
||||||
|
} catch (cv::Exception &e) {
|
||||||
|
const char *err_msg = e.what();
|
||||||
|
Nan::ThrowError(err_msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cv::distanceTransform
|
||||||
|
NAN_METHOD(Histogram::Emd) {
|
||||||
|
Nan::EscapableHandleScope scope;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Arg 0 is the first signature
|
||||||
|
//std::vector<std::vector<float>> sig1 = nodeArrayToVec(info[0]->ToObject());
|
||||||
|
Matrix* m0 = Nan::ObjectWrap::Unwrap<Matrix>(info[0]->ToObject());
|
||||||
|
cv::Mat sig1 = m0->mat;
|
||||||
|
|
||||||
|
// Arg 1 is the second signature
|
||||||
|
//std::vector<std::vector<float>> sig2 = nodeArrayToVec(info[1]->ToObject());
|
||||||
|
Matrix* m1 = Nan::ObjectWrap::Unwrap<Matrix>(info[1]->ToObject());
|
||||||
|
cv::Mat sig2 = m1->mat;
|
||||||
|
|
||||||
|
// Arg 2 is the distance type
|
||||||
|
int distType = info[2]->IntegerValue();
|
||||||
|
|
||||||
|
float emd;
|
||||||
|
|
||||||
|
// Arg 3 is the cost matrix
|
||||||
|
if (info.Length() > 3) {
|
||||||
|
Matrix* m3 = Nan::ObjectWrap::Unwrap<Matrix>(info[3]->ToObject());
|
||||||
|
cv::Mat costs = m3->mat;
|
||||||
|
|
||||||
|
emd = cv::EMD(sig1, sig2, distType, costs);
|
||||||
|
info.GetReturnValue().Set(emd);
|
||||||
|
} else {
|
||||||
|
emd = cv::EMD(sig1, sig2, distType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("similarity %5.5f %%\n, DistanceType is %i\n", (1-emd)*100, distType);
|
||||||
|
info.GetReturnValue().Set(emd);
|
||||||
|
|
||||||
|
} catch (cv::Exception &e) {
|
||||||
|
const char *err_msg = e.what();
|
||||||
|
Nan::ThrowError(err_msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Histogram.h
Normal file
16
src/Histogram.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef __NODE_HISTOGRAM_H
|
||||||
|
#define __NODE_HISTOGRAM_H
|
||||||
|
|
||||||
|
#include "OpenCV.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of histogram.hpp functions
|
||||||
|
*/
|
||||||
|
class Histogram: public Nan::ObjectWrap {
|
||||||
|
public:
|
||||||
|
static void Init(Local<Object> target);
|
||||||
|
static NAN_METHOD(CalcHist);
|
||||||
|
static NAN_METHOD(Emd);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -117,6 +117,7 @@ void Matrix::Init(Local<Object> target) {
|
|||||||
Nan::SetPrototypeMethod(ctor, "release", Release);
|
Nan::SetPrototypeMethod(ctor, "release", Release);
|
||||||
Nan::SetPrototypeMethod(ctor, "subtract", Subtract);
|
Nan::SetPrototypeMethod(ctor, "subtract", Subtract);
|
||||||
Nan::SetPrototypeMethod(ctor, "compare", Compare);
|
Nan::SetPrototypeMethod(ctor, "compare", Compare);
|
||||||
|
Nan::SetPrototypeMethod(ctor, "mul", Mul);
|
||||||
|
|
||||||
target->Set(Nan::New("Matrix").ToLocalChecked(), ctor->GetFunction());
|
target->Set(Nan::New("Matrix").ToLocalChecked(), ctor->GetFunction());
|
||||||
};
|
};
|
||||||
@ -2853,7 +2854,23 @@ NAN_METHOD(Matrix::Compare) {
|
|||||||
cv::Mat res = cv::Mat(width, height, CV_8UC1);
|
cv::Mat res = cv::Mat(width, height, CV_8UC1);
|
||||||
|
|
||||||
cv::compare(self->mat, other->mat, res, cmpop);
|
cv::compare(self->mat, other->mat, res, cmpop);
|
||||||
|
Local<Object> out = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||||
|
Matrix *m_out = Nan::ObjectWrap::Unwrap<Matrix>(out);
|
||||||
|
m_out->mat = res;
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NAN_METHOD(Matrix::Mul) {
|
||||||
|
SETUP_FUNCTION(Matrix)
|
||||||
|
|
||||||
|
if (info.Length() < 1) {
|
||||||
|
Nan::ThrowTypeError("Invalid number of arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix *other = Nan::ObjectWrap::Unwrap<Matrix>(info[0]->ToObject());
|
||||||
|
|
||||||
|
cv::Mat res = self->mat.mul(other->mat);
|
||||||
Local<Object> out = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
Local<Object> out = Nan::NewInstance(Nan::GetFunction(Nan::New(Matrix::constructor)).ToLocalChecked()).ToLocalChecked();
|
||||||
Matrix *m_out = Nan::ObjectWrap::Unwrap<Matrix>(out);
|
Matrix *m_out = Nan::ObjectWrap::Unwrap<Matrix>(out);
|
||||||
m_out->mat = res;
|
m_out->mat = res;
|
||||||
|
|||||||
@ -135,6 +135,7 @@ public:
|
|||||||
|
|
||||||
JSFUNC(Subtract)
|
JSFUNC(Subtract)
|
||||||
JSFUNC(Compare)
|
JSFUNC(Compare)
|
||||||
|
JSFUNC(Mul)
|
||||||
/*
|
/*
|
||||||
static Handle<Value> Val(const Arguments& info);
|
static Handle<Value> Val(const Arguments& info);
|
||||||
static Handle<Value> RowRange(const Arguments& info);
|
static Handle<Value> RowRange(const Arguments& info);
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
#include "Stereo.h"
|
#include "Stereo.h"
|
||||||
#include "BackgroundSubtractor.h"
|
#include "BackgroundSubtractor.h"
|
||||||
#include "LDAWrap.h"
|
#include "LDAWrap.h"
|
||||||
|
#include "Histogram.h"
|
||||||
|
|
||||||
extern "C" void init(Local<Object> target) {
|
extern "C" void init(Local<Object> target) {
|
||||||
Nan::HandleScope scope;
|
Nan::HandleScope scope;
|
||||||
@ -30,6 +31,7 @@ extern "C" void init(Local<Object> target) {
|
|||||||
Constants::Init(target);
|
Constants::Init(target);
|
||||||
Calib3D::Init(target);
|
Calib3D::Init(target);
|
||||||
ImgProc::Init(target);
|
ImgProc::Init(target);
|
||||||
|
Histogram::Init(target);
|
||||||
#if CV_MAJOR_VERSION < 3
|
#if CV_MAJOR_VERSION < 3
|
||||||
StereoBM::Init(target);
|
StereoBM::Init(target);
|
||||||
StereoSGBM::Init(target);
|
StereoSGBM::Init(target);
|
||||||
|
|||||||
34
test/unit.js
34
test/unit.js
@ -398,15 +398,16 @@ test('Mean', function(assert) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Compare', function(assert) {
|
test('Compare', function(assert) {
|
||||||
var b = new cv.Matrix.Zeros(2, 2, cv.Constants.CV_8UC1);
|
var a = cv.Matrix.fromArray([[[0],[-20]],[[2],[-18]]], cv.Constants.CV_8SC1);
|
||||||
var a = new cv.Matrix.Zeros(2, 2, cv.Constants.CV_8UC1);
|
var b = cv.Matrix.fromArray([[[3],[-20]],[[0],[-16]]], cv.Constants.CV_8SC1);
|
||||||
|
|
||||||
a.set(0, 0, 3);
|
var compare1 = a.compare(b, cv.Constants.CMP_EQ);
|
||||||
|
var compare2 = a.compare(b, cv.Constants.CMP_GT);
|
||||||
|
var compare3 = a.compare(b, cv.Constants.CMP_LE);
|
||||||
|
|
||||||
var compare = a.compare(b, cv.Constants.CMP_EQ);
|
assert.deepEqual(compare1.toArray(), [[[0],[255]],[[0],[0]]]);
|
||||||
var buf = compare.getData();
|
assert.deepEqual(compare2.toArray(), [[[0],[0]],[[255],[0]]]);
|
||||||
compare.save("./test.png");
|
assert.deepEqual(compare3.toArray(), [[[255],[255]],[[0],[255]]]);
|
||||||
console.log(compare.norm());
|
|
||||||
|
|
||||||
assert.end();
|
assert.end();
|
||||||
});
|
});
|
||||||
@ -463,5 +464,24 @@ test('setColor works will alpha channels', function(assert) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('toArray/fromArray working in both ways', function(assert) {
|
||||||
|
var cv = require('../lib/opencv');
|
||||||
|
|
||||||
|
cv.readImage("./examples/files/mona.png", function(err, orig) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
var a = orig.toArray();
|
||||||
|
var type = orig.type();
|
||||||
|
var doubleConversion = cv.Matrix.fromArray(a, type).toArray();
|
||||||
|
|
||||||
|
var randomI = Math.floor(Math.random()*a.length)
|
||||||
|
var randomJ = Math.floor(Math.random()*a[randomI].length)
|
||||||
|
var randomK = Math.floor(Math.random()*a[randomI][randomJ].length)
|
||||||
|
|
||||||
|
assert.equal(a[randomI][randomJ][randomK], doubleConversion[randomI][randomJ][randomK]);
|
||||||
|
assert.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Test the examples folder.
|
// Test the examples folder.
|
||||||
require('./examples')()
|
require('./examples')()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user