Skip to content

add svd async #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ffigen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ headers:
- src/core/core.h
- src/core/exception.h
- src/core/svd.h
- src/core/svd_async.h
- src/core/types.h
- src/core/vec.h
- src/core/version.h
Expand All @@ -45,6 +46,7 @@ headers:
- src/core/core.h
- src/core/exception.h
- src/core/svd.h
- src/core/svd_async.h
- src/core/vec.h
- src/core/version.h
- src/dnn/asyncarray.h
Expand Down
2 changes: 2 additions & 0 deletions lib/src/core/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ Future<T> cvRunAsync5<T>(
void matCompleter(Completer<Mat> completer, VoidPtr p) => completer.complete(Mat.fromPointer(p.cast()));
void matCompleter2(Completer<(Mat, Mat)> completer, VoidPtr p, VoidPtr p1) =>
completer.complete((Mat.fromPointer(p.cast()), Mat.fromPointer(p1.cast())));
void matCompleter3(Completer<(Mat, Mat, Mat)> completer, VoidPtr p, VoidPtr p1, VoidPtr p2) =>
completer.complete((Mat.fromPointer(p.cast()), Mat.fromPointer(p1.cast()), Mat.fromPointer(p2.cast())));

// Arena wrapper
R cvRunArena<R>(
Expand Down
78 changes: 72 additions & 6 deletions lib/src/opencv.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14587,9 +14587,9 @@ class CvNative {

ffi.Pointer<CvStatus> SVD_Compute(
Mat src,
Mat w,
Mat u,
Mat vt,
ffi.Pointer<Mat> w,
ffi.Pointer<Mat> u,
ffi.Pointer<Mat> vt,
int flags,
) {
return _SVD_Compute(
Expand All @@ -14603,10 +14603,76 @@ class CvNative {

late final _SVD_ComputePtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(
Mat, Mat, Mat, Mat, ffi.Int)>>('SVD_Compute');
ffi.Pointer<CvStatus> Function(Mat, ffi.Pointer<Mat>,
ffi.Pointer<Mat>, ffi.Pointer<Mat>, ffi.Int)>>('SVD_Compute');
late final _SVD_Compute = _SVD_ComputePtr.asFunction<
ffi.Pointer<CvStatus> Function(Mat, Mat, Mat, Mat, int)>();
ffi.Pointer<CvStatus> Function(
Mat, ffi.Pointer<Mat>, ffi.Pointer<Mat>, ffi.Pointer<Mat>, int)>();

ffi.Pointer<CvStatus> SVD_Compute_Async(
Mat src,
int flags,
CvCallback_3 callback,
) {
return _SVD_Compute_Async(
src,
flags,
callback,
);
}

late final _SVD_Compute_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(
Mat, ffi.Int, CvCallback_3)>>('SVD_Compute_Async');
late final _SVD_Compute_Async = _SVD_Compute_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(Mat, int, CvCallback_3)>();

ffi.Pointer<CvStatus> SVD_backSubst(
Mat w,
Mat u,
Mat vt,
Mat rhs,
ffi.Pointer<Mat> dst,
) {
return _SVD_backSubst(
w,
u,
vt,
rhs,
dst,
);
}

late final _SVD_backSubstPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(
Mat, Mat, Mat, Mat, ffi.Pointer<Mat>)>>('SVD_backSubst');
late final _SVD_backSubst = _SVD_backSubstPtr.asFunction<
ffi.Pointer<CvStatus> Function(Mat, Mat, Mat, Mat, ffi.Pointer<Mat>)>();

ffi.Pointer<CvStatus> SVD_backSubst_Async(
Mat w,
Mat u,
Mat vt,
Mat rhs,
CvCallback_1 callback,
) {
return _SVD_backSubst_Async(
w,
u,
vt,
rhs,
callback,
);
}

late final _SVD_backSubst_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(
Mat, Mat, Mat, Mat, CvCallback_1)>>('SVD_backSubst_Async');
late final _SVD_backSubst_Async = _SVD_backSubst_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(Mat, Mat, Mat, Mat, CvCallback_1)>();

ffi.Pointer<CvStatus> Scharr(
Mat src,
Expand Down
27 changes: 25 additions & 2 deletions lib/src/svd/svd.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
library cv;

import 'dart:ffi' as ffi;

import 'package:ffi/ffi.dart';

import '../core/base.dart';
import '../core/mat.dart';
import '../opencv.g.dart' as cvg;

/// SVDCompute decomposes matrix and stores the results to user-provided matrices
///
/// https://docs.opencv.org/4.1.2/df/df7/classcv_1_1SVD.html#a76f0b2044df458160292045a3d3714c6
class SVD {
static void compute(Mat src, Mat w, Mat u, Mat vt, {int flags = 0}) {
cvRun(() => CFFI.SVD_Compute(src.ref, w.ref, u.ref, vt.ref, flags));
static (Mat w, Mat u, Mat vt) compute(Mat src, {Mat? w, Mat? u, Mat? vt, int flags = 0}) {
final pw = w?.ptr ?? calloc<cvg.Mat>();
final pu = u?.ptr ?? calloc<cvg.Mat>();
final pvt = vt?.ptr ?? calloc<cvg.Mat>();
cvRun(() => CFFI.SVD_Compute(src.ref, pw, pu, pvt, flags));
return (w ?? Mat.fromPointer(pw), u ?? Mat.fromPointer(pu), vt ?? Mat.fromPointer(pvt));
}

static Future<(Mat w, Mat u, Mat vt)> computeAsync(Mat src, {int flags = 0}) async =>
cvRunAsync3((callback) => CFFI.SVD_Compute_Async(src.ref, flags, callback), matCompleter3);

static Mat backSubst(Mat w, Mat u, Mat vt, Mat rhs, {Mat? dst}) {
final pdst = dst?.ptr ?? calloc<cvg.Mat>();
cvRun(() => CFFI.SVD_backSubst(w.ref, u.ref, vt.ref, rhs.ref, pdst));
return dst ?? Mat.fromPointer(pdst);
}

static Future<Mat> backSubstAsync(Mat w, Mat u, Mat vt, Mat rhs, {Mat? dst}) async => cvRunAsync(
(callback) => CFFI.SVD_backSubst_Async(w.ref, u.ref, vt.ref, rhs.ref, callback),
matCompleter,
);
}
17 changes: 14 additions & 3 deletions src/core/svd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,20 @@

#include "svd.h"

CvStatus *SVD_Compute(Mat src, Mat w, Mat u, Mat vt, int flags)
{
CvStatus *SVD_Compute(Mat src, Mat *w, Mat *u, Mat *vt, int flags) {
BEGIN_WRAP
cv::SVD::compute(*src.ptr, *w.ptr, *u.ptr, *vt.ptr, flags);
cv::Mat _w, _u, _vt;
cv::SVD::compute(*src.ptr, _w, _u, _vt, flags);
*w = {new cv::Mat(_w)};
*u = {new cv::Mat(_u)};
*vt = {new cv::Mat(_vt)};
END_WRAP
}

CvStatus *SVD_backSubst(Mat w, Mat u, Mat vt, Mat rhs, Mat *dst) {
BEGIN_WRAP
cv::Mat _dst;
cv::SVD::backSubst(*w.ptr, *u.ptr, *vt.ptr, *rhs.ptr, _dst);
*dst = {new cv::Mat(_dst)};
END_WRAP
}
3 changes: 2 additions & 1 deletion src/core/svd.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ extern "C" {

#include "core.h"

CvStatus *SVD_Compute(Mat src, Mat w, Mat u, Mat vt, int flags);
CvStatus *SVD_Compute(Mat src, Mat *w, Mat *u, Mat *vt, int flags);
CvStatus *SVD_backSubst(Mat w, Mat u, Mat vt, Mat rhs, Mat *dst);

#ifdef __cplusplus
}
Expand Down
17 changes: 17 additions & 0 deletions src/core/svd_async.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "svd_async.h"
#include "core/types.h"

CvStatus *SVD_Compute_Async(Mat src, int flags, CvCallback_3 callback) {
BEGIN_WRAP
cv::Mat w, u, vt;
cv::SVD::compute(*src.ptr, w, u, vt, flags);
callback(new Mat{new cv::Mat(w)}, new Mat{new cv::Mat(u)}, new Mat{new cv::Mat(vt)});
END_WRAP
}
CvStatus *SVD_backSubst_Async(Mat w, Mat u, Mat vt, Mat rhs, CvCallback_1 callback) {
BEGIN_WRAP
cv::Mat dst;
cv::SVD::backSubst(*w.ptr, *u.ptr, *vt.ptr, *rhs.ptr, dst);
callback(new Mat{new cv::Mat(dst)});
END_WRAP
}
24 changes: 24 additions & 0 deletions src/core/svd_async.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Created by Rainyl.
Licensed: Apache 2.0 license. Copyright (c) 2024 Rainyl.
*/
#pragma once
#ifndef CVD_SVD_ASYNC_H_
#define CVD_SVD_ASYNC_H_

#ifdef __cplusplus
#include <opencv2/opencv.hpp>

extern "C" {
#endif

#include "types.h"

CvStatus *SVD_Compute_Async(Mat src, int flags, CvCallback_3 callback);
CvStatus *SVD_backSubst_Async(Mat w, Mat u, Mat vt, Mat rhs, CvCallback_1 callback);

#ifdef __cplusplus
}
#endif

#endif // CVD_SVD_ASYNC_H_
91 changes: 62 additions & 29 deletions test/svd_test.dart
Original file line number Diff line number Diff line change
@@ -1,50 +1,83 @@
import 'package:opencv_dart/opencv_dart.dart' as cv;
import 'package:test/test.dart';

final resultW = [6.410056, 3.4595323];
final resultU = [-0.32415637, -0.9460035, 0.94600356, -0.3241564];
final resultVt = [-0.32415637, 0.9460035, 0.9460035, -0.32415637];

bool checkFunc(List<double> a, List<double> b, {double eps = 1e-4}) {
if (a.length != b.length) {
return false;
}
return List.generate(a.length, (i) => a[i] - b[i] < eps).every((e) => e);
}

void main() async {
test('SVD.compute', () {
final resultW = [6.410056, 3.4595323];
final resultU = [-0.32415637, -0.9460035, 0.94600356, -0.3241564];
final resultVt = [-0.32415637, 0.9460035, 0.9460035, -0.32415637];
void checkSVD(cv.Mat w, cv.Mat u, cv.Mat vt) {
expect(w.isEmpty || u.isEmpty || vt.isEmpty, false);
expect(w.size, [2, 1]);
expect(u.size, [2, 2]);
expect(vt.size, [2, 2]);

expect(checkFunc([w.at<double>(0, 0), w.at<double>(1, 0)], resultW), true);
expect(
checkFunc(
[u.at<double>(0, 0), u.at<double>(0, 1), u.at<double>(1, 0), u.at<double>(1, 1)],
resultU,
),
true,
);
expect(
checkFunc(
[vt.at<double>(0, 0), vt.at<double>(0, 1), vt.at<double>(1, 0), vt.at<double>(1, 1)],
resultVt,
),
true,
);
}

void main() async {
test('SVD.compute', () async {
final src = cv.Mat.zeros(2, 2, cv.MatType.CV_32FC1);
src.set<double>(0, 0, 3.76956568);
src.set<double>(0, 1, -0.90478725);
src.set<double>(1, 0, -0.90478725);
src.set<double>(1, 1, 6.10002347);
expect(src.at<double>(0, 0), closeTo(3.76956568, 1e-4));

final w = cv.Mat.empty();
final u = cv.Mat.empty();
final vt = cv.Mat.empty();

cv.SVD.compute(src, w, u, vt);
expect(w.isEmpty || u.isEmpty || vt.isEmpty, false);
expect(w.size, [2, 1]);
expect(u.size, [2, 2]);
expect(vt.size, [2, 2]);
{
final w = cv.Mat.empty();
final u = cv.Mat.empty();
final vt = cv.Mat.empty();
cv.SVD.compute(src, w: w, u: u, vt: vt);
checkSVD(w, u, vt);
}
{
final (w, u, vt) = await cv.SVD.computeAsync(src);
checkSVD(w, u, vt);
}
});

expect(checkFunc([w.at<double>(0, 0), w.at<double>(1, 0)], resultW), true);
expect(
checkFunc(
[u.at<double>(0, 0), u.at<double>(0, 1), u.at<double>(1, 0), u.at<double>(1, 1)],
resultU,
),
true,
);
expect(
checkFunc(
[vt.at<double>(0, 0), vt.at<double>(0, 1), vt.at<double>(1, 0), vt.at<double>(1, 1)],
resultVt,
),
true,
);
test('cv.SVD.backSubst', () async {
final src = cv.Mat.zeros(2, 2, cv.MatType.CV_32FC1);
src.set<double>(0, 0, 3.76956568);
src.set<double>(0, 1, -0.90478725);
src.set<double>(1, 0, -0.90478725);
src.set<double>(1, 1, 6.10002347);
expect(src.at<double>(0, 0), closeTo(3.76956568, 1e-4));
{
final w = cv.Mat.empty();
final u = cv.Mat.empty();
final vt = cv.Mat.empty();
cv.SVD.compute(src, w: w, u: u, vt: vt);
checkSVD(w, u, vt);
final dst = cv.SVD.backSubst(w, u, vt, src);
expect(dst.isEmpty, false);
}
{
final (w, u, vt) = await cv.SVD.computeAsync(src);
checkSVD(w, u, vt);
final dst = await cv.SVD.backSubstAsync(w, u, vt, src);
expect(dst.isEmpty, false);
}
});
}