diff --git a/ext/cvmat.cpp b/ext/cvmat.cpp
index 89e031b..7ddfb8d 100644
--- a/ext/cvmat.cpp
+++ b/ext/cvmat.cpp
@@ -233,7 +233,8 @@ void define_ruby_class()
rb_define_method(rb_klass, "sub", RUBY_METHOD_FUNC(rb_sub), -1);
rb_define_alias(rb_klass, "-", "sub");
rb_define_method(rb_klass, "mul", RUBY_METHOD_FUNC(rb_mul), -1);
- rb_define_alias(rb_klass, "*", "mul");
+ rb_define_method(rb_klass, "mat_mul", RUBY_METHOD_FUNC(rb_mat_mul), -1);
+ rb_define_alias(rb_klass, "*", "mat_mul");
rb_define_method(rb_klass, "div", RUBY_METHOD_FUNC(rb_div), -1);
rb_define_alias(rb_klass, "/", "div");
rb_define_method(rb_klass, "and", RUBY_METHOD_FUNC(rb_and), -1);
@@ -1693,7 +1694,7 @@ rb_mul(int argc, VALUE *argv, VALUE self)
if (rb_scan_args(argc, argv, "11", &val, &scale) < 2)
scale = rb_float_new(1.0);
dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
- if (rb_obj_is_kind_of(val, rb_klass)) {
+ if (rb_obj_is_kind_of(val, rb_klass)) {
cvMul(CVARR(self), CVARR(val), CVARR(dest), NUM2DBL(scale));
}else{
CvScalar scl = VALUE_TO_CVSCALAR(val);
@@ -1704,6 +1705,28 @@ rb_mul(int argc, VALUE *argv, VALUE self)
return dest;
}
+/*
+ * call-seq:
+ * mat_mul(val[,shiftvec]) -> cvmat
+ * Performs matrix multiplication
+ * dst = src1 * src2 + shiftvec
+ * val and shiftvec should be CvMat
+ * All the matrices should have the same data type and coordinated sizes.
+ * Real or complex floating-point matrices are supported.
+ */
+VALUE
+rb_mat_mul(int argc, VALUE *argv, VALUE self)
+{
+ VALUE val, shiftvec, dest;
+ rb_scan_args(argc, argv, "11", &val, &shiftvec);
+ dest = new_object(CVMAT(self)->rows, CVMAT(val)->cols, cvGetElemType(CVARR(self)));
+ if (NIL_P(shiftvec))
+ cvMatMul(CVARR(self), CVARR(val), CVARR(dest));
+ else
+ cvMatMulAdd(CVARR(self), CVARR(val), CVARR(shiftvec), CVARR(dest));
+ return dest;
+}
+
/*
* call-seq:
* div(val[,scale = 1.0]) -> cvmat
diff --git a/ext/cvmat.h b/ext/cvmat.h
index 02c865f..2857446 100644
--- a/ext/cvmat.h
+++ b/ext/cvmat.h
@@ -93,6 +93,7 @@ VALUE rb_convert_scale_abs(VALUE self, VALUE hash);
VALUE rb_add(int argc, VALUE *argv, VALUE self);
VALUE rb_sub(int argc, VALUE *argv, VALUE self);
VALUE rb_mul(int argc, VALUE *argv, VALUE self);
+VALUE rb_mat_mul(int argc, VALUE *argv, VALUE self);
VALUE rb_div(int argc, VALUE *argv, VALUE self);
VALUE rb_and(int argc, VALUE *argv, VALUE self);
VALUE rb_or(int argc, VALUE *argv, VALUE self);
diff --git a/test/test_cvmat.rb b/test/test_cvmat.rb
index d3dd9d9..5295036 100755
--- a/test/test_cvmat.rb
+++ b/test/test_cvmat.rb
@@ -1041,7 +1041,47 @@ class TestCvMat < OpenCVTestCase
end
def test_mat_mul
- flunk('FIXME: CvMat#mat_mul is not implemented yet.')
+ m0 = create_cvmat(3, 3, :cv32f, 1) { |j, i, c|
+ CvScalar.new(c * 0.1)
+ }
+ m1 = create_cvmat(3, 3, :cv32f, 1) { |j, i, c|
+ CvScalar.new(c)
+ }
+ m2 = create_cvmat(3, 3, :cv32f, 1) { |j, i, c|
+ CvScalar.new(c + 1)
+ }
+
+ m3 = m0.mat_mul(m1)
+ m4 = m0 * m1
+
+ [m3, m4].each { |m|
+ assert_equal(m1.width, m.width)
+ assert_equal(m1.height, m.height)
+ assert_in_delta(1.5, m[0, 0][0], 0.001)
+ assert_in_delta(1.8, m[0, 1][0], 0.001)
+ assert_in_delta(2.1, m[0, 2][0], 0.001)
+ assert_in_delta(4.2, m[1, 0][0], 0.001)
+ assert_in_delta(5.4, m[1, 1][0], 0.001)
+ assert_in_delta(6.6, m[1, 2][0], 0.001)
+ assert_in_delta(6.9, m[2, 0][0], 0.001)
+ assert_in_delta(9, m[2, 1][0], 0.001)
+ assert_in_delta(11.1, m[2, 2][0], 0.001)
+ }
+
+ m5 = m0.mat_mul(m1, m2)
+ [m5].each { |m|
+ assert_equal(m1.width, m.width)
+ assert_equal(m1.height, m.height)
+ assert_in_delta(2.5, m[0, 0][0], 0.001)
+ assert_in_delta(3.8, m[0, 1][0], 0.001)
+ assert_in_delta(5.1, m[0, 2][0], 0.001)
+ assert_in_delta(8.2, m[1, 0][0], 0.001)
+ assert_in_delta(10.4, m[1, 1][0], 0.001)
+ assert_in_delta(12.6, m[1, 2][0], 0.001)
+ assert_in_delta(13.9, m[2, 0][0], 0.001)
+ assert_in_delta(17, m[2, 1][0], 0.001)
+ assert_in_delta(20.1, m[2, 2][0], 0.001)
+ }
end
def test_div