Skip to content

Commit 97a7d1d

Browse files
authored
Merge pull request #58 from rainyl/at-set-perf
Improve the performance of at and set, add Mat.atU8, Mat.setU8, etc.
2 parents 66fa454 + f24dab0 commit 97a7d1d

File tree

6 files changed

+310
-185
lines changed

6 files changed

+310
-185
lines changed

lib/src/core/mat.dart

Lines changed: 141 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -237,72 +237,81 @@ class Mat extends CvStruct<cvg.Mat> {
237237
});
238238
}
239239

240-
T _atNum<T>(int row, int col, [int? cn]) {
241-
return cvRunArena<T>((arena) {
242-
switch (type.depth) {
243-
case MatType.CV_8U:
244-
final p = arena<ffi.Uint8>();
245-
if (type.channels == 1 || cn == null) {
246-
cvRun(() => CFFI.Mat_GetUChar(ref, row, col, p));
247-
} else {
248-
cvRun(() => CFFI.Mat_GetUChar3(ref, row, col, cn, p));
249-
}
250-
return p.value as T;
251-
case MatType.CV_8S:
252-
final p = arena<ffi.Int8>();
253-
if (type.channels == 1 || cn == null) {
254-
cvRun(() => CFFI.Mat_GetSChar(ref, row, col, p));
255-
} else {
256-
cvRun(() => CFFI.Mat_GetSChar3(ref, row, col, cn, p));
257-
}
258-
return p.value as T;
259-
case MatType.CV_16U:
260-
final p = arena<ffi.Uint16>();
261-
if (type.channels == 1 || cn == null) {
262-
cvRun(() => CFFI.Mat_GetUShort(ref, row, col, p));
263-
} else {
264-
cvRun(() => CFFI.Mat_GetUShort3(ref, row, col, cn, p));
265-
}
266-
return p.value as T;
267-
case MatType.CV_16S:
268-
final p = arena<ffi.Int16>();
269-
if (type.channels == 1 || cn == null) {
270-
cvRun(() => CFFI.Mat_GetShort(ref, row, col, p));
271-
} else {
272-
cvRun(() => CFFI.Mat_GetShort3(ref, row, col, cn, p));
273-
}
274-
return p.value as T;
275-
case MatType.CV_32S:
276-
final p = arena<ffi.Int32>();
277-
if (type.channels == 1 || cn == null) {
278-
cvRun(() => CFFI.Mat_GetInt(ref, row, col, p));
279-
} else {
280-
cvRun(() => CFFI.Mat_GetInt3(ref, row, col, cn, p));
281-
}
282-
return p.value as T;
283-
case MatType.CV_32F:
284-
final p = arena<ffi.Float>();
285-
if (type.channels == 1 || cn == null) {
286-
cvRun(() => CFFI.Mat_GetFloat(ref, row, col, p));
287-
} else {
288-
cvRun(() => CFFI.Mat_GetFloat3(ref, row, col, cn, p));
289-
}
290-
return p.value as T;
291-
case MatType.CV_64F:
292-
final p = arena<ffi.Double>();
293-
if (type.channels == 1 || cn == null) {
294-
cvRun(() => CFFI.Mat_GetDouble(ref, row, col, p));
295-
} else {
296-
cvRun(() => CFFI.Mat_GetDouble3(ref, row, col, cn, p));
297-
}
298-
return p.value as T;
299-
default:
300-
throw UnsupportedError("at() for $type is not supported!");
301-
}
240+
int atU8(int row, int col, [int? i2]) => using<int>((arena) {
241+
final p = arena<ffi.Uint8>();
242+
i2 == null
243+
? cvRun(() => CFFI.Mat_GetUChar(ref, row, col, p))
244+
: cvRun(() => CFFI.Mat_GetUChar3(ref, row, col, i2, p));
245+
return p.value;
246+
});
247+
248+
int atI8(int row, int col, [int? i2]) => using<int>((arena) {
249+
final p = arena<ffi.Int8>();
250+
i2 == null
251+
? cvRun(() => CFFI.Mat_GetSChar(ref, row, col, p))
252+
: cvRun(() => CFFI.Mat_GetSChar3(ref, row, col, i2, p));
253+
return p.value;
254+
});
255+
256+
int atU16(int row, int col, [int? i2]) => using<int>((arena) {
257+
final p = arena<ffi.Uint16>();
258+
i2 == null
259+
? cvRun(() => CFFI.Mat_GetUShort(ref, row, col, p))
260+
: cvRun(() => CFFI.Mat_GetUShort3(ref, row, col, i2, p));
261+
return p.value;
262+
});
263+
264+
int atI16(int row, int col, [int? i2]) => using<int>((arena) {
265+
final p = arena<ffi.Int16>();
266+
i2 == null
267+
? cvRun(() => CFFI.Mat_GetShort(ref, row, col, p))
268+
: cvRun(() => CFFI.Mat_GetShort3(ref, row, col, i2, p));
269+
return p.value;
270+
});
271+
272+
int atI32(int row, int col, [int? i2]) => using<int>((arena) {
273+
final p = arena<ffi.Int32>();
274+
i2 == null
275+
? cvRun(() => CFFI.Mat_GetInt(ref, row, col, p))
276+
: cvRun(() => CFFI.Mat_GetInt3(ref, row, col, i2, p));
277+
return p.value;
278+
});
279+
280+
double atF32(int row, int col, [int? i2]) => using<double>((arena) {
281+
final p = arena<ffi.Float>();
282+
i2 == null
283+
? cvRun(() => CFFI.Mat_GetFloat(ref, row, col, p))
284+
: cvRun(() => CFFI.Mat_GetFloat3(ref, row, col, i2, p));
285+
return p.value;
286+
});
287+
288+
double atF64(int row, int col, [int? i2]) => using<double>((arena) {
289+
final p = arena<ffi.Double>();
290+
i2 == null
291+
? cvRun(() => CFFI.Mat_GetDouble(ref, row, col, p))
292+
: cvRun(() => CFFI.Mat_GetDouble3(ref, row, col, i2, p));
293+
return p.value;
294+
});
295+
296+
num atNum<T extends num>(int row, int col, [int? i2]) {
297+
return using<num>((arena) {
298+
final p = arena<ffi.Int>();
299+
cvRun(() => CFFI.Mat_Type(ref, p));
300+
final depth = p.value & (MatType.CV_DEPTH_MAX - 1);
301+
return switch (depth) {
302+
MatType.CV_8U => atU8(row, col, i2),
303+
MatType.CV_8S => atI8(row, col, i2),
304+
MatType.CV_16U => atU16(row, col, i2),
305+
MatType.CV_16S => atI16(row, col, i2),
306+
MatType.CV_32S => atI32(row, col, i2),
307+
MatType.CV_32F => atF32(row, col, i2),
308+
MatType.CV_64F => atF64(row, col, i2),
309+
_ => throw UnsupportedError("Unsupported type: $type")
310+
};
302311
});
303312
}
304313

305-
T _atVec<T>(int row, int col) {
314+
T atVec<T>(int row, int col) {
306315
final v = cvRunArena<T>((arena) {
307316
// Vec2b, Vec3b, Vec4b
308317
if (T == Vec2b) {
@@ -412,76 +421,25 @@ class Mat extends CvStruct<cvg.Mat> {
412421

413422
/// cv::Mat::at\<T\>(i0, i1, i2) of cv::Mat
414423
///
415-
///
416-
/// - If matrix is of type [MatType.CV_8U] then use Mat.at\<uchar\>(y,x).
417-
/// - If matrix is of type [MatType.CV_8S] then use Mat.at\<schar\>(y,x).
418-
/// - If matrix is of type [MatType.CV_16U] then use Mat.at\<ushort\>(y,x).
419-
/// - If matrix is of type [MatType.CV_16S] then use Mat.at\<short\>(y,x).
420-
/// - If matrix is of type [MatType.CV_32S] then use Mat.at\<int\>(y,x).
421-
/// - If matrix is of type [MatType.CV_32F] then use Mat.at\<float\>(y,x).
422-
/// - If matrix is of type [MatType.CV_64F] then use Mat.at\<double\>(y,x).
423-
///
424424
/// example:
425425
/// ```dart
426426
/// var m = cv.Mat.fromScalar(cv.Scalar(2, 4, 1, 0), cv.MatType.CV_32FC3);
427-
/// m.at<double>(0, 0); // 2
427+
/// m.at<double>(0, 0); // 2.0
428428
/// m.at<cv.Vec3f>(0, 0); // cv.Vec3f(2, 4, 1)
429429
/// ```
430430
///
431431
/// https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#a7a6d7e3696b8b19b9dfac3f209118c40
432432
T at<T>(int row, int col, [int? i2]) {
433433
if (T == int || T == double) {
434-
return _atNum<T>(row, col, i2);
434+
return atNum(row, col, i2) as T;
435435
} else if (isSubtype<T, CvVec>()) {
436-
return _atVec<T>(row, col);
436+
return atVec<T>(row, col);
437437
} else {
438438
throw UnsupportedError("T must be num or CvVec(e.g., Vec3b), but got $T");
439439
}
440440
}
441441

442-
void _setNum<T>(row, col, T val, [int? i2]) {
443-
switch (type.depth) {
444-
case MatType.CV_8U:
445-
assert(T == int, "$type only support int");
446-
type.channels == 1 || i2 == null
447-
? cvRun(() => CFFI.Mat_SetUChar(ref, row, col, val as int))
448-
: cvRun(() => CFFI.Mat_SetUChar3(ref, row, col, i2, val as int));
449-
case MatType.CV_8S:
450-
assert(T == int, "$type only support int");
451-
type.channels == 1 || i2 == null
452-
? cvRun(() => CFFI.Mat_SetSChar(ref, row, col, val as int))
453-
: cvRun(() => CFFI.Mat_SetSChar3(ref, row, col, i2, val as int));
454-
case MatType.CV_16U:
455-
assert(T == int, "$type only support int");
456-
type.channels == 1 || i2 == null
457-
? cvRun(() => CFFI.Mat_SetUShort(ref, row, col, val as int))
458-
: cvRun(() => CFFI.Mat_SetUShort3(ref, row, col, i2, val as int));
459-
case MatType.CV_16S:
460-
assert(T == int, "$type only support int");
461-
type.channels == 1 || i2 == null
462-
? cvRun(() => CFFI.Mat_SetShort(ref, row, col, val as int))
463-
: cvRun(() => CFFI.Mat_SetShort3(ref, row, col, i2, val as int));
464-
case MatType.CV_32S:
465-
assert(T == int, "$type only support int");
466-
type.channels == 1 || i2 == null
467-
? cvRun(() => CFFI.Mat_SetInt(ref, row, col, val as int))
468-
: cvRun(() => CFFI.Mat_SetInt3(ref, row, col, i2, val as int));
469-
case MatType.CV_32F:
470-
assert(T == double, "$type only support double");
471-
type.channels == 1 || i2 == null
472-
? cvRun(() => CFFI.Mat_SetFloat(ref, row, col, val as double))
473-
: cvRun(() => CFFI.Mat_SetFloat3(ref, row, col, i2, val as double));
474-
case MatType.CV_64F:
475-
assert(T == double, "$type only support double");
476-
type.channels == 1 || i2 == null
477-
? cvRun(() => CFFI.Mat_SetDouble(ref, row, col, val as double))
478-
: cvRun(() => CFFI.Mat_SetDouble3(ref, row, col, i2, val as double));
479-
default:
480-
throw UnsupportedError("setValue() for $type is not supported!");
481-
}
482-
}
483-
484-
void _setVec<T>(int row, int col, T val) {
442+
void setVec<T>(int row, int col, T val) {
485443
cvRunArena((arena) {
486444
// Vec2b, Vec3b, Vec4b
487445
if (val is Vec2b) {
@@ -544,8 +502,54 @@ class Mat extends CvStruct<cvg.Mat> {
544502
});
545503
}
546504

505+
void setU8(int row, int col, int val, [int? i2]) => i2 == null
506+
? cvRun(() => CFFI.Mat_SetUChar(ref, row, col, val))
507+
: cvRun(() => CFFI.Mat_SetUChar3(ref, row, col, i2, val));
508+
509+
void setI8(int row, int col, int val, [int? i2]) => i2 == null
510+
? cvRun(() => CFFI.Mat_SetSChar(ref, row, col, val))
511+
: cvRun(() => CFFI.Mat_SetSChar3(ref, row, col, i2, val));
512+
513+
void setU16(int row, int col, int val, [int? i2]) => i2 == null
514+
? cvRun(() => CFFI.Mat_SetUShort(ref, row, col, val))
515+
: cvRun(() => CFFI.Mat_SetUShort3(ref, row, col, i2, val));
516+
517+
void setI16(int row, int col, int val, [int? i2]) => i2 == null
518+
? cvRun(() => CFFI.Mat_SetShort(ref, row, col, val))
519+
: cvRun(() => CFFI.Mat_SetShort3(ref, row, col, i2, val));
520+
521+
void setI32(int row, int col, int val, [int? i2]) => i2 == null
522+
? cvRun(() => CFFI.Mat_SetInt(ref, row, col, val))
523+
: cvRun(() => CFFI.Mat_SetInt3(ref, row, col, i2, val));
524+
525+
void setF32(int row, int col, double val, [int? i2]) => i2 == null
526+
? cvRun(() => CFFI.Mat_SetFloat(ref, row, col, val))
527+
: cvRun(() => CFFI.Mat_SetFloat3(ref, row, col, i2, val));
528+
529+
void setF64(int row, int col, double val, [int? i2]) => i2 == null
530+
? cvRun(() => CFFI.Mat_SetDouble(ref, row, col, val))
531+
: cvRun(() => CFFI.Mat_SetDouble3(ref, row, col, i2, val));
532+
533+
void setNum<T extends num>(int row, int col, T val, [int? i2]) {
534+
using((arena) {
535+
final p = arena<ffi.Int>();
536+
cvRun(() => CFFI.Mat_Type(ref, p));
537+
final depth = p.value & (MatType.CV_DEPTH_MAX - 1);
538+
return switch (depth) {
539+
MatType.CV_8U => setU8(row, col, val as int, i2),
540+
MatType.CV_8S => setI8(row, col, val as int, i2),
541+
MatType.CV_16U => setU16(row, col, val as int, i2),
542+
MatType.CV_16S => setI16(row, col, val as int, i2),
543+
MatType.CV_32S => setI32(row, col, val as int, i2),
544+
MatType.CV_32F => setF32(row, col, val as double, i2),
545+
MatType.CV_64F => setF64(row, col, val as double, i2),
546+
_ => throw UnsupportedError("Unsupported type: $type")
547+
};
548+
});
549+
}
550+
547551
/// equivalent to Mat::at\<T\>(i0, i1, i2) = val;
548-
/// where T might be int, double.
552+
/// where T might be int, double, [U8], [I8], [U16], [I16], [I32], [F32], [F64].
549553
/// or cv::Vec<> like cv::Vec3b
550554
///
551555
/// example
@@ -555,13 +559,27 @@ class Mat extends CvStruct<cvg.Mat> {
555559
/// m.set<cv.Vec3f>(0, 0, cv.Vec3f(9, 9, 9));
556560
/// m.at<cv.Vec3f>(0, 0); // cv.Vec3f(9, 9, 9)
557561
/// ```
558-
void set<T>(int row, int col, T val, [int? i2]) {
562+
void set<T>(int row, int col, Object val, [int? i2]) {
559563
if (T == int || T == double) {
560-
_setNum<T>(row, col, val, i2);
564+
setNum(row, col, val as num, i2);
561565
} else if (isSubtype<T, CvVec>()) {
562-
_setVec<T>(row, col, val);
566+
setVec<T>(row, col, val as T);
567+
} else if (T == U8) {
568+
setU8(row, col, val as int);
569+
} else if (T == I8) {
570+
setI8(row, col, val as int);
571+
} else if (T == U16) {
572+
setU16(row, col, val as int);
573+
} else if (T == I16) {
574+
setI16(row, col, val as int);
575+
} else if (T == I32) {
576+
setI32(row, col, val as int);
577+
} else if (T == F32) {
578+
setF32(row, col, val as double);
579+
} else if (T == F64) {
580+
setF64(row, col, val as double);
563581
} else {
564-
throw UnsupportedError("T must be num or CvVec(e.g., Vec3b), but got $T");
582+
throw UnsupportedError("Unsupported type $T");
565583
}
566584
}
567585

lib/src/core/mat_type.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class MatType extends Equatable {
102102
CV_64FC4 = CV_64FC(4);
103103

104104
/*
105-
static const int
105+
static const int
106106
CV_8UC1 = 0,
107107
CV_8SC1 = 1,
108108
CV_16UC1 = 2,

0 commit comments

Comments
 (0)