From b070ab60ca2f1b94e4e67129ebf54d80e2adf9d5 Mon Sep 17 00:00:00 2001 From: Solganik Alexander Date: Sun, 27 Jun 2021 18:18:29 +0300 Subject: [PATCH] core: allow to construct CvMat from native cv::Mat pointer. This patch solves the use-case when there is a mix of native code that uses opencv and gocv. In case that native code that utilizes opencv creates a CvMat and there is a need to pass it to the golang environment without creating a copy. The solution is to pass a native pointer to gocv and eventually call cv::Mat copy constructor that performs shallow copy of the origin CvMat. (See https://docs.opencv.org/4.5.2/d3/d63/classcv_1_1Mat.html#a294eaf8a95d2f9c7be19ff594d06278e) for more details. --- core.cpp | 4 ++++ core.go | 8 ++++++++ core.h | 1 + core_test.go | 17 +++++++++++++++++ 4 files changed, 30 insertions(+) diff --git a/core.cpp b/core.cpp index 1d4fc5b0..5ab421c0 100644 --- a/core.cpp +++ b/core.cpp @@ -77,6 +77,10 @@ Mat Mat_FromPtr(Mat m, int rows, int cols, int type, int prow, int pcol) { return new cv::Mat(rows, cols, type, m->ptr(prow, pcol)); } +Mat Mat_FromCVMat(Mat m) { + return new cv::Mat(*m); +} + // Mat_Close deletes an existing Mat void Mat_Close(Mat m) { delete m; diff --git a/core.go b/core.go index d9e90479..2599f874 100644 --- a/core.go +++ b/core.go @@ -289,6 +289,14 @@ func NewMatFromBytes(rows int, cols int, mt MatType, data []byte) (Mat, error) { return mat, nil } +// NewMatFromCVMat returns a new Mat from native CVMat pointer. This can be used in case +// some of the application code uses third party native libraries that return CVMat, so we can +// construct gocv Mat from them. Data is not copied, Copy Constructor of cv::Mat is called. +func NewMatFromCVMat(cvMatPtr unsafe.Pointer) Mat { + newMat := C.Mat_FromCVMat(C.Mat(cvMatPtr)) + return Mat{p: newMat} +} + // Returns an identity matrix of the specified size and type. // // The method returns a Matlab-style identity matrix initializer, similarly to Mat::zeros. Similarly to Mat::ones. diff --git a/core.h b/core.h index 27478028..6a621b37 100644 --- a/core.h +++ b/core.h @@ -247,6 +247,7 @@ Mat Mat_NewFromScalar(const Scalar ar, int type); Mat Mat_NewWithSizeFromScalar(const Scalar ar, int rows, int cols, int type); Mat Mat_NewFromBytes(int rows, int cols, int type, struct ByteArray buf); Mat Mat_FromPtr(Mat m, int rows, int cols, int type, int prows, int pcols); +Mat Mat_FromCVMat(Mat m); void Mat_Close(Mat m); int Mat_Empty(Mat m); bool Mat_IsContinuous(Mat m); diff --git a/core_test.go b/core_test.go index 7b8bbcc1..02400d71 100644 --- a/core_test.go +++ b/core_test.go @@ -9,6 +9,7 @@ import ( "runtime" "strings" "testing" + "unsafe" ) func TestMat(t *testing.T) { @@ -19,6 +20,22 @@ func TestMat(t *testing.T) { } } +func TestMatNativeCopy(t *testing.T) { + mat := NewMatWithSize(10, 10, MatTypeCV32F) + mat.SetTo(NewScalar(1, 2, 3, 4)) + matData := mat.ToBytes() + + mat2 := NewMatFromCVMat(unsafe.Pointer(mat.p)) + mat.Close() + runtime.GC() + + if !bytes.Equal(matData, mat2.ToBytes()) { + t.Error("TestMatNativeCopy: mats are not equal") + } + + mat.Close() +} + func TestMatWithSizes(t *testing.T) { t.Run("create mat with multidimensional array", func(t *testing.T) { sizes := []int{100, 100, 100}