mirror of
https://github.com/ruby-opencv/ruby-opencv
synced 2023-03-27 23:22:12 -04:00
implemented CvMat#threshold, modified CvMat#threshold_* to return threshold value calculated in Otsu's algorithm.
This commit is contained in:
parent
6b6a771207
commit
b61adde119
5 changed files with 162 additions and 25 deletions
|
@ -347,6 +347,7 @@ void define_ruby_class()
|
|||
rb_define_method(rb_klass, "copy_make_border_constant", RUBY_METHOD_FUNC(rb_copy_make_border_constant), -1);
|
||||
rb_define_method(rb_klass, "copy_make_border_replicate", RUBY_METHOD_FUNC(rb_copy_make_border_replicate), -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, "threshold_binary", RUBY_METHOD_FUNC(rb_threshold_binary), -1);
|
||||
rb_define_method(rb_klass, "threshold_binary_inverse", RUBY_METHOD_FUNC(rb_threshold_binary_inverse), -1);
|
||||
rb_define_method(rb_klass, "threshold_trunc", RUBY_METHOD_FUNC(rb_threshold_trunc), -1);
|
||||
|
@ -3883,6 +3884,42 @@ rb_integral(int argc, VALUE *argv, VALUE self)
|
|||
return dest;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_threshold_internal(int threshold_type, VALUE threshold, VALUE max_value, VALUE use_otsu, VALUE self)
|
||||
{
|
||||
CvArr* self_ptr = CVARR(self);
|
||||
VALUE dest = cCvMat::new_object(cvGetSize(self_ptr), cvGetElemType(self_ptr));
|
||||
int otsu = (use_otsu == Qtrue) && ((threshold_type & CV_THRESH_OTSU) == 0);
|
||||
int type = threshold_type | (otsu ? CV_THRESH_OTSU : 0);
|
||||
double otsu_threshold = cvThreshold(self_ptr, CVARR(dest), NUM2DBL(threshold), NUM2DBL(max_value), type);
|
||||
|
||||
if ((use_otsu == Qtrue) || (threshold_type & CV_THRESH_OTSU)) {
|
||||
return rb_assoc_new(dest, DBL2NUM(otsu_threshold));
|
||||
}
|
||||
else
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* threshold(<i>threshold, max_value, threshold_type[,use_otsu = false]</i>)
|
||||
*
|
||||
* Applies fixed-level threshold to array elements.
|
||||
*
|
||||
*/
|
||||
VALUE
|
||||
rb_threshold(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE threshold, max_value, threshold_type, use_otsu;
|
||||
rb_scan_args(argc, argv, "31", &threshold, &max_value, &threshold_type, &use_otsu);
|
||||
const int INVALID_TYPE = -1;
|
||||
int type = CVMETHOD("THRESHOLD_TYPE", threshold_type, INVALID_TYPE);
|
||||
if (type == INVALID_TYPE)
|
||||
rb_raise(rb_eArgError, "Invalid threshold type.");
|
||||
|
||||
return rb_threshold_internal(type, threshold, max_value, use_otsu, self);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* threshold_binary(<i>threshold, max_value[,use_otsu = false]</i>)
|
||||
|
@ -3895,11 +3932,9 @@ rb_integral(int argc, VALUE *argv, VALUE self)
|
|||
VALUE
|
||||
rb_threshold_binary(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE threshold, max_value, use_otsu, dest;
|
||||
VALUE threshold, max_value, use_otsu;
|
||||
rb_scan_args(argc, argv, "21", &threshold, &max_value, &use_otsu);
|
||||
dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
|
||||
cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), NUM2DBL(max_value), CV_THRESH_BINARY | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0));
|
||||
return dest;
|
||||
return rb_threshold_internal(CV_THRESH_BINARY, threshold, max_value, use_otsu, self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3914,11 +3949,9 @@ rb_threshold_binary(int argc, VALUE *argv, VALUE self)
|
|||
VALUE
|
||||
rb_threshold_binary_inverse(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE threshold, max_value, use_otsu, dest;
|
||||
VALUE threshold, max_value, use_otsu;
|
||||
rb_scan_args(argc, argv, "21", &threshold, &max_value, &use_otsu);
|
||||
dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
|
||||
cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), NUM2DBL(max_value), CV_THRESH_BINARY_INV | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0));
|
||||
return dest;
|
||||
return rb_threshold_internal(CV_THRESH_BINARY_INV, threshold, max_value, use_otsu, self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3933,11 +3966,9 @@ rb_threshold_binary_inverse(int argc, VALUE *argv, VALUE self)
|
|||
VALUE
|
||||
rb_threshold_trunc(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE threshold, use_otsu, dest;
|
||||
VALUE threshold, use_otsu;
|
||||
rb_scan_args(argc, argv, "11", &threshold, &use_otsu);
|
||||
dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
|
||||
cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), 0, CV_THRESH_TRUNC | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0));
|
||||
return dest;
|
||||
return rb_threshold_internal(CV_THRESH_TRUNC, threshold, INT2NUM(0), use_otsu, self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3952,11 +3983,9 @@ rb_threshold_trunc(int argc, VALUE *argv, VALUE self)
|
|||
VALUE
|
||||
rb_threshold_to_zero(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE threshold, use_otsu, dest;
|
||||
VALUE threshold, use_otsu;
|
||||
rb_scan_args(argc, argv, "11", &threshold, &use_otsu);
|
||||
dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
|
||||
cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), 0, CV_THRESH_TOZERO | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0));
|
||||
return dest;
|
||||
return rb_threshold_internal(CV_THRESH_TOZERO, threshold, INT2NUM(0), use_otsu, self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3971,11 +4000,9 @@ rb_threshold_to_zero(int argc, VALUE *argv, VALUE self)
|
|||
VALUE
|
||||
rb_threshold_to_zero_inverse(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE threshold, use_otsu, dest;
|
||||
VALUE threshold, use_otsu;
|
||||
rb_scan_args(argc, argv, "11", &threshold, &use_otsu);
|
||||
dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
|
||||
cvThreshold(CVARR(self), CVARR(dest), NUM2DBL(threshold), 0, CV_THRESH_TOZERO_INV | (use_otsu == Qtrue ? CV_THRESH_OTSU : 0));
|
||||
return dest;
|
||||
return rb_threshold_internal(CV_THRESH_TOZERO_INV, threshold, INT2NUM(0), use_otsu, self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -207,6 +207,7 @@ VALUE rb_filter2d(int argc, VALUE *argv, VALUE self);
|
|||
VALUE rb_copy_make_border_constant(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_copy_make_border_replicate(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_integral(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_threshold(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_threshold_binary(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_threshold_binary_inverse(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_threshold_trunc(int argc, VALUE *argv, VALUE self);
|
||||
|
|
|
@ -207,6 +207,14 @@ define_ruby_module()
|
|||
rb_define_const(rb_module, "CV_MEDIAN", INT2FIX(CV_MEDIAN));
|
||||
rb_define_const(rb_module, "CV_BILATERAL", INT2FIX(CV_BILATERAL));
|
||||
|
||||
/* Thresholding types */
|
||||
rb_define_const(rb_module, "CV_THRESH_BINARY", INT2FIX(CV_THRESH_BINARY));
|
||||
rb_define_const(rb_module, "CV_THRESH_BINARY_INV", INT2FIX(CV_THRESH_BINARY_INV));
|
||||
rb_define_const(rb_module, "CV_THRESH_TRUNC", INT2FIX(CV_THRESH_TRUNC));
|
||||
rb_define_const(rb_module, "CV_THRESH_TOZERO", INT2FIX(CV_THRESH_TOZERO));
|
||||
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));
|
||||
|
||||
VALUE inversion_method = rb_hash_new();
|
||||
/* {:lu, :svd, :svd_sym(:svd_symmetric)}: Inversion method */
|
||||
rb_define_const(rb_module, "INVERSION_METHOD", inversion_method);
|
||||
|
@ -319,6 +327,15 @@ define_ruby_module()
|
|||
RESIST_CVMETHOD(smoothing_type, "median", CV_MEDIAN);
|
||||
RESIST_CVMETHOD(smoothing_type, "bilateral", CV_BILATERAL);
|
||||
|
||||
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);
|
||||
RESIST_CVMETHOD(threshold_type, "binary", CV_THRESH_BINARY);
|
||||
RESIST_CVMETHOD(threshold_type, "binary_inv", CV_THRESH_BINARY_INV);
|
||||
RESIST_CVMETHOD(threshold_type, "trunc", CV_THRESH_TRUNC);
|
||||
RESIST_CVMETHOD(threshold_type, "tozero", CV_THRESH_TOZERO);
|
||||
RESIST_CVMETHOD(threshold_type, "tozero_inv", CV_THRESH_TOZERO_INV);
|
||||
RESIST_CVMETHOD(threshold_type, "otsu", CV_THRESH_OTSU);
|
||||
|
||||
/* color convert methods */
|
||||
rb_define_module_function(rb_module, "BGR2BGRA", RUBY_METHOD_FUNC(rb_BGR2BGRA), 1);
|
||||
|
|
|
@ -932,6 +932,58 @@ class TestCvMat_imageprocessing < OpenCVTestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_threshold
|
||||
mat0 = create_cvmat(3, 3, :cv8u, 1) { |j, i, n| CvScalar.new(n) }
|
||||
test_proc = lambda { |type, type_sym, expected_mat, expected_threshold|
|
||||
mat1 = mat0.threshold(3, 7, type)
|
||||
mat2 = mat0.threshold(3, 7, type_sym)
|
||||
mat3, th3 = mat0.threshold(5, 7, type | CV_THRESH_OTSU)
|
||||
mat4, th4 = mat0.threshold(3, 7, type_sym, true)
|
||||
mat5, th5 = mat0.threshold(5, 7, type | CV_THRESH_OTSU, true)
|
||||
[mat1, mat2, mat3, mat4, mat5].each { |m|
|
||||
expected_mat.each_with_index { |x, i|
|
||||
assert_equal(x, m[i][0])
|
||||
}
|
||||
}
|
||||
[th3, th4, th5].each { |th|
|
||||
assert_in_delta(expected_threshold, th, 0.001)
|
||||
}
|
||||
}
|
||||
# Binary
|
||||
expected = [0, 0, 0,
|
||||
0, 7, 7,
|
||||
7, 7, 7]
|
||||
test_proc.call(CV_THRESH_BINARY, :binary, expected, 3)
|
||||
|
||||
# Binary inverse
|
||||
expected = [7, 7, 7,
|
||||
7, 0, 0,
|
||||
0, 0, 0]
|
||||
test_proc.call(CV_THRESH_BINARY_INV, :binary_inv, expected, 3)
|
||||
|
||||
# Trunc
|
||||
expected = [0, 1, 2,
|
||||
3, 3, 3,
|
||||
3, 3, 3]
|
||||
test_proc.call(CV_THRESH_TRUNC, :trunc, expected, 3)
|
||||
|
||||
# To zero
|
||||
expected = [0, 0, 0,
|
||||
0, 4, 5,
|
||||
6, 7, 8]
|
||||
test_proc.call(CV_THRESH_TOZERO, :tozero, expected, 3)
|
||||
|
||||
# To zero inverse
|
||||
expected = [0, 1, 2,
|
||||
3, 0, 0,
|
||||
0, 0, 0]
|
||||
test_proc.call(CV_THRESH_TOZERO_INV, :tozero_inv, expected, 3)
|
||||
|
||||
assert_raise(ArgumentError) {
|
||||
mat0.threshold(1, 2, :foobar)
|
||||
}
|
||||
end
|
||||
|
||||
def test_threshold_binary
|
||||
mat0 = create_cvmat(3, 3, :cv8u, 1) { |j, i, n| CvScalar.new(n) }
|
||||
mat1 = mat0.threshold_binary(3, 7)
|
||||
|
@ -942,7 +994,11 @@ class TestCvMat_imageprocessing < OpenCVTestCase
|
|||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
|
||||
flunk('FIXME: Cases of CV_THRESH_OTSU are not tested yet.')
|
||||
mat2, thresh2 = mat0.threshold_binary(5, 7, true)
|
||||
assert_in_delta(3, thresh2, 0.001)
|
||||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
end
|
||||
|
||||
def test_threshold_binary_inverse
|
||||
|
@ -954,7 +1010,12 @@ class TestCvMat_imageprocessing < OpenCVTestCase
|
|||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
flunk('FIXME: Cases of CV_THRESH_OTSU are not tested yet.')
|
||||
|
||||
mat2, thresh2 = mat0.threshold_binary_inverse(5, 7, true)
|
||||
assert_in_delta(3, thresh2, 0.001)
|
||||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
end
|
||||
|
||||
def test_threshold_trunc
|
||||
|
@ -966,7 +1027,12 @@ class TestCvMat_imageprocessing < OpenCVTestCase
|
|||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
flunk('FIXME: Cases of CV_THRESH_OTSU are not tested yet.')
|
||||
|
||||
mat2, thresh2 = mat0.threshold_trunc(5, true)
|
||||
assert_in_delta(3, thresh2, 0.001)
|
||||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
end
|
||||
|
||||
def test_threshold_to_zero
|
||||
|
@ -978,7 +1044,12 @@ class TestCvMat_imageprocessing < OpenCVTestCase
|
|||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
flunk('FIXME: Cases of CV_THRESH_OTSU are not tested yet.')
|
||||
|
||||
mat2, thresh2 = mat0.threshold_to_zero(5, true)
|
||||
assert_in_delta(3, thresh2, 0.001)
|
||||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
end
|
||||
|
||||
def test_threshold_to_zero_inverse
|
||||
|
@ -990,7 +1061,12 @@ class TestCvMat_imageprocessing < OpenCVTestCase
|
|||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
flunk('FIXME: Cases of CV_THRESH_OTSU are not tested yet.')
|
||||
|
||||
mat2, thresh2 = mat0.threshold_to_zero_inverse(5, true)
|
||||
assert_in_delta(3, thresh2, 0.001)
|
||||
expected.each_with_index { |x, i|
|
||||
assert_equal(x, mat1[i][0])
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -43,6 +43,14 @@ class TestOpenCV < OpenCVTestCase
|
|||
assert_equal(2, CV_GAUSSIAN)
|
||||
assert_equal(3, CV_MEDIAN)
|
||||
assert_equal(4, CV_BILATERAL)
|
||||
|
||||
# Thresholding types
|
||||
assert_equal(0, CV_THRESH_BINARY)
|
||||
assert_equal(1, CV_THRESH_BINARY_INV)
|
||||
assert_equal(2, CV_THRESH_TRUNC)
|
||||
assert_equal(3, CV_THRESH_TOZERO)
|
||||
assert_equal(4, CV_THRESH_TOZERO_INV)
|
||||
assert_equal(8, CV_THRESH_OTSU)
|
||||
end
|
||||
|
||||
def test_symbols
|
||||
|
@ -129,6 +137,14 @@ class TestOpenCV < OpenCVTestCase
|
|||
assert_equal(2, SMOOTHING_TYPE[:gaussian])
|
||||
assert_equal(3, SMOOTHING_TYPE[:median])
|
||||
assert_equal(4, SMOOTHING_TYPE[:bilateral])
|
||||
|
||||
# Thresholding types
|
||||
assert_equal(0, THRESHOLD_TYPE[:binary])
|
||||
assert_equal(1, THRESHOLD_TYPE[:binary_inv])
|
||||
assert_equal(2, THRESHOLD_TYPE[:trunc])
|
||||
assert_equal(3, THRESHOLD_TYPE[:tozero])
|
||||
assert_equal(4, THRESHOLD_TYPE[:tozero_inv])
|
||||
assert_equal(8, THRESHOLD_TYPE[:otsu])
|
||||
end
|
||||
|
||||
def test_cvt_color_funcs
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue