From 71b2743c762ea6087cb76d37deb5674a4baf84af Mon Sep 17 00:00:00 2001 From: ser1zw Date: Wed, 15 Feb 2012 02:11:41 +0900 Subject: [PATCH] add CvMat#adaptive_threshold --- ext/opencv/cvmat.cpp | 55 +++++++++++++++++++++++++ ext/opencv/opencv.cpp | 10 +++++ test/test_cvmat_imageprocessing.rb | 66 ++++++++++++++++++++++++++++++ test/test_opencv.rb | 4 ++ 4 files changed, 135 insertions(+) diff --git a/ext/opencv/cvmat.cpp b/ext/opencv/cvmat.cpp index 5a6d1af..dc65f32 100644 --- a/ext/opencv/cvmat.cpp +++ b/ext/opencv/cvmat.cpp @@ -338,6 +338,7 @@ void define_ruby_class() rb_define_method(rb_klass, "filter2d", RUBY_METHOD_FUNC(rb_filter2d), -1); rb_define_method(rb_klass, "integral", RUBY_METHOD_FUNC(rb_integral), -1); rb_define_method(rb_klass, "threshold", RUBY_METHOD_FUNC(rb_threshold), -1); + rb_define_method(rb_klass, "adaptive_threshold", RUBY_METHOD_FUNC(rb_adaptive_threshold), -1); rb_define_method(rb_klass, "pyr_down", RUBY_METHOD_FUNC(rb_pyr_down), -1); rb_define_method(rb_klass, "pyr_up", RUBY_METHOD_FUNC(rb_pyr_up), -1); @@ -4418,6 +4419,60 @@ rb_threshold(int argc, VALUE *argv, VALUE self) return rb_threshold_internal(type, threshold, max_value, use_otsu, self); } + +/* + * call-seq: + * adaptive_threshold(max_value[, options]) -> cvmat + * + * Applies an adaptive threshold to an array. + * + * ==== params: + * + * * max_value (Number) - Maximum value that is used with +CV_THRESH_BINARY+ and +CV_THRESH_BINARY_INV+ + * * options (Hash) - threshold option + * * :threshold_type (Integer or Symbol) - Thresholding type; must be one of +CV_THRESH_BINARY+ or +:binary+, +CV_THRESH_BINARY_INV+ or +:binary_inv+ (default: +CV_THRESH_BINARY+) + * * :adaptive_method (Integer or Symbol) - Adaptive thresholding algorithm to use: +CV_ADAPTIVE_THRESH_MEAN_C+ or +:mean_c+, +CV_ADAPTIVE_THRESH_GAUSSIAN_C+ or +:gaussian_c+ (default: +CV_ADAPTIVE_THRESH_MEAN_C+) + * * :block_size (Integer) - The size of a pixel neighborhood that is used to calculate a threshold value for the pixel: 3, 5, 7, and so on (default: 3) + * * :param1 (Number) - The method-dependent parameter. For the methods +CV_ADAPTIVE_THRESH_MEAN_C+ and +CV_ADAPTIVE_THRESH_GAUSSIAN_C+ it is a constant subtracted from the mean or weighted mean, though it may be negative (default: 5) + */ +VALUE +rb_adaptive_threshold(int argc, VALUE *argv, VALUE self) +{ + VALUE max_value, options; + rb_scan_args(argc, argv, "11", &max_value, &options); + + int threshold_type = CV_THRESH_BINARY; + int adaptive_method = CV_ADAPTIVE_THRESH_MEAN_C; + int block_size = 3; + double param1 = 5; + if (!NIL_P(options)) { + Check_Type(options, T_HASH); + threshold_type = CVMETHOD("THRESHOLD_TYPE", LOOKUP_CVMETHOD(options, "threshold_type"), + CV_THRESH_BINARY); + adaptive_method = CVMETHOD("ADAPTIVE_METHOD", LOOKUP_CVMETHOD(options, "adaptive_method"), + CV_ADAPTIVE_THRESH_MEAN_C); + VALUE _block_size = LOOKUP_CVMETHOD(options, "block_size"); + if (!NIL_P(_block_size)) { + block_size = NUM2INT(_block_size); + } + VALUE _param1 = LOOKUP_CVMETHOD(options, "param1"); + if (!NIL_P(_param1)) { + param1 = NUM2INT(_param1); + } + } + CvArr* self_ptr = CVARR(self); + VALUE dst = new_mat_kind_object(cvGetSize(self_ptr), self); + try { + cvAdaptiveThreshold(self_ptr, CVARR(dst), NUM2DBL(max_value), adaptive_method, threshold_type, + block_size, param1); + } + catch (cv::Exception& e) { + raise_cverror(e); + } + + return dst; +} + /* * call-seq: * pyr_down([filter = :gaussian_5x5]) -> cvmat diff --git a/ext/opencv/opencv.cpp b/ext/opencv/opencv.cpp index 7c89488..889339b 100644 --- a/ext/opencv/opencv.cpp +++ b/ext/opencv/opencv.cpp @@ -216,6 +216,10 @@ define_ruby_module() rb_define_const(rb_module, "CV_THRESH_TOZERO_INV", INT2FIX(CV_THRESH_TOZERO_INV)); rb_define_const(rb_module, "CV_THRESH_OTSU", INT2FIX(CV_THRESH_OTSU)); + /* Adaptive methods */ + rb_define_const(rb_module, "CV_ADAPTIVE_THRESH_MEAN_C", INT2FIX(CV_ADAPTIVE_THRESH_MEAN_C)); + rb_define_const(rb_module, "CV_ADAPTIVE_THRESH_GAUSSIAN_C", INT2FIX(CV_ADAPTIVE_THRESH_GAUSSIAN_C)); + /* Border type */ rb_define_const(rb_module, "IPL_BORDER_CONSTANT", INT2FIX(IPL_BORDER_CONSTANT)); rb_define_const(rb_module, "IPL_BORDER_REPLICATE", INT2FIX(IPL_BORDER_REPLICATE)); @@ -413,6 +417,12 @@ define_ruby_module() REGISTER_CVMETHOD(smoothing_type, "median", CV_MEDIAN); REGISTER_CVMETHOD(smoothing_type, "bilateral", CV_BILATERAL); + VALUE adaptive_method = rb_hash_new(); + /* {:mean_c, :gaussian_c}: Adaptive thresholding algorithm */ + rb_define_const(rb_module, "ADAPTIVE_METHOD", adaptive_method); + REGISTER_CVMETHOD(adaptive_method, "mean_c", CV_ADAPTIVE_THRESH_MEAN_C); + REGISTER_CVMETHOD(adaptive_method, "gaussian_c", CV_ADAPTIVE_THRESH_GAUSSIAN_C); + VALUE threshold_type = rb_hash_new(); /* {:binary, :binary_inv, :trunc, :tozero, :tozero_inv, :otsu} : Thresholding types */ rb_define_const(rb_module, "THRESHOLD_TYPE", threshold_type); diff --git a/test/test_cvmat_imageprocessing.rb b/test/test_cvmat_imageprocessing.rb index 95e6a57..51b8b79 100755 --- a/test/test_cvmat_imageprocessing.rb +++ b/test/test_cvmat_imageprocessing.rb @@ -983,6 +983,72 @@ class TestCvMat_imageprocessing < OpenCVTestCase mat0.threshold(1, 2, :binary, DUMMY_OBJ) end + def test_adaptive_threshold + mat0 = create_cvmat(5, 5, :cv8u, 1) { |j, i, c| (c + 1) * 10 } + + mat1 = mat0.adaptive_threshold(128) + expected1 = [0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128] + expected1.each_with_index { |expected, i| + assert_equal(expected, mat1[i][0]) + } + + mat2a = mat0.adaptive_threshold(255, :adaptive_method => :mean_c, + :threshold_type => :binary, :block_size => 5, + :param1 => 10) + mat2b = mat0.adaptive_threshold(255, :adaptive_method => CV_THRESH_BINARY, + :threshold_type => CV_ADAPTIVE_THRESH_MEAN_C, :block_size => 5, + :param1 => 10) + expected2 = [0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255] + [mat2a, mat2b].each { |mat2| + assert_equal(CvMat, mat2.class) + assert_equal(mat0.rows, mat2.rows) + assert_equal(mat0.cols, mat2.cols) + assert_equal(mat0.depth, mat2.depth) + assert_equal(mat0.channel, mat2.channel) + expected2.each_with_index { |expected, i| + assert_equal(expected, mat2[i][0]) + } + } + + + mat3a = mat0.adaptive_threshold(255, :adaptive_method => :gaussian_c, + :threshold_type => :binary_inv, :block_size => 5, + :param1 => 10) + mat3b = mat0.adaptive_threshold(255, :adaptive_method => CV_ADAPTIVE_THRESH_GAUSSIAN_C, + :threshold_type => CV_THRESH_BINARY_INV, :block_size => 5, + :param1 => 10) + expected3 = [255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [mat3a, mat3b].each { |mat3| + assert_equal(CvMat, mat3.class) + assert_equal(mat0.rows, mat3.rows) + assert_equal(mat0.cols, mat3.cols) + assert_equal(mat0.depth, mat3.depth) + assert_equal(mat0.channel, mat3.channel) + expected3.each_with_index { |expected, i| + assert_equal(expected, mat3[i][0]) + } + } + + assert_raise(TypeError) { + mat0.adaptive_threshold(DUMMY_OBJ) + } + assert_raise(TypeError) { + mat0.adaptive_threshold(0, DUMMY_OBJ) + } + assert_raise(TypeError) { + mat0.adaptive_threshold(0, :adaptive_method => DUMMY_OBJ) + } + assert_raise(TypeError) { + mat0.adaptive_threshold(0, :threshold_type => DUMMY_OBJ) + } + assert_raise(TypeError) { + mat0.adaptive_threshold(0, :block_size => DUMMY_OBJ) + } + assert_raise(TypeError) { + mat0.adaptive_threshold(0, :param1 => DUMMY_OBJ) + } + end + def test_pyr_down mat0 = CvMat.load(FILENAME_LENA256x256, CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH) mat1 = mat0.pyr_down diff --git a/test/test_opencv.rb b/test/test_opencv.rb index bd77f08..cf21cbd 100755 --- a/test/test_opencv.rb +++ b/test/test_opencv.rb @@ -62,6 +62,10 @@ class TestOpenCV < OpenCVTestCase assert_equal(4, CV_THRESH_TOZERO_INV) assert_equal(8, CV_THRESH_OTSU) + # Adaptive methods + assert_equal(0, CV_ADAPTIVE_THRESH_MEAN_C) + assert_equal(1, CV_ADAPTIVE_THRESH_GAUSSIAN_C) + # Retrieval mode assert_equal(0, CV_RETR_EXTERNAL) assert_equal(1, CV_RETR_LIST)