Opencv Node Addon
Opencv 装置运用
下载Opencv装置包: http://opencv.org/releases.html
解压进入Opencv目次
编译Opencv(须要cmake)
mkdir release
cd release
cmake -G "Unix Makefiles" .. (为Unix 系统生成Makefile,Mac OSX是基于Unix的。未装置cmake 能够经由过程Homebrew装置,未装置Homebrew需装置Homebrew)
make
装置Opencv
make install
装置完成的目次
/usr/local/lib (Opencv库文件)
/usr/local/include (Opencv头文件)
/usr/local/share/ (Opencv xml配置文件)
运用Opencv(C++ Version)
编写CMakeLists.txt文件
project( ORBFeatureAndCompare ) // 项目的称号 cmake_minimum_required(VERSION 2.8) // cmake的版本请求 find_package( OpenCV REQUIRED ) // 查找对应的Opencv依靠库 find_package(Boost COMPONENTS log log_setup thread filesystem system) // 查找对应的Boost依靠库(下文涌现Boost的装置要领) add_executable( ORBFeatureAndCompare ORBFeatureAndCompare ) // 指定可运转的文件 // 引入对应的依靠库文件的位置 target_link_libraries(ORBFeatureAndCompare ${OpenCV_LIBS} ${Boost_LOG_SETUP_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} )
编写Opencv的cpp文件
//必要的头文件 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/features2d/features2d.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> #include <iostream> #include <fstream> #include <cstring> #include <iterator> #include <vector> using namespace boost::filesystem; namespace newfs = boost::filesystem; using namespace cv; using namespace std; int main () { .... return 0; }
建立一个images(其他定名都能够)的资本文件夹
cd images cmake .. make ./ORBFeatureAndCompare //编译出的可执行顺序
装置运用Boost举行数据序列化
下载Boost装置包: https://dl.bintray.com/boosto…
解压进入Boost目次
编译装置Boost
./bootstrap.sh
./b2
引入Boost库举行数据序列化,同样是在CmakeList中引入文件途径, 在cpp文件中运用
封装cpp顺序为Node Addon
依靠装置
全局装置node-gyp
当地装置nan
编写binding.gyp
{ "targets": [ { "target_name": "feature", "sources": [ "./src/feature.cc" ], "include_dirs": [ "<!(node -e \"require('nan')\")", "/usr/local/include/boost", "/usr/local/include/opencv2" ], "conditions": [ [ "OS==\"linux\" or OS==\"freebsd\" or OS==\"openbsd\" or OS==\"solaris\" or OS==\"aix\"", { } ], ["OS==\"mac\"", { "libraries": [ "/usr/local/lib/libboost_log_setup-mt.dylib", "/usr/local/lib/libboost_log-mt.dylib", "/usr/local/lib/libboost_filesystem-mt.dylib", "/usr/local/lib/libboost_thread-mt.dylib", "/usr/local/lib/libboost_system-mt.dylib", "/usr/local/lib/libopencv_core.3.2.0.dylib", "/usr/local/lib/libopencv_highgui.3.2.0.dylib", "/usr/local/lib/libopencv_imgproc.3.2.0.dylib", "/usr/local/lib/libopencv_features2d.3.2.0.dylib" ] } ] ] } ] }
编写node c++ 插件
#include <node.h>
#include <nan.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <vector>
using namespace boost::filesystem;
namespace newfs = boost::filesystem;
using namespace v8;
using namespace std;
vector<uchar> matToString(cv::Mat descriptorMat) {
vector<uchar> buf;
imencode(".png", descriptorMat, buf);
return buf;
}
vector<uchar> descriptorMat(cv::Mat image) {
vector<cv::KeyPoint> keyPoint;
cv::Ptr<cv::ORB> orb = cv::ORB::create(4000, 1.2f, 8, 31, 0, 2, cv::ORB::HARRIS_SCORE, 31, 20);
orb->detect(image, keyPoint);
cv::Mat descriptorMat;
orb->compute(image, keyPoint, descriptorMat);
return matToString(descriptorMat);
}
void imageFeature(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 1) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong number of arguments")));
return;
}
if (!args[0]->IsString()) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong arguments")));
return;
}
String::Utf8Value pathValue(Local<String>::Cast(args[0]));
string path = string(*pathValue);
cv::Mat image = cv::imread(path, 1);
if (image.empty()) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Input image error")));
return;
}
vector<uchar> descriptorString = descriptorMat(image);
Local<Object> buf = Nan::NewBuffer(descriptorString.size()).ToLocalChecked();
uchar* data = (uchar*) node::Buffer::Data(buf);
memcpy(data, &descriptorString[0], descriptorString.size());
v8::Local<v8::Object> globalObj = Nan::GetCurrentContext()->Global();
v8::Local<v8::Function> bufferConstructor = v8::Local<v8::Function>::Cast(globalObj->Get(Nan::New<String>("Buffer").ToLocalChecked()));
v8::Local<v8::Value> constructorArgs[3] = {buf, Nan::New<v8::Integer>((unsigned)descriptorString.size()), Nan::New<v8::Integer>(0)};
v8::Local<v8::Object> actualBuffer = bufferConstructor->NewInstance(3, constructorArgs);
args.GetReturnValue().Set(actualBuffer);
}
int bfMatcherCompare (cv::Mat &descriptors1, cv::Mat &descriptors2) {
cv::BFMatcher matcher(cv::NORM_HAMMING);
vector<cv::DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);
double max_dist = 0;
double min_dist = 100;
/*
for (int i = 0; i < descriptors1.rows; i++)
{
double dist = matches[i].distance;
if (dist < min_dist)
min_dist = dist;
if (dist > max_dist)
max_dist = dist;
}
vector<cv::DMatch> good_matches;
for (int i = 0; i < descriptors1.rows; i++)
{
if (matches[i].distance < 3 * min_dist)
good_matches.push_back(matches[i]);
}
return good_matches.size();
*/
for (int i = 0; i < descriptors1.rows; i++) {
double dist = matches[i].distance;
if (dist < min_dist) {
min_dist = dist;
}
if (dist > max_dist) {
max_dist = dist;
}
}
std::vector<cv::DMatch> good_matches;
double good_matches_sum = 0.0;
for (int i = 0; i < descriptors1.rows; i++) {
double distance = matches[i].distance;
if (distance <= std::max(2 * min_dist, 0.02)) {
good_matches.push_back(matches[i]);
good_matches_sum += distance;
}
}
return (double) good_matches_sum / (double) good_matches.size();
}
void similarity(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Object> arg1 = args[0]->ToObject();
int size1 = args[1]->NumberValue();
Local<Object> arg2 = args[2]->ToObject();
int size2 = args[3]->NumberValue();
if (args.Length() < 4) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong number of arguments")));
return;
}
uchar*buffer1 = (uchar*) node::Buffer::Data(arg1);
std::vector<uchar> vec1(buffer1, buffer1 + (unsigned int) size1);
cv::Mat img_decode1;
img_decode1 = cv::imdecode(vec1, CV_8U);
uchar*buffer2 = (uchar*) node::Buffer::Data(arg2);
std::vector<uchar> vec2(buffer2, buffer2 + (unsigned int) size2);
cv::Mat img_decode2;
img_decode2 = cv::imdecode(vec2, CV_8U);
int similarity = bfMatcherCompare(img_decode1, img_decode2);
args.GetReturnValue().Set(similarity);
}
void init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(exports, "imageFeature", imageFeature);
NODE_SET_METHOD(exports, "similarity", similarity);
}
NODE_MODULE(addon, init)
编写Js文件
const feature = require('./build/Release/feature');
exports.getImageFeature = (filePath) => {
return feature.imageFeature(filePath).toString('utf8');
};
exports.getImageSimilarity = (descriptor1, descriptor2) => {
let matBuffer1 = Buffer.from(descriptor1);
let matBuffer2 = Buffer.from(descriptor2);
return feature.similarity(matBuffer1, matBuffer1.length, matBuffer2, matBuffer2.length);
};
编译运转
node-gyp configure build
node test.js