1
0
Fork 0
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:
ser1zw 2011-01-30 03:49:47 +09:00
parent 6b6a771207
commit b61adde119
5 changed files with 162 additions and 25 deletions

View file

@ -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);
}
/*

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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