From 661fb978f6bf7cae8c9a564a4ec5045daa1eb2b5 Mon Sep 17 00:00:00 2001 From: Ryan Heacock Date: Tue, 13 Jun 2023 10:31:29 -0700 Subject: [PATCH] Adds support for PCACompute This PR adds support for PCACompute via wrapping one of the opencv versions with this function signature. A smoke test has been added that calls the wrapped function and verifies that the parameters are being passed correctly. In opencv there are four versions with this function signature, I have chosen to wrap (what I think is) the most common with the most parameters. Link to supported functionality now: https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga4e2073c7311f292a0648f04c37b73781 --- ROADMAP.md | 2 +- core.cpp | 4 ++++ core.go | 14 ++++++++++++++ core.h | 1 + core_test.go | 23 +++++++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 1557b5db..b11e4b85 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -18,7 +18,7 @@ Your pull requests will be greatly appreciated! - [ ] [Mahalanobis](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4493aee129179459cbfc6064f051aa7d) - [ ] [mulTransposed](https://docs.opencv.org/master/d2/de8/group__core__array.html#gadc4e49f8f7a155044e3be1b9e3b270ab) - [ ] [PCABackProject](https://docs.opencv.org/master/d2/de8/group__core__array.html#gab26049f30ee8e94f7d69d82c124faafc) - - [ ] [PCACompute](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4e2073c7311f292a0648f04c37b73781) + - [X] [PCACompute](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga4e2073c7311f292a0648f04c37b73781) - [ ] [PCAProject](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga6b9fbc7b3a99ebfd441bbec0a6bc4f88) - [ ] [PSNR](https://docs.opencv.org/master/d2/de8/group__core__array.html#ga07aaf34ae31d226b1b847d8bcff3698f) - [ ] [randn](https://docs.opencv.org/master/d2/de8/group__core__array.html#gaeff1f61e972d133a04ce3a5f81cf6808) diff --git a/core.cpp b/core.cpp index 97d0f8f2..79ef8a29 100644 --- a/core.cpp +++ b/core.cpp @@ -504,6 +504,10 @@ void Mat_EigenNonSymmetric(Mat src, Mat eigenvalues, Mat eigenvectors) { cv::eigenNonSymmetric(*src, *eigenvalues, *eigenvectors); } +void Mat_PCACompute(Mat src, Mat mean, Mat eigenvalues, Mat eigenvectors, int maxComponents) { + cv::PCACompute(*src, *mean, *eigenvalues, *eigenvectors, maxComponents); +} + void Mat_Exp(Mat src, Mat dst) { cv::exp(*src, *dst); } diff --git a/core.go b/core.go index 3f30900b..be51a59b 100644 --- a/core.go +++ b/core.go @@ -1219,6 +1219,20 @@ func EigenNonSymmetric(src Mat, eigenvalues *Mat, eigenvectors *Mat) { C.Mat_EigenNonSymmetric(src.p, eigenvalues.p, eigenvectors.p) } +// PCACompute performs PCA. +// +// The computed eigenvalues are sorted from the largest to the smallest and the corresponding +// eigenvectors are stored as eigenvectors rows. +// +// Note: Calling with maxComponents == 0 (opencv default) will cause all components to be retained. +// +// For further details, please see: +// https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga27a565b31d820b05dcbcd47112176b6e +// +func PCACompute(src Mat, mean *Mat, eigenvalues *Mat, eigenvectors *Mat, maxComponents int) { + C.Mat_PCACompute(src.p, mean.p, eigenvalues.p, eigenvectors.p, C.int(maxComponents)) +} + // Exp calculates the exponent of every array element. // // For further details, please see: diff --git a/core.h b/core.h index 19dc3ed5..12f1c318 100644 --- a/core.h +++ b/core.h @@ -379,6 +379,7 @@ void Mat_DFT(Mat m, Mat dst, int flags); void Mat_Divide(Mat src1, Mat src2, Mat dst); bool Mat_Eigen(Mat src, Mat eigenvalues, Mat eigenvectors); void Mat_EigenNonSymmetric(Mat src, Mat eigenvalues, Mat eigenvectors); +void Mat_PCACompute(Mat src, Mat mean, Mat eigenvalues, Mat eigenvectors, int maxComponents); void Mat_Exp(Mat src, Mat dst); void Mat_ExtractChannel(Mat src, Mat dst, int coi); void Mat_FindNonZero(Mat src, Mat idx); diff --git a/core_test.go b/core_test.go index 64b795f3..633c311a 100644 --- a/core_test.go +++ b/core_test.go @@ -2070,6 +2070,29 @@ func TestMatEigenNonSymmetric(t *testing.T) { eigenvalues.Close() } +func TestPCACompute(t *testing.T) { + src := NewMatWithSize(10, 10, MatTypeCV32F) + // Set some source data so the PCA is done on a non-zero matrix. + src.SetFloatAt(0, 0, 17) + src.SetFloatAt(2, 1, 5) + src.SetFloatAt(9, 9, 25) + mean := NewMat() + eigenvalues := NewMat() + eigenvectors := NewMat() + maxComponents := 2 + PCACompute(src, &mean, &eigenvalues, &eigenvectors, maxComponents) + if mean.Empty() || eigenvectors.Empty() || eigenvalues.Empty() { + t.Error("TestPCACompute should not have empty eigenvectors or eigenvalues.") + } + if eigenvectors.Rows() > maxComponents { + t.Errorf("TestPCACompute unexpected numComponents, got=%d, want<=%d", eigenvectors.Rows(), maxComponents) + } + src.Close() + mean.Close() + eigenvectors.Close() + eigenvalues.Close() +} + func TestMatExp(t *testing.T) { src := NewMatWithSize(10, 10, MatTypeCV32F) dst := NewMat()