From 88ebe4b59189df93b38aef9013299100e9373c21 Mon Sep 17 00:00:00 2001 From: ser1zw Date: Thu, 5 May 2016 08:15:00 +0900 Subject: [PATCH] add array concatenatation functions --- ext/opencv/mat.cpp | 53 ++++++++++++++++++++++++++++++++++++ ext/opencv/mat.hpp | 2 ++ ext/opencv/opencv.cpp | 2 ++ test/test_opencv.rb | 63 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 119 insertions(+), 1 deletion(-) diff --git a/ext/opencv/mat.cpp b/ext/opencv/mat.cpp index cbc6102..2712577 100644 --- a/ext/opencv/mat.cpp +++ b/ext/opencv/mat.cpp @@ -1080,6 +1080,31 @@ namespace rubyopencv { return result; } + VALUE rb_merge_array_internal(VALUE self, VALUE src, + void (*merge_func)(cv::InputArrayOfArrays, cv::OutputArray)) { + Check_Type(src, T_ARRAY); + + const long size = RARRAY_LEN(src); + std::vector matrixes; + for (long i = 0; i < size; i++) { + VALUE elt = RARRAY_AREF(src, i); + cv::Mat* tmp = obj2mat(elt); + matrixes.push_back(*tmp); + } + + cv::Mat* dstptr = NULL; + try { + dstptr = new cv::Mat(); + merge_func(matrixes, *dstptr); + } + catch (cv::Exception& e) { + delete dstptr; + Error::raise(e); + } + + return mat2obj(dstptr); + } + /* * Creates one multi-channel array out of several single-channel ones. * The function merge merges several arrays to make a single multi-channel array. @@ -1114,6 +1139,34 @@ namespace rubyopencv { return mat2obj(dstptr); } + /* + * Applies horizontal concatenation to given matrices. + * The function horizontally concatenates two or more Cv::Mat matrices (with the same number of rows). + * + * @overload hconcat(src) + * @param src [Array] Input array of matrices. all of the matrices must have the same number of rows and the same depth. + * @return [Mat] Output array + * @!scope class + * @opencv_func cv::hconcat + */ + VALUE rb_hconcat(VALUE self, VALUE src) { + return rb_merge_array_internal(self, src, &cv::hconcat); + } + + /* + * Applies vertical concatenation to given matrices. + * The function vertically concatenates two or more cv::Mat matrices (with the same number of cols). + * + * @overload vconcat(src) + * @param src [Array] Input array of matrices. all of the matrices must have the same number of rows and the same depth. + * @return [Mat] Output array + * @!scope class + * @opencv_func cv::vconcat + */ + VALUE rb_vconcat(VALUE self, VALUE src) { + return rb_merge_array_internal(self, src, &cv::vconcat); + } + void init() { VALUE opencv = rb_define_module("Cv"); diff --git a/ext/opencv/mat.hpp b/ext/opencv/mat.hpp index 9aa6bbe..2fbd036 100644 --- a/ext/opencv/mat.hpp +++ b/ext/opencv/mat.hpp @@ -15,6 +15,8 @@ namespace rubyopencv { VALUE rb_clone(VALUE self); VALUE rb_add_weighted(int argc, VALUE *argv, VALUE self); VALUE rb_merge(VALUE self, VALUE mv); + VALUE rb_hconcat(VALUE self, VALUE src); + VALUE rb_vconcat(VALUE self, VALUE src); cv::Mat* obj2mat(VALUE obj); VALUE mat2obj(cv::Mat* ptr); diff --git a/ext/opencv/opencv.cpp b/ext/opencv/opencv.cpp index 1b64502..e406b86 100644 --- a/ext/opencv/opencv.cpp +++ b/ext/opencv/opencv.cpp @@ -106,6 +106,8 @@ namespace rubyopencv { rb_define_singleton_method(rb_module, "add_weighted", RUBY_METHOD_FUNC(Mat::rb_add_weighted), -1); // in ext/opencv/mat.cpp rb_define_singleton_method(rb_module, "merge", RUBY_METHOD_FUNC(Mat::rb_merge), 1); // in ext/opencv/mat.cpp + rb_define_singleton_method(rb_module, "hconcat", RUBY_METHOD_FUNC(Mat::rb_hconcat), 1); // in ext/opencv/mat.cpp + rb_define_singleton_method(rb_module, "vconcat", RUBY_METHOD_FUNC(Mat::rb_vconcat), 1); // in ext/opencv/mat.cpp rb_define_singleton_method(rb_module, "CV_MAKETYPE", RUBY_METHOD_FUNC(rb_maketype), 2); diff --git a/test/test_opencv.rb b/test/test_opencv.rb index 1ef5679..4734f2f 100755 --- a/test/test_opencv.rb +++ b/test/test_opencv.rb @@ -64,5 +64,66 @@ class TestOpenCV < OpenCVTestCase # w.show(m) # w.wait_key end -end + def test_hconcat + m1 = Mat::ones(2, 2, CV_8U) + 1 + m2 = Mat::ones(2, 2, CV_8U) + 2 + + m = Cv::hconcat([m1, m2]); + assert_equal(m1.class, m1.class) + assert_equal(m1.rows, m.rows) + assert_equal(m1.cols + m2.cols, m.cols) + assert_equal(m1.depth, m.depth) + assert_equal(m1.channels, m.channels) + + m1.rows.times { |r| + (m1.cols + m2.cols).times { |c| + expected = (c < m1.cols) ? m1[r, c][0] : m2[r, c - m1.cols][0] + assert_equal(expected, m[r, c][0]) + } + } + + assert_raise(TypeError) { + Cv::hconcat(DUMMY_OBJ) + } + assert_raise(TypeError) { + Cv::hconcat([DUMMY_OBJ]) + } + + # img = Cv::imread(FILENAME_LENA256x256, -1) + # dst = Cv::hconcat([img, img]) + # Cv::Window.new('hconcat').show(dst) + # Cv::wait_key + end + + def test_vconcat + m1 = Mat::ones(2, 2, CV_8U) + 1 + m2 = Mat::ones(2, 2, CV_8U) + 2 + + m = Cv::vconcat([m1, m2]); + assert_equal(m1.class, m1.class) + assert_equal(m1.rows + m2.rows, m.rows) + assert_equal(m1.cols, m.cols) + assert_equal(m1.depth, m.depth) + assert_equal(m1.channels, m.channels) + + (m1.rows + m2.rows).times { |r| + m1.cols.times { |c| + expected = (r < m1.rows) ? m1[r, c][0] : m2[r - m1.rows, c][0] + assert_equal(expected, m[r, c][0]) + } + } + + assert_raise(TypeError) { + Cv::vconcat(DUMMY_OBJ) + } + assert_raise(TypeError) { + Cv::vconcat([DUMMY_OBJ]) + } + + # img = Cv::imread(FILENAME_LENA256x256, -1) + # dst = Cv::vconcat([img, img]) + # Cv::Window.new('vconcat').show(dst) + # Cv::wait_key + end +end