Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit 2395aa4

Browse files
committed
ADD: knnMatch and knnMatch to BFMatcher
ADD: more tests to BFMatcher
1 parent c94691c commit 2395aa4

File tree

5 files changed

+169
-5
lines changed

5 files changed

+169
-5
lines changed

cc/modules/features2d/BFMatcher.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ NAN_MODULE_INIT(BFMatcher::Init) {
1717

1818
Nan::SetPrototypeMethod(ctor, "match", match);
1919
Nan::SetPrototypeMethod(ctor, "matchAsync", matchAsync);
20+
Nan::SetPrototypeMethod(ctor, "knnMatch", knnMatch);
21+
Nan::SetPrototypeMethod(ctor, "knnMatchAsync", knnMatchAsync);
2022

2123
target->Set(Nan::New("BFMatcher").ToLocalChecked(), ctor->GetFunction());
2224
};
@@ -57,8 +59,24 @@ NAN_METHOD(BFMatcher::match) {
5759
NAN_METHOD(BFMatcher::matchAsync) {
5860
FF::AsyncBinding(
5961
std::make_shared<BFMatcherBindings::MatchWorker>(BFMatcher::Converter::unwrap(info.This())),
60-
"FeatureDetector::matchAsync",
62+
"BFMatcher::matchAsync",
6163
info
6264
);
6365
}
6466

67+
NAN_METHOD(BFMatcher::knnMatch) {
68+
FF::SyncBinding(
69+
std::make_shared<BFMatcherBindings::MatchKnnWorker>(BFMatcher::Converter::unwrap(info.This())),
70+
"BFMatcher::knnMatch",
71+
info
72+
);
73+
}
74+
75+
76+
NAN_METHOD(BFMatcher::knnMatchAsync) {
77+
FF::AsyncBinding(
78+
std::make_shared<BFMatcherBindings::MatchKnnWorker>(BFMatcher::Converter::unwrap(info.This())),
79+
"BFMatcher::knnMatchAsync",
80+
info
81+
);
82+
}

cc/modules/features2d/BFMatcher.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class BFMatcher : public Nan::ObjectWrap {
3030
static NAN_METHOD(New);
3131
static NAN_METHOD(match);
3232
static NAN_METHOD(matchAsync);
33+
static NAN_METHOD(knnMatch);
34+
static NAN_METHOD(knnMatchAsync);
3335

3436
static const char* getClassName() {
3537
return "BFMatcher";

cc/modules/features2d/BFMatcherBindings.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,37 @@ struct MatchWorker : public CatchCvExceptionWorker {
3232
return ObjectArrayConverter<DescriptorMatch, cv::DMatch>::wrap(dmatches);
3333
}
3434
};
35+
36+
37+
struct MatchKnnWorker : public CatchCvExceptionWorker {
38+
public:
39+
cv::BFMatcher bfmatcher;
40+
41+
MatchKnnWorker(cv::BFMatcher _bfmatcher) {
42+
this->bfmatcher = _bfmatcher;
43+
}
44+
45+
cv::Mat descFrom;
46+
cv::Mat descTo;
47+
int k;
48+
std::vector<std::vector<cv::DMatch>> dmatches;
49+
50+
std::string executeCatchCvExceptionWorker() {
51+
bfmatcher.knnMatch(descFrom, descTo, dmatches, k);
52+
return "";
53+
}
54+
55+
bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
56+
return Mat::Converter::arg(0, &descFrom, info)
57+
|| Mat::Converter::arg(1, &descTo, info)
58+
|| IntConverter::arg(2, &k, info);
59+
}
60+
61+
FF_VAL getReturnValue() {
62+
return ObjectArrayOfArraysConverter<DescriptorMatch, cv::DMatch>::wrap(dmatches);
63+
}
64+
};
65+
3566
}
3667

3768
#endif

examples/matchFeatures.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,13 @@ const orbMatchesImg = matchFeatures({
5151
});
5252
cv.imshowWait('ORB matches', orbMatchesImg);
5353

54+
// Match using the BFMatcher with crossCheck true
55+
const bf = new cv.BFMatcher(cv.NORM_L2, true);
56+
const orbBFMatchIMG = matchFeatures({
57+
img1,
58+
img2,
59+
detector: new cv.ORBDetector(),
60+
matchFunc: (desc1, desc2) => bf.match(desc1, desc2)
61+
});
62+
cv.imshowWait('ORB with BFMatcher - crossCheck true', orbBFMatchIMG);
63+

test/tests/modules/features2d/BFMatcherTests.js

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,19 @@ module.exports = (getTestImg) => {
2727
});
2828
});
2929

30-
describe('match', () => {
30+
describe('crossCheck match', () => {
3131
let BFMatcher;
32+
let crossCheck = true;
3233

3334
before(() => {
34-
BFMatcher = new cv.BFMatcher(cv.NORM_L2, true);
35+
BFMatcher = new cv.BFMatcher(cv.NORM_L2, crossCheck);
3536

3637
const kaze = new cv.KAZEDetector();
3738
kazeKps = kaze.detect(getTestImg());
3839
kazeDesc = kaze.compute(getTestImg(), kazeKps);
3940
});
4041

41-
describe('matchBruteForce', () => {
42+
describe('match', () => {
4243
it('sync', () => {
4344
const matches = BFMatcher.match(kazeDesc, kazeDesc);
4445
expect(kazeKps.length).to.be.above(0);
@@ -47,14 +48,116 @@ module.exports = (getTestImg) => {
4748
});
4849

4950
it('async', (done) => {
50-
cv.matchBruteForceAsync(kazeDesc, kazeDesc, (err, matches) => {
51+
BFMatcher.matchAsync(kazeDesc, kazeDesc, (err, matches) => {
5152
expect(kazeKps.length).to.be.above(0);
5253
expect(matches).to.be.an('array').lengthOf(kazeKps.length);
5354
matches.forEach(match => expect(match).instanceOf(cv.DescriptorMatch));
5455
done();
5556
});
5657
});
5758
});
59+
60+
describe('knnMatch', () => {
61+
let k = 1; //k can only be 1 if crossCheck is true
62+
63+
it('sync', () => {
64+
const matches = BFMatcher.knnMatch(kazeDesc, kazeDesc, k);
65+
expect(kazeKps.length).to.be.above(0);
66+
expect(matches).to.be.an('array').lengthOf(kazeKps.length);
67+
68+
// if crossCheck is true, there can be points with no matches (empty arrays)
69+
const matchesKnn = matches.filter(el => el.length);
70+
matchesKnn.forEach(
71+
match => (
72+
expect(match).to.be.an('array').lengthOf(k)
73+
&&
74+
expect(match[0]).instanceOf(cv.DescriptorMatch)
75+
)
76+
);
77+
});
78+
79+
it('async', (done) => {
80+
BFMatcher.knnMatchAsync(kazeDesc, kazeDesc, k, (err, matches) => {
81+
expect(kazeKps.length).to.be.above(0);
82+
expect(matches).to.be.an('array').lengthOf(kazeKps.length);
83+
84+
// if crossCheck is true, there can be points with no matches (empty arrays)
85+
const matchesKnn = matches.filter(el => el.length);
86+
matchesKnn.forEach(
87+
match => (
88+
expect(match).to.be.an('array').lengthOf(k)
89+
&&
90+
expect(match[0]).instanceOf(cv.DescriptorMatch)
91+
)
92+
);
93+
done();
94+
});
95+
});
96+
});
5897
});
98+
99+
describe('no crossCheck match', () => {
100+
let BFMatcher;
101+
let crossCheck = false;
102+
103+
before(() => {
104+
BFMatcher = new cv.BFMatcher(cv.NORM_L2, crossCheck);
105+
106+
const kaze = new cv.KAZEDetector();
107+
kazeKps = kaze.detect(getTestImg());
108+
kazeDesc = kaze.compute(getTestImg(), kazeKps);
109+
});
110+
111+
describe('match', () => {
112+
it('sync', () => {
113+
const matches = BFMatcher.match(kazeDesc, kazeDesc);
114+
expect(kazeKps.length).to.be.above(0);
115+
expect(matches).to.be.an('array').lengthOf(kazeKps.length);
116+
matches.forEach(match => expect(match).instanceOf(cv.DescriptorMatch));
117+
});
118+
119+
it('async', (done) => {
120+
BFMatcher.matchAsync(kazeDesc, kazeDesc, (err, matches) => {
121+
expect(kazeKps.length).to.be.above(0);
122+
expect(matches).to.be.an('array').lengthOf(kazeKps.length);
123+
matches.forEach(match => expect(match).instanceOf(cv.DescriptorMatch));
124+
done();
125+
});
126+
});
127+
});
128+
129+
describe('knnMatch', () => {
130+
let k = 5; //crossCheck off so k can be larger.
131+
132+
it('sync', () => {
133+
const matches = BFMatcher.knnMatch(kazeDesc, kazeDesc, k);
134+
expect(kazeKps.length).to.be.above(0);
135+
expect(matches).to.be.an('array').lengthOf(kazeKps.length);
136+
137+
matches.forEach(
138+
match => (
139+
expect(match).to.be.an('array').lengthOf(k)
140+
&&
141+
expect(match[0]).instanceOf(cv.DescriptorMatch)
142+
)
143+
);
144+
});
145+
146+
it('async', (done) => {
147+
BFMatcher.knnMatchAsync(kazeDesc, kazeDesc, k, (err, matches) => {
148+
expect(kazeKps.length).to.be.above(0);
149+
expect(matches).to.be.an('array').lengthOf(kazeKps.length);
150+
matches.forEach(
151+
match => (
152+
expect(match).to.be.an('array').lengthOf(k)
153+
&&
154+
expect(match[0]).instanceOf(cv.DescriptorMatch)
155+
)
156+
);
157+
done();
158+
});
159+
});
160+
});
161+
});
59162
});
60163
};

0 commit comments

Comments
 (0)