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,