From 41bf713cd30a5d64ef93546c29634fca37a39b5c Mon Sep 17 00:00:00 2001 From: ser1zw Date: Sun, 18 Sep 2011 18:22:21 +0900 Subject: [PATCH] added CvMat#svd --- ext/opencv/cvmat.cpp | 47 +++++++++++++++++------ ext/opencv/opencv.cpp | 5 +++ test/test_cvmat.rb | 86 ++++++++++++++++++++++++++++++++++++++++++- test/test_opencv.rb | 5 +++ 4 files changed, 130 insertions(+), 13 deletions(-) diff --git a/ext/opencv/cvmat.cpp b/ext/opencv/cvmat.cpp index 47bf2d6..f4b8cfa 100644 --- a/ext/opencv/cvmat.cpp +++ b/ext/opencv/cvmat.cpp @@ -2630,24 +2630,47 @@ rb_solve(int argc, VALUE *argv, VALUE self) /* * call-seq: - * svd(u = nil, v = nil) + * svd(l[flag=0]) * - * not implementated. * Performs singular value decomposition of real floating-point matrix. */ VALUE rb_svd(int argc, VALUE *argv, VALUE self) { - rb_raise(rb_eNotImpError, ""); - /* - VALUE u = Qnil, v = Qnil; - rb_scan_args(argc, argv, "02", &u, &v); - CvMat - *matU = NIL_P(u) ? NULL : CVARR(u), - *matV = NIL_P(v) ? NULL : CVARR(v); - cvSVD(CVARR(self), matU, matV); - return dest; - */ + VALUE _flag = Qnil; + int flag = 0; + if (rb_scan_args(argc, argv, "01", &_flag) > 0) { + flag = NUM2INT(_flag); + } + + CvMat* self_ptr = CVMAT(self); + VALUE w = new_mat_kind_object(cvSize(self_ptr->cols, self_ptr->rows), self); + + int rows = 0; + int cols = 0; + if (flag & CV_SVD_U_T) { + rows = MIN(self_ptr->rows, self_ptr->cols); + cols = self_ptr->rows; + } + else { + rows = self_ptr->rows; + cols = MIN(self_ptr->rows, self_ptr->cols); + } + VALUE u = new_mat_kind_object(cvSize(cols, rows), self); + + if (flag & CV_SVD_V_T) { + rows = MIN(self_ptr->rows, self_ptr->cols); + cols = self_ptr->cols; + } + else { + rows = self_ptr->cols; + cols = MIN(self_ptr->rows, self_ptr->cols); + } + VALUE v = new_mat_kind_object(cvSize(cols, rows), self); + + cvSVD(self_ptr, CVARR(w), CVARR(u), CVARR(v), flag); + + return rb_ary_new3(3, w, u, v); } /* diff --git a/ext/opencv/opencv.cpp b/ext/opencv/opencv.cpp index 17216c4..78ac639 100644 --- a/ext/opencv/opencv.cpp +++ b/ext/opencv/opencv.cpp @@ -277,6 +277,11 @@ define_ruby_module() /* Warp affine optional flags */ rb_define_const(rb_module, "CV_WARP_FILL_OUTLIERS", INT2FIX(CV_WARP_FILL_OUTLIERS)); rb_define_const(rb_module, "CV_WARP_INVERSE_MAP", INT2FIX(CV_WARP_INVERSE_MAP)); + + /* SVD optional flags */ + rb_define_const(rb_module, "CV_SVD_MODIFY_A", INT2FIX(CV_SVD_MODIFY_A)); + rb_define_const(rb_module, "CV_SVD_U_T", INT2FIX(CV_SVD_U_T)); + rb_define_const(rb_module, "CV_SVD_V_T", INT2FIX(CV_SVD_V_T)); VALUE inversion_method = rb_hash_new(); /* {:lu, :svd, :svd_sym(:svd_symmetric)}: Inversion method */ diff --git a/test/test_cvmat.rb b/test/test_cvmat.rb index 17d10a3..acd9b3b 100755 --- a/test/test_cvmat.rb +++ b/test/test_cvmat.rb @@ -2133,7 +2133,91 @@ class TestCvMat < OpenCVTestCase end def test_svd - flunk('FIXME: CvMat#svd is not implemented yet') + rows = 2 + cols = 3 + m0 = create_cvmat(rows, cols, :cv32f, 1) { |j, i, c| + CvScalar.new(c + 1) + } + + [m0.svd, m0.clone.svd(CV_SVD_MODIFY_A)].each { |w, u, v| + expected = [0.38632, -0.92237, + 0.92237, 0.38632] + assert_equal(rows, u.rows) + assert_equal(rows, u.cols) + expected.each_with_index { |x, i| + assert_in_delta(x, u[i][0], 0.0001) + } + + assert_equal(rows, w.rows) + assert_equal(cols, w.cols) + expected = [9.50803, 0, 0, + 0, 0.77287, 0] + expected.each_with_index { |x, i| + assert_in_delta(x, w[i][0], 0.0001) + } + + assert_equal(cols, v.rows) + assert_equal(rows, v.cols) + expected = [0.42867, 0.80596, + 0.56631, 0.11238, + 0.70395, -0.58120] + + expected.each_with_index { |x, i| + assert_in_delta(x, v[i][0], 0.0001) + } + } + + w, ut, v = m0.svd(CV_SVD_U_T) + expected = [0.38632, 0.92237, + -0.92237, 0.38632] + assert_equal(rows, ut.rows) + assert_equal(rows, ut.cols) + expected.each_with_index { |x, i| + assert_in_delta(x, ut[i][0], 0.0001) + } + + assert_equal(rows, w.rows) + assert_equal(cols, w.cols) + expected = [9.50803, 0, 0, + 0, 0.77287, 0] + expected.each_with_index { |x, i| + assert_in_delta(x, w[i][0], 0.0001) + } + + assert_equal(cols, v.rows) + assert_equal(rows, v.cols) + expected = [0.42867, 0.80596, + 0.56631, 0.11238, + 0.70395, -0.58120] + + expected.each_with_index { |x, i| + assert_in_delta(x, v[i][0], 0.0001) + } + + w, u, vt = m0.svd(CV_SVD_V_T) + expected = [0.38632, -0.92237, + 0.92237, 0.38632] + assert_equal(rows, u.rows) + assert_equal(rows, u.cols) + expected.each_with_index { |x, i| + assert_in_delta(x, u[i][0], 0.0001) + } + + assert_equal(rows, w.rows) + assert_equal(cols, w.cols) + expected = [9.50803, 0, 0, + 0, 0.77287, 0] + expected.each_with_index { |x, i| + assert_in_delta(x, w[i][0], 0.0001) + } + + assert_equal(rows, vt.rows) + assert_equal(cols, vt.cols) + expected = [0.42867, 0.56631, 0.70395, + 0.80596, 0.11238, -0.58120] + expected.each_with_index { |x, i| + assert_in_delta(x, vt[i][0], 0.0001) + } end def test_svdksb diff --git a/test/test_opencv.rb b/test/test_opencv.rb index 597612d..ad0b43a 100755 --- a/test/test_opencv.rb +++ b/test/test_opencv.rb @@ -119,6 +119,11 @@ class TestOpenCV < OpenCVTestCase # Warp affine optional flags assert_equal(8, CV_WARP_FILL_OUTLIERS) assert_equal(16, CV_WARP_INVERSE_MAP) + + # SVD operation flags + assert_equal(1, CV_SVD_MODIFY_A) + assert_equal(2, CV_SVD_U_T) + assert_equal(4, CV_SVD_V_T) end def test_symbols