diff --git a/ext/opencv/cvmat.cpp b/ext/opencv/cvmat.cpp index 8861a4e..aafdcf1 100644 --- a/ext/opencv/cvmat.cpp +++ b/ext/opencv/cvmat.cpp @@ -225,8 +225,8 @@ void define_ruby_class() rb_define_method(rb_klass, "to_CvMat", RUBY_METHOD_FUNC(rb_to_CvMat), 0); rb_define_method(rb_klass, "sub_rect", RUBY_METHOD_FUNC(rb_sub_rect), -2); rb_define_alias(rb_klass, "subrect", "sub_rect"); - rb_define_method(rb_klass, "get_rows", RUBY_METHOD_FUNC(rb_get_rows), -2); - rb_define_method(rb_klass, "get_cols", RUBY_METHOD_FUNC(rb_get_cols), -2); + rb_define_method(rb_klass, "get_rows", RUBY_METHOD_FUNC(rb_get_rows), -1); + rb_define_method(rb_klass, "get_cols", RUBY_METHOD_FUNC(rb_get_cols), 1); rb_define_method(rb_klass, "each_row", RUBY_METHOD_FUNC(rb_each_row), 0); rb_define_method(rb_klass, "each_col", RUBY_METHOD_FUNC(rb_each_col), 0); rb_define_alias(rb_klass, "each_column", "each_col"); @@ -1058,77 +1058,71 @@ rb_sub_rect(VALUE self, VALUE args) return DEPEND_OBJECT(rb_klass, mat, self); } -/* - * call-seq: - * get_rows(n) -> Return row - * get_rows(n1, n2, ...) -> Return Array of row - * - * Return row(or rows) of matrix. - * argument should be Fixnum or CvSlice compatible object. - */ -VALUE -rb_get_rows(VALUE self, VALUE args) -{ - int len = RARRAY_LEN(args); - if (len < 1) - rb_raise(rb_eArgError, "wrong number of argument.(more than 1)"); - VALUE ary = rb_ary_new2(len); - for (int i = 0; i < len; ++i) { - VALUE value = rb_ary_entry(args, i); - - CvMat* row = NULL; - try { - if (FIXNUM_P(value)) - row = cvGetRow(CVARR(self), RB_CVALLOC(CvMat), FIX2INT(value)); - else { - CvSlice slice = VALUE_TO_CVSLICE(value); - row = cvGetRows(CVARR(self), RB_CVALLOC(CvMat), slice.start_index, slice.end_index); - } +void +rb_get_range_index(VALUE index, int* start, int *end) { + if (rb_obj_is_kind_of(index, rb_cRange)) { + *start = NUM2INT(rb_funcall3(index, rb_intern("begin"), 0, NULL)); + *end = NUM2INT(rb_funcall3(index, rb_intern("end"), 0, NULL)); + if (rb_funcall3(index, rb_intern("exclude_end?"), 0, NULL) == Qfalse) { + (*end)++; } - catch (cv::Exception& e) { - if (row != NULL) - cvReleaseMat(&row); - raise_cverror(e); - } - rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, row, self)); } - return RARRAY_LEN(ary) > 1 ? ary : rb_ary_entry(ary, 0); + else { + *start = NUM2INT(index); + *end = *start + 1; + } } /* * call-seq: - * get_cols(n) -> Return column - * get_cols(n1, n2, ...) -> Return Array of columns + * get_rows(row, delta_row = 1) -> cvmat * - * Return column(or columns) of matrix. - * argument should be Fixnum or CvSlice compatible object. + * Return row(or rows) of matrix. + * argument row should be Fixnum or Range object. */ VALUE -rb_get_cols(VALUE self, VALUE args) +rb_get_rows(int argc, VALUE* argv, VALUE self) { - int len = RARRAY_LEN(args); - if (len < 1) - rb_raise(rb_eArgError, "wrong number of argument.(more than 1)"); - VALUE ary = rb_ary_new2(len); - for (int i = 0; i < len; ++i) { - VALUE value = rb_ary_entry(args, i); - CvMat* col = NULL; - try { - if (FIXNUM_P(value)) - col = cvGetCol(CVARR(self), RB_CVALLOC(CvMat), FIX2INT(value)); - else { - CvSlice slice = VALUE_TO_CVSLICE(value); - col = cvGetCols(CVARR(self), RB_CVALLOC(CvMat), slice.start_index, slice.end_index); - } - } - catch (cv::Exception& e) { - if (col != NULL) - cvReleaseMat(&col); - raise_cverror(e); - } - rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, col, self)); + VALUE row_val, delta_val; + rb_scan_args(argc, argv, "11", &row_val, &delta_val); + + int start, end; + rb_get_range_index(row_val, &start, &end); + int delta = NIL_P(delta_val) ? 1 : NUM2INT(delta_val); + CvMat* submat = RB_CVALLOC(CvMat); + try { + cvGetRows(CVARR(self), submat, start, end, delta); } - return RARRAY_LEN(ary) > 1 ? ary : rb_ary_entry(ary, 0); + catch (cv::Exception& e) { + cvFree(&submat); + raise_cverror(e); + } + + return DEPEND_OBJECT(rb_klass, submat, self); +} + +/* + * call-seq: + * get_cols(col) -> cvmat + * + * Return column(or columns) of matrix. + * argument col should be Fixnum or Range object. + */ +VALUE +rb_get_cols(VALUE self, VALUE col) +{ + int start, end; + rb_get_range_index(col, &start, &end); + CvMat* submat = RB_CVALLOC(CvMat); + try { + cvGetCols(CVARR(self), submat, start, end); + } + catch (cv::Exception& e) { + cvFree(&submat); + raise_cverror(e); + } + + return DEPEND_OBJECT(rb_klass, submat, self); } /* diff --git a/ext/opencv/cvmat.h b/ext/opencv/cvmat.h index 4138454..fae26c6 100644 --- a/ext/opencv/cvmat.h +++ b/ext/opencv/cvmat.h @@ -58,8 +58,8 @@ VALUE rb_square_q(VALUE self); VALUE rb_to_CvMat(VALUE self); VALUE rb_to_IplImage(VALUE self); VALUE rb_sub_rect(VALUE self, VALUE args); -VALUE rb_get_rows(VALUE self, VALUE args); -VALUE rb_get_cols(VALUE self, VALUE args); +VALUE rb_get_rows(int argc, VALUE* argv, VALUE self); +VALUE rb_get_cols(VALUE self, VALUE col); VALUE rb_each_row(VALUE self); VALUE rb_each_col(VALUE self); VALUE rb_diag(int argc, VALUE *argv, VALUE self); diff --git a/test/test_cvmat.rb b/test/test_cvmat.rb index 3cf0973..daa19b8 100755 --- a/test/test_cvmat.rb +++ b/test/test_cvmat.rb @@ -439,48 +439,77 @@ class TestCvMat < OpenCVTestCase end def test_get_rows - m1 = create_cvmat(10, 20) + m1 = create_cvmat(10, 20) { |j, i, c| CvScalar.new(c) } - m2 = m1.get_rows(2) - assert_equal(1, m2.height) - assert_equal(m1.width, m2.width) - m1.width.times { |i| - assert_cvscalar_equal(m1[2, i], m2[i]) + row = 2 + m2 = m1.get_rows(row) + assert_equal(1, m2.rows) + assert_equal(m1.cols, m2.cols) + m1.cols.times { |i| + assert_cvscalar_equal(m1[row, i], m2[i]) } - m2, m3 = m1.get_rows(1, 2) - [m2, m3].each { |m| - assert_equal(1, m.height) - assert_equal(m1.width, m.width) + row1 = 3..7 + row2 = 2...8 + [row1, row2].each { |row| + m3 = m1.get_rows(row) + w = (row.exclude_end?) ? row.last - row.begin : row.last - row.begin + 1 + assert_equal(w, m3.rows) + assert_equal(m1.cols, m3.cols) + + m3.rows.times { |j| + m3.cols.times { |i| + assert_cvscalar_equal(m1[row.begin + j, i], m3[j, i]) + } + } } - m1.width.times { |i| - assert_cvscalar_equal(m1[1, i], m2[i]) - assert_cvscalar_equal(m1[2, i], m3[i]) + + [row1, row2].each { |row| + delta = 2 + m3 = m1.get_rows(row, 2) + w = (((row.exclude_end?) ? row.last - row.begin : row.last - row.begin + 1).to_f / delta).ceil + assert_equal(w, m3.rows) + assert_equal(m1.cols, m3.cols) + + m3.rows.times { |j| + m3.cols.times { |i| + assert_cvscalar_equal(m1[row.begin + j * delta, i], m3[j, i]) + } + } } assert_raise(TypeError) { m1.get_rows(DUMMY_OBJ) } + assert_raise(TypeError) { + m1.get_rows(1, DUMMY_OBJ) + } end def test_get_cols - m1 = create_cvmat(10, 20) + m1 = create_cvmat(10, 20) { |j, i, c| CvScalar.new(c) } - m2 = m1.get_cols(2) - assert_equal(1, m2.width) - assert_equal(m1.height, m2.height) + col = 2 + m2 = m1.get_cols(col) + assert_equal(m1.rows, m2.rows) + assert_equal(1, m2.cols) m1.height.times { |j| - assert_cvscalar_equal(m1[j, 2], m2[j]) + assert_cvscalar_equal(m1[j, col], m2[j]) } - m2, m3 = m1.get_cols(1, 2) - [m2, m3].each { |m| - assert_equal(1, m.width) - assert_equal(m1.height, m.height) - } - m1.height.times { |j| - assert_cvscalar_equal(m1[j, 1], m2[j]) - assert_cvscalar_equal(m1[j, 2], m3[j]) + col1 = 3..7 + col2 = 2...8 + [col1, col2].each { |col| + m3 = m1.get_cols(col) + w = (col.exclude_end?) ? col.last - col.begin : col.last - col.begin + 1 + assert_equal(m1.rows, m3.rows) + assert_equal(w, m3.cols) + + m3.rows.times { |j| + m3.cols.times { |i| + assert_cvscalar_equal(m1[j, col.begin + i], m3[j, i]) + } + } } assert_raise(TypeError) {