Skip to content

Commit

Permalink
Add img_hash module with phash
Browse files Browse the repository at this point in the history
  • Loading branch information
ht-jo committed Oct 29, 2021
1 parent a0c9af9 commit ebe0daa
Show file tree
Hide file tree
Showing 18 changed files with 309 additions and 3 deletions.
5 changes: 4 additions & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@
"cc/features2d/detectors/SimpleBlobDetectorParams.cc",
"cc/xfeatures2d/xfeatures2d.cc",
# "cc/xfeatures2d/SIFTDetector.cc", https://github.com/justadudewhohacks/opencv4nodejs/issues/805#issuecomment-806314329
"cc/xfeatures2d/SURFDetector.cc"
"cc/xfeatures2d/SURFDetector.cc",
"cc/img_hash/img_hash.cc",
"cc/img_hash/ImgHashBase.cc",
"cc/img_hash/PHash.cc"
],

"cflags" : [
Expand Down
49 changes: 49 additions & 0 deletions cc/img_hash/ImgHashBase.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "opencv_modules.h"

#ifdef HAVE_OPENCV_IMG_HASH

#include "ImgHashBase.h"
#include "ImgHashBaseBindings.h"


void ImgHashBase::Init(v8::Local<v8::FunctionTemplate> ctor) {
Nan::SetPrototypeMethod(ctor, "compare", Compare);
Nan::SetPrototypeMethod(ctor, "compareAsync", CompareAsync);
Nan::SetPrototypeMethod(ctor, "compute", Compute);
Nan::SetPrototypeMethod(ctor, "computeAsync", ComputeAsync);
};

NAN_METHOD(ImgHashBase::Compare) {
FF::executeSyncBinding(
std::make_shared<ImgHashBaseBindings::CompareWorker>(ImgHashBase::unwrapThis(info)->getImgHashBase()),
"ImgHashBase::Compare",
info
);
}

NAN_METHOD(ImgHashBase::CompareAsync) {
FF::executeAsyncBinding(
std::make_shared<ImgHashBaseBindings::CompareWorker>(ImgHashBase::unwrapThis(info)->getImgHashBase()),
"ImgHashBase::CompareAsync",
info
);
}

NAN_METHOD(ImgHashBase::Compute) {
FF::executeSyncBinding(
std::make_shared<ImgHashBaseBindings::ComputeWorker>(ImgHashBase::unwrapThis(info)->getImgHashBase()),
"ImgHashBase::Compute",
info
);
}

NAN_METHOD(ImgHashBase::ComputeAsync) {
FF::executeAsyncBinding(
std::make_shared<ImgHashBaseBindings::ComputeWorker>(ImgHashBase::unwrapThis(info)->getImgHashBase()),
"ImgHashBase::ComputeAsync",
info
);
}


#endif
25 changes: 25 additions & 0 deletions cc/img_hash/ImgHashBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "NativeNodeUtils.h"
#include "Mat.h"
#include "Point.h"
#include "Rect.h"
#include "macros.h"
#include <iostream>
#include <opencv2/img_hash.hpp>


#ifndef __FF_IMGHASHBASE_H__
#define __FF_IMGHASHBASE_H__

class ImgHashBase : public FF::ObjectWrapBase<ImgHashBase>, public Nan::ObjectWrap {
public:
virtual cv::Ptr<cv::img_hash::ImgHashBase> getImgHashBase() = 0;

static void Init(v8::Local<v8::FunctionTemplate>);

static NAN_METHOD(Compare);
static NAN_METHOD(CompareAsync);
static NAN_METHOD(Compute);
static NAN_METHOD(ComputeAsync);
};

#endif
65 changes: 65 additions & 0 deletions cc/img_hash/ImgHashBaseBindings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "ImgHashBase.h"

#ifndef __FF_IMGHASHBASEBINDINGS_H_
#define __FF_IMGHASHBASEBINDINGS_H_

namespace ImgHashBaseBindings {

struct CompareWorker : public CatchCvExceptionWorker {
public:
cv::Ptr<cv::img_hash::ImgHashBase> self;
CompareWorker(cv::Ptr<cv::img_hash::ImgHashBase> self) { this->self = self; }

std::vector<uchar> hashOne;
std::vector<uchar> hashTwo;
double returnValue;

std::string executeCatchCvExceptionWorker() {
returnValue = self->compare(hashOne, hashTwo);
return "";
}

v8::Local<v8::Value> getReturnValue() {
v8::Local<v8::Value> ret = FF::DoubleConverter::wrap(returnValue);
return ret;
}

bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
return (FF::UcharArrayConverter::arg(0, &hashOne, info) ||
FF::UcharArrayConverter::arg(1, &hashTwo, info));
}
};

struct ComputeWorker : public CatchCvExceptionWorker {
public:
cv::Ptr<cv::img_hash::ImgHashBase> self;
ComputeWorker(cv::Ptr<cv::img_hash::ImgHashBase> self) { this->self = self; }

cv::Mat inputArr;
std::vector<uchar> outputArr;

std::string executeCatchCvExceptionWorker() {
self->compute(inputArr, outputArr);
return "";
}

v8::Local<v8::Value> getReturnValue() {
v8::Local<v8::Value> ret = FF::UcharArrayConverter::wrap(outputArr);
return ret;
}

bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
return (Mat::Converter::arg(0, &inputArr, info));
}

bool unwrapOptionalArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
return (FF::UcharArrayConverter::optArg(1, &outputArr, info));
}

};

}

#endif


34 changes: 34 additions & 0 deletions cc/img_hash/PHash.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "opencv_modules.h"

#ifdef HAVE_OPENCV_IMG_HASH

#include "PHash.h"

Nan::Persistent<v8::FunctionTemplate> PHash::constructor;

NAN_MODULE_INIT(PHash::Init)
{
v8::Local<v8::FunctionTemplate> ctor = Nan::New<v8::FunctionTemplate>(PHash::New);
v8::Local<v8::ObjectTemplate> instanceTemplate = ctor->InstanceTemplate();

ImgHashBase::Init(ctor);
constructor.Reset(ctor);
ctor->SetClassName(FF::newString("PHash"));
instanceTemplate->SetInternalFieldCount(1);

Nan::Set(target, FF::newString("PHash"), FF::getFunction(ctor));
};

NAN_METHOD(PHash::New)
{
FF::TryCatch tryCatch("PHash::New");
FF_ASSERT_CONSTRUCT_CALL();

PHash *self = new PHash();
self->Wrap(info.Holder());
self->imgHashBase = cv::img_hash::PHash::create();

info.GetReturnValue().Set(info.Holder());
};

#endif
17 changes: 17 additions & 0 deletions cc/img_hash/PHash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "ImgHashBase.h"

#ifndef __FF_PHASH_H__
#define __FF_PHASH_H__

class PHash : public ImgHashBase {
public:
cv::Ptr<cv::img_hash::ImgHashBase> imgHashBase;

static NAN_MODULE_INIT(Init);
static NAN_METHOD(New);

static Nan::Persistent<v8::FunctionTemplate> constructor;
cv::Ptr<cv::img_hash::ImgHashBase> getImgHashBase() { return imgHashBase; }
};

#endif
12 changes: 12 additions & 0 deletions cc/img_hash/img_hash.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "opencv_modules.h"

#ifdef HAVE_OPENCV_IMG_HASH

#include "img_hash.h"
#include "PHash.h"

NAN_MODULE_INIT(ImgHash::Init) {
PHash::Init(target);
};

#endif
13 changes: 13 additions & 0 deletions cc/img_hash/img_hash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "NativeNodeUtils.h"
#include "macros.h"
#include "opencv2/img_hash.hpp"

#ifndef __FF_IMGHASH_H__
#define __FF_IMGHASH_H__

class ImgHash {
public:
static NAN_MODULE_INIT(Init);
};

#endif
7 changes: 7 additions & 0 deletions cc/opencv4nodejs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
#ifdef HAVE_OPENCV_XIMGPROC
#include "ximgproc/ximgproc.h"
#endif
#ifdef HAVE_OPENCV_IMG_HASH
#include "img_hash/img_hash.h"
#endif

int customCvErrorHandler(int status, const char* func_name, const char* err_msg, const char* file_name, int line, void* userdata) {
std::string msg = "OpenCV Error: (" + std::string(err_msg) + ")"
Expand Down Expand Up @@ -133,6 +136,10 @@ void init(v8::Local<v8::Object> target) {
Nan::Set(modules, FF::newString("ximgproc"), Nan::New(true));
XImgproc::Init(target);
#endif
#ifdef HAVE_OPENCV_IMG_HASH
Nan::Set(modules, FF::newString("img_hash"), Nan::New(true));
ImgHash::Init(target);
#endif
};

NODE_MODULE(opencv4nodejs, init)
3 changes: 3 additions & 0 deletions cc/opencv_modules.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
#ifdef OPENCV4NODEJS_FOUND_LIBRARY_XIMGPROC
#define HAVE_OPENCV_XIMGPROC
#endif
#ifdef OPENCV4NODEJS_FOUND_LIBRARY_IMG_HASH
#define HAVE_OPENCV_IMG_HASH
#endif

#endif

Expand Down
2 changes: 2 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,5 @@ export * from './typings/SURFDetector.d';
export * from './typings/SuperpixelLSC.d';
export * from './typings/SuperpixelSLIC.d';
export * from './typings/SuperpixelSEEDS.d';
export * from './typings/ImgHashBase.d';
export * from './typings/PHash.d';
8 changes: 8 additions & 0 deletions lib/typings/ImgHashBase.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Mat } from "./Mat.d";

export class ImgHashBase {
compute(inputArr: Mat): string[];
computeAsync(inputArr: Mat): Promise<string[]>;
compare(hashOne: string[], hashTwo: string[]): number;
compareAsync(hashOne: string[], hashTwo: string[]): Promise<number>;
}
3 changes: 3 additions & 0 deletions lib/typings/PHash.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ImgHashBase } from "./ImgHashBase.d";

export class PHash extends ImgHashBase {}
1 change: 1 addition & 0 deletions lib/typings/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const xmodules: {
tracking: boolean;
xfeatures2d: boolean;
ximgproc: boolean;
img_hash: boolean;
}

export const version: {
Expand Down
1 change: 0 additions & 1 deletion test/requireCv.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@

// manipulate binary path for testing
//process.env.path = process.env.path.replace(process.env.OPENCV_BIN_DIR, process.env.OPENCV30_BIN_DIR);

module.exports = () => require('../');
41 changes: 41 additions & 0 deletions test/tests/img_hash/imgHashTests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { expect } = require('chai');

module.exports = ({ cv, utils, getTestImg }) => (ImgHash) => {

const {
generateAPITests,
clearTmpData,
getTmpDataFilePath,
cvVersionLowerThan
} = utils;

describe('constructor', () => {
it('is constructable without args', () => {
expect(() => new ImgHash()).to.not.throw();
});
});


describe.only('api tests', () => {
let imgHash;

before(() => {
imgHash = new ImgHash();
});

describe('compute', () => {
const expectOutput = (res) => {
expect(res).to.be.an('array');
};

generateAPITests({
getDut: () => imgHash,
methodName: 'compute',
methodNameSpace: 'ImgHashBase',
getRequiredArgs: () => [getTestImg().bgrToGray()],
expectOutput
});
});

});
};
19 changes: 19 additions & 0 deletions test/tests/img_hash/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const imgHashTestsFactory = require('./imgHashTests')

module.exports = ({ cv, utils, getTestImg }) => {

const {
cvVersionGreaterEqual
} = utils

const imgHashTests = imgHashTestsFactory({ cv, utils, getTestImg })

describe('ImgHash', () => {

describe('PHash', () => {
imgHashTests(cv.PHash);
});

});

};
7 changes: 6 additions & 1 deletion test/tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ const trackingTestSuite = require('./tracking')
const videoTestSuite = require('./video')
// const xfeatures2dTestSuite = require('./xfeatures2d')
const ximgprocTestSuite = require('./ximgproc')
const imgHashTestSuite = require('./img_hash')

const modules = [
'core', 'imgproc', 'calib3d', 'features2d', 'io',
'dnn', 'ml', 'objdetect', 'photo', 'video'
]

const xmodules = [
'face', 'text', 'tracking', 'xfeatures2d', 'ximgproc'
'face', 'text', 'tracking', 'xfeatures2d', 'ximgproc', 'img_hash'
]

describe('cv', () => {
Expand Down Expand Up @@ -147,4 +148,8 @@ describe('cv', () => {
describe('ximgproc', () => ximgprocTestSuite({ cv, utils, getTestImg }));
}

if (cv.modules.img_hash) {
describe('img_hash', () => imgHashTestSuite({ cv, utils, getTestImg }));
}

})

0 comments on commit ebe0daa

Please sign in to comment.