Skip to content

Commit dbd12d5

Browse files
authored
Merge pull request #120 from nut-tree/feature/101/improve_findMatch_error_msg
Feature/101/improve find match error msg
2 parents 4f23ab8 + 064eb68 commit dbd12d5

File tree

4 files changed

+89
-60
lines changed

4 files changed

+89
-60
lines changed
11.5 KB
Loading
13.4 KB
Loading
Lines changed: 82 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,94 @@
11
import * as path from "path";
2-
import { Image } from "../../image.class";
3-
import { MatchRequest } from "../../match-request.class";
4-
import { Region } from "../../region.class";
5-
import { ImageReader } from "./image-reader.class";
6-
import { TemplateMatchingFinder } from "./template-matching-finder.class";
2+
import {Image} from "../../image.class";
3+
import {MatchRequest} from "../../match-request.class";
4+
import {Region} from "../../region.class";
5+
import {ImageReader} from "./image-reader.class";
6+
import {TemplateMatchingFinder} from "./template-matching-finder.class";
77

88
describe("Template-matching finder", () => {
9-
it("findMatch should return a match when present in image", async () => {
10-
// GIVEN
11-
const imageLoader = new ImageReader();
12-
const SUT = new TemplateMatchingFinder();
13-
const haystackPath = path.resolve(__dirname, "./__mocks__/mouse.png");
14-
const needlePath = path.resolve(__dirname, "./__mocks__/needle.png");
15-
const haystack = await imageLoader.load(haystackPath);
16-
const needle = await imageLoader.load(needlePath);
17-
const minConfidence = 0.99;
18-
const searchRegion = new Region(0, 0, haystack.width, haystack.height);
19-
const matchRequest = new MatchRequest(haystack, needlePath, searchRegion, minConfidence);
20-
const expectedResult = new Region(16, 31, needle.width, needle.height);
9+
it("findMatch should return a match when present in image", async () => {
10+
// GIVEN
11+
const imageLoader = new ImageReader();
12+
const SUT = new TemplateMatchingFinder();
13+
const haystackPath = path.resolve(__dirname, "./__mocks__/mouse.png");
14+
const needlePath = path.resolve(__dirname, "./__mocks__/needle.png");
15+
const haystack = await imageLoader.load(haystackPath);
16+
const needle = await imageLoader.load(needlePath);
17+
const minConfidence = 0.99;
18+
const searchRegion = new Region(0, 0, haystack.width, haystack.height);
19+
const matchRequest = new MatchRequest(haystack, needlePath, searchRegion, minConfidence);
20+
const expectedResult = new Region(16, 31, needle.width, needle.height);
2121

22-
// WHEN
23-
const result = await SUT.findMatch(matchRequest);
22+
// WHEN
23+
const result = await SUT.findMatch(matchRequest);
2424

25-
// THEN
26-
expect(result.confidence).toBeGreaterThanOrEqual(minConfidence);
27-
expect(result.location).toEqual(expectedResult);
28-
});
25+
// THEN
26+
expect(result.confidence).toBeGreaterThanOrEqual(minConfidence);
27+
expect(result.location).toEqual(expectedResult);
28+
});
2929

30-
it("findMatch should return a match within a search region when present in image", async () => {
31-
// GIVEN
32-
const imageLoader = new ImageReader();
33-
const SUT = new TemplateMatchingFinder();
34-
const haystackPath = path.resolve(__dirname, "./__mocks__/mouse.png");
35-
const needlePath = path.resolve(__dirname, "./__mocks__/needle.png");
36-
const haystack = await imageLoader.load(haystackPath);
37-
const needle = await imageLoader.load(needlePath);
38-
const minConfidence = 0.99;
39-
const searchRegion = new Region(10, 20, 140, 100);
40-
const matchRequest = new MatchRequest(haystack, needlePath, searchRegion, minConfidence);
41-
const expectedResult = new Region(6, 11, needle.width, needle.height);
30+
it("findMatch should return a match within a search region when present in image", async () => {
31+
// GIVEN
32+
const imageLoader = new ImageReader();
33+
const SUT = new TemplateMatchingFinder();
34+
const haystackPath = path.resolve(__dirname, "./__mocks__/mouse.png");
35+
const needlePath = path.resolve(__dirname, "./__mocks__/needle.png");
36+
const haystack = await imageLoader.load(haystackPath);
37+
const needle = await imageLoader.load(needlePath);
38+
const minConfidence = 0.99;
39+
const searchRegion = new Region(10, 20, 140, 100);
40+
const matchRequest = new MatchRequest(haystack, needlePath, searchRegion, minConfidence);
41+
const expectedResult = new Region(6, 11, needle.width, needle.height);
4242

43-
// WHEN
44-
const result = await SUT.findMatch(matchRequest);
43+
// WHEN
44+
const result = await SUT.findMatch(matchRequest);
4545

46-
// THEN
47-
expect(result.confidence).toBeGreaterThanOrEqual(minConfidence);
48-
expect(result.location).toEqual(expectedResult);
49-
});
46+
// THEN
47+
expect(result.confidence).toBeGreaterThanOrEqual(minConfidence);
48+
expect(result.location).toEqual(expectedResult);
49+
});
5050

51-
it("findMatch should throw on invalid image paths", async () => {
52-
// GIVEN
53-
const imageLoader = new ImageReader();
54-
const SUT = new TemplateMatchingFinder();
55-
const pathToNeedle = path.resolve(__dirname, "./__mocks__/mouse.png");
56-
const pathToHaystack = "./__mocks__/foo.png";
57-
const needle = await imageLoader.load(pathToNeedle);
58-
const minConfidence = 0.99;
59-
const searchRegion = new Region(0, 0, 100, 100);
60-
const haystack = new Image(needle.width, needle.height, needle.data, 3);
61-
const matchRequest = new MatchRequest(haystack, pathToHaystack, searchRegion, minConfidence);
51+
it("findMatch should return confidence and location of best match if no match with sufficient confidence is found", async () => {
52+
// GIVEN
53+
const imageLoader = new ImageReader();
54+
const SUT = new TemplateMatchingFinder();
55+
const haystackPath = path.resolve(__dirname, "./__mocks__/downloads.png");
56+
const needlePath = path.resolve(__dirname, "./__mocks__/coverage.png");
57+
const haystack = await imageLoader.load(haystackPath);
58+
const minConfidence = 0.99;
59+
const searchRegion = new Region(0, 0, 320, 72);
60+
const matchRequest = new MatchRequest(haystack, needlePath, searchRegion, minConfidence);
61+
const expectedRejection = new RegExp(`^No match with required confidence ${minConfidence}. Best match: \\d.\\d* at \\(\\d*, \\d*, \\d*, \\d*\\)$`)
6262

63-
// WHEN
64-
const result = SUT.findMatch(matchRequest);
63+
// WHEN
6564

66-
// THEN
67-
await expect(result)
68-
.rejects
69-
.toThrowError(`Failed to load ${pathToHaystack}. Reason: 'Failed to load image from '${pathToHaystack}''.`);
70-
});
65+
// THEN
66+
await expect(SUT.findMatch(matchRequest))
67+
.rejects
68+
.toEqual(
69+
expect
70+
.stringMatching(expectedRejection)
71+
);
72+
});
73+
74+
it("findMatch should throw on invalid image paths", async () => {
75+
// GIVEN
76+
const imageLoader = new ImageReader();
77+
const SUT = new TemplateMatchingFinder();
78+
const pathToNeedle = path.resolve(__dirname, "./__mocks__/mouse.png");
79+
const pathToHaystack = "./__mocks__/foo.png";
80+
const needle = await imageLoader.load(pathToNeedle);
81+
const minConfidence = 0.99;
82+
const searchRegion = new Region(0, 0, 100, 100);
83+
const haystack = new Image(needle.width, needle.height, needle.data, 3);
84+
const matchRequest = new MatchRequest(haystack, pathToHaystack, searchRegion, minConfidence);
85+
86+
// WHEN
87+
const result = SUT.findMatch(matchRequest);
88+
89+
// THEN
90+
await expect(result)
91+
.rejects
92+
.toThrowError(`Failed to load ${pathToHaystack}. Reason: 'Failed to load image from '${pathToHaystack}''.`);
93+
});
7194
});

lib/provider/opencv/template-matching-finder.class.ts

100644100755
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,13 @@ export class TemplateMatchingFinder implements FinderInterface {
179179
const potentialMatches = matches
180180
.filter(match => match.confidence >= matchRequest.confidence);
181181
if (potentialMatches.length === 0) {
182-
reject(`Unable to locate ${matchRequest.pathToNeedle}, no match!`);
182+
matches.sort((a, b) => a.confidence - b.confidence);
183+
const bestMatch = matches.pop();
184+
if (bestMatch) {
185+
reject(`No match with required confidence ${matchRequest.confidence}. Best match: ${bestMatch.confidence} at ${bestMatch.location}`)
186+
} else {
187+
reject(`Unable to locate ${matchRequest.pathToNeedle}, no match!`);
188+
}
183189
}
184190
resolve(potentialMatches[0]);
185191
} catch (e) {

0 commit comments

Comments
 (0)