diff --git a/ext/opencv/cvmat.cpp b/ext/opencv/cvmat.cpp
index 159d7ed..2f6dccc 100644
--- a/ext/opencv/cvmat.cpp
+++ b/ext/opencv/cvmat.cpp
@@ -352,6 +352,7 @@ void define_ruby_class()
rb_define_method(rb_klass, "resize", RUBY_METHOD_FUNC(rb_resize), -1);
rb_define_method(rb_klass, "warp_affine", RUBY_METHOD_FUNC(rb_warp_affine), -1);
rb_define_singleton_method(rb_klass, "rotation_matrix2D", RUBY_METHOD_FUNC(rb_rotation_matrix2D), 3);
+ rb_define_singleton_method(rb_klass, "get_perspective_transform", RUBY_METHOD_FUNC(rb_get_perspective_transform), 2);
rb_define_method(rb_klass, "warp_perspective", RUBY_METHOD_FUNC(rb_warp_perspective), -1);
rb_define_singleton_method(rb_klass, "find_homography", RUBY_METHOD_FUNC(rb_find_homograpy), -1);
rb_define_method(rb_klass, "remap", RUBY_METHOD_FUNC(rb_remap), -1);
@@ -4053,6 +4054,40 @@ rb_rotation_matrix2D(VALUE self, VALUE center, VALUE angle, VALUE scale)
return map_matrix;
}
+/*
+ * call-seq:
+ * CvMat.get_perspective_transform(from_points,to_points) -> cvmat
+ *
+ * Calculates a perspective transform from four pairs of the corresponding points.
+ * Returns a matrix suitable for use with warp_perspective
+ */
+VALUE
+rb_get_perspective_transform(VALUE self, VALUE source, VALUE dest)
+{
+ Check_Type(source, T_ARRAY);
+ Check_Type(dest, T_ARRAY);
+
+ int count = RARRAY_LEN(source);
+
+ CvPoint2D32f* source_buff = ALLOCA_N(CvPoint2D32f, count);
+ CvPoint2D32f* dest_buff = ALLOCA_N(CvPoint2D32f, count);
+
+ for (int i = 0; i < count; i++) {
+ source_buff[i] = *(CVPOINT2D32F(RARRAY_PTR(source)[i]));
+ dest_buff[i] = *(CVPOINT2D32F(RARRAY_PTR(dest)[i]));
+ }
+
+ VALUE map_matrix = new_object(cvSize(3, 3), CV_MAKETYPE(CV_32F, 1));
+
+ try {
+ cvGetPerspectiveTransform(source_buff, dest_buff, CVMAT(map_matrix));
+ }
+ catch (cv::Exception& e) {
+ raise_cverror(e);
+ }
+ return map_matrix;
+}
+
/*
* call-seq:
* warp_perspective(map_matrix[,flags = CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS][,fillval=0])) -> cvmat
diff --git a/ext/opencv/cvmat.h b/ext/opencv/cvmat.h
index a65bb2a..900be16 100644
--- a/ext/opencv/cvmat.h
+++ b/ext/opencv/cvmat.h
@@ -175,6 +175,7 @@ VALUE rb_quadrangle_sub_pix(int argc, VALUE *argv, VALUE self);
VALUE rb_resize(int argc, VALUE *argv, VALUE self);
VALUE rb_warp_affine(int argc, VALUE *argv, VALUE self);
VALUE rb_rotation_matrix2D(VALUE self, VALUE center, VALUE angle, VALUE scale);
+VALUE rb_get_perspective_transform(VALUE self, VALUE source, VALUE dest);
VALUE rb_warp_perspective(int argc, VALUE *argv, VALUE self);
VALUE rb_find_homograpy(int argc, VALUE *argv, VALUE self);
VALUE rb_remap(int argc, VALUE *argv, VALUE self);
diff --git a/test/test_cvmat_imageprocessing.rb b/test/test_cvmat_imageprocessing.rb
index e3bc9f0..05a4019 100755
--- a/test/test_cvmat_imageprocessing.rb
+++ b/test/test_cvmat_imageprocessing.rb
@@ -450,6 +450,40 @@ class TestCvMat_imageprocessing < OpenCVTestCase
# snap mat0, mat1, mat2, mat3, mat4
end
+ def test_get_perspective_transform
+ from = [
+ OpenCV::CvPoint2D32f.new(540, 382),
+ OpenCV::CvPoint2D32f.new(802, 400),
+ OpenCV::CvPoint2D32f.new(850, 731),
+ OpenCV::CvPoint2D32f.new(540, 731),
+ ]
+ to = [
+ OpenCV::CvPoint2D32f.new(0, 0),
+ OpenCV::CvPoint2D32f.new(233, 0),
+ OpenCV::CvPoint2D32f.new(233, 310),
+ OpenCV::CvPoint2D32f.new(0, 310),
+ ]
+ transform = OpenCV::CvMat.get_perspective_transform(from, to)
+ assert_equal 3, transform.rows
+ assert_equal 3, transform.columns
+ expected = [
+ 0.923332154750824,
+ 0.0,
+ 0.0,
+ 1.4432899320127035e-15,
+ 0.0,
+ 0.0,
+ -498.599365234375,
+ 0.0,
+ 0.0,
+ ]
+ 3.times do |i|
+ 3.times do |j|
+ assert_in_delta(expected.shift, transform[i][j], 0.001)
+ end
+ end
+ end
+
def test_rotation_matrix2D
mat1 = CvMat.rotation_matrix2D(CvPoint2D32f.new(10, 20), 60, 2.0)
expected = [1.0, 1.73205, -34.64102,