Skip to content

Commit e5e20a3

Browse files
committed
feat: added match template all
1 parent ee90acb commit e5e20a3

11 files changed

+334
-39
lines changed

demo/20250123-112630.png

6.1 KB
Loading

demo/20250123-112635.png

1.91 MB
Loading

demo/test.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ function createWorker() {
1414
}
1515

1616
async function main() {
17-
const full = await fs.readFile('./demo/full.jpg');
18-
const image = await fs.readFile('./demo/1.jpg');
17+
const full = await fs.readFile('./demo/20250123-112635.png');
18+
const image = await fs.readFile('./demo/20250123-112630.png');
1919
try {
2020
const a = cv.imdecode(Buffer.from('hello world'));
2121
} catch (error) {
@@ -28,20 +28,29 @@ async function main() {
2828
cv.imreadAsync('./demo/1.jpg'),
2929
]);
3030

31+
3132
const matched = await image1.matchTemplateAsync(image2, cv.TM_CCOEFF_NORMED);
32-
const minMax = await matched.minMaxLocAsync();
33+
console.time('matchTemplateAllAsync')
34+
const result1 = await image1.matchTemplateAllAsync(image2, cv.TM_CCOEFF_NORMED, 0.8, 0.1);
35+
console.log(result1)
36+
const result = await image3.matchTemplateAllAsync(image4, cv.TM_CCOEFF_NORMED, 0.8, 0.1);
37+
console.log(result)
38+
console.timeEnd('matchTemplateAllAsync')
3339
// const matched2 = await image3.matchTemplateAsync(image4, cv.TM_CCOEFF_NORMED);
3440
// const minMax2 = await matched2.minMaxLocAsync();
35-
console.log(image1.cols, image3.rows, image2.data, minMax)
41+
// console.log(minMax)
42+
const minMax2 = await matched.minMaxLocAsync();
43+
console.log(minMax2)
44+
3645

3746
// console.log(minMax.maxVal * 100);
38-
console.log(image2.size)
39-
matched.release();
40-
// matched2.release();
41-
image1.release();
42-
image2.release();
43-
image3.release();
44-
image4.release();
47+
// console.log(image2.size)
48+
// matched.release();
49+
// // matched2.release();
50+
// image1.release();
51+
// image2.release();
52+
// image3.release();
53+
// image4.release();
4554
// console.log(1)
4655
// console.log(image4)
4756
// const b = cv.imread('./full.jpg');

index.d.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export const IMREAD_IGNORE_ORIENTATION: number
2525
export declare function getTickFrequency(): number
2626
export declare function getBuildInformation(): string
2727
export declare function getTickCount(): number
28+
export declare function imencode(ext: string, img: JSMat): Buffer
29+
export declare function imencodeCallback(ext: string, mat: JSMat, callback: (...args: any[]) => any): void
2830
export declare function imread(path: string, flags?: number | undefined | null): JSMat
2931
export declare function imreadCallback(path: string, callback: (...args: any[]) => any): void
3032
export declare function imdecode(buffer: Buffer): JSMat
@@ -33,13 +35,21 @@ export interface Size {
3335
width: number
3436
height: number
3537
}
38+
export interface Point {
39+
x: number
40+
y: number
41+
}
42+
export interface Rect {
43+
x: number
44+
y: number
45+
width: number
46+
height: number
47+
}
3648
export interface MinMaxResult {
3749
minVal: number
3850
maxVal: number
39-
minX: number
40-
minY: number
41-
maxX: number
42-
maxY: number
51+
minLoc: Point
52+
maxLoc: Point
4353
}
4454
export type JSMat = Mat
4555
export declare class Mat {
@@ -50,5 +60,12 @@ export declare class Mat {
5060
get data(): Buffer
5161
matchTemplateCallback(template: Mat, method: number, callback: (...args: any[]) => any): void
5262
minMaxLocCallback(callback: (...args: any[]) => any): void
63+
thresholdCallback(thresh: number, maxval: number, typ: number, callback: (...args: any[]) => any): void
64+
matchTemplateAllCallback(template: Mat, method: number, score: number, nmsThreshold: number, callback: (...args: any[]) => any): void
5365
release(): void
5466
}
67+
export type DNN = Dnn
68+
export declare class Dnn {
69+
constructor()
70+
nmsBoxes(bboxes: Array<Rect>, scores: Array<number>, scoreThreshold: number, nmsThreshold: number, callback: (...args: any[]) => any): void
71+
}

main.d.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,21 @@ export interface Size {
77
width: number
88
height: number
99
}
10+
export interface Point {
11+
x: number
12+
y: number
13+
}
1014
export interface MinMaxResult {
1115
minVal: number
1216
maxVal: number
13-
minX: number
14-
minY: number
15-
maxX: number
16-
maxY: number
17+
minLoc: Point
18+
maxLoc: Point
19+
}
20+
export interface Rect {
21+
x: number
22+
y: number
23+
width: number
24+
height: number
1725
}
1826
export declare function getTickFrequency(): number
1927
export declare function getBuildInformation(): string
@@ -24,6 +32,9 @@ export declare function imreadAsync(path: string): Promise<Mat>
2432
export declare function imdecode(buffer: Buffer): Mat
2533
export declare function imdecodeCallback(buffer: Buffer, callback: (...args: any[]) => any): void
2634
export declare function imdecodeAsync(buffer: Buffer): Promise<Mat>
35+
export declare function imencode(ext: string, mat: JSMat): Buffer
36+
export declare function imencodeCallback(ext: string, mat: JSMat, callback: (...args: any[]) => any): void
37+
export declare function imencodeAsync(ext: string, mat: JSMat): Promise<Buffer>
2738
export const TM_SQDIFF: number
2839
export const TM_SQDIFF_NORMED: number
2940
export const TM_CCORR: number
@@ -50,9 +61,16 @@ export declare class Mat {
5061
get cols(): number
5162
get size(): Size
5263
get data(): Buffer
64+
matchTemplateAllCallback(template: Mat, method: number, score: number, nmsThreshold: number, callback: (...args: any[]) => any): void
65+
matchTemplateAllAsync(template: Mat, method: number, score: number, nmsThreshold: number): Promise<Array<Rect>>
5366
matchTemplateCallback(template: Mat, method: number, callback: (...args: any[]) => any): void
54-
matchTemplateAsync(template: Mat, method: number): Promise<MinMaxResult>
67+
matchTemplateAsync(template: Mat, method: number): Promise<Mat>
5568
minMaxLocCallback(callback: (...args: any[]) => any): void
5669
minMaxLocAsync(): Promise<MinMaxResult>
5770
release(): void
5871
}
72+
export type DNN = Dnn
73+
export declare class Dnn {
74+
constructor()
75+
nmsBoxes(bboxes: Array<Rect>, scores: Array<number>, scoreThreshold: number, nmsThreshold: number, callback: (...args: any[]) => any): void
76+
}

main.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ const { promisify } = require('util');
33

44
const imdecodeAsync = promisify(cv.imdecodeCallback);
55
const imreadAsync = promisify(cv.imreadCallback);
6+
const imencodeAsync = promisify(cv.imencodeCallback);
67

78
cv.Mat.prototype.matchTemplateAsync = promisify(cv.Mat.prototype.matchTemplateCallback);
9+
cv.Mat.prototype.matchTemplateAllAsync = promisify(cv.Mat.prototype.matchTemplateAllCallback);
810
cv.Mat.prototype.minMaxLocAsync = promisify(cv.Mat.prototype.minMaxLocCallback);
911

1012
const cvProxy = new Proxy(cv, {
@@ -13,6 +15,8 @@ const cvProxy = new Proxy(cv, {
1315
return imdecodeAsync;
1416
} else if (prop === 'imreadAsync') {
1517
return imreadAsync;
18+
} else if (prop === 'imencodeAsync') {
19+
return imencodeAsync;
1620
} else {
1721
return target[prop];
1822
}

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,5 @@
2323
"build": "napi build --release",
2424
"build:debug": "napi build --platform",
2525
"test": "node demo/test.js"
26-
},
27-
"packageManager": "yarn@4.6.0"
26+
}
2827
}

src/dnn.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use opencv::{dnn, core::Vector};
2+
use napi::bindgen_prelude::*;
3+
use napi::{
4+
threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode},
5+
};
6+
7+
#[napi(object)]
8+
pub struct Rect {
9+
pub x: i32,
10+
pub y: i32,
11+
pub width: i32,
12+
pub height: i32,
13+
}
14+
15+
#[napi]
16+
pub struct DNN {}
17+
18+
#[napi]
19+
impl DNN {
20+
#[napi(constructor)]
21+
pub fn new() -> Self {
22+
DNN {}
23+
}
24+
25+
#[napi]
26+
pub fn nms_boxes(
27+
&self,
28+
bboxes: Vec<Rect>,
29+
scores: Vec<f64>,
30+
score_threshold: f64,
31+
nms_threshold: f64,
32+
callback: JsFunction,
33+
) -> Result<()> {
34+
let tsfn: ThreadsafeFunction<Result<Vec<i32>>> =
35+
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?;
36+
37+
let mut opencv_bboxes = Vector::new();
38+
for r in bboxes {
39+
opencv_bboxes.push(opencv::core::Rect::new(r.x, r.y, r.width, r.height));
40+
}
41+
42+
let mut opencv_scores = Vector::new();
43+
for s in scores {
44+
opencv_scores.push(s as f32);
45+
}
46+
47+
let score_threshold_f32 = score_threshold as f32;
48+
let nms_threshold_f32 = nms_threshold as f32;
49+
50+
std::thread::spawn(move || {
51+
let mut indices = Vector::new();
52+
53+
let js_result = dnn::nms_boxes(
54+
&opencv_bboxes,
55+
&opencv_scores,
56+
score_threshold_f32,
57+
nms_threshold_f32,
58+
&mut indices,
59+
1.0,
60+
0,
61+
)
62+
.map_err(|e| napi::Error::from_reason(e.to_string()))
63+
.map(|_| {
64+
let mut result = Vec::new();
65+
for i in 0..indices.len() {
66+
result.push(indices.get(i).unwrap());
67+
}
68+
result
69+
});
70+
71+
tsfn.call(Ok(js_result), ThreadsafeFunctionCallMode::Blocking);
72+
});
73+
74+
Ok(())
75+
}
76+
}

src/image.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use napi::{
44
};
55
use opencv::{
66
core::Vector,
7-
imgcodecs::{imdecode, imread, IMREAD_COLOR},
7+
imgcodecs::{imdecode, imencode, imread, IMREAD_COLOR},
88
prelude::*,
99
};
1010
use crate::{JSMat, OpenCVError};
@@ -24,6 +24,38 @@ pub fn get_tick_count() -> i64 {
2424
opencv::core::get_tick_count().expect("Failed to get tick count")
2525
}
2626

27+
#[napi(js_name = "imencode")]
28+
pub fn imencode_sync(ext: String, img: &JSMat) -> Result<Buffer> {
29+
let mut buf = Vector::new();
30+
opencv::imgcodecs::imencode(&ext, &img.mat, &mut buf, &Vector::new())
31+
.map_err(OpenCVError)?;
32+
Ok(Buffer::from(buf.to_vec()))
33+
}
34+
35+
#[napi]
36+
pub fn imencode_callback(
37+
ext: String,
38+
#[napi(ts_arg_type = "JSMat")] mat: &JSMat,
39+
callback: JsFunction
40+
) -> Result<()> {
41+
let tsfn: ThreadsafeFunction<Result<Buffer>> =
42+
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?;
43+
44+
let mat = mat.mat.clone();
45+
46+
std::thread::spawn(move || {
47+
let mut buf = Vector::new();
48+
let result = match imencode(&ext, &mat, &mut buf, &Vector::new()) {
49+
Ok(_) => Ok(Buffer::from(buf.to_vec())),
50+
Err(e) => Err(Error::from(OpenCVError(e)))
51+
};
52+
53+
tsfn.call(Ok(result), ThreadsafeFunctionCallMode::Blocking);
54+
});
55+
56+
Ok(())
57+
}
58+
2759
#[napi(js_name = "imread")]
2860
pub fn imread_sync(path: String, flags: Option<i32>) -> Result<JSMat> {
2961
let flags = flags.unwrap_or(IMREAD_COLOR);

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod constants;
44
mod error;
55
mod image;
66
mod mat;
7+
mod dnn;
78

89
#[macro_use]
910
extern crate napi_derive;
@@ -12,3 +13,4 @@ pub use constants::*;
1213
pub use error::OpenCVError;
1314
pub use image::*;
1415
pub use mat::JSMat;
16+
pub use dnn::*;

0 commit comments

Comments
 (0)