diff --git a/ext/opencv/cvchain.cpp b/ext/opencv/cvchain.cpp index a80372c..6c21677 100644 --- a/ext/opencv/cvchain.cpp +++ b/ext/opencv/cvchain.cpp @@ -20,7 +20,7 @@ __NAMESPACE_BEGIN_CVCHAIN #define APPROX_CHAIN_OPTION(op) rb_get_option_table(rb_klass, "APPROX_CHAIN_OPTION", op) #define APPROX_CHAIN_METHOD(op) CVMETHOD("APPROX_CHAIN_METHOD", LOOKUP_CVMETHOD(op, "method"), CV_CHAIN_APPROX_SIMPLE) #define APPROX_CHAIN_PARAMETER(op) NUM2INT(LOOKUP_CVMETHOD(op, "parameter")) -#define APPROX_CHAIN_MINIMAL_PARAMETER(op) NUM2INT(LOOKUP_CVMETHOD(op, "minimal_parameter")) +#define APPROX_CHAIN_MINIMAL_PERIMETER(op) NUM2INT(LOOKUP_CVMETHOD(op, "minimal_perimeter")) #define APPROX_CHAIN_RECURSIVE(op) TRUE_OR_FALSE(LOOKUP_CVMETHOD(op, "recursive")) VALUE rb_klass; @@ -52,7 +52,7 @@ define_ruby_class() rb_define_const(rb_klass, "APPROX_CHAIN_OPTION", approx_chain_option); rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("method")), ID2SYM(rb_intern("approx_simple"))); rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("parameter")), rb_float_new(0)); - rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("minimal_parameter")), INT2FIX(0)); + rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("minimal_perimeter")), INT2FIX(0)); rb_hash_aset(approx_chain_option, ID2SYM(rb_intern("recursive")), Qfalse); rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); @@ -60,8 +60,8 @@ define_ruby_class() rb_define_method(rb_klass, "origin=", RUBY_METHOD_FUNC(rb_set_origin), 1); rb_define_method(rb_klass, "codes", RUBY_METHOD_FUNC(rb_codes), 0); rb_define_method(rb_klass, "points", RUBY_METHOD_FUNC(rb_points), 0); - rb_define_method(rb_klass, "approx_chain", RUBY_METHOD_FUNC(rb_approx_chain), -1); - rb_define_alias(rb_klass, "approx", "approx_chain"); + rb_define_method(rb_klass, "approx_chains", RUBY_METHOD_FUNC(rb_approx_chains), -1); + rb_define_alias(rb_klass, "approx", "approx_chains"); } VALUE @@ -172,7 +172,7 @@ rb_points(VALUE self) /* * call-seq: - * approx_chain([approx_chain_option]) -> cvcontour + * approx_chains([approx_chain_option]) -> cvcontour * * Approximates Freeman chain(s) with polygonal curve. * approx_chain_option should be Hash include these keys. @@ -193,21 +193,22 @@ rb_points(VALUE self) * */ VALUE -rb_approx_chain(int argc, VALUE *argv, VALUE self) +rb_approx_chains(int argc, VALUE *argv, VALUE self) { - VALUE approx_chain_option, storage; + VALUE approx_chain_option; rb_scan_args(argc, argv, "01", &approx_chain_option); + approx_chain_option = APPROX_CHAIN_OPTION(approx_chain_option); - /* can't compile VC - storage = cCvMemStorage::new_object(); + VALUE storage = cCvMemStorage::new_object(); CvSeq *seq = cvApproxChains(CVSEQ(self), CVMEMSTORAGE(storage), APPROX_CHAIN_METHOD(approx_chain_option), - APPROX_CHAIN_PARAMETER(approx_chain_option), - APPROX_CHAIN_MINIMAL_PARAMETER(approx_chain_option), + APPROX_CHAIN_PARAMETER(approx_chain_option), + APPROX_CHAIN_MINIMAL_PERIMETER(approx_chain_option), APPROX_CHAIN_RECURSIVE(approx_chain_option)); - - return cCvSeq::new_sequence(cCvContour::rb_class(), seq, cCvPoint::rb_class(), storage); - */ + + if (seq && seq->total > 0) { + return cCvSeq::new_sequence(cCvChain::rb_class(), seq, cCvPoint::rb_class(), storage); + } return Qnil; } diff --git a/ext/opencv/cvchain.h b/ext/opencv/cvchain.h index 987c534..49ed367 100644 --- a/ext/opencv/cvchain.h +++ b/ext/opencv/cvchain.h @@ -28,7 +28,7 @@ VALUE rb_origin(VALUE self); VALUE rb_set_origin(VALUE self, VALUE origin); VALUE rb_codes(VALUE self); VALUE rb_points(VALUE self); -VALUE rb_approx_chain(int argc, VALUE *argv, VALUE self); +VALUE rb_approx_chains(int argc, VALUE *argv, VALUE self); VALUE new_object(); diff --git a/test/test_cvchain.rb b/test/test_cvchain.rb index 8bc963c..e1fcb7f 100755 --- a/test/test_cvchain.rb +++ b/test/test_cvchain.rb @@ -54,8 +54,55 @@ class TestCvChain < OpenCVTestCase assert(chain.points.all? { |a| a.class == CvPoint }) end - def test_approx_chain - flunk('FIXME: CvChain#approx_chain is not implemented yet.') + def test_approx_chains + mat0 = create_cvmat(128, 128, :cv8u, 1) { |j, i| + (j - 64) ** 2 + (i - 64) ** 2 <= (32 ** 2) ? CvColor::White : CvColor::Black + } + chain = mat0.find_contours(:mode => CV_RETR_EXTERNAL, :method => CV_CHAIN_CODE) + + contours = chain.approx_chains + assert_equal(CvChain, contours.class) + assert(contours.size > 0) + assert(contours.all? { |c| c.class == CvPoint }) + + [CV_CHAIN_APPROX_NONE, CV_CHAIN_APPROX_SIMPLE, + CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_TC89_KCOS, + :approx_none, :approx_simple, :approx_tc89_l1, :approx_tc89_kcos].each { |method| + contours = chain.approx_chains(:method => method) + assert_equal(CvChain, contours.class) + assert(contours.size > 0) + assert(contours.all? { |c| c.class == CvPoint }) + } + + contours = chain.approx_chains(:minimal_parameter => 10) + assert_equal(CvChain, contours.class) + assert(contours.size > 0) + assert(contours.all? { |c| c.class == CvPoint }) + + contours = chain.approx_chains(:minimal_perimeter => (32 * 2 * Math::PI).ceil) + assert_nil(contours) + + [true, false].each { |recursive| + contours = chain.approx_chains(:recursive => recursive) + assert_equal(CvChain, contours.class) + assert(contours.size > 0) + assert(contours.all? { |c| c.class == CvPoint }) + } + + contours = chain.approx_chains(:method => :approx_simple, + :minimal_parameter => 100, :recursive => false) + assert_equal(CvChain, contours.class) + assert(contours.size > 0) + assert(contours.all? { |c| c.class == CvPoint }) + + # Uncomment the following lines to show the result + # contours = chain.approx_chains + # dst = mat0.clone.zero + # begin + # dst.draw_contours!(contours, CvColor::White, CvColor::Black, 2, + # :thickness => 1, :line_type => :aa) + # end while (contours = contours.h_next) + # snap dst end end