/ext/opencv/cvmat.cpp

http://github.com/ryanfb/ruby-opencv · C++ · 5218 lines · 2671 code · 293 blank · 2254 comment · 255 complexity · ded9e7fe3ff7bdf9aa6be0064b9aa05c MD5 · raw file

  1. /************************************************************
  2. cvmat.cpp -
  3. $Author: lsxi $
  4. Copyright (C) 2005-2008 Masakazu Yonekura
  5. ************************************************************/
  6. #include "cvmat.h"
  7. /*
  8. * Document-class: OpenCV::CvMat
  9. *
  10. * CvMat is basic 2D matrix class in OpenCV.
  11. *
  12. * C structure is here.
  13. * typedef struct CvMat{
  14. * int type;
  15. * int step;
  16. * int *refcount;
  17. * union
  18. * {
  19. * uchar *ptr;
  20. * short *s;
  21. * int *i;
  22. * float *fl;
  23. * double *db;
  24. * } data;
  25. * #ifdef __cplusplus
  26. * union
  27. * {
  28. * int rows;
  29. * int height;
  30. * };
  31. * union
  32. * {
  33. * int cols;
  34. * int width;
  35. * };
  36. * #else
  37. * int rows; // number of row
  38. * int cols; // number of columns
  39. * }CvMat;
  40. */
  41. __NAMESPACE_BEGIN_OPENCV
  42. __NAMESPACE_BEGIN_CVMAT
  43. #define SUPPORT_8UC1_ONLY(value) if (cvGetElemType(CVARR(value)) != CV_8UC1) {rb_raise(rb_eNotImpError, "support single-channel 8bit unsigned image only.");}
  44. #define SUPPORT_8U_ONLY(value) if (CV_MAT_DEPTH(cvGetElemType(CVARR(value))) != CV_8U) {rb_raise(rb_eNotImpError, "support 8bit unsigned image only.");}
  45. #define SUPPORT_C1_ONLY(value) if (CV_MAT_CN(cvGetElemType(CVARR(value))) != 1) {rb_raise(rb_eNotImpError, "support single-channel image only.");}
  46. #define SUPPORT_C1C3_ONLY(value) if (CV_MAT_CN(cvGetElemType(CVARR(value))) != 1 && CV_MAT_CN(cvGetElemType(CVARR(value))) != 3) {rb_raise(rb_eNotImpError, "support single-channel or 3-channnel image only.");}
  47. #define DRAWING_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("DRAWING_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("DRAWING_OPTION")), rb_intern("merge"), 1, op)
  48. #define DO_COLOR(op) VALUE_TO_CVSCALAR(rb_hash_aref(op, ID2SYM(rb_intern("color"))))
  49. #define DO_THICKNESS(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("thickness"))))
  50. #define DO_LINE_TYPE(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("line_type"))))
  51. #define DO_SHIFT(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("shift"))))
  52. #define DO_IS_CLOSED(op) ({VALUE _is_closed = rb_hash_aref(op, ID2SYM(rb_intern("is_closed"))); NIL_P(_is_closed) ? 0 : _is_closed == Qfalse ? 0 : 1;})
  53. #define GOOD_FEATURES_TO_TRACK_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("GOOD_FEATURES_TO_TRACK_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("GOOD_FEATURES_TO_TRACK_OPTION")), rb_intern("merge"), 1, op)
  54. #define GF_MAX(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("max"))))
  55. #define GF_MASK(op) MASK(rb_hash_aref(op, ID2SYM(rb_intern("mask"))))
  56. #define GF_BLOCK_SIZE(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("block_size"))))
  57. #define GF_USE_HARRIS(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("use_harris"))), 0)
  58. #define GF_K(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("k"))))
  59. #define FLOOD_FILL_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("FLOOD_FILL_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("FLOOD_FILL_OPTION")), rb_intern("merge"), 1, op)
  60. #define FF_CONNECTIVITY(op) NUM2INT(rb_hash_aref(op, ID2SYM(rb_intern("connectivity"))))
  61. #define FF_FIXED_RANGE(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("fixed_range"))), 0)
  62. #define FF_MASK_ONLY(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("mask_only"))), 0)
  63. #define FIND_CONTOURS_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("FIND_CONTOURS_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("FIND_CONTOURS_OPTION")), rb_intern("merge"), 1, op)
  64. #define FC_MODE(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("mode"))))
  65. #define FC_METHOD(op) FIX2INT(rb_hash_aref(op, ID2SYM(rb_intern("method"))))
  66. #define FC_OFFSET(op)VALUE_TO_CVPOINT(rb_hash_aref(op, ID2SYM(rb_intern("offset"))))
  67. #define OPTICAL_FLOW_HS_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_HS_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_HS_OPTION")), rb_intern("merge"), 1, op)
  68. #define HS_LAMBDA(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("lambda"))))
  69. #define HS_CRITERIA(op) VALUE_TO_CVTERMCRITERIA(rb_hash_aref(op, ID2SYM(rb_intern("criteria"))))
  70. #define OPTICAL_FLOW_BM_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_BM_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("OPTICAL_FLOW_BM_OPTION")), rb_intern("merge"), 1, op)
  71. #define BM_BLOCK_SIZE(op) VALUE_TO_CVSIZE(rb_hash_aref(op, ID2SYM(rb_intern("block_size"))))
  72. #define BM_SHIFT_SIZE(op) VALUE_TO_CVSIZE(rb_hash_aref(op, ID2SYM(rb_intern("shift_size"))))
  73. #define BM_MAX_RANGE(op) VALUE_TO_CVSIZE(rb_hash_aref(op, ID2SYM(rb_intern("max_range"))))
  74. #define FIND_FUNDAMENTAL_MAT_OPTION(op) NIL_P(op) ? rb_const_get(rb_class(), rb_intern("FIND_FUNDAMENTAL_MAT_OPTION")) : rb_funcall(rb_const_get(rb_class(), rb_intern("FIND_FUNDAMENTAL_MAT_OPTION")), rb_intern("merge"), 1, op)
  75. #define FFM_WITH_STATUS(op) TRUE_OR_FALSE(rb_hash_aref(op, ID2SYM(rb_intern("with_status"))), 0)
  76. #define FFM_MAXIMUM_DISTANCE(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("maximum_distance"))))
  77. #define FFM_DESIRABLE_LEVEL(op) NUM2DBL(rb_hash_aref(op, ID2SYM(rb_intern("desirable_level"))))
  78. VALUE rb_klass;
  79. VALUE
  80. rb_class()
  81. {
  82. return rb_klass;
  83. }
  84. void define_ruby_class()
  85. {
  86. if (rb_klass)
  87. return;
  88. /*
  89. * opencv = rb_define_module("OpenCV");
  90. *
  91. * note: this comment is used by rdoc.
  92. */
  93. VALUE opencv = rb_module_opencv();
  94. rb_klass = rb_define_class_under(opencv, "CvMat", rb_cObject);
  95. rb_define_alloc_func(rb_klass, rb_allocate);
  96. VALUE drawing_option = rb_hash_new();
  97. rb_define_const(rb_klass, "DRAWING_OPTION", drawing_option);
  98. rb_hash_aset(drawing_option, ID2SYM(rb_intern("color")), cCvScalar::new_object(cvScalarAll(0)));
  99. rb_hash_aset(drawing_option, ID2SYM(rb_intern("thickness")), INT2FIX(1));
  100. rb_hash_aset(drawing_option, ID2SYM(rb_intern("line_type")), INT2FIX(8));
  101. rb_hash_aset(drawing_option, ID2SYM(rb_intern("shift")), INT2FIX(0));
  102. VALUE good_features_to_track_option = rb_hash_new();
  103. rb_define_const(rb_klass, "GOOD_FEATURES_TO_TRACK_OPTION", good_features_to_track_option);
  104. rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("max")), INT2FIX(0xFF));
  105. rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("mask")), Qnil);
  106. rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("block_size")), INT2FIX(3));
  107. rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("use_harris")), Qfalse);
  108. rb_hash_aset(good_features_to_track_option, ID2SYM(rb_intern("k")), rb_float_new(0.04));
  109. VALUE flood_fill_option = rb_hash_new();
  110. rb_define_const(rb_klass, "FLOOD_FILL_OPTION", flood_fill_option);
  111. rb_hash_aset(flood_fill_option, ID2SYM(rb_intern("connectivity")), INT2FIX(4));
  112. rb_hash_aset(flood_fill_option, ID2SYM(rb_intern("fixed_range")), Qfalse);
  113. rb_hash_aset(flood_fill_option, ID2SYM(rb_intern("mask_only")), Qfalse);
  114. VALUE find_contours_option = rb_hash_new();
  115. rb_define_const(rb_klass, "FIND_CONTOURS_OPTION", find_contours_option);
  116. rb_hash_aset(find_contours_option, ID2SYM(rb_intern("mode")), INT2FIX(CV_RETR_LIST));
  117. rb_hash_aset(find_contours_option, ID2SYM(rb_intern("method")), INT2FIX(CV_CHAIN_APPROX_SIMPLE));
  118. rb_hash_aset(find_contours_option, ID2SYM(rb_intern("offset")), cCvPoint::new_object(cvPoint(0,0)));
  119. VALUE optical_flow_hs_option = rb_hash_new();
  120. rb_define_const(rb_klass, "OPTICAL_FLOW_HS_OPTION", optical_flow_hs_option);
  121. rb_hash_aset(optical_flow_hs_option, ID2SYM(rb_intern("lambda")), rb_float_new(0.0005));
  122. rb_hash_aset(optical_flow_hs_option, ID2SYM(rb_intern("criteria")), cCvTermCriteria::new_object(cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1, 0.001)));
  123. VALUE optical_flow_bm_option = rb_hash_new();
  124. rb_define_const(rb_klass, "OPTICAL_FLOW_BM_OPTION", optical_flow_bm_option);
  125. rb_hash_aset(optical_flow_bm_option, ID2SYM(rb_intern("block_size")), cCvSize::new_object(cvSize(4, 4)));
  126. rb_hash_aset(optical_flow_bm_option, ID2SYM(rb_intern("shift_size")), cCvSize::new_object(cvSize(1, 1)));
  127. rb_hash_aset(optical_flow_bm_option, ID2SYM(rb_intern("max_range")), cCvSize::new_object(cvSize(4, 4)));
  128. VALUE find_fundamental_matrix_option = rb_hash_new();
  129. rb_define_const(rb_klass, "FIND_FUNDAMENTAL_MAT_OPTION", find_fundamental_matrix_option);
  130. rb_hash_aset(find_fundamental_matrix_option, ID2SYM(rb_intern("with_status")), Qfalse);
  131. rb_hash_aset(find_fundamental_matrix_option, ID2SYM(rb_intern("maximum_distance")), rb_float_new(1.0));
  132. rb_hash_aset(find_fundamental_matrix_option, ID2SYM(rb_intern("desirable_level")), rb_float_new(0.99));
  133. rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1);
  134. rb_define_singleton_method(rb_klass, "load", RUBY_METHOD_FUNC(rb_load_imageM), -1);
  135. // Ruby/OpenCV original functions
  136. rb_define_method(rb_klass, "method_missing", RUBY_METHOD_FUNC(rb_method_missing), -1);
  137. rb_define_method(rb_klass, "to_s", RUBY_METHOD_FUNC(rb_to_s), 0);
  138. rb_define_method(rb_klass, "has_parent?", RUBY_METHOD_FUNC(rb_has_parent_q), 0);
  139. rb_define_method(rb_klass, "parent", RUBY_METHOD_FUNC(rb_parent), 0);
  140. rb_define_method(rb_klass, "inside?", RUBY_METHOD_FUNC(rb_inside_q), 1);
  141. rb_define_method(rb_klass, "to_IplConvKernel", RUBY_METHOD_FUNC(rb_to_IplConvKernel), 1);
  142. rb_define_method(rb_klass, "create_mask", RUBY_METHOD_FUNC(rb_create_mask), 0);
  143. rb_define_method(rb_klass, "width", RUBY_METHOD_FUNC(rb_width), 0);
  144. rb_define_alias(rb_klass, "columns", "width");
  145. rb_define_alias(rb_klass, "cols", "width");
  146. rb_define_method(rb_klass, "height", RUBY_METHOD_FUNC(rb_height), 0);
  147. rb_define_alias(rb_klass, "rows", "height");
  148. rb_define_method(rb_klass, "depth", RUBY_METHOD_FUNC(rb_depth), 0);
  149. rb_define_method(rb_klass, "channel", RUBY_METHOD_FUNC(rb_channel), 0);
  150. rb_define_method(rb_klass, "data", RUBY_METHOD_FUNC(rb_data), 0);
  151. rb_define_method(rb_klass, "clone", RUBY_METHOD_FUNC(rb_clone), 0);
  152. rb_define_method(rb_klass, "copy", RUBY_METHOD_FUNC(rb_copy), -1);
  153. rb_define_method(rb_klass, "to_8u", RUBY_METHOD_FUNC(rb_to_8u), 0);
  154. rb_define_method(rb_klass, "to_8s", RUBY_METHOD_FUNC(rb_to_8s), 0);
  155. rb_define_method(rb_klass, "to_16u", RUBY_METHOD_FUNC(rb_to_16u), 0);
  156. rb_define_method(rb_klass, "to_16s", RUBY_METHOD_FUNC(rb_to_16s), 0);
  157. rb_define_method(rb_klass, "to_32s", RUBY_METHOD_FUNC(rb_to_32s), 0);
  158. rb_define_method(rb_klass, "to_32f", RUBY_METHOD_FUNC(rb_to_32f), 0);
  159. rb_define_method(rb_klass, "to_64f", RUBY_METHOD_FUNC(rb_to_64f), 0);
  160. rb_define_method(rb_klass, "vector?", RUBY_METHOD_FUNC(rb_vector_q), 0);
  161. rb_define_method(rb_klass, "square?", RUBY_METHOD_FUNC(rb_square_q), 0);
  162. rb_define_method(rb_klass, "to_CvMat", RUBY_METHOD_FUNC(rb_to_CvMat), 0);
  163. rb_define_method(rb_klass, "sub_rect", RUBY_METHOD_FUNC(rb_sub_rect), -2);
  164. rb_define_alias(rb_klass, "subrect", "sub_rect");
  165. rb_define_method(rb_klass, "slice_width", RUBY_METHOD_FUNC(rb_slice_width), 1);
  166. rb_define_method(rb_klass, "slice_height", RUBY_METHOD_FUNC(rb_slice_height), 1);
  167. rb_define_method(rb_klass, "row", RUBY_METHOD_FUNC(rb_row), -2);
  168. rb_define_method(rb_klass, "col", RUBY_METHOD_FUNC(rb_col), -2);
  169. rb_define_alias(rb_klass, "column", "col");
  170. rb_define_method(rb_klass, "each_row", RUBY_METHOD_FUNC(rb_each_row), 0);
  171. rb_define_method(rb_klass, "each_col", RUBY_METHOD_FUNC(rb_each_col), 0);
  172. rb_define_alias(rb_klass, "each_column", "each_col");
  173. rb_define_method(rb_klass, "diag", RUBY_METHOD_FUNC(rb_diag), -1);
  174. rb_define_alias(rb_klass, "diagonal", "diag");
  175. rb_define_method(rb_klass, "size", RUBY_METHOD_FUNC(rb_size), 0);
  176. rb_define_method(rb_klass, "dims", RUBY_METHOD_FUNC(rb_dims), 0);
  177. rb_define_method(rb_klass, "dim_size", RUBY_METHOD_FUNC(rb_dim_size), 1);
  178. rb_define_method(rb_klass, "[]", RUBY_METHOD_FUNC(rb_aref), -2);
  179. rb_define_alias(rb_klass, "at", "[]");
  180. rb_define_method(rb_klass, "[]=", RUBY_METHOD_FUNC(rb_aset), -2);
  181. rb_define_method(rb_klass, "fill", RUBY_METHOD_FUNC(rb_fill), -1);
  182. rb_define_alias(rb_klass, "set", "fill");
  183. rb_define_method(rb_klass, "fill!", RUBY_METHOD_FUNC(rb_fill_bang), -1);
  184. rb_define_alias(rb_klass, "set!", "fill!");
  185. rb_define_method(rb_klass, "clear", RUBY_METHOD_FUNC(rb_clear), 0);
  186. rb_define_alias(rb_klass, "set_zero", "clear");
  187. rb_define_method(rb_klass, "clear!", RUBY_METHOD_FUNC(rb_clear_bang), 0);
  188. rb_define_alias(rb_klass, "set_zero!", "clear!");
  189. rb_define_method(rb_klass, "identity", RUBY_METHOD_FUNC(rb_set_identity), -1);
  190. rb_define_method(rb_klass, "identity!", RUBY_METHOD_FUNC(rb_set_identity_bang), -1);
  191. rb_define_method(rb_klass, "range", RUBY_METHOD_FUNC(rb_range), -1);
  192. rb_define_method(rb_klass, "range!", RUBY_METHOD_FUNC(rb_range_bang), -1);
  193. rb_define_method(rb_klass, "reshape", RUBY_METHOD_FUNC(rb_reshape), 1);
  194. rb_define_method(rb_klass, "repeat", RUBY_METHOD_FUNC(rb_repeat), 1);
  195. rb_define_method(rb_klass, "flip", RUBY_METHOD_FUNC(rb_flip), -1);
  196. rb_define_method(rb_klass, "flip!", RUBY_METHOD_FUNC(rb_flip_bang), -1);
  197. rb_define_method(rb_klass, "split", RUBY_METHOD_FUNC(rb_split), 0);
  198. rb_define_singleton_method(rb_klass, "merge", RUBY_METHOD_FUNC(rb_merge), -2);
  199. rb_define_method(rb_klass, "rand_shuffle", RUBY_METHOD_FUNC(rb_rand_shuffle), -1);
  200. rb_define_method(rb_klass, "rand_shuffle!", RUBY_METHOD_FUNC(rb_rand_shuffle_bang), -1);
  201. rb_define_method(rb_klass, "lut", RUBY_METHOD_FUNC(rb_lut), 1);
  202. rb_define_method(rb_klass, "convert_scale", RUBY_METHOD_FUNC(rb_convert_scale), 1);
  203. rb_define_method(rb_klass, "convert_scale_abs", RUBY_METHOD_FUNC(rb_convert_scale_abs), 1);
  204. rb_define_method(rb_klass, "add", RUBY_METHOD_FUNC(rb_add), -1);
  205. rb_define_alias(rb_klass, "+", "add");
  206. rb_define_method(rb_klass, "sub", RUBY_METHOD_FUNC(rb_sub), -1);
  207. rb_define_alias(rb_klass, "-", "sub");
  208. rb_define_method(rb_klass, "mul", RUBY_METHOD_FUNC(rb_mul), -1);
  209. rb_define_method(rb_klass, "mat_mul", RUBY_METHOD_FUNC(rb_mat_mul), -1);
  210. rb_define_alias(rb_klass, "*", "mat_mul");
  211. rb_define_method(rb_klass, "div", RUBY_METHOD_FUNC(rb_div), -1);
  212. rb_define_alias(rb_klass, "/", "div");
  213. rb_define_method(rb_klass, "and", RUBY_METHOD_FUNC(rb_and), -1);
  214. rb_define_alias(rb_klass, "&", "and");
  215. rb_define_method(rb_klass, "or", RUBY_METHOD_FUNC(rb_or), -1);
  216. rb_define_alias(rb_klass, "|", "or");
  217. rb_define_method(rb_klass, "xor", RUBY_METHOD_FUNC(rb_xor), -1);
  218. rb_define_alias(rb_klass, "^", "xor");
  219. rb_define_method(rb_klass, "not", RUBY_METHOD_FUNC(rb_not), 0);
  220. rb_define_method(rb_klass, "not!", RUBY_METHOD_FUNC(rb_not_bang), 0);
  221. rb_define_method(rb_klass, "eq", RUBY_METHOD_FUNC(rb_eq), 1);
  222. rb_define_method(rb_klass, "gt", RUBY_METHOD_FUNC(rb_gt), 1);
  223. rb_define_method(rb_klass, "ge", RUBY_METHOD_FUNC(rb_ge), 1);
  224. rb_define_method(rb_klass, "lt", RUBY_METHOD_FUNC(rb_lt), 1);
  225. rb_define_method(rb_klass, "le", RUBY_METHOD_FUNC(rb_le), 1);
  226. rb_define_method(rb_klass, "ne", RUBY_METHOD_FUNC(rb_ne), 1);
  227. rb_define_method(rb_klass, "in_range", RUBY_METHOD_FUNC(rb_in_range), 2);
  228. rb_define_method(rb_klass, "abs_diff", RUBY_METHOD_FUNC(rb_abs_diff), 1);
  229. rb_define_method(rb_klass, "count_non_zero", RUBY_METHOD_FUNC(rb_count_non_zero), 0);
  230. rb_define_method(rb_klass, "sum", RUBY_METHOD_FUNC(rb_sum), 0);
  231. rb_define_method(rb_klass, "avg", RUBY_METHOD_FUNC(rb_avg), -1);
  232. rb_define_method(rb_klass, "avg_sdv", RUBY_METHOD_FUNC(rb_avg_sdv), -1);
  233. rb_define_method(rb_klass, "sdv", RUBY_METHOD_FUNC(rb_sdv), -1);
  234. rb_define_method(rb_klass, "min_max_loc", RUBY_METHOD_FUNC(rb_min_max_loc), -1);
  235. rb_define_method(rb_klass, "dot_product", RUBY_METHOD_FUNC(rb_dot_product), 1);
  236. rb_define_method(rb_klass, "cross_product", RUBY_METHOD_FUNC(rb_cross_product), 1);
  237. rb_define_method(rb_klass, "transform", RUBY_METHOD_FUNC(rb_transform), -1);
  238. rb_define_method(rb_klass, "perspective_transform", RUBY_METHOD_FUNC(rb_perspective_transform), 1);
  239. rb_define_method(rb_klass, "mul_transposed", RUBY_METHOD_FUNC(rb_mul_transposed), -2);
  240. rb_define_method(rb_klass, "trace", RUBY_METHOD_FUNC(rb_trace), 0);
  241. rb_define_method(rb_klass, "transpose", RUBY_METHOD_FUNC(rb_transpose), 0);
  242. rb_define_alias(rb_klass, "t", "transpose");
  243. rb_define_method(rb_klass, "transpose!", RUBY_METHOD_FUNC(rb_transpose_bang), 0);
  244. rb_define_alias(rb_klass, "t!", "transpose!");
  245. rb_define_method(rb_klass, "det", RUBY_METHOD_FUNC(rb_det), 0);
  246. rb_define_alias(rb_klass, "determinant", "det");
  247. rb_define_method(rb_klass, "invert", RUBY_METHOD_FUNC(rb_invert), -1);
  248. rb_define_method(rb_klass, "solve", RUBY_METHOD_FUNC(rb_solve), -1);
  249. rb_define_method(rb_klass, "svd", RUBY_METHOD_FUNC(rb_svd), -1);
  250. rb_define_method(rb_klass, "svbksb", RUBY_METHOD_FUNC(rb_svbksb), -1);
  251. rb_define_method(rb_klass, "eigenvv", RUBY_METHOD_FUNC(rb_eigenvv), -1);
  252. rb_define_method(rb_klass, "calc_covar_matrix", RUBY_METHOD_FUNC(rb_calc_covar_matrix), -1);
  253. rb_define_method(rb_klass, "mahalonobis", RUBY_METHOD_FUNC(rb_mahalonobis), -1);
  254. /* drawing function */
  255. rb_define_method(rb_klass, "line", RUBY_METHOD_FUNC(rb_line), -1);
  256. rb_define_method(rb_klass, "line!", RUBY_METHOD_FUNC(rb_line_bang), -1);
  257. rb_define_method(rb_klass, "rectangle", RUBY_METHOD_FUNC(rb_rectangle), -1);
  258. rb_define_method(rb_klass, "rectangle!", RUBY_METHOD_FUNC(rb_rectangle_bang), -1);
  259. rb_define_method(rb_klass, "circle", RUBY_METHOD_FUNC(rb_circle), -1);
  260. rb_define_method(rb_klass, "circle!", RUBY_METHOD_FUNC(rb_circle_bang), -1);
  261. rb_define_method(rb_klass, "ellipse", RUBY_METHOD_FUNC(rb_ellipse), -1);
  262. rb_define_method(rb_klass, "ellipse!", RUBY_METHOD_FUNC(rb_ellipse_bang), -1);
  263. rb_define_method(rb_klass, "ellipse_box", RUBY_METHOD_FUNC(rb_ellipse_box), -1);
  264. rb_define_method(rb_klass, "ellipse_box!", RUBY_METHOD_FUNC(rb_ellipse_box_bang), -1);
  265. rb_define_method(rb_klass, "fill_poly", RUBY_METHOD_FUNC(rb_fill_poly), -1);
  266. rb_define_method(rb_klass, "fill_poly!", RUBY_METHOD_FUNC(rb_fill_poly_bang), -1);
  267. rb_define_method(rb_klass, "fill_convex_poly", RUBY_METHOD_FUNC(rb_fill_convex_poly), -1);
  268. rb_define_method(rb_klass, "fill_convex_poly!", RUBY_METHOD_FUNC(rb_fill_convex_poly_bang), -1);
  269. rb_define_method(rb_klass, "poly_line", RUBY_METHOD_FUNC(rb_poly_line), -1);
  270. rb_define_method(rb_klass, "poly_line!", RUBY_METHOD_FUNC(rb_poly_line_bang), -1);
  271. rb_define_method(rb_klass, "put_text", RUBY_METHOD_FUNC(rb_put_text), -1);
  272. rb_define_method(rb_klass, "put_text!", RUBY_METHOD_FUNC(rb_put_text_bang), -1);
  273. rb_define_method(rb_klass, "dft", RUBY_METHOD_FUNC(rb_dft), -1);
  274. rb_define_method(rb_klass, "dct", RUBY_METHOD_FUNC(rb_dct), -1);
  275. rb_define_method(rb_klass, "sobel", RUBY_METHOD_FUNC(rb_sobel), -1);
  276. rb_define_method(rb_klass, "laplace", RUBY_METHOD_FUNC(rb_laplace), -1);
  277. rb_define_method(rb_klass, "canny", RUBY_METHOD_FUNC(rb_canny), -1);
  278. rb_define_method(rb_klass, "pre_corner_detect", RUBY_METHOD_FUNC(rb_pre_corner_detect), -1);
  279. rb_define_method(rb_klass, "corner_eigenvv", RUBY_METHOD_FUNC(rb_corner_eigenvv), -1);
  280. rb_define_method(rb_klass, "corner_min_eigen_val", RUBY_METHOD_FUNC(rb_corner_min_eigen_val), -1);
  281. rb_define_method(rb_klass, "corner_harris", RUBY_METHOD_FUNC(rb_corner_harris), -1);
  282. rb_define_private_method(rb_klass, "__find_corner_sub_pix", RUBY_METHOD_FUNC(rbi_find_corner_sub_pix), -1);
  283. rb_define_method(rb_klass, "good_features_to_track", RUBY_METHOD_FUNC(rb_good_features_to_track), -1);
  284. rb_define_method(rb_klass, "sample_line", RUBY_METHOD_FUNC(rb_sample_line), 2);
  285. rb_define_method(rb_klass, "rect_sub_pix", RUBY_METHOD_FUNC(rb_rect_sub_pix), -1);
  286. rb_define_method(rb_klass, "quadrangle_sub_pix", RUBY_METHOD_FUNC(rb_quadrangle_sub_pix), -1);
  287. rb_define_method(rb_klass, "resize", RUBY_METHOD_FUNC(rb_resize), -1);
  288. rb_define_method(rb_klass, "warp_affine", RUBY_METHOD_FUNC(rb_warp_affine), -1);
  289. rb_define_singleton_method(rb_klass, "rotation_matrix2D", RUBY_METHOD_FUNC(rb_rotation_matrix2D), 3);
  290. rb_define_method(rb_klass, "warp_perspective", RUBY_METHOD_FUNC(rb_warp_perspective), -1);
  291. rb_define_singleton_method(rb_klass, "find_homography", RUBY_METHOD_FUNC(rb_find_homograpy), -1);
  292. //rb_define_method(rb_klass, "get_perspective_transform", RUBY_METHOD_FUNC(rb_get_perspective_transform), -1);
  293. //rb_define_alias(rb_klass, "warp_perspective_q_matrix", "get_perspective_transform");
  294. rb_define_method(rb_klass, "remap", RUBY_METHOD_FUNC(rb_remap), -1);
  295. //rb_define_method(rb_klass, "log_polar", RUBY_METHOD_FUNC(rb_log_polar), -1);
  296. rb_define_method(rb_klass, "erode", RUBY_METHOD_FUNC(rb_erode), -1);
  297. rb_define_method(rb_klass, "erode!", RUBY_METHOD_FUNC(rb_erode_bang), -1);
  298. rb_define_method(rb_klass, "dilate", RUBY_METHOD_FUNC(rb_dilate), -1);
  299. rb_define_method(rb_klass, "dilate!", RUBY_METHOD_FUNC(rb_dilate_bang), -1);
  300. rb_define_method(rb_klass, "morphology", RUBY_METHOD_FUNC(rb_morphology), -1);
  301. rb_define_method(rb_klass, "morphology_open", RUBY_METHOD_FUNC(rb_morphology_open), -1);
  302. rb_define_method(rb_klass, "morphology_close", RUBY_METHOD_FUNC(rb_morphology_close), -1);
  303. rb_define_method(rb_klass, "morphology_gradient", RUBY_METHOD_FUNC(rb_morphology_gradient), -1);
  304. rb_define_method(rb_klass, "morphology_tophat", RUBY_METHOD_FUNC(rb_morphology_tophat), -1);
  305. rb_define_method(rb_klass, "morphology_blackhat", RUBY_METHOD_FUNC(rb_morphology_blackhat), -1);
  306. rb_define_method(rb_klass, "smooth", RUBY_METHOD_FUNC(rb_smooth), -1);
  307. rb_define_method(rb_klass, "smooth_blur_no_scale", RUBY_METHOD_FUNC(rb_smooth_blur_no_scale), -1);
  308. rb_define_method(rb_klass, "smooth_blur", RUBY_METHOD_FUNC(rb_smooth_blur), -1);
  309. rb_define_method(rb_klass, "smooth_gaussian", RUBY_METHOD_FUNC(rb_smooth_gaussian), -1);
  310. rb_define_method(rb_klass, "smooth_median", RUBY_METHOD_FUNC(rb_smooth_median), -1);
  311. rb_define_method(rb_klass, "smooth_bilateral", RUBY_METHOD_FUNC(rb_smooth_bilateral), -1);
  312. rb_define_method(rb_klass, "filter2d", RUBY_METHOD_FUNC(rb_filter2d), -1);
  313. rb_define_method(rb_klass, "copy_make_border_constant", RUBY_METHOD_FUNC(rb_copy_make_border_constant), -1);
  314. rb_define_method(rb_klass, "copy_make_border_replicate", RUBY_METHOD_FUNC(rb_copy_make_border_replicate), -1);
  315. rb_define_method(rb_klass, "integral", RUBY_METHOD_FUNC(rb_integral), -1);
  316. rb_define_method(rb_klass, "threshold", RUBY_METHOD_FUNC(rb_threshold), -1);
  317. rb_define_method(rb_klass, "threshold_binary", RUBY_METHOD_FUNC(rb_threshold_binary), -1);
  318. rb_define_method(rb_klass, "threshold_binary_inverse", RUBY_METHOD_FUNC(rb_threshold_binary_inverse), -1);
  319. rb_define_method(rb_klass, "threshold_trunc", RUBY_METHOD_FUNC(rb_threshold_trunc), -1);
  320. rb_define_method(rb_klass, "threshold_to_zero", RUBY_METHOD_FUNC(rb_threshold_to_zero), -1);
  321. rb_define_method(rb_klass, "threshold_to_zero_inverse", RUBY_METHOD_FUNC(rb_threshold_to_zero_inverse), -1);
  322. rb_define_method(rb_klass, "pyr_down", RUBY_METHOD_FUNC(rb_pyr_down), -1);
  323. rb_define_method(rb_klass, "pyr_up", RUBY_METHOD_FUNC(rb_pyr_up), -1);
  324. rb_define_method(rb_klass, "flood_fill", RUBY_METHOD_FUNC(rb_flood_fill), -1);
  325. rb_define_method(rb_klass, "flood_fill!", RUBY_METHOD_FUNC(rb_flood_fill_bang), -1);
  326. rb_define_method(rb_klass, "find_contours", RUBY_METHOD_FUNC(rb_find_contours), -1);
  327. rb_define_method(rb_klass, "find_contours!", RUBY_METHOD_FUNC(rb_find_contours_bang), -1);
  328. rb_define_method(rb_klass, "pyr_segmentation", RUBY_METHOD_FUNC(rb_pyr_segmentation), -1);
  329. rb_define_method(rb_klass, "pyr_mean_shift_filtering", RUBY_METHOD_FUNC(rb_pyr_mean_shift_filtering), -1);
  330. rb_define_method(rb_klass, "watershed", RUBY_METHOD_FUNC(rb_watershed), 1);
  331. rb_define_method(rb_klass, "moments", RUBY_METHOD_FUNC(rb_moments), -1);
  332. rb_define_method(rb_klass, "hough_lines", RUBY_METHOD_FUNC(rb_hough_lines), -1);
  333. rb_define_method(rb_klass, "hough_lines_standard", RUBY_METHOD_FUNC(rb_hough_lines_standard), 3);
  334. rb_define_method(rb_klass, "hough_lines_probabilistic", RUBY_METHOD_FUNC(rb_hough_lines_probabilistic), 5);
  335. rb_define_method(rb_klass, "hough_lines_multi_scale", RUBY_METHOD_FUNC(rb_hough_lines_multi_scale), 5);
  336. rb_define_method(rb_klass, "hough_circles", RUBY_METHOD_FUNC(rb_hough_circles), -1);
  337. rb_define_method(rb_klass, "hough_circles_gradient", RUBY_METHOD_FUNC(rb_hough_circles_gradient), -1);
  338. //rb_define_method(rb_klass, "dist_transform", RUBY_METHOD_FUNC(rb_dist_transform), -1);
  339. rb_define_method(rb_klass, "inpaint", RUBY_METHOD_FUNC(rb_inpaint), 3);
  340. rb_define_method(rb_klass, "inpaint_ns", RUBY_METHOD_FUNC(rb_inpaint_ns), 2);
  341. rb_define_method(rb_klass, "inpaint_telea", RUBY_METHOD_FUNC(rb_inpaint_telea), 2);
  342. rb_define_method(rb_klass, "equalize_hist", RUBY_METHOD_FUNC(rb_equalize_hist), 0);
  343. rb_define_method(rb_klass, "match_template", RUBY_METHOD_FUNC(rb_match_template), -1);
  344. rb_define_method(rb_klass, "match_shapes", RUBY_METHOD_FUNC(rb_match_shapes), -1);
  345. rb_define_method(rb_klass, "match_shapes_i1", RUBY_METHOD_FUNC(rb_match_shapes_i1), -1);
  346. rb_define_method(rb_klass, "match_shapes_i2", RUBY_METHOD_FUNC(rb_match_shapes_i2), -1);
  347. rb_define_method(rb_klass, "match_shapes_i3", RUBY_METHOD_FUNC(rb_match_shapes_i3), -1);
  348. rb_define_method(rb_klass, "mean_shift", RUBY_METHOD_FUNC(rb_mean_shift), 2);
  349. rb_define_method(rb_klass, "cam_shift", RUBY_METHOD_FUNC(rb_cam_shift), 2);
  350. rb_define_method(rb_klass, "snake_image", RUBY_METHOD_FUNC(rb_snake_image), -1);
  351. rb_define_method(rb_klass, "optical_flow_hs", RUBY_METHOD_FUNC(rb_optical_flow_hs), -1);
  352. rb_define_method(rb_klass, "optical_flow_lk", RUBY_METHOD_FUNC(rb_optical_flow_lk), 2);
  353. rb_define_method(rb_klass, "optical_flow_bm", RUBY_METHOD_FUNC(rb_optical_flow_bm), -1);
  354. rb_define_singleton_method(rb_klass, "find_fundamental_mat_7point",
  355. RUBY_METHOD_FUNC(rb_find_fundamental_mat_7point), 2);
  356. rb_define_singleton_method(rb_klass, "find_fundamental_mat_8point",
  357. RUBY_METHOD_FUNC(rb_find_fundamental_mat_8point), 2);
  358. rb_define_singleton_method(rb_klass, "find_fundamental_mat_ransac",
  359. RUBY_METHOD_FUNC(rb_find_fundamental_mat_ransac), -1);
  360. rb_define_singleton_method(rb_klass, "find_fundamental_mat_lmeds",
  361. RUBY_METHOD_FUNC(rb_find_fundamental_mat_lmeds), -1);
  362. rb_define_singleton_method(rb_klass, "find_fundamental_mat",
  363. RUBY_METHOD_FUNC(rb_find_fundamental_mat), -1);
  364. rb_define_singleton_method(rb_klass, "compute_correspond_epilines",
  365. RUBY_METHOD_FUNC(rb_compute_correspond_epilines), 3);
  366. rb_define_method(rb_klass, "save_image", RUBY_METHOD_FUNC(rb_save_image), 1);
  367. }
  368. VALUE
  369. rb_allocate(VALUE klass)
  370. {
  371. return OPENCV_OBJECT(klass, 0);
  372. }
  373. /*
  374. * call-seq:
  375. * CvMat.new(<i>row, col[, depth = CV_8U][, channel = 3]</i>) -> cvmat
  376. *
  377. * Create col * row matrix. Each element set 0.
  378. *
  379. * Each element possigle range is set by <i>depth</i>. Default is unsigned 8bit.
  380. *
  381. * Number of channel is set by <i>channel</i>. <i>channel</i> should be 1..4.
  382. *
  383. */
  384. VALUE
  385. rb_initialize(int argc, VALUE *argv, VALUE self)
  386. {
  387. VALUE row, column, depth, channel;
  388. rb_scan_args(argc, argv, "22", &row, &column, &depth, &channel);
  389. DATA_PTR(self) = cvCreateMat(FIX2INT(row), FIX2INT(column),
  390. CV_MAKETYPE(CVMETHOD("DEPTH", depth, CV_8U), argc < 4 ? 3 : FIX2INT(channel)));
  391. return self;
  392. }
  393. /*
  394. * call-seq:
  395. * CvMat::load(<i>filename[,iscolor = CV_LOAD_IMAGE_COLOR]</i>)
  396. *
  397. * Load an image from file.
  398. * iscolor = CV_LOAD_IMAGE_COLOR, the loaded image is forced to be a 3-channel color image
  399. * iscolor = CV_LOAD_IMAGE_GRAYSCALE, the loaded image is forced to be grayscale
  400. * iscolor = CV_LOAD_IMAGE_UNCHANGED, the loaded image will be loaded as is.
  401. * Currently the following file format are supported.
  402. * * Windows bitmaps - BMP,DIB
  403. * * JPEG files - JPEG,JPG,JPE
  404. * * Portable Network Graphics - PNG
  405. * * Portable image format - PBM,PGM,PPM
  406. * * Sun rasters - SR,RAS
  407. * * TIFF files - TIFF,TIF
  408. */
  409. VALUE
  410. rb_load_imageM(int argc, VALUE *argv, VALUE self)
  411. {
  412. VALUE filename, iscolor;
  413. rb_scan_args(argc, argv, "11", &filename, &iscolor);
  414. Check_Type(filename, T_STRING);
  415. int _iscolor;
  416. if (TYPE(iscolor) == T_NIL) {
  417. _iscolor = CV_LOAD_IMAGE_COLOR;
  418. }
  419. else {
  420. Check_Type(iscolor, T_FIXNUM);
  421. _iscolor = FIX2INT(iscolor);
  422. }
  423. CvMat *mat;
  424. if ((mat = cvLoadImageM(StringValueCStr(filename), _iscolor)) == NULL) {
  425. rb_raise(rb_eStandardError, "file does not exist or invalid format image.");
  426. }
  427. return OPENCV_OBJECT(rb_klass, mat);
  428. }
  429. /*
  430. * nodoc
  431. */
  432. VALUE
  433. rb_method_missing(int argc, VALUE *argv, VALUE self)
  434. {
  435. /*
  436. const char *to_str = "\\Ato_(\\w+)";
  437. VALUE name, args, str[3], method;
  438. rb_scan_args(argc, argv, "1*", &name, &args);
  439. if (RARRAY_LEN(args) != 0)
  440. return rb_call_super(argc, argv);
  441. if(rb_reg_match(rb_reg_new(to_str, strlen(to_str), 0), rb_funcall(name, rb_intern("to_s"), 0)) == Qnil)
  442. return rb_call_super(argc, argv);
  443. str[0] = rb_str_new2("%s2%s");
  444. str[1] = rb_color_model(self);
  445. str[2] = rb_reg_nth_match(1, rb_backref_get());
  446. method = rb_f_sprintf(3, str);
  447. if (rb_respond_to(rb_module_opencv(), rb_intern(StringValuePtr(method))))
  448. return rb_funcall(rb_module_opencv(), rb_intern(StringValuePtr(method)), 1, self);
  449. return rb_call_super(argc, argv);
  450. */
  451. VALUE name, args, method;
  452. rb_scan_args(argc, argv, "1*", &name, &args);
  453. method = rb_funcall(name, rb_intern("to_s"), 0);
  454. if (RARRAY_LEN(args) != 0 || !rb_respond_to(rb_module_opencv(), rb_intern(StringValuePtr(method))))
  455. return rb_call_super(argc, argv);
  456. return rb_funcall(rb_module_opencv(), rb_intern(StringValuePtr(method)), 1, self);
  457. }
  458. /*
  459. * call-seq:
  460. * to_s -> string
  461. *
  462. * Return following string.
  463. * m = CvMat.new(100, 100, :cv8u, 3)
  464. * m.to_s # => <CvMat:100x100,depth=cv8u,channel=3>
  465. */
  466. VALUE
  467. rb_to_s(VALUE self)
  468. {
  469. const int i = 6;
  470. VALUE str[i];
  471. str[0] = rb_str_new2("<%s:%dx%d,depth=%s,channel=%d>");
  472. str[1] = rb_str_new2(rb_class2name(CLASS_OF(self)));
  473. str[2] = rb_width(self);
  474. str[3] = rb_height(self);
  475. str[4] = rb_depth(self);
  476. str[5] = rb_channel(self);
  477. return rb_f_sprintf(i, str);
  478. }
  479. /*
  480. * call-seq:
  481. * has_parent? -> true or false
  482. *
  483. * Return <tt>true</tt> if this matrix has parent object, otherwise <tt>false</tt>.
  484. */
  485. VALUE
  486. rb_has_parent_q(VALUE self)
  487. {
  488. return lookup_root_object(CVMAT(self)) ? Qtrue : Qfalse;
  489. }
  490. /*
  491. * call-seq:
  492. * parent -> obj or nil
  493. *
  494. * Return root object that refer this object.
  495. */
  496. VALUE
  497. rb_parent(VALUE self)
  498. {
  499. VALUE root = lookup_root_object(CVMAT(self));
  500. return root ? root : Qnil;
  501. }
  502. /*
  503. * call-seq:
  504. * inside?(obj) -> true or false
  505. *
  506. *
  507. */
  508. VALUE
  509. rb_inside_q(VALUE self, VALUE object)
  510. {
  511. if (cCvPoint::rb_compatible_q(cCvPoint::rb_class(), object)) {
  512. CvMat *mat = CVMAT(self);
  513. int x = NUM2INT(rb_funcall(object, rb_intern("x"), 0));
  514. int y = NUM2INT(rb_funcall(object, rb_intern("y"), 0));
  515. if (cCvRect::rb_compatible_q(cCvRect::rb_class(), object)) {
  516. int width = NUM2INT(rb_funcall(object, rb_intern("width"), 0));
  517. int height = NUM2INT(rb_funcall(object, rb_intern("height"), 0));
  518. return x >= 0 && y >= 0 && x < mat->width && x + width < mat->width && y < mat->height && y + height < mat->height ? Qtrue : Qfalse;
  519. } else {
  520. return x >= 0 && y >= 0 && x < mat->width && y < mat->height ? Qtrue : Qfalse;
  521. }
  522. }
  523. rb_raise(rb_eArgError, "argument 1 should have method \"x\", \"y\"");
  524. }
  525. /*
  526. * call-seq:
  527. * to_IplConvKernel -> iplconvkernel
  528. *
  529. * Create IplConvKernel from this matrix.
  530. */
  531. VALUE
  532. rb_to_IplConvKernel(VALUE self, VALUE anchor)
  533. {
  534. CvMat *src = CVMAT(self);
  535. CvPoint p = VALUE_TO_CVPOINT(anchor);
  536. IplConvKernel *kernel = cvCreateStructuringElementEx(src->cols, src->rows, p.x, p.y, CV_SHAPE_CUSTOM, src->data.i);
  537. return DEPEND_OBJECT(cIplConvKernel::rb_class(), kernel, self);
  538. }
  539. /*
  540. * call-seq:
  541. * create_mask -> cvmat(single-channel 8bit unsinged image)
  542. *
  543. * Create single-channel 8bit unsinged image that filled 0.
  544. */
  545. VALUE
  546. rb_create_mask(VALUE self)
  547. {
  548. VALUE mask = cCvMat::new_object(cvGetSize(CVARR(self)), CV_8UC1);
  549. cvZero(CVARR(self));
  550. return mask;
  551. }
  552. /*
  553. * call-seq:
  554. * width -> int
  555. *
  556. * Return number of columns.
  557. */
  558. VALUE
  559. rb_width(VALUE self)
  560. {
  561. return INT2FIX(CVMAT(self)->width);
  562. }
  563. /*
  564. * call-seq:
  565. * height -> int
  566. *
  567. * Return number of rows.
  568. */
  569. VALUE
  570. rb_height(VALUE self)
  571. {
  572. return INT2FIX(CVMAT(self)->height);
  573. }
  574. /*
  575. * call-seq:
  576. * depth -> symbol
  577. *
  578. * Return depth symbol. (see OpenCV::DEPTH)
  579. */
  580. VALUE
  581. rb_depth(VALUE self)
  582. {
  583. return rb_hash_aref(rb_funcall(rb_const_get(rb_module_opencv(), rb_intern("DEPTH")), rb_intern("invert"), 0), INT2FIX(CV_MAT_DEPTH(CVMAT(self)->type)));
  584. }
  585. /*
  586. * call-seq:
  587. * channel -> int (1 < channel < 4)
  588. *
  589. * Return number of channel.
  590. */
  591. VALUE
  592. rb_channel(VALUE self)
  593. {
  594. return INT2FIX(CV_MAT_CN(CVMAT(self)->type));
  595. }
  596. /*
  597. * call-seq:
  598. * data -> binary (by String class)
  599. *
  600. * Return raw data of matrix.
  601. */
  602. VALUE
  603. rb_data(VALUE self)
  604. {
  605. IplImage *image = IPLIMAGE(self);
  606. return rb_str_new((char *)image->imageData, image->imageSize);
  607. }
  608. /*
  609. * call-seq:
  610. * clone -> cvmat
  611. *
  612. * Clone matrix. The parent and child relation is not succeeded.
  613. * Instance-specific method is succeeded.
  614. *
  615. * module M
  616. * def example
  617. * true
  618. * end
  619. * end
  620. *
  621. * mat.extend M
  622. * mat.example #=> true
  623. * clone = mat.clone
  624. * clone.example #=> true
  625. * copy = mat.copy
  626. * copy.example #=> raise NoMethodError
  627. */
  628. VALUE
  629. rb_clone(VALUE self)
  630. {
  631. VALUE clone = rb_obj_clone(self);
  632. DATA_PTR(clone) = cvClone(CVARR(self));
  633. return clone;
  634. }
  635. /*
  636. * call-seq:
  637. * copy() -> cvmat
  638. * copy(<i>mat</i>) -> mat
  639. * copy(<i>val</i>) -> array(include cvmat)
  640. *
  641. * Copy matrix. The parent and child relation is not succeeded.
  642. * Instance-specific method is *NOT* succeeded. see also #clone.
  643. *
  644. * There are 3 kind behavior depending on the argument.
  645. *
  646. * copy()
  647. * Return one copied matrix.
  648. * copy(mat)
  649. * Copy own elements to target matrix. Return nil.
  650. * Size (or ROI) and channel and depth should be match.
  651. * If own width or height does not match target matrix, raise CvUnmatchedSizes
  652. * If own channel or depth does not match target matrix, raise CvUnmatchedFormats
  653. * copy(val)
  654. * The amounts of the specified number are copied. Return Array with copies.
  655. * If you give the 0 or negative value. Return nil.
  656. * mat.copy(3) #=> [mat1, mat2, mat3]
  657. * mat.copy(-1) #=> nil
  658. *
  659. * When not apply to any, raise ArgumentError
  660. */
  661. VALUE
  662. rb_copy(int argc, VALUE *argv, VALUE self)
  663. {
  664. VALUE value, copied, tmp;
  665. CvMat *src = CVMAT(self);
  666. rb_scan_args(argc, argv, "01", &value);
  667. if (argc == 0) {
  668. CvSize size = cvGetSize(src);
  669. copied = new_object(cvGetSize(src), cvGetElemType(src));
  670. cvCopy(src, CVMAT(copied));
  671. return copied;
  672. }else{
  673. if (rb_obj_is_kind_of(value, rb_klass)) {
  674. cvCopy(src, CVMAT(value));
  675. return Qnil;
  676. }else if (rb_obj_is_kind_of(value, rb_cFixnum)) {
  677. int n = FIX2INT(value);
  678. if (n > 0) {
  679. copied = rb_ary_new2(n);
  680. for (int i = 0; i < n; i++) {
  681. tmp = new_object(src->rows, src->cols, cvGetElemType(src));
  682. cvCopy(src, CVMAT(tmp));
  683. rb_ary_store(copied, i, tmp);
  684. }
  685. return copied;
  686. }else{
  687. return Qnil;
  688. }
  689. }else
  690. rb_raise(rb_eArgError, "");
  691. }
  692. }
  693. VALUE
  694. copy(VALUE mat)
  695. {
  696. CvMat *src = CVMAT(mat);
  697. VALUE copied = new_object(cvGetSize(src), cvGetElemType(src));
  698. cvCopy(src, CVMAT(copied));
  699. return copied;
  700. }
  701. /*
  702. * call-seq:
  703. * to_8u -> cvmat(depth = CV_8U)
  704. *
  705. * Return the new matrix that elements is converted to unsigned 8bit.
  706. */
  707. VALUE
  708. rb_to_8u(VALUE self)
  709. {
  710. CvMat *src = CVMAT(self);
  711. VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_8U, CV_MAT_CN(src->type)));
  712. cvConvert(src, CVMAT(dest));
  713. return dest;
  714. }
  715. /*
  716. * call-seq:
  717. * to_8s -> cvmat(depth = CV_8S)
  718. *
  719. * Return the new matrix that elements is converted to signed 8bit.
  720. */
  721. VALUE
  722. rb_to_8s(VALUE self)
  723. {
  724. CvMat *src = CVMAT(self);
  725. VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_8S, CV_MAT_CN(src->type)));
  726. cvConvert(src, CVMAT(dest));
  727. return dest;
  728. }
  729. /*
  730. * call-seq:
  731. * to_16u -> cvmat(depth = CV_16U)
  732. *
  733. * Return the new matrix that elements is converted to unsigned 16bit.
  734. */
  735. VALUE rb_to_16u(VALUE self)
  736. {
  737. CvMat *src = CVMAT(self);
  738. VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_16U, CV_MAT_CN(src->type)));
  739. cvConvert(src, CVMAT(dest));
  740. return dest;
  741. }
  742. /*
  743. * call-seq:
  744. * to_16s -> cvmat(depth = CV_16s)
  745. *
  746. * Return the new matrix that elements is converted to signed 16bit.
  747. */
  748. VALUE
  749. rb_to_16s(VALUE self)
  750. {
  751. CvMat *src = CVMAT(self);
  752. VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_16S, CV_MAT_CN(src->type)));
  753. cvConvert(src, CVMAT(dest));
  754. return dest;
  755. }
  756. /*
  757. * call-seq:
  758. * to_32s -> cvmat(depth = CV_32S)
  759. *
  760. * Return the new matrix that elements is converted to signed 32bit.
  761. */
  762. VALUE
  763. rb_to_32s(VALUE self)
  764. {
  765. CvMat *src = CVMAT(self);
  766. VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_32S, CV_MAT_CN(src->type)));
  767. cvConvert(src, CVMAT(dest));
  768. return dest;
  769. }
  770. /*
  771. * call-seq:
  772. * to_32f -> cvmat(depth = CV_32F)
  773. *
  774. * Return the new matrix that elements is converted to 32bit floating-point.
  775. */
  776. VALUE
  777. rb_to_32f(VALUE self)
  778. {
  779. CvMat *src = CVMAT(self);
  780. VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_32F, CV_MAT_CN(src->type)));
  781. cvConvert(src, CVMAT(dest));
  782. return dest;
  783. }
  784. /*
  785. * call-seq:
  786. * to_64F -> cvmat(depth = CV_64F)
  787. *
  788. * Return the new matrix that elements is converted to 64bit floating-point.
  789. */
  790. VALUE
  791. rb_to_64f(VALUE self)
  792. {
  793. CvMat *src = CVMAT(self);
  794. VALUE dest = new_object(src->rows, src->cols, CV_MAKETYPE(CV_64F, CV_MAT_CN(src->type)));
  795. cvConvert(src, CVMAT(dest));
  796. return dest;
  797. }
  798. /*
  799. * call-seq:
  800. * vector? -> true or false
  801. *
  802. * If #width or #height is 1, return true. Otherwise return false.
  803. */
  804. VALUE
  805. rb_vector_q(VALUE self)
  806. {
  807. CvMat *mat = CVMAT(self);
  808. return (mat->width == 1|| mat->height == 1) ? Qtrue : Qfalse;
  809. }
  810. /*
  811. * call-seq:
  812. * square? -> true or false
  813. *
  814. * If #width == #height return true. Otherwise return false.
  815. */
  816. VALUE
  817. rb_square_q(VALUE self)
  818. {
  819. CvMat *mat = CVMAT(self);
  820. return mat->width == mat->height ? Qtrue : Qfalse;
  821. }
  822. /************************************************************
  823. cxcore function
  824. ************************************************************/
  825. /*
  826. * Return CvMat object with reference to caller-object.
  827. *
  828. * src = CvMat.new(10, 10)
  829. * src.has_parent? #=> false
  830. * src.parent #=> nil
  831. * mat = src.to_CvMat
  832. * mat.has_parent? #=> true
  833. * mat.parent #=> CvMat object "src"
  834. *
  835. * This case, 'src' is root-object. and 'mat' is child-object refer to 'src'.
  836. * src <=refer= mat
  837. * In C, 'src->data' and 'mat->data' is common. Therefore, they cause the change each other.
  838. * object 'src' don't GC.
  839. */
  840. VALUE
  841. rb_to_CvMat(VALUE self)
  842. {
  843. return DEPEND_OBJECT(rb_klass, cvGetMat(CVARR(self), CVALLOC(CvMat)), self);
  844. }
  845. /*
  846. * call-seq:
  847. * sub_rect(<i>rect</i>) -> cvmat
  848. * sub_rect(<i>topleft</i>, <i>size</i>) -> cvmat
  849. * sub_rect(<i>x, y, width, height</i>) -> cvmat
  850. *
  851. * Return parts of self as CvMat.
  852. *
  853. * <i>p</i> or <i>x</i>,<i>y</i> mean top-left coordinate.
  854. * <i>size</i> or <i>width</i>,<i>height</i> is size.
  855. *
  856. * link:../images/CvMat_sub_rect.png
  857. */
  858. VALUE
  859. rb_sub_rect(VALUE self, VALUE args)
  860. {
  861. CvRect area;
  862. CvPoint topleft;
  863. CvSize size;
  864. switch(RARRAY_LEN(args)) {
  865. case 1:
  866. area = VALUE_TO_CVRECT(RARRAY_PTR(args)[0]);
  867. break;
  868. case 2:
  869. topleft = VALUE_TO_CVPOINT(RARRAY_PTR(args)[0]);
  870. size = VALUE_TO_CVSIZE(RARRAY_PTR(args)[1]);
  871. area.x = topleft.x;
  872. area.y = topleft.y;
  873. area.width = size.width;
  874. area.height = size.height;
  875. break;
  876. case 4:
  877. area.x = NUM2INT(RARRAY_PTR(args)[0]);
  878. area.y = NUM2INT(RARRAY_PTR(args)[1]);
  879. area.width = NUM2INT(RARRAY_PTR(args)[2]);
  880. area.height = NUM2INT(RARRAY_PTR(args)[3]);
  881. break;
  882. default:
  883. rb_raise(rb_eArgError, "wrong number of arguments (%ld of 1 or 2 or 4)", RARRAY_LEN(args));
  884. }
  885. return DEPEND_OBJECT(rb_klass,
  886. cvGetSubRect(CVARR(self), CVALLOC(CvMat), area),
  887. self);
  888. }
  889. /*
  890. * call-seq:
  891. * slice_width(<i>n</i>)
  892. *
  893. * The matrix is divided into <i>n</i> piece by the width.
  894. * If it cannot be just divided, warning is displayed.
  895. *
  896. * e.g.
  897. * m = OpenCV::CvMat.new(10, 10) #=> size 10x10 matrix
  898. * ml, mr = m.slice_width(2) #=> 5x10 and 5x10 matrix
  899. *
  900. * ml, mm, mr = m.slice_width(3)#=> 3x10 3x10 3x10 matrix
  901. * warning : width does not div correctly.
  902. */
  903. VALUE
  904. rb_slice_width(VALUE self, VALUE num)
  905. {
  906. int n = NUM2INT(num);
  907. if (n < 1) {rb_raise(rb_eArgError, "number of piece should be > 0");}
  908. CvSize size = cvGetSize(CVARR(self));
  909. if (size.width % n != 0) {rb_warn("width does not div correctly.");}
  910. int div_x = size.width / n;
  911. VALUE ary = rb_ary_new2(n);
  912. for (int i = 0; i < n; i++) {
  913. CvRect rect = {div_x * i, 0, div_x, size.height};
  914. rb_ary_push(ary, DEPEND_OBJECT(rb_klass, cvGetSubRect(CVARR(self), CVALLOC(CvMat), rect), self));
  915. }
  916. return ary;
  917. }
  918. /*
  919. * call-seq:
  920. * slice_height(<i>n</i>)
  921. *
  922. * The matrix is divided into <i>n</i> piece by the height.
  923. * If it cannot be just divided, warning is displayed.
  924. *
  925. * see also #slice_width.
  926. */
  927. VALUE
  928. rb_slice_height(VALUE self, VALUE num)
  929. {
  930. int n = NUM2INT(num);
  931. if (n < 1) {rb_raise(rb_eArgError, "number of piece should be > 0");}
  932. CvSize size = cvGetSize(CVARR(self));
  933. if (size.height % n != 0) {rb_warn("height does not div correctly.");}
  934. int div_y = size.height / n;
  935. VALUE ary = rb_ary_new2(n);
  936. for (int i = 0; i < n; i++) {
  937. CvRect rect = {0, div_y * i, size.width, div_y};
  938. rb_ary_push(ary, DEPEND_OBJECT(rb_klass, cvGetSubRect(CVARR(self), CVALLOC(CvMat), rect), self));
  939. }
  940. return ary;
  941. }
  942. /*
  943. * call-seq:
  944. * row(<i>n</i>) -> Return row
  945. * row(<i>n1, n2, ...</i>) -> Return Array of row
  946. *
  947. * Return row(or rows) of matrix.
  948. * argument should be Fixnum or CvSlice compatible object.
  949. */
  950. VALUE
  951. rb_row(VALUE self, VALUE args)
  952. {
  953. int len = RARRAY_LEN(args);
  954. if (len < 1) {rb_raise(rb_eArgError, "wrong number of argument.(more than 1)");}
  955. VALUE ary = rb_ary_new2(len);
  956. for (int i = 0; i < len; i++) {
  957. VALUE value = rb_ary_entry(args, i);
  958. if (FIXNUM_P(value)) {
  959. rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetRow(CVARR(self), CVALLOC(CvMat), FIX2INT(value)), self));
  960. }else{
  961. CvSlice slice = VALUE_TO_CVSLICE(value);
  962. rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetRows(CVARR(self), CVALLOC(CvMat), slice.start_index, slice.end_index), self));
  963. }
  964. }
  965. return RARRAY_LEN(ary) > 1 ? ary : rb_ary_entry(ary, 0);
  966. }
  967. /*
  968. * call-seq:
  969. * col(<i>n</i>) -> Return column
  970. * col(<i>n1, n2, ...</i>) -> Return Array of columns
  971. *
  972. * Return column(or columns) of matrix.
  973. * argument should be Fixnum or CvSlice compatible object.
  974. */
  975. VALUE
  976. rb_col(VALUE self, VALUE args)
  977. {
  978. int len = RARRAY_LEN(args);
  979. if (len < 1) {rb_raise(rb_eArgError, "wrong number of argument.(more than 1)");}
  980. VALUE ary = rb_ary_new2(len);
  981. for (int i = 0; i < len; i++) {
  982. VALUE value = rb_ary_entry(args, i);
  983. if (FIXNUM_P(value)) {
  984. rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetCol(CVARR(self), CVALLOC(CvMat), FIX2INT(value)), self));
  985. }else{
  986. CvSlice slice = VALUE_TO_CVSLICE(value);
  987. rb_ary_store(ary, i, DEPEND_OBJECT(rb_klass, cvGetCols(CVARR(self), CVALLOC(CvMat), slice.start_index, slice.end_index), self));
  988. }
  989. }
  990. return RARRAY_LEN(ary) > 1 ? ary : rb_ary_entry(ary, 0);
  991. }
  992. /*
  993. * call-seq:
  994. * each_row{|row| ... } -> self
  995. *
  996. * Calls block once for each row in self, passing that element as a parameter.
  997. *
  998. * see also CvMat#each_col
  999. */
  1000. VALUE
  1001. rb_each_row(VALUE self)
  1002. {
  1003. int rows = CVMAT(self)->rows;
  1004. for (int i = 0; i < rows; i++) {
  1005. rb_yield(DEPEND_OBJECT(rb_klass, cvGetRow(CVARR(self), CVALLOC(CvMat), i), self));
  1006. }
  1007. return self;
  1008. }
  1009. /*
  1010. * call-seq:
  1011. * each_col{|col| ... } -> self
  1012. *
  1013. * Calls block once for each column in self, passing that element as a parameter.
  1014. *
  1015. * see also CvMat#each_row
  1016. */
  1017. VALUE
  1018. rb_each_col(VALUE self)
  1019. {
  1020. int cols = CVMAT(self)->cols;
  1021. for (int i = 0; i < cols; i++) {
  1022. rb_yield(DEPEND_OBJECT(rb_klass, cvGetCol(CVARR(self), CVALLOC(CvMat), i), self));
  1023. }
  1024. return self;
  1025. }
  1026. /*
  1027. * call-seq:
  1028. * diag(<i>[val = 0]</i>) -> cvmat
  1029. *
  1030. * Return one of array diagonals.
  1031. * <i>val</i> is zeo corresponds to the main diagonal, -1 corresponds to the diagonal above the main etc, 1 corresponds to the diagonal below the main etc.
  1032. *
  1033. */
  1034. VALUE
  1035. rb_diag(int argc, VALUE *argv, VALUE self)
  1036. {
  1037. VALUE val;
  1038. if (rb_scan_args(argc, argv, "01", &val) < 1) {
  1039. val = INT2FIX(0);
  1040. }
  1041. return DEPEND_OBJECT(rb_klass, cvGetDiag(CVARR(self), CVALLOC(CvMat), NUM2INT(val)), self);
  1042. }
  1043. /*
  1044. * call-seq:
  1045. * size -> cvsize
  1046. *
  1047. * Return size by CvSize
  1048. */
  1049. VALUE
  1050. rb_size(VALUE self)
  1051. {
  1052. return cCvSize::new_object(cvGetSize(CVARR(self)));
  1053. }
  1054. /*
  1055. VALUE rb_elem_type(VALUE self) {
  1056. return INT2FIX(cvGetElemType(CVARR(self)));
  1057. }
  1058. */
  1059. /*
  1060. * call-seq:
  1061. * dims -> array(int, int, ...)
  1062. *
  1063. * Return number of array dimensions and their sizes or the size of particular dimension.
  1064. * In case of CvMat it always returns 2 regardless of number of matrix rows.
  1065. */
  1066. VALUE
  1067. rb_dims(VALUE self)
  1068. {
  1069. int size[CV_MAX_DIM];
  1070. int dims = cvGetDims(CVARR(self), size);
  1071. VALUE ary = rb_ary_new2(dims);
  1072. for (int i = 0; i < dims; i++) {
  1073. rb_ary_store(ary, i, INT2FIX(size[i]));
  1074. }
  1075. return ary;
  1076. }
  1077. /*
  1078. * call-seq:
  1079. * dim_size(<i>index</i>) -> int
  1080. *
  1081. * Return number of dimension.
  1082. * almost same as CvMat#dims[<i>index</i>].
  1083. * If the dimension specified with index doesn't exist, CvStatusOutOfRange raise.
  1084. */
  1085. VALUE
  1086. rb_dim_size(VALUE self, VALUE index)
  1087. {
  1088. return INT2FIX(cvGetDimSize(CVARR(self), FIX2INT(index)));
  1089. }
  1090. /*
  1091. * call-seq:
  1092. * [<i>idx1[,idx2]...</i>]
  1093. *
  1094. * Return value of the particular array element as CvScalar.
  1095. */
  1096. VALUE
  1097. rb_aref(VALUE self, VALUE args)
  1098. {
  1099. int index[CV_MAX_DIM];
  1100. for (int i = 0; i < RARRAY_LEN(args); i++) {
  1101. index[i] = NUM2INT(rb_ary_entry(args, i));
  1102. }
  1103. CvScalar scalar = cvScalarAll(0);
  1104. switch(RARRAY_LEN(args)) {
  1105. case 1:
  1106. scalar = cvGet1D(CVARR(self), index[0]);
  1107. break;
  1108. case 2:
  1109. scalar = cvGet2D(CVARR(self), index[0], index[1]);
  1110. break;
  1111. default:
  1112. scalar = cvGetND(CVARR(self), index);
  1113. }
  1114. return cCvScalar::new_object(scalar);
  1115. }
  1116. /*
  1117. * call-seq:
  1118. * [<i>idx1[,idx2]...</i>] = <i>value</i>
  1119. *
  1120. * Set value of the particular array element to <i>value</i>.
  1121. * <i>value</i> should be CvScalar.
  1122. */
  1123. VALUE
  1124. rb_aset(VALUE self, VALUE args)
  1125. {
  1126. CvScalar scalar = VALUE_TO_CVSCALAR(rb_ary_pop(args));
  1127. int index[CV_MAX_DIM];
  1128. for (int i = 0; i < RARRAY_LEN(args); i++) {
  1129. index[i] = NUM2INT(rb_ary_entry(args, i));
  1130. }
  1131. switch(RARRAY_LEN(args)) {
  1132. case 1:
  1133. cvSet1D(CVARR(self), index[0], scalar);
  1134. break;
  1135. case 2:
  1136. cvSet2D(CVARR(self), index[0], index[1], scalar);
  1137. break;
  1138. default:
  1139. cvSetND(CVARR(self), index, scalar);
  1140. }
  1141. return self;
  1142. }
  1143. /*
  1144. * call-seq:
  1145. * fill(<i>value[, mask]</i>) -> cvmat
  1146. *
  1147. * Return CvMat copied value to every selected element. value should be CvScalar or compatible object.
  1148. * self[I] = value if mask(I)!=0
  1149. *
  1150. * note: This method support ROI on IplImage class. but COI not support. COI should not be set.
  1151. * image = IplImage.new(10, 20) #=> create 3 channel image.
  1152. * image.coi = 1 #=> set COI
  1153. * image.fill(CvScalar.new(10, 20, 30)) #=> raise CvBadCOI error.
  1154. */
  1155. VALUE
  1156. rb_fill(int argc, VALUE *argv, VALUE self)
  1157. {
  1158. return rb_fill_bang(argc, argv, copy(self));
  1159. }
  1160. /*
  1161. * call-seq:
  1162. * fill!(<i>value[, mask]</i>) -> self
  1163. *
  1164. * Copie value to every selected element.
  1165. * self[I] = value if mask(I)!=0
  1166. *
  1167. * see also #fill.
  1168. */
  1169. VALUE
  1170. rb_fill_bang(int argc, VALUE *argv, VALUE self)
  1171. {
  1172. VALUE value, mask;
  1173. rb_scan_args(argc, argv, "11", &value, &mask);
  1174. cvSet(CVARR(self), VALUE_TO_CVSCALAR(value), MASK(mask));
  1175. return self;
  1176. }
  1177. /*
  1178. * call-seq:
  1179. * save_image(<i>filename</i>) -> self
  1180. *
  1181. * Saves an image to file. The image format is chosen depending on the filename extension.
  1182. * Only 8bit single-channel or 3-channel(with 'BGR' channel order) image can be saved.
  1183. *
  1184. * e.g.
  1185. * image = OpenCV::CvMat.new(10, 10, CV_8U, 3)
  1186. * image.save_image("image.jpg") #=> save as JPEG format
  1187. * image.save_image("image.png") #=> save as PNG format
  1188. */
  1189. VALUE
  1190. rb_save_image(VALUE self, VALUE filename)
  1191. {
  1192. Check_Type(filename, T_STRING);
  1193. cvSaveImage(StringValueCStr(filename), CVARR(self));
  1194. return self;
  1195. }
  1196. /*
  1197. * call-seq:
  1198. * clear -> cvmat
  1199. *
  1200. * Return new matrix all element-value cleared.
  1201. */
  1202. VALUE
  1203. rb_clear(VALUE self)
  1204. {
  1205. return rb_clear_bang(copy(self));
  1206. }
  1207. /*
  1208. * call-seq:
  1209. * clear! -> self
  1210. *
  1211. * Clear all element-value. Return self.
  1212. */
  1213. VALUE
  1214. rb_clear_bang(VALUE self)
  1215. {
  1216. cvSetZero(CVARR(self));
  1217. return self;
  1218. }
  1219. /*
  1220. * call-seq:
  1221. * identity(<i>[val = [1]]</i>) -> cvmat
  1222. *
  1223. * Return initializes scaled identity matrix.
  1224. * <i>val</i> should be CvScalar.
  1225. *
  1226. * arr(i, j) = val if i = j, 0 otherwise
  1227. */
  1228. VALUE
  1229. rb_set_identity(int argc, VALUE *argv, VALUE self)
  1230. {
  1231. return rb_set_identity_bang(argc, argv, copy(self));
  1232. }
  1233. /*
  1234. * call-seq:
  1235. * identity!(<i>[val = [1]]</i>) -> self
  1236. *
  1237. * Initialize scaled identity matrix.
  1238. * <i>val</i> should be CvScalar.
  1239. *
  1240. * arr(i, j) = val if i = j, 0 otherwise
  1241. */
  1242. VALUE
  1243. rb_set_identity_bang(int argc, VALUE *argv, VALUE self)
  1244. {
  1245. VALUE val;
  1246. CvScalar value;
  1247. if (rb_scan_args(argc, argv, "01", &val) < 1) {
  1248. value = cvRealScalar(1);
  1249. }else{
  1250. value = VALUE_TO_CVSCALAR(val);
  1251. }
  1252. cvSetIdentity(CVARR(self), value);
  1253. return self;
  1254. }
  1255. /*
  1256. * call-seq:
  1257. * range(start, end) -> cvmat
  1258. *
  1259. * Create and return filled matrix with given range of numbers.
  1260. *
  1261. * see range!
  1262. */
  1263. VALUE
  1264. rb_range(int argc, VALUE *argv, VALUE self)
  1265. {
  1266. return rb_range_bang(argc, argv, copy(self));
  1267. }
  1268. /*
  1269. * call-seq:
  1270. * range!(start, end) -> self
  1271. *
  1272. * Fills matrix with given range of numbers.
  1273. *
  1274. * initializes the matrix as following:
  1275. * arr(i,j)=(end-start)*(i*cols(arr)+j)/(cols(arr)*rows(arr))
  1276. * For example, the following code will initilize 1D vector with subsequent integer numbers.
  1277. * m = CvMat.new(1, 10, :cv32s)
  1278. * m.range!(0, m.cols); // m will be initialized as [0,1,2,3,4,5,6,7,8,9]
  1279. */
  1280. VALUE
  1281. rb_range_bang(int argc, VALUE *argv, VALUE self)
  1282. {
  1283. VALUE start, end;
  1284. rb_scan_args(argc, argv, "20", &start, &end);
  1285. cvRange(CVARR(self), NUM2DBL(start), NUM2DBL(end));
  1286. return self;
  1287. }
  1288. /*
  1289. * call-seq:
  1290. * reshape(<i>[:rows => num][, :channel => cn]</i>) -> cvmat(refer self)
  1291. *
  1292. * Change shape of matrix/image without copying data.
  1293. *
  1294. * e.g.
  1295. * mat = CvMat.new(3, 3, CV_8U, 3) #=> 3x3 3-channel matrix
  1296. * vec = mat.reshape(:rows => 1) #=> 1x9 3-channel matrix
  1297. * ch1 = mat.reshape(:channel => 1) #=> 9x9 1-channel matrix
  1298. */
  1299. VALUE
  1300. rb_reshape(VALUE self, VALUE hash)
  1301. {
  1302. if (TYPE(hash) != T_HASH)
  1303. rb_raise(rb_eTypeError, "argument should be Hash that contaion key (:row, :channel).");
  1304. VALUE channel = rb_hash_aref(hash, ID2SYM(rb_intern("channel")));
  1305. VALUE rows = rb_hash_aref(hash, ID2SYM(rb_intern("rows")));
  1306. return DEPEND_OBJECT(rb_klass, cvReshape(CVARR(self), CVALLOC(CvMat), NIL_P(channel) ? 0 : FIX2INT(channel), NIL_P(rows) ? 0 : FIX2INT(rows)), self);
  1307. }
  1308. /*
  1309. * call-seq:
  1310. * repeat(<i>mat</i>) -> cvmat
  1311. *
  1312. * Tiled <i>mat</i> by self.
  1313. */
  1314. VALUE
  1315. rb_repeat(VALUE self, VALUE object)
  1316. {
  1317. if (!rb_obj_is_kind_of(object, rb_class()))
  1318. rb_raise(rb_eTypeError, "argument should be CvMat subclass.");
  1319. cvRepeat(CVARR(self), CVARR(object));
  1320. return object;
  1321. }
  1322. /*
  1323. * call-seq:
  1324. * flip(:x) -> cvmat
  1325. * flip(:y) -> cvmat
  1326. * flip(:xy) -> cvmat
  1327. * flip -> cvmat
  1328. *
  1329. * Return new flipped 2D array.
  1330. * * flip(:x) - flip around horizontal
  1331. * * flip(:y) - flip around vertical
  1332. * * flip(:xy) - flip around both axises
  1333. * * flip - flip around vertical
  1334. */
  1335. VALUE
  1336. rb_flip(int argc, VALUE *argv, VALUE self)
  1337. {
  1338. return rb_flip_bang(argc, argv, copy(self));
  1339. }
  1340. /*
  1341. * call-seq:
  1342. * flip!(:x) -> self
  1343. * flip!(:y) -> self
  1344. * flip!(:xy) -> self
  1345. * flip! -> self
  1346. *
  1347. * Flip 2D array. Return self.
  1348. *
  1349. * see also CvMat#flip
  1350. */
  1351. VALUE
  1352. rb_flip_bang(int argc, VALUE *argv, VALUE self)
  1353. {
  1354. VALUE format;
  1355. int mode = 0;
  1356. if (rb_scan_args(argc, argv, "01", &format) > 0) {
  1357. if (rb_to_id(format) == rb_intern("x"))
  1358. mode = 1;
  1359. else if (rb_to_id(format) == rb_intern("y"))
  1360. mode = 0;
  1361. else if (rb_to_id(format) == rb_intern("xy"))
  1362. mode = -1;
  1363. else
  1364. rb_warn("argument may be :x or :y or :xy");
  1365. }
  1366. cvFlip(CVARR(self), NULL, mode);
  1367. return self;
  1368. }
  1369. /*
  1370. * call-seq:
  1371. * split -> array(include cvmat)
  1372. *
  1373. * Divides multi-channel array into several single-chanel arrays.
  1374. *
  1375. * e.g.
  1376. * image = CvMat.new 640, 480, CV_8U, 3 #=> 3-channel image
  1377. * image.split #=> [image1, image2, image3] : each image have single-channel
  1378. *
  1379. * e.g. switch red <-> blue channel.
  1380. * image = IplImage.load "sample.bmp"
  1381. * i = image.split
  1382. * new_image = CvMat.merge i[2], i[1], i[0]
  1383. */
  1384. VALUE
  1385. rb_split(VALUE self)
  1386. {
  1387. int type = CVMAT(self)->type, depth = CV_MAT_DEPTH(type), channel = CV_MAT_CN(type);
  1388. CvSize size = cvGetSize(CVARR(self));
  1389. CvMat *dest[] = {NULL, NULL, NULL, NULL};
  1390. for (int i = 0; i < channel; i++)
  1391. dest[i] = cvCreateMat(size.height, size.width, CV_MAKETYPE(depth, 1));
  1392. cvSplit(CVARR(self), dest[0], dest[1], dest[2], dest[3]);
  1393. VALUE ary = rb_ary_new2(channel);
  1394. for (int i = 0; i < channel; i++)
  1395. rb_ary_store(ary, i, OPENCV_OBJECT(rb_klass, dest[i]));
  1396. return ary;
  1397. }
  1398. /*
  1399. * call-seq:
  1400. * CvMat.merge(<i>mat1[,mat2][,mat3][,mat4]</i>) -> cvmat
  1401. *
  1402. * Composes multi-channel array from several single-channel arrays.
  1403. * Each argument should be single-channel image(CvMat or subclass).
  1404. * All image should be same size and same depth.
  1405. *
  1406. * see also CvMat#split
  1407. */
  1408. VALUE
  1409. rb_merge(VALUE klass, VALUE args)
  1410. {
  1411. VALUE object, dest;
  1412. int len = RARRAY_LEN(args);
  1413. if (!(len > 0) || len > CV_CN_MAX) {
  1414. rb_raise(rb_eArgError, "wrong number of argument (%d for 1..4)", len);
  1415. }
  1416. CvMat *src[] = {NULL, NULL, NULL, NULL}, *tmp = 0;
  1417. for (int i = 0; i < len; i++) {
  1418. if (rb_obj_is_kind_of((object = rb_ary_entry(args, i)), rb_klass)) {
  1419. src[i] = CVMAT(object);
  1420. if (CV_MAT_CN(src[i]->type) != 1) {
  1421. rb_raise(rb_eStandardError, "image should be single-channel CvMat.");
  1422. }
  1423. if (!tmp)
  1424. tmp = src[i];
  1425. else{
  1426. if (!CV_ARE_SIZES_EQ(tmp, src[i]))
  1427. rb_raise(rb_eStandardError, "image size should be same.");
  1428. if (!CV_ARE_DEPTHS_EQ(tmp, src[i]))
  1429. rb_raise(rb_eStandardError, "image depth should be same.");
  1430. }
  1431. }else if (NIL_P(object)) {
  1432. src[i] = NULL;
  1433. }else
  1434. rb_raise(rb_eTypeError, "argument should be CvMat or subclass of it.");
  1435. }
  1436. dest = new_object(cvGetSize(tmp), CV_MAKETYPE(CV_MAT_DEPTH(tmp->type), len));
  1437. cvMerge(src[0], src[1], src[2], src[3], CVARR(dest));
  1438. return dest;
  1439. }
  1440. /*
  1441. * call-seq:
  1442. * CvMat.mix_channels(srcs,dests,from_to = {1 => 1, 2 => 2, 3 => 3, 4 => 4}) -> dests
  1443. */
  1444. VALUE
  1445. rb_mix_channels(int argc, VALUE *argv, VALUE self)
  1446. {
  1447. VALUE srcs, dests, from_to;
  1448. rb_scan_args(argc, argv, "21", &srcs, &dests, &from_to);
  1449. /* not yet */
  1450. return Qnil;
  1451. }
  1452. /*
  1453. * call-seq:
  1454. * rand_shuffle([seed = nil][,iter_factor = 1]) -> cvmat
  1455. *
  1456. * Return shuffled matrix
  1457. *
  1458. * see rand_shuffle!
  1459. */
  1460. VALUE
  1461. rb_rand_shuffle(int argc, VALUE *argv, VALUE self)
  1462. {
  1463. return rb_rand_shuffle_bang(argc, argv, copy(self));
  1464. }
  1465. /*
  1466. * call-seq:
  1467. * rand_shuffle!([seed = nil][,iter_factor = 1]) -> cvmat
  1468. *
  1469. * Shuffles the matrix by swapping randomly chosen pairs of the matrix elements on each iteration
  1470. * (where each element may contain several components in case of multi-channel arrays). The number of
  1471. * iterations (i.e. pairs swapped) is (iter_factor*mat.rows*mat.cols).round, so iter_factor=0 means
  1472. * that no shuffling is done, iter_factor=1 means that the function swaps rows(mat)*cols(mat) random
  1473. * pairs etc.
  1474. */
  1475. VALUE
  1476. rb_rand_shuffle_bang(int argc, VALUE *argv, VALUE self)
  1477. {
  1478. VALUE seed, iter;
  1479. CvRNG rng;
  1480. rb_scan_args(argc, argv, "02", &seed, &iter);
  1481. if(NIL_P(seed))
  1482. cvRandShuffle(CVARR(self), NULL, IF_INT(iter, 1));
  1483. else{
  1484. rng = cvRNG(rb_num2ll(seed));
  1485. cvRandShuffle(CVARR(self), &rng, IF_INT(iter, 1));
  1486. }
  1487. return self;
  1488. }
  1489. /*
  1490. * call-seq:
  1491. * lut(<i>lookup_table</i>) -> cvmat
  1492. *
  1493. * Return new matrix performed lookup-table transform.
  1494. *
  1495. * <i>lookup_table</i> should be CvMat that have 256 element (e.g. 1x256 matrix).
  1496. * Otherwise, raise CvStatusBadArgument error.
  1497. *
  1498. * And <i>lookup_table</i> should either have a single-channel, or the same number of channels.
  1499. * When single-channel lookup-table given, same table is used for all channels.
  1500. */
  1501. VALUE
  1502. rb_lut(VALUE self, VALUE lut)
  1503. {
  1504. VALUE dest = copy(self);
  1505. cvLUT(CVARR(self), CVARR(dest), CVARR(lut));
  1506. return dest;
  1507. }
  1508. /*
  1509. * call-seq:
  1510. * convert_scale(<i>:depth => nil, :scale => 1.0, :shift => 0.0</i>)
  1511. *
  1512. * Return new array with optional linear transformation.
  1513. * mat(I) = src(I) * scale + (shift, shift, ...)
  1514. */
  1515. VALUE
  1516. rb_convert_scale(VALUE self, VALUE hash)
  1517. {
  1518. if (TYPE(hash) != T_HASH)
  1519. rb_raise(rb_eTypeError, "argument should be Hash that contaion key [:depth, :scale, :shift].");
  1520. VALUE depth = rb_hash_aref(hash, ID2SYM(rb_intern("depth"))),
  1521. scale = rb_hash_aref(hash, ID2SYM(rb_intern("scale"))),
  1522. shift = rb_hash_aref(hash, ID2SYM(rb_intern("shift"))),
  1523. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CVMETHOD("DEPTH", depth, CV_MAT_DEPTH(CVMAT(self)->type)), CV_MAT_CN(CVMAT(self)->type)));
  1524. cvConvertScale(CVARR(self), CVARR(dest), IF_DBL(scale, 1.0), IF_DBL(shift, 0.0));
  1525. return dest;
  1526. }
  1527. /*
  1528. * call-seq:
  1529. * convert_scale_abs(<i>:scale => 1.0, :shift => 0.0</i>)
  1530. *
  1531. * Return new array with optional linear transformation.
  1532. * It is similar to CvMat#convert_scale, but it stores absolute values of the conversion result
  1533. * mat(I) = (src(I) * scale + (shift, shift, ...)).abs
  1534. */
  1535. VALUE
  1536. rb_convert_scale_abs(VALUE self, VALUE hash)
  1537. {
  1538. if (TYPE(hash) != T_HASH)
  1539. rb_raise(rb_eTypeError, "argument should be Hash that contaion key [:depth, :scale, :shift].");
  1540. VALUE
  1541. scale = rb_hash_aref(hash, ID2SYM(rb_intern("scale"))),
  1542. shift = rb_hash_aref(hash, ID2SYM(rb_intern("shift"))),
  1543. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_8U, CV_MAT_CN(CVMAT(self)->type)));
  1544. cvConvertScaleAbs(CVARR(self), CVARR(dest), IF_DBL(scale, 1.0), IF_DBL(shift, 0.0));
  1545. return dest;
  1546. }
  1547. /*
  1548. * call-seq:
  1549. * add(<i>val[,mask]</i>) -> cvmat
  1550. *
  1551. * Return new matrix computed per-element sum.
  1552. * <i>val</i> should be CvMat or CvScalar.
  1553. * If <i>val</i> is CvMat, it must have same type (depth and channel).
  1554. * <i>mask</i> should be CvMat(8bit single-channel).
  1555. * For each element (I)
  1556. * dst(I) = src1(I) + src2(I) if mask(I) != 0
  1557. */
  1558. VALUE
  1559. rb_add(int argc, VALUE *argv, VALUE self)
  1560. {
  1561. VALUE val, mask, dest;
  1562. rb_scan_args(argc, argv, "11", &val, &mask);
  1563. dest = copy(self);
  1564. if (rb_obj_is_kind_of(val, rb_klass))
  1565. cvAdd(CVARR(self), CVARR(val), CVARR(dest), MASK(mask));
  1566. else
  1567. cvAddS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask));
  1568. return dest;
  1569. }
  1570. /*
  1571. * call-seq:
  1572. * sub(<i>val[,mask]</i>) -> cvmat
  1573. *
  1574. * Return new matrix computed per-element difference.
  1575. * <i>val</i> should be CvMat or CvScalar.
  1576. * If <i>val</i> is CvMat, it must have same type (depth and channel).
  1577. * <i>mask</i> should be CvMat(8bit single-channel).
  1578. * For each element (I)
  1579. * dst(I) = src1(I) - src2(I) if mask(I) != 0
  1580. */
  1581. VALUE
  1582. rb_sub(int argc, VALUE *argv, VALUE self)
  1583. {
  1584. VALUE val, mask, dest;
  1585. rb_scan_args(argc, argv, "11", &val, &mask);
  1586. dest = copy(self);
  1587. if (rb_obj_is_kind_of(val, rb_klass)) {
  1588. cvSub(CVARR(self), CVARR(val), CVARR(dest), MASK(mask));
  1589. }
  1590. else {
  1591. cvSubS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask));
  1592. }
  1593. return dest;
  1594. }
  1595. /*
  1596. * call-seq:
  1597. * mul(<i>val[,scale = 1.0]</i>) -> cvmat
  1598. *
  1599. * Return new matrix computed per-element product.
  1600. * <i>val</i> should be CvMat or CvScalar.
  1601. * If <i>val</i> is CvMat, it must have same type (depth and channel).
  1602. * For each element (I)
  1603. * dst(I) = scale * src1(I) * src2(I)
  1604. */
  1605. VALUE
  1606. rb_mul(int argc, VALUE *argv, VALUE self)
  1607. {
  1608. VALUE val, scale, dest;
  1609. if (rb_scan_args(argc, argv, "11", &val, &scale) < 2)
  1610. scale = rb_float_new(1.0);
  1611. dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1612. if (rb_obj_is_kind_of(val, rb_klass)) {
  1613. cvMul(CVARR(self), CVARR(val), CVARR(dest), NUM2DBL(scale));
  1614. }else{
  1615. CvScalar scl = VALUE_TO_CVSCALAR(val);
  1616. VALUE mat = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1617. cvSet(CVARR(mat), scl);
  1618. cvMul(CVARR(self), CVARR(mat), CVARR(dest), NUM2DBL(scale));
  1619. }
  1620. return dest;
  1621. }
  1622. /*
  1623. * call-seq:
  1624. * mat_mul(<i>val[,shiftvec]</i>) -> cvmat
  1625. * Performs matrix multiplication
  1626. * dst = src1 * src2 + shiftvec
  1627. * <i>val</i> and <i>shiftvec</i> should be CvMat
  1628. * All the matrices should have the same data type and coordinated sizes.
  1629. * Real or complex floating-point matrices are supported.
  1630. */
  1631. VALUE
  1632. rb_mat_mul(int argc, VALUE *argv, VALUE self)
  1633. {
  1634. VALUE val, shiftvec, dest;
  1635. rb_scan_args(argc, argv, "11", &val, &shiftvec);
  1636. dest = new_object(CVMAT(self)->rows, CVMAT(val)->cols, cvGetElemType(CVARR(self)));
  1637. if (NIL_P(shiftvec))
  1638. cvMatMul(CVARR(self), CVARR(val), CVARR(dest));
  1639. else
  1640. cvMatMulAdd(CVARR(self), CVARR(val), CVARR(shiftvec), CVARR(dest));
  1641. return dest;
  1642. }
  1643. /*
  1644. * call-seq:
  1645. * div(<i>val[,scale = 1.0]</i>) -> cvmat
  1646. *
  1647. * Return new matrix computed per-element division.
  1648. * <i>val</i> should be CvMat or CvScalar.
  1649. * If <i>val</i> is CvMat, it must have same type (depth and channel).
  1650. * For each element (I)
  1651. * dst(I) = scale * src1(I) / src2(I)
  1652. */
  1653. VALUE
  1654. rb_div(int argc, VALUE *argv, VALUE self)
  1655. {
  1656. VALUE val, scale, dest;
  1657. if (rb_scan_args(argc, argv, "11", &val, &scale) < 2)
  1658. scale = rb_float_new(1.0);
  1659. dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1660. if (rb_obj_is_kind_of(val, rb_klass)) {
  1661. cvDiv(CVARR(self), CVARR(val), CVARR(dest), NUM2DBL(scale));
  1662. }else{
  1663. CvScalar scl = VALUE_TO_CVSCALAR(val);
  1664. VALUE mat = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1665. cvSet(CVARR(mat), scl);
  1666. cvDiv(CVARR(self), CVARR(mat), CVARR(dest), NUM2DBL(scale));
  1667. }
  1668. return dest;
  1669. }
  1670. /*
  1671. * call-seq:
  1672. * and(<i>val[,mask]</i>) -> cvmat
  1673. *
  1674. * Return new matrix computed per-element bit-wise conjunction.
  1675. * <i>val</i> should be CvMat or CvScalar.
  1676. * If <i>val</i> is CvMat, it must have same type (depth and channel).
  1677. * For each element (I)
  1678. * dst(I) = src1(I) & src2(I) if mask(I) != 0
  1679. */
  1680. VALUE
  1681. rb_and(int argc, VALUE *argv, VALUE self)
  1682. {
  1683. VALUE val, mask, dest;
  1684. rb_scan_args(argc, argv, "11", &val, &mask);
  1685. dest = copy(self);
  1686. if (rb_obj_is_kind_of(val, rb_klass))
  1687. cvAnd(CVARR(self), CVARR(val), CVARR(dest), MASK(mask));
  1688. else
  1689. cvAndS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask));
  1690. return dest;
  1691. }
  1692. /*
  1693. * call-seq:
  1694. * or(<i>val[,mask]</i>) -> cvmat
  1695. *
  1696. * Return new matrix computed per-element bit-wise disjunction.
  1697. * <i>val</i> should be CvMat or CvScalar.
  1698. * If <i>val</i> is CvMat, it must have same type (depth and channel).
  1699. * For each element (I)
  1700. * dst(I) = src1(I) | src2(I) if mask(I) != 0
  1701. */
  1702. VALUE
  1703. rb_or(int argc, VALUE *argv, VALUE self)
  1704. {
  1705. VALUE val, mask, dest;
  1706. rb_scan_args(argc, argv, "11", &val, &mask);
  1707. dest = copy(self);
  1708. if (rb_obj_is_kind_of(val, rb_klass))
  1709. cvOr(CVARR(self), CVARR(val), CVARR(dest), MASK(mask));
  1710. else
  1711. cvOrS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask));
  1712. return dest;
  1713. }
  1714. /*
  1715. * call-seq:
  1716. * xor(<i>val[,mask]</i>) -> cvmat
  1717. *
  1718. * Return new matrix computed per-element bit-wise "exclusive or" operation.
  1719. * <i>val</i> should be CvMat or CvScalar.
  1720. * If <i>val</i> is CvMat, it must have same type (depth and channel).
  1721. * For each element (I)
  1722. * dst(I) = src1(I) ^ src2(I) if mask(I) != 0
  1723. */
  1724. VALUE
  1725. rb_xor(int argc, VALUE *argv, VALUE self)
  1726. {
  1727. VALUE val, mask, dest;
  1728. rb_scan_args(argc, argv, "11", &val, &mask);
  1729. dest = copy(self);
  1730. if (rb_obj_is_kind_of(val, rb_klass))
  1731. cvXor(CVARR(self), CVARR(val), CVARR(dest), MASK(mask));
  1732. else
  1733. cvXorS(CVARR(self), VALUE_TO_CVSCALAR(val), CVARR(dest), MASK(mask));
  1734. return dest;
  1735. }
  1736. /*
  1737. * call-seq:
  1738. * not -> cvmat
  1739. *
  1740. * Return new matrix performed per-element bit-wise inversion.
  1741. * dst(I) =~ src(I)
  1742. */
  1743. VALUE
  1744. rb_not(VALUE self)
  1745. {
  1746. VALUE dest = copy(self);
  1747. cvNot(CVARR(self), CVARR(dest));
  1748. return dest;
  1749. }
  1750. /*
  1751. * call-seq:
  1752. * not! -> self
  1753. *
  1754. * Performe per-element bit-wise inversion.
  1755. */
  1756. VALUE
  1757. rb_not_bang(VALUE self)
  1758. {
  1759. cvNot(CVARR(self), CVARR(self));
  1760. return self;
  1761. }
  1762. VALUE
  1763. rb_cmp_internal(VALUE self, VALUE val, int operand)
  1764. {
  1765. VALUE dest = new_object(cvGetSize(CVARR(self)), CV_8U);
  1766. if (rb_obj_is_kind_of(val, rb_klass))
  1767. cvCmp(CVARR(self), CVARR(val), CVARR(dest), operand);
  1768. else if (CV_MAT_CN(cvGetElemType(CVARR(self))) == 1 && rb_obj_is_kind_of(val, rb_cNumeric)) {
  1769. cvCmpS(CVARR(self), NUM2DBL(val), CVARR(dest), operand);
  1770. }else{
  1771. VALUE mat = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1772. cvSet(CVARR(mat), VALUE_TO_CVSCALAR(val));
  1773. cvCmp(CVARR(self), CVARR(mat), CVARR(dest), operand);
  1774. }
  1775. return dest;
  1776. }
  1777. /*
  1778. * call-seq:
  1779. * eq(<i>val</i>) -> cvmat
  1780. *
  1781. * Return new matrix performed per-element comparision "equal".
  1782. * dst(I) = (self(I) == val(I) ? 0xFF : 0)
  1783. */
  1784. VALUE
  1785. rb_eq(VALUE self, VALUE val)
  1786. {
  1787. return rb_cmp_internal(self, val, CV_CMP_EQ);
  1788. }
  1789. /*
  1790. * call-seq:
  1791. * gt(<i>val</i>) -> cvmat
  1792. *
  1793. * Return new matrix performed per-element comparision "greater than".
  1794. * dst(I) = (self(I) > val(I) ? 0xFF : 0)
  1795. */
  1796. VALUE
  1797. rb_gt(VALUE self, VALUE val)
  1798. {
  1799. return rb_cmp_internal(self, val, CV_CMP_GT);
  1800. }
  1801. /*
  1802. * call-seq:
  1803. * ge(<i>val</i>) -> cvmat
  1804. *
  1805. * Return new matrix performed per-element comparision "greater or equal".
  1806. * dst(I) = (self(I) >= val(I) ? 0xFF : 0)
  1807. */
  1808. VALUE
  1809. rb_ge(VALUE self, VALUE val)
  1810. {
  1811. return rb_cmp_internal(self, val, CV_CMP_GE);
  1812. }
  1813. /*
  1814. * call-seq:
  1815. * lt(<i>val</i>) -> cvmat
  1816. *
  1817. * Return new matrix performed per-element comparision "less than".
  1818. * dst(I) = (self(I) < val(I) ? 0xFF : 0)
  1819. */
  1820. VALUE
  1821. rb_lt(VALUE self, VALUE val)
  1822. {
  1823. return rb_cmp_internal(self, val, CV_CMP_LT);
  1824. }
  1825. /*
  1826. * call-seq:
  1827. * le(<i>val</i>) -> cvmat
  1828. *
  1829. * Return new matrix performed per-element comparision "less or equal".
  1830. * dst(I) = (self(I) <= val(I) ? 0xFF : 0)
  1831. */
  1832. VALUE
  1833. rb_le(VALUE self, VALUE val)
  1834. {
  1835. return rb_cmp_internal(self, val, CV_CMP_LE);
  1836. }
  1837. /*
  1838. * call-seq:
  1839. * ne(<i>val</i>) -> cvmat
  1840. *
  1841. * Return new matrix performed per-element comparision "not equal".
  1842. * dst(I) = (self(I) != val(I) ? 0xFF : 0)
  1843. */
  1844. VALUE
  1845. rb_ne(VALUE self, VALUE val)
  1846. {
  1847. return rb_cmp_internal(self, val, CV_CMP_NE);
  1848. }
  1849. /*
  1850. * call-seq:
  1851. * in_range(<i>min, max</i>) -> cvmat
  1852. *
  1853. * Check that element lie between two object.
  1854. * <i>min</i> and <i>max</i> should be CvMat that have same size and type, or CvScalar.
  1855. * Return new matrix performed per-element,
  1856. * dst(I) = within the range ? 0xFF : 0
  1857. */
  1858. VALUE
  1859. rb_in_range(VALUE self, VALUE min, VALUE max)
  1860. {
  1861. VALUE dest = dest = new_object(cvGetSize(CVARR(self)), CV_8UC1), tmp;
  1862. if (rb_obj_is_kind_of(min, rb_klass) && rb_obj_is_kind_of(max, rb_klass)) {
  1863. cvInRange(CVARR(self), CVARR(min), CVARR(max), CVARR(dest));
  1864. }else if (rb_obj_is_kind_of(min, rb_klass)) {
  1865. tmp = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1866. cvSet(CVARR(tmp), VALUE_TO_CVSCALAR(max));
  1867. cvInRange(CVARR(self), CVARR(min), CVARR(tmp), CVARR(dest));
  1868. }else if (rb_obj_is_kind_of(max, rb_klass)) {
  1869. tmp = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1870. cvSet(CVARR(tmp), VALUE_TO_CVSCALAR(min));
  1871. cvInRange(CVARR(self), CVARR(tmp), CVARR(max), CVARR(dest));
  1872. }else
  1873. cvInRangeS(CVARR(self), VALUE_TO_CVSCALAR(min), VALUE_TO_CVSCALAR(max), CVARR(dest));
  1874. return dest;
  1875. }
  1876. /*
  1877. * call-seq:
  1878. * abs_diff(<i>val</i>) -> cvmat
  1879. *
  1880. * Calculate absolute difference between two.
  1881. * <i>val</i> should be CvMat that have same size and same type, or CvScalar.
  1882. * dst(I) = (src(I) - val(I)).abs
  1883. */
  1884. VALUE
  1885. rb_abs_diff(VALUE self, VALUE val)
  1886. {
  1887. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  1888. if (rb_obj_is_kind_of(val, rb_klass)) {
  1889. cvAbsDiff(CVARR(self), CVARR(val), CVARR(dest));
  1890. }else{
  1891. cvAbsDiffS(CVARR(self), CVARR(dest), VALUE_TO_CVSCALAR(val));
  1892. }
  1893. return dest;
  1894. }
  1895. /*
  1896. * call-seq:
  1897. * count_non_zero -> int
  1898. *
  1899. * Returns the number of non-zero elements.
  1900. * result = sumI arr(I)!=0
  1901. *
  1902. * In case of IplImage both ROI and COI are supported.
  1903. */
  1904. VALUE
  1905. rb_count_non_zero(VALUE self)
  1906. {
  1907. return INT2FIX(cvCountNonZero(CVARR(self)));
  1908. }
  1909. /*
  1910. * call-seq:
  1911. * sum -> scalar
  1912. *
  1913. * Return summerizes elements as CvScalar. Independently for each channel.
  1914. *
  1915. * note: If COI is setted in IplImage, the method processes the selected channel only and store the sum to the first component scalar[0].
  1916. */
  1917. VALUE
  1918. rb_sum(VALUE self)
  1919. {
  1920. return cCvScalar::new_object(cvSum(CVARR(self)));
  1921. }
  1922. /*
  1923. * call-seq:
  1924. * avg(<i>[mask]</i>) -> mean(as scalar)
  1925. *
  1926. * Return the average(mean) of elements as CvScalar. Independently for each channel.
  1927. */
  1928. VALUE
  1929. rb_avg(int argc, VALUE *argv, VALUE self)
  1930. {
  1931. VALUE mask, mean;
  1932. rb_scan_args(argc, argv, "01", &mask);
  1933. return cCvScalar::new_object(cvAvg(CVARR(self), MASK(mask)));
  1934. }
  1935. /*
  1936. * call-seq:
  1937. * avg_sdv(<i>mask</i>) -> [mean(as scalar), std_dev(as scalar)]
  1938. *
  1939. * Calculates the average value and standard deviation of array elements, independently for each channel.
  1940. *
  1941. * note: same as [CvMat#avg, CvMat#sdv]
  1942. */
  1943. VALUE
  1944. rb_avg_sdv(int argc, VALUE *argv, VALUE self)
  1945. {
  1946. VALUE mask, mean, std_dev;
  1947. rb_scan_args(argc, argv, "01", &mask);
  1948. mean = cCvScalar::new_object();
  1949. std_dev = cCvScalar::new_object();
  1950. cvAvgSdv(CVARR(self), CVSCALAR(mean), CVSCALAR(std_dev), MASK(mask));
  1951. return rb_ary_new3(2, mean, std_dev);
  1952. }
  1953. /*
  1954. * call-seq:
  1955. * sdv(<i>[mask]</i>) -> std_dev(as scalar)
  1956. *
  1957. * Return the standard deviation of elements as CvScalar. Independently for each channel.
  1958. */
  1959. VALUE
  1960. rb_sdv(int argc, VALUE *argv, VALUE self)
  1961. {
  1962. VALUE mask, std_dev;
  1963. rb_scan_args(argc, argv, "01", &mask);
  1964. std_dev = cCvScalar::new_object();
  1965. cvAvgSdv(CVARR(self), NULL, CVSCALAR(std_dev), MASK(mask));
  1966. return std_dev;
  1967. }
  1968. /*
  1969. * call-seq:
  1970. * min_max_loc(<i>[mask]</i>) -> [min_val, max_val, min_loc(as point), max_loc(as point)]
  1971. *
  1972. * Finds minimum and maximum element values and their positions.
  1973. * The extremums are searched over the whole array, selected ROI(in case of IplImage) or, if mask is not NULL, in the specified array region.
  1974. * If the array has more than one channel, it must be IplImage with COI set.
  1975. * In case if multi-dimensional arrays min_loc.x and max_loc.x will contain raw (linear) positions of the extremums.
  1976. */
  1977. VALUE
  1978. rb_min_max_loc(int argc, VALUE *argv, VALUE self)
  1979. {
  1980. VALUE mask, min_loc, max_loc;
  1981. double min_val = 0.0, max_val = 0.0;
  1982. rb_scan_args(argc, argv, "01", &mask);
  1983. min_loc = cCvPoint::new_object();
  1984. max_loc = cCvPoint::new_object();
  1985. cvMinMaxLoc(CVARR(self), &min_val, &max_val, CVPOINT(min_loc), CVPOINT(max_loc), MASK(mask));
  1986. return rb_ary_new3(4,
  1987. rb_float_new(min_val),
  1988. rb_float_new(max_val),
  1989. min_loc,
  1990. max_loc);
  1991. }
  1992. /*
  1993. * call-seq:
  1994. * dot_product(<i>mat</i>) -> float
  1995. *
  1996. * Calculates dot product of two arrays in Euclidian metrics.
  1997. * <i>mat</i> should be CvMat have same size and same type.
  1998. *
  1999. * src1.src2 = sum(src1(I) * src2(I))
  2000. */
  2001. VALUE
  2002. rb_dot_product(VALUE self, VALUE mat)
  2003. {
  2004. if (!rb_obj_is_kind_of(mat, rb_klass))
  2005. rb_raise(rb_eTypeError, "argument should be CvMat.");
  2006. return rb_float_new(cvDotProduct(CVARR(self), CVARR(mat)));
  2007. }
  2008. /*
  2009. * call-seq:
  2010. * cross_product(<i>mat</i>) -> cvmat
  2011. *
  2012. * Calculate cross product of two 3D vectors.
  2013. * <i>mat</i> should be CvMat have same size and same type.
  2014. */
  2015. VALUE
  2016. rb_cross_product(VALUE self, VALUE mat)
  2017. {
  2018. if (!rb_obj_is_kind_of(mat, rb_klass))
  2019. rb_raise(rb_eTypeError, "argument should be CvMat.");
  2020. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  2021. cvCrossProduct(CVARR(self), CVARR(mat), CVARR(dest));
  2022. return dest;
  2023. }
  2024. /*
  2025. * call-seq:
  2026. * transform(<i>transmat[,shiftvec]</i>) -> cvmat
  2027. *
  2028. * performs matrix transform of every element.
  2029. * dst(I) = transmat * src(I) + shiftvec
  2030. */
  2031. VALUE
  2032. rb_transform(int argc, VALUE *argv, VALUE self)
  2033. {
  2034. VALUE transmat, shiftvec;
  2035. rb_scan_args(argc, argv, "11", &transmat, &shiftvec);
  2036. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  2037. if (NIL_P(shiftvec))
  2038. cvTransform(CVARR(self), CVARR(dest), CVMAT(transmat), NULL);
  2039. else
  2040. cvTransform(CVARR(self), CVARR(dest), CVMAT(transmat), CVMAT(shiftvec));
  2041. return dest;
  2042. }
  2043. /*
  2044. * call-seq:
  2045. * perspective_transform(<i>mat</i>) -> cvmat
  2046. *
  2047. * Return performed perspective matrix transform of vector array.
  2048. * <i>mat</i> should be 3x3 or 4x4 transform matrix (CvMat).
  2049. * Every element (by treating it as 2D or 3D vector) in the following way:
  2050. * (x, y, z) -> (x'/w, y'/w, z'/w) or
  2051. * (x, y) -> (x'/w, y'/w)
  2052. * where
  2053. * (x', y', z', w') = mat4x4*(x, y, z, 1) or
  2054. * (x', y', w') = mat3x3*(x, y, 1)
  2055. * and
  2056. * w = w' if w'!=0, inf otherwise.
  2057. */
  2058. VALUE
  2059. rb_perspective_transform(VALUE self, VALUE mat)
  2060. {
  2061. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  2062. cvPerspectiveTransform(CVARR(self), CVARR(dest), CVMAT(mat));
  2063. return dest;
  2064. }
  2065. /*
  2066. * call-seq:
  2067. * mul_transposed(<i>:order => :default or :inverse, :delta => nil or cvmat</i>)
  2068. *
  2069. * Calculates the product of self and its transposition.
  2070. *
  2071. * options
  2072. * * :order -> should be :default or :inverse (default is :default)
  2073. * see below.
  2074. * * :delta -> should be nil or CvMat (default is nil)
  2075. * An optional array, subtracted from source before multiplication.
  2076. *
  2077. * mul_transposed evaluates:
  2078. * :order => :default
  2079. * dst = (self - delta) * (self - delta)T
  2080. * :order => :inverse
  2081. * dst = (self - delta)T * (self - delta)
  2082. *
  2083. */
  2084. VALUE
  2085. rb_mul_transposed(VALUE self, VALUE args)
  2086. {
  2087. //VALUE options = extract_options_from_args_bang(args);
  2088. //assert_valid_keys(options, 2, "order", "delta");
  2089. //VALUE order;
  2090. //OPTIONS(order, options, "order", ID2SYM(rb_intern("default")));
  2091. //ID2SYM(rb_intern("order")), rb_intern("")
  2092. return Qnil;
  2093. }
  2094. /*
  2095. * call-seq:
  2096. * trace -> scalar
  2097. *
  2098. * Returns trace of matrix. "trace" is sum of diagonal elements of the matrix.
  2099. */
  2100. VALUE
  2101. rb_trace(VALUE self)
  2102. {
  2103. return cCvScalar::new_object(cvTrace(CVARR(self)));
  2104. }
  2105. /*
  2106. * call-seq:
  2107. * transpose -> cvmat
  2108. *
  2109. * Return transposed matrix.
  2110. */
  2111. VALUE
  2112. rb_transpose(VALUE self)
  2113. {
  2114. CvSize size = cvGetSize(CVARR(self));
  2115. VALUE dest = new_object(size.width, size.height, cvGetElemType(CVARR(self)));
  2116. cvTranspose(CVARR(self), CVARR(dest));
  2117. return dest;
  2118. }
  2119. /*
  2120. * call-seq:
  2121. * transpose! -> self
  2122. *
  2123. * Transposed matrix.
  2124. *
  2125. * <b>rectangular matrix only (CvMat#square? = true).</b>
  2126. */
  2127. VALUE
  2128. rb_transpose_bang(VALUE self)
  2129. {
  2130. cvTranspose(CVARR(self), CVARR(self));
  2131. return self;
  2132. }
  2133. /*
  2134. * call-seq:
  2135. * det -> float
  2136. *
  2137. * Return determinant of matrix.
  2138. * <i>self</i> should be single-channel and floating-point depth.
  2139. */
  2140. VALUE
  2141. rb_det(VALUE self)
  2142. {
  2143. return rb_float_new(cvDet(CVARR(self)));
  2144. }
  2145. /*
  2146. * call-seq:
  2147. * invert(<i>inversion_method=:lu[,delta]</i>) -> float
  2148. *
  2149. * Finds inverse or pseudo-inverse of matrix.
  2150. * <i>inversion_method</i> should be following symbol.
  2151. * * :lu
  2152. * Gaussian elimincation with optimal pivot element chose.
  2153. * Return self determinant (self must be square).
  2154. * * :svd
  2155. * Singular value decomposition(SVD) method.
  2156. * Return the inversed condition number of self(ratio of the smallest singular value to the largest singular value)
  2157. * and 0 if self is all zeros. The SVD method calculate a pseudo-inverse matrix if self is singular.
  2158. * * :svd_sym or :svd_symmetric
  2159. * SVD method for a symmetric positively-defined matrix.
  2160. *
  2161. * <i>self</i> type should be single-channel and floating-point matrix.
  2162. */
  2163. VALUE
  2164. rb_invert(int argc, VALUE *argv, VALUE self)
  2165. {
  2166. VALUE symbol;
  2167. rb_scan_args(argc, argv, "01", &symbol);
  2168. int method = CVMETHOD("INVERSION_METHOD", symbol, CV_LU);
  2169. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  2170. cvInvert(CVARR(self), CVARR(dest), method);
  2171. return dest;
  2172. }
  2173. /*
  2174. * call-seq:
  2175. * solve(<i>mat, inversion_method=:lu</i>)
  2176. *
  2177. * Solves linear system or least-squares problem (the latter is possible with SVD method).
  2178. *
  2179. * <i>inversion_method</i> should be following symbol.
  2180. * * :lu
  2181. * Gaussian elimincation with optimal pivot element chose.
  2182. * Return self determinant (self must be square).
  2183. * * :svd
  2184. * Singular value decomposition(SVD) method.
  2185. * Return the inversed condition number of self(ratio of the smallest singular value to the largest singular value)
  2186. * and 0 if self is all zeros. The SVD method calculate a pseudo-inverse matrix if self is singular.
  2187. * * :svd_sym or :svd_symmetric
  2188. * SVD method for a symmetric positively-defined matrix.
  2189. */
  2190. VALUE
  2191. rb_solve(int argc, VALUE *argv, VALUE self)
  2192. {
  2193. VALUE mat, symbol;
  2194. rb_scan_args(argc, argv, "11", &mat, &symbol);
  2195. if (!rb_obj_is_kind_of(mat, rb_klass))
  2196. rb_raise(rb_eTypeError, "argument 1 (right-hand part of the linear system) should be %s.)", rb_class2name(rb_klass));
  2197. VALUE dest = new_object(CVMAT(self)->rows, CVMAT(mat)->cols, cvGetElemType(CVARR(self)));
  2198. cvSolve(CVARR(self), CVARR(mat), CVARR(dest), CVMETHOD("INVERSION_METHOD", symbol, CV_LU));
  2199. return dest;
  2200. }
  2201. /*
  2202. * call-seq:
  2203. * svd(u = nil, v = nil</i>)
  2204. *
  2205. * not implementated.
  2206. * Performs singular value decomposition of real floating-point matrix.
  2207. */
  2208. VALUE
  2209. rb_svd(int argc, VALUE *argv, VALUE self)
  2210. {
  2211. rb_raise(rb_eNotImpError, "");
  2212. /*
  2213. VALUE u = Qnil, v = Qnil;
  2214. rb_scan_args(argc, argv, "02", &u, &v);
  2215. CvMat
  2216. *matU = NIL_P(u) ? NULL : CVARR(u),
  2217. *matV = NIL_P(v) ? NULL : CVARR(v);
  2218. cvSVD(CVARR(self), matU, matV);
  2219. return dest;
  2220. */
  2221. }
  2222. /*
  2223. * call-seq:
  2224. * svbksb
  2225. *
  2226. * not yet.
  2227. */
  2228. VALUE
  2229. rb_svbksb(int argc, VALUE *argv, VALUE self)
  2230. {
  2231. rb_raise(rb_eNotImpError, "");
  2232. }
  2233. /*
  2234. * call-seq:
  2235. * eigenvv!(<i>[eps = 0.0]</i>) -> [eigen_vectors(cvmat), eigen_values(cvmat)]
  2236. *
  2237. * Computes eigenvalues and eigenvectors of symmetric matrix.
  2238. * <i>self</i> should be symmetric square matrix. <i>self</i> is modified during the processing.
  2239. *
  2240. * self * eigen_vectors(i,:)' = eigen_values(i) * eigen_vectors(i,:)'
  2241. *
  2242. * Currently the function is slower than #svd yet less accurate, so if <i>self</i> is known to be positively-defined
  2243. * (e.g., it is a convariation matrix), it is recommanded to use #svd to find eigenvalues and eigenvectors of <i>self</i>,
  2244. * especially if eigenvectors are not required.
  2245. */
  2246. VALUE
  2247. rb_eigenvv(int argc, VALUE *argv, VALUE self)
  2248. {
  2249. VALUE epsilon, lowindex, highindex;
  2250. rb_scan_args(argc, argv, "03", &epsilon, &lowindex, &highindex);
  2251. double eps = (NIL_P(epsilon)) ? 0.0 : NUM2DBL(epsilon);
  2252. int lowidx = (NIL_P(lowindex)) ? -1 : NUM2INT(lowindex);
  2253. int highidx = (NIL_P(highindex)) ? -1 : NUM2INT(highindex);
  2254. CvSize size = cvGetSize(CVARR(self));
  2255. int type = cvGetElemType(CVARR(self));
  2256. VALUE eigen_vectors = new_object(size, type), eigen_values = new_object(size.height, 1, type);
  2257. cvEigenVV(CVARR(self), CVARR(eigen_vectors), CVARR(eigen_values), eps, lowidx, highidx);
  2258. return rb_ary_new3(2, eigen_vectors, eigen_values);
  2259. }
  2260. /*
  2261. * call-seq:
  2262. * calc_covar_matrix()
  2263. *
  2264. * not yet.
  2265. *
  2266. */
  2267. VALUE
  2268. rb_calc_covar_matrix(int argc, VALUE *argv, VALUE self)
  2269. {
  2270. rb_raise(rb_eNotImpError, "");
  2271. }
  2272. /*
  2273. * call-seq:
  2274. * mahalonobis(vec, mat) -> float
  2275. *
  2276. * not yet.
  2277. */
  2278. VALUE
  2279. rb_mahalonobis(int argc, VALUE *argv, VALUE self)
  2280. {
  2281. rb_raise(rb_eNotImpError, "");
  2282. }
  2283. /*
  2284. * call-seq:
  2285. * dft(<i>anyflags...</i>) -> cvmat
  2286. *
  2287. * Performs forward or inverse Discrete Fourier Transform(DFT) of 1D or 2D floating-point array.
  2288. * Argument should be following symbol or combination of these.
  2289. *
  2290. * * :forward or :inverse
  2291. * Do forward or inverse transform. The result is not scaled.
  2292. * * :scale
  2293. * Scale the result: divide it by the number of array elements.
  2294. * * :rows
  2295. * Do forward or inverse transform of every individual row of the self.
  2296. * This flag allow user to transofrm multiple vectors simulaneously and can be used to decrease the overhand
  2297. * (which sometimes several times larger then the processing itself), to do 3D and higher-dimensional transforms etc.
  2298. *
  2299. * e.g.
  2300. * mat.dft(:inverse)
  2301. * mat.dft(:forward, :scale) etc...
  2302. */
  2303. VALUE
  2304. rb_dft(int argc, VALUE *argv, VALUE self)
  2305. {
  2306. int type = CV_DXT_FORWARD;
  2307. int num_rows = 0;
  2308. if (argc > 0) {
  2309. int num_flags = argc;
  2310. if (TYPE(argv[argc -1]) == T_FIXNUM) {
  2311. num_flags = argc - 1;
  2312. num_rows = FIX2INT(argv[argc - 1]);
  2313. }
  2314. for (int i = 0; i < num_flags; i++) {
  2315. type |= CVMETHOD("DXT_FLAG", argv[i]);
  2316. }
  2317. }
  2318. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  2319. cvDFT(CVARR(self), CVARR(dest), type, num_rows);
  2320. return dest;
  2321. }
  2322. /*
  2323. * call-seq:
  2324. * dct(<i>anyflags...</i>) -> cvmat
  2325. *
  2326. * Performs forward or inverse Discrete Cosine Transform(DCT) of 1D or 2D floating-point array.
  2327. * Argument should be following symbol or combination of these.
  2328. *
  2329. * * :forward or :inverse
  2330. * Do forward or inverse transform.
  2331. * * :rows
  2332. * Do forward or inverse transform of every individual row of the self.
  2333. * This flag allow user to transofrm multiple vectors simulaneously and can be used to decrease the overhand
  2334. * (which sometimes several times larger then the processing itself), to do 3D and higher-dimensional transforms etc.
  2335. */
  2336. VALUE
  2337. rb_dct(int argc, VALUE *argv, VALUE self)
  2338. {
  2339. int type = CV_DXT_FORWARD;
  2340. if (argc > 0) {
  2341. for (int i = 0; i < argc; i++) {
  2342. type |= CVMETHOD("DXT_FLAG", argv[i]);
  2343. }
  2344. }
  2345. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  2346. cvDCT(CVARR(self), CVARR(dest), type);
  2347. return dest;
  2348. }
  2349. /*
  2350. * call-seq:
  2351. * line(<i>p1, p2[, drawing_option]</i>) -> mat
  2352. *
  2353. * Return image is drawn a line segment connecting two points.
  2354. *
  2355. * <i>drawing_option</i> should be Hash include these keys.
  2356. * :color
  2357. * Line color.
  2358. * :thickness
  2359. * Line Thickness.
  2360. * :line_type
  2361. * Type of the line:
  2362. * * 0 or 8 - 8-connected line(default).
  2363. * * 4 - 4-connected line.
  2364. * * negative-value - antialiased line.
  2365. * :shift
  2366. * Number of fractional bits in the point coordinates.
  2367. *
  2368. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2369. *
  2370. * for example
  2371. * mat = CvMat.new(100, 100)
  2372. * mat.line(CvPoint.new(10, 10), CvPoint.new(90, 90), :thickness => 3, :line_type => :aa)
  2373. */
  2374. VALUE
  2375. rb_line(int argc, VALUE *argv, VALUE self)
  2376. {
  2377. return rb_line_bang(argc, argv, rb_clone(self));
  2378. }
  2379. /*
  2380. * call-seq:
  2381. * line!(<i>p1, p2[, drawing_option]</i>) -> self
  2382. *
  2383. * Draws a line segment connecting two points.
  2384. * Same as CvMat#line, but modifies the receiver in place.
  2385. * see CvMat#line
  2386. */
  2387. VALUE
  2388. rb_line_bang(int argc, VALUE *argv, VALUE self)
  2389. {
  2390. VALUE p1, p2, drawing_option;
  2391. rb_scan_args(argc, argv, "21", &p1, &p2, &drawing_option);
  2392. drawing_option = DRAWING_OPTION(drawing_option);
  2393. cvLine(CVARR(self), VALUE_TO_CVPOINT(p1), VALUE_TO_CVPOINT(p2),
  2394. DO_COLOR(drawing_option),
  2395. DO_THICKNESS(drawing_option),
  2396. DO_LINE_TYPE(drawing_option),
  2397. DO_SHIFT(drawing_option));
  2398. return self;
  2399. }
  2400. /*
  2401. * call-seq:
  2402. * rectangle(<i>p1, p2[, drawing_option]</i>) -> mat
  2403. *
  2404. * Return image is drawn a rectangle with two opposite corners <i>p1</i> and <i>p2</i>.
  2405. *
  2406. * <i>drawing_options</i> should be Hash include these keys.
  2407. * :color
  2408. * Line color.
  2409. * :thickness
  2410. * Thickness of lines that make up the rectangle.
  2411. * Negative values make the function to draw a filled rectangle.
  2412. * :line_type
  2413. * Type of the line:
  2414. * * 0 or 8 - 8-connected line(default).
  2415. * * 4 - 4-connected line.
  2416. * * negative-value - antialiased line.
  2417. * :shift
  2418. * Number of fractional bits in the point coordinates.
  2419. *
  2420. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2421. */
  2422. VALUE
  2423. rb_rectangle(int argc, VALUE *argv, VALUE self)
  2424. {
  2425. return rb_rectangle_bang(argc, argv, rb_clone(self));
  2426. }
  2427. /*
  2428. * call-seq:
  2429. * rectangle!(<i>p1, p2[, drawing_option]</i>) -> self
  2430. *
  2431. * Draws simple, thick or filled rectangle.
  2432. * Same as CvMat#rectangle, but modifies the receiver in place.
  2433. * see CvMat#rectangle
  2434. */
  2435. VALUE
  2436. rb_rectangle_bang(int argc, VALUE *argv, VALUE self)
  2437. {
  2438. VALUE p1, p2, drawing_option;
  2439. rb_scan_args(argc, argv, "21", &p1, &p2, &drawing_option);
  2440. drawing_option = DRAWING_OPTION(drawing_option);
  2441. cvRectangle(CVARR(self), VALUE_TO_CVPOINT(p1), VALUE_TO_CVPOINT(p2),
  2442. DO_COLOR(drawing_option),
  2443. DO_THICKNESS(drawing_option),
  2444. DO_LINE_TYPE(drawing_option),
  2445. DO_SHIFT(drawing_option));
  2446. return self;
  2447. }
  2448. /*
  2449. * call-seq:
  2450. * circle(<i>center, radius[,drawing_option]</i>) -> cvmat
  2451. *
  2452. * Return image is drawn a simple or filled circle with given center and radius.
  2453. *
  2454. * <i>drawing_options</i> should be Hash include these keys.
  2455. * :color
  2456. * Circle color.
  2457. * :thickness
  2458. * Thickness of the circle outline if positive, otherwise that a filled circle has to be drawn.
  2459. * :line_type
  2460. * Type of the circle boundary:
  2461. * * 0 or 8 - 8-connected line(default).
  2462. * * 4 - 4-connected line.
  2463. * * negative-value - antialiased line.
  2464. * :shift
  2465. * Number of fractional bits in the center coordinates and radius value.
  2466. *
  2467. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2468. */
  2469. VALUE
  2470. rb_circle(int argc, VALUE *argv, VALUE self)
  2471. {
  2472. return rb_circle_bang(argc, argv, rb_clone(self));
  2473. }
  2474. /*
  2475. * call-seq:
  2476. * circle!(<i>center, radius[,drawing_option]</i>) -> cvmat
  2477. *
  2478. * Draw a circle.
  2479. * Same as CvMat#circle, but modifies the receiver in place.
  2480. *
  2481. * see CvMat#circle
  2482. */
  2483. VALUE
  2484. rb_circle_bang(int argc, VALUE *argv, VALUE self)
  2485. {
  2486. VALUE center, radius, drawing_option;
  2487. rb_scan_args(argc, argv, "21", &center, &radius, &drawing_option);
  2488. drawing_option = DRAWING_OPTION(drawing_option);
  2489. cvCircle(CVARR(self), VALUE_TO_CVPOINT(center), NUM2INT(radius),
  2490. DO_COLOR(drawing_option),
  2491. DO_THICKNESS(drawing_option),
  2492. DO_LINE_TYPE(drawing_option),
  2493. DO_SHIFT(drawing_option));
  2494. return self;
  2495. }
  2496. /*
  2497. * call-seq:
  2498. * ellipse(<i>center, axis, angle, start_angle, end_angle[,drawing_option]</i>) -> mat
  2499. *
  2500. * Return image is drawn a simple or thick elliptic arc or fills an ellipse sector.
  2501. *
  2502. * <i>drawing_options</i> should be Hash include these keys.
  2503. * :color
  2504. * Ellipse color.
  2505. * :thickness
  2506. * Thickness of the ellipse arc.
  2507. * :line_type
  2508. * Type of the ellipse boundary:
  2509. * * 0 or 8 - 8-connected line(default).
  2510. * * 4 - 4-connected line.
  2511. * * negative-value - antialiased line.
  2512. * :shift
  2513. * Number of fractional bits in the center coordinates and axes' value.
  2514. *
  2515. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2516. */
  2517. VALUE
  2518. rb_ellipse(int argc, VALUE *argv, VALUE self)
  2519. {
  2520. return rb_ellipse_bang(argc, argv, rb_clone(self));
  2521. }
  2522. /*
  2523. * call-seq:
  2524. * ellipse!(<i>center, axis, angle, start_angle, end_angle[,drawing_option]</i>) -> self
  2525. *
  2526. * Draws simple or thick elliptic arc or fills ellipse sector.
  2527. * Same as CvMat#ellipse, but modifies the receiver in place.
  2528. *
  2529. * see CvMat#ellipse
  2530. */
  2531. VALUE
  2532. rb_ellipse_bang(int argc, VALUE *argv, VALUE self)
  2533. {
  2534. VALUE center, axis, angle, start_angle, end_angle, drawing_option;
  2535. rb_scan_args(argc, argv, "51", &center, &axis, &angle, &start_angle, &end_angle, &drawing_option);
  2536. drawing_option = DRAWING_OPTION(drawing_option);
  2537. cvEllipse(CVARR(self), VALUE_TO_CVPOINT(center),
  2538. VALUE_TO_CVSIZE(axis),
  2539. NUM2DBL(angle), NUM2DBL(start_angle), NUM2DBL(end_angle),
  2540. DO_COLOR(drawing_option),
  2541. DO_THICKNESS(drawing_option),
  2542. DO_LINE_TYPE(drawing_option),
  2543. DO_SHIFT(drawing_option));
  2544. return self;
  2545. }
  2546. /*
  2547. * call-seq:
  2548. * ellipse_box(<i>box[, drawing_option]</i>) -> mat
  2549. *
  2550. * Return image is drawn a simple or thick ellipse outline, or fills an ellipse.
  2551. * The method provides a convenient way to draw an ellipse approximating some shape.
  2552. *
  2553. * <i>drawing_options</i> should be Hash include these keys.
  2554. * :color
  2555. * Ellipse color.
  2556. * :thickness
  2557. * Thickness of the ellipse drawn.
  2558. * :line_type
  2559. * Type of the ellipse boundary:
  2560. * * 0 or 8 - 8-connected line(default).
  2561. * * 4 - 4-connected line.
  2562. * * negative-value - antialiased line.
  2563. * :shift
  2564. * Number of fractional bits in the box vertex coordinates.
  2565. *
  2566. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2567. */
  2568. VALUE
  2569. rb_ellipse_box(int argc, VALUE *argv, VALUE self)
  2570. {
  2571. return rb_ellipse_box_bang(argc, argv, rb_clone(self));
  2572. }
  2573. /*
  2574. * call-seq:
  2575. * ellipse_box!(<i>box[, drawing_option]</i>) -> self
  2576. *
  2577. * Draws simple or thick elliptic arc or fills ellipse sector.
  2578. * Same as CvMat#ellipse_box, but modifies the receiver in place.
  2579. *
  2580. * see CvMat#ellipse_box
  2581. */
  2582. VALUE
  2583. rb_ellipse_box_bang(int argc, VALUE *argv, VALUE self)
  2584. {
  2585. VALUE box, drawing_option;
  2586. rb_scan_args(argc, argv, "11", &box, &drawing_option);
  2587. drawing_option = DRAWING_OPTION(drawing_option);
  2588. cvEllipseBox(CVARR(self), VALUE_TO_CVBOX2D(box),
  2589. DO_COLOR(drawing_option),
  2590. DO_THICKNESS(drawing_option),
  2591. DO_LINE_TYPE(drawing_option),
  2592. DO_SHIFT(drawing_option));
  2593. return self;
  2594. }
  2595. /*
  2596. * call-seq:
  2597. * fill_poly(<i>points[,drawing_option]</i>) -> mat
  2598. *
  2599. * Return image is filled an area bounded by several polygonal contours.
  2600. * The method fills complex areas, for example, areas with holes, contour self-intersection, etc.
  2601. */
  2602. VALUE
  2603. rb_fill_poly(int argc, VALUE *argv, VALUE self)
  2604. {
  2605. return rb_fill_poly_bang(argc, argv, self);
  2606. }
  2607. /*
  2608. * call-seq:
  2609. * fill_poly!(<i>points[,drawing_option]</i>) -> self
  2610. *
  2611. * Fills polygons interior.
  2612. * Same as CvMat#fill_poly, but modifies the receiver in place.
  2613. *
  2614. * drawing_options should be Hash include these keys.
  2615. * :color
  2616. * Polygon color.
  2617. * :line_type
  2618. * Type of the polygon boundaries:
  2619. * * 0 or 8 - 8-connected line(default).
  2620. * * 4 - 4-connected line.
  2621. * * negative-value - antialiased line.
  2622. * :shift
  2623. * Number of fractional bits in the vertex coordinates.
  2624. *
  2625. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2626. */
  2627. VALUE
  2628. rb_fill_poly_bang(int argc, VALUE *argv, VALUE self)
  2629. {
  2630. VALUE polygons, drawing_option;
  2631. VALUE points;
  2632. int i, j;
  2633. int num_polygons;
  2634. int *num_points;
  2635. CvPoint **p;
  2636. rb_scan_args(argc, argv, "11", &polygons, &drawing_option);
  2637. // TODO: Check type of argument
  2638. drawing_option = DRAWING_OPTION(drawing_option);
  2639. num_polygons = RARRAY_LEN(polygons);
  2640. num_points = ALLOCA_N(int, num_polygons);
  2641. p = ALLOCA_N(CvPoint*, num_polygons);
  2642. for (j = 0; j < num_polygons; j++) {
  2643. points = rb_ary_entry(polygons, j);
  2644. num_points[j] = RARRAY_LEN(points);
  2645. p[j] = ALLOCA_N(CvPoint, num_points[j]);
  2646. for (i = 0; i < num_points[j]; i++) {
  2647. p[j][i] = VALUE_TO_CVPOINT(rb_ary_entry(points, i));
  2648. }
  2649. }
  2650. cvFillPoly(CVARR(self),
  2651. p,
  2652. num_points,
  2653. num_polygons,
  2654. DO_COLOR(drawing_option),
  2655. DO_LINE_TYPE(drawing_option),
  2656. DO_SHIFT(drawing_option));
  2657. return self;
  2658. }
  2659. /*
  2660. * call-seq:
  2661. * fill_convex_poly(<i>points[,drawing_option]</i>) -> mat
  2662. *
  2663. * Return image is filled convex polygon interior.
  2664. * This method is much faster than The function CvMat#fill_poly
  2665. * and can fill not only the convex polygons but any monotonic polygon,
  2666. * i.e. a polygon whose contour intersects every horizontal line (scan line)
  2667. * twice at the most.
  2668. *
  2669. * <i>drawing_options</i> should be Hash include these keys.
  2670. * :color
  2671. * Polygon color.
  2672. * :line_type
  2673. * Type of the polygon boundaries:
  2674. * * 0 or 8 - 8-connected line(default).
  2675. * * 4 - 4-connected line.
  2676. * * negative-value - antialiased line.
  2677. * :shift
  2678. * Number of fractional bits in the vertex coordinates.
  2679. *
  2680. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2681. */
  2682. VALUE
  2683. rb_fill_convex_poly(int argc, VALUE *argv, VALUE self)
  2684. {
  2685. return rb_fill_convex_poly_bang(argc, argv, rb_clone(self));
  2686. }
  2687. /*
  2688. * call-seq:
  2689. * fill_convex_poly!(<i>points[,drawing_option]</i>) -> self
  2690. *
  2691. * Fills convex polygon.
  2692. * Same as CvMat#fill_convex_poly, but modifies the receiver in place.
  2693. *
  2694. * see CvMat#fill_convex_poly
  2695. */
  2696. VALUE
  2697. rb_fill_convex_poly_bang(int argc, VALUE *argv, VALUE self)
  2698. {
  2699. VALUE points, drawing_option;
  2700. int i, num_points;
  2701. CvPoint *p;
  2702. rb_scan_args(argc, argv, "11", &points, &drawing_option);
  2703. // TODO: Check type of argument
  2704. drawing_option = DRAWING_OPTION(drawing_option);
  2705. num_points = RARRAY_LEN(points);
  2706. p = ALLOCA_N(CvPoint, num_points);
  2707. for (i = 0; i < num_points; i++)
  2708. p[i] = VALUE_TO_CVPOINT(rb_ary_entry(points, i));
  2709. cvFillConvexPoly(CVARR(self),
  2710. p,
  2711. num_points,
  2712. DO_COLOR(drawing_option),
  2713. DO_LINE_TYPE(drawing_option),
  2714. DO_SHIFT(drawing_option));
  2715. return self;
  2716. }
  2717. /*
  2718. * call-seq:
  2719. * poly_line(<i>points[,drawing_option]</i>) -> mat
  2720. *
  2721. * Return image drawed a single or multiple polygonal curves.
  2722. *
  2723. * <i>drawing_option</i> should be Hash include these keys.
  2724. * :is_closed
  2725. * Indicates whether the polylines must be drawn closed.
  2726. * If closed, the method draws the line from the last vertex
  2727. * of every contour to the first vertex.
  2728. * :color
  2729. * Polyline color.
  2730. * :thickness
  2731. * Thickness of the polyline edges
  2732. * :line_type
  2733. * Type of line segments:
  2734. * * 0 or 8 - 8-connected line(default).
  2735. * * 4 - 4-connected line.
  2736. * * negative-value - antialiased line.
  2737. * :shift
  2738. * Number of fractional bits in the vertex coordinates.
  2739. *
  2740. * note: <i>drawing_option</i>'s default value is CvMat::DRAWING_OPTION.
  2741. */
  2742. VALUE
  2743. rb_poly_line(int argc, VALUE *argv, VALUE self)
  2744. {
  2745. return rb_poly_line_bang(argc, argv, rb_clone(self));
  2746. }
  2747. /*
  2748. * call-seq:
  2749. * poly_line!(<i>points[,drawing_option]</i>) -> self
  2750. *
  2751. * Draws simple or thick polygons.
  2752. *
  2753. * Same as CvMat#poly_line, but modifies the receiver in place.
  2754. *
  2755. * see CvMat#poly_line
  2756. */
  2757. VALUE
  2758. rb_poly_line_bang(int argc, VALUE *argv, VALUE self)
  2759. {
  2760. VALUE polygons, drawing_option;
  2761. VALUE points;
  2762. int i, j;
  2763. int num_polygons;
  2764. int *num_points;
  2765. CvPoint **p;
  2766. rb_scan_args(argc, argv, "11", &polygons, &drawing_option);
  2767. // TODO: Check type of argument
  2768. drawing_option = DRAWING_OPTION(drawing_option);
  2769. num_polygons = RARRAY_LEN(polygons);
  2770. num_points = ALLOCA_N(int, num_polygons);
  2771. p = ALLOCA_N(CvPoint*, num_polygons);
  2772. for (j = 0; j < num_polygons; j++) {
  2773. points = rb_ary_entry(polygons, j);
  2774. num_points[j] = RARRAY_LEN(points);
  2775. p[j] = ALLOCA_N(CvPoint, num_points[j]);
  2776. for (i = 0; i < num_points[j]; i++) {
  2777. p[j][i] = VALUE_TO_CVPOINT(rb_ary_entry(points, i));
  2778. }
  2779. }
  2780. cvPolyLine(CVARR(self),
  2781. p,
  2782. num_points,
  2783. num_polygons,
  2784. DO_IS_CLOSED(drawing_option),
  2785. DO_COLOR(drawing_option),
  2786. DO_THICKNESS(drawing_option),
  2787. DO_LINE_TYPE(drawing_option),
  2788. DO_SHIFT(drawing_option));
  2789. return self;
  2790. }
  2791. /*
  2792. * call-seq:
  2793. * put_text(<i>str, point, font[,color]</i>) -> cvmat
  2794. *
  2795. * Return image is drawn text string.
  2796. * <i>font</i> should be CvFont object.
  2797. */
  2798. VALUE
  2799. rb_put_text(int argc, VALUE *argv, VALUE self)
  2800. {
  2801. return rb_put_text_bang(argc, argv, rb_clone(self));
  2802. }
  2803. /*
  2804. * call-seq:
  2805. * put_text!(<i>str, point ,font[,color]</i>) -> self
  2806. *
  2807. * Draws text string. Return self.
  2808. */
  2809. VALUE
  2810. rb_put_text_bang(int argc, VALUE *argv, VALUE self)
  2811. {
  2812. VALUE text, point, font, color;
  2813. rb_scan_args(argc, argv, "22", &text, &point, &font, &color);
  2814. cvPutText(CVARR(self), StringValueCStr(text), VALUE_TO_CVPOINT(point), CVFONT(font), *CVSCALAR(color));
  2815. return self;
  2816. }
  2817. /*
  2818. * call-seq:
  2819. * sobel(<i>xorder,yorder[,aperture_size=3]</i>) -> cvmat
  2820. *
  2821. * Calculates first, second, third or mixed image derivatives using extended Sobel operator.
  2822. * <i>self</i> should be single-channel 8bit unsigned or 32bit floating-point.
  2823. *
  2824. * link:../images/CvMat_sobel.png
  2825. */
  2826. VALUE
  2827. rb_sobel(int argc, VALUE *argv, VALUE self)
  2828. {
  2829. VALUE xorder, yorder, aperture_size, dest;
  2830. if (rb_scan_args(argc, argv, "21", &xorder, &yorder, &aperture_size) < 3)
  2831. aperture_size = INT2FIX(3);
  2832. switch(CV_MAT_DEPTH(CVMAT(self)->type)) {
  2833. case CV_8U:
  2834. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_16S, 1));
  2835. break;
  2836. case CV_32F:
  2837. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  2838. break;
  2839. default:
  2840. rb_raise(rb_eRuntimeError, "source depth should be CV_8U or CV_32F.");
  2841. }
  2842. cvSobel(CVARR(self), CVARR(dest), NUM2INT(xorder), NUM2INT(yorder), NUM2INT(aperture_size));
  2843. return dest;
  2844. }
  2845. /*
  2846. * call-seq:
  2847. * laplace(<i>[aperture_size = 3]</i>) -> cvmat
  2848. *
  2849. * Calculates Laplacian of the image.
  2850. * <i>self</i> should be single-channel 8bit unsigned or 32bit floating-point.
  2851. */
  2852. VALUE
  2853. rb_laplace(int argc, VALUE *argv, VALUE self)
  2854. {
  2855. VALUE aperture_size, dest;
  2856. if (rb_scan_args(argc, argv, "01", &aperture_size) < 1)
  2857. aperture_size = INT2FIX(3);
  2858. switch(CV_MAT_DEPTH(CVMAT(self)->type)) {
  2859. case CV_8U:
  2860. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_16S, 1));
  2861. break;
  2862. case CV_32F:
  2863. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  2864. break;
  2865. default:
  2866. rb_raise(rb_eRuntimeError, "source depth should be CV_8U or CV_32F.");
  2867. }
  2868. cvLaplace(CVARR(self), CVARR(dest), NUM2INT(aperture_size));
  2869. return dest;
  2870. }
  2871. /*
  2872. * call-seq:
  2873. * canny(<i>thresh1,thresh2[,aperture_size = 3]</i>) -> cvmat
  2874. *
  2875. * Canny algorithm for edge detection.
  2876. */
  2877. VALUE
  2878. rb_canny(int argc, VALUE *argv, VALUE self)
  2879. {
  2880. VALUE thresh1, thresh2, aperture_size;
  2881. if (rb_scan_args(argc, argv, "21", &thresh1, &thresh2, &aperture_size) < 3)
  2882. aperture_size = INT2FIX(3);
  2883. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  2884. cvCanny(CVARR(self), CVARR(dest), NUM2INT(thresh1), NUM2INT(thresh2), NUM2INT(aperture_size));
  2885. return dest;
  2886. }
  2887. /*
  2888. * call-seq:
  2889. * pre_corner_detect(<i>[aperture_size = 3]</i>) -> cvmat
  2890. *
  2891. * Calculates feature map for corner detection.
  2892. * <i>aperture_size</i> is parameter for sobel operator(see #sobel).
  2893. *
  2894. * The corners can be found as local maximums of the function.
  2895. */
  2896. VALUE
  2897. rb_pre_corner_detect(int argc, VALUE *argv, VALUE self)
  2898. {
  2899. VALUE aperture_size, dest;
  2900. if (rb_scan_args(argc, argv, "01", &aperture_size) < 1)
  2901. aperture_size = INT2FIX(3);
  2902. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  2903. cvPreCornerDetect(CVARR(self), CVARR(dest), NUM2INT(aperture_size));
  2904. return dest;
  2905. }
  2906. /*
  2907. * call-seq:
  2908. * corner_eigenvv(<i>block_size[,aperture_size]</i>) -> cvmat
  2909. *
  2910. * For every pixel considers <i>block_size x block_size</i> neighborhood S(p).
  2911. * It calculates convariation matrix of derivatives over the neighborhood.
  2912. */
  2913. VALUE
  2914. rb_corner_eigenvv(int argc, VALUE *argv, VALUE self)
  2915. {
  2916. VALUE block_size, aperture_size, dest;
  2917. if (rb_scan_args(argc, argv, "11", &block_size, &aperture_size) < 2)
  2918. aperture_size = INT2FIX(3);
  2919. Check_Type(block_size, T_FIXNUM);
  2920. CvSize size = cvGetSize(CVARR(self));
  2921. dest = new_object(cvSize(size.width * 6, size.height), CV_MAKETYPE(CV_32F, 1));
  2922. cvCornerEigenValsAndVecs(CVARR(self), CVARR(dest), NUM2INT(block_size), NUM2INT(aperture_size));
  2923. return dest;
  2924. }
  2925. /*
  2926. * call-seq:
  2927. * corner_min_eigen_val(<i>block_size[,aperture_size = 3]</i>) -> cvmat
  2928. *
  2929. * Calculates minimal eigenvalue of gradient matrices for corner detection.
  2930. */
  2931. VALUE
  2932. rb_corner_min_eigen_val(int argc, VALUE *argv, VALUE self)
  2933. {
  2934. VALUE block_size, aperture_size, dest;
  2935. if (rb_scan_args(argc, argv, "11", &block_size, &aperture_size) < 2)
  2936. aperture_size = INT2FIX(3);
  2937. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  2938. cvCornerMinEigenVal(CVARR(self), CVARR(dest), FIX2INT(block_size), FIX2INT(aperture_size));
  2939. return dest;
  2940. }
  2941. /*
  2942. * call-seq:
  2943. * corner_harris(<i>block_size[,aperture_size = 3][,k = 0.04]</i>) -> cvmat
  2944. *
  2945. * Return image Applied Harris edge detector.
  2946. */
  2947. VALUE
  2948. rb_corner_harris(int argc, VALUE *argv, VALUE self)
  2949. {
  2950. SUPPORT_8UC1_ONLY(self);
  2951. VALUE block_size, aperture_size, k, dest;
  2952. rb_scan_args(argc, argv, "12", &block_size, &aperture_size, &k);
  2953. dest = new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  2954. cvCornerHarris(CVARR(self), CVARR(dest), FIX2INT(block_size), IF_INT(aperture_size, 3), IF_DBL(k, 0.04));
  2955. return dest;
  2956. }
  2957. /*
  2958. * call-seq:
  2959. * find_corner_sub_pix(<i></i>)
  2960. *
  2961. * Refines corner locations.
  2962. * This method iterates to find the sub-pixel accurate location of corners,
  2963. * or radial saddle points, as shown in on the picture below.
  2964. */
  2965. VALUE
  2966. rbi_find_corner_sub_pix(int argc, VALUE *argv, VALUE self)
  2967. {
  2968. /*
  2969. VALUE corners, win, zero_zone, criteria;
  2970. rb_scan_args(argc, argv, "13", &corners, &win, &zero_zone, &criteria);
  2971. if (!rb_obj_is_kind_of(corners, mPointSet::rb_module()))
  2972. rb_raise(rb_eTypeError, "argument 1 (corners) should be %s.", rb_class2name(mPointSet::rb_module()));
  2973. int count = CVSEQ(corners)->total;
  2974. VALUE storage = cCvMemStorage::new_object();
  2975. CvPoint2D32f *pointset = POINTSET2D32f(corners);
  2976. //cvFindCornerSubPix(CVARR(self), pointset, count, VALUE_TO_CVSIZE(win), VALUE_TO_CVSIZE(zero_zone), VALUE_TO_CVTERMCRITERIA(criteria));
  2977. //return cCvSeq::new_sequence();
  2978. */
  2979. return Qnil;
  2980. }
  2981. /*
  2982. * call-seq:
  2983. * good_features_to_track(<i>quality_level, min_distance[, good_features_to_track_option]</i>)
  2984. * -> array (include CvPoint2D32f)
  2985. * Determines strong corners on an image.
  2986. *
  2987. * quality_level – Multiplier for the max/min eigenvalue; specifies the minimal accepted quality of image corners
  2988. * min_distance – Limit, specifying the minimum possible distance between the returned corners; Euclidian distance is used
  2989. * <i>good_features_to_track_option</i> should be Hash include these keys.
  2990. * :mask
  2991. * Region of interest. The function selects points either in the specified region or in the whole image
  2992. * if the mask is nil.
  2993. * :block_size
  2994. * Size of the averaging block, passed to the underlying CornerMinEigenVal or CornerHarris used by the function.
  2995. * :use_harris
  2996. * If true, Harris operator ( CornerHarris ) is used instead of default CornerMinEigenVal
  2997. * :k
  2998. * Free parameter of Harris detector; used only if ( :use_harris => true )
  2999. * note: <i>good_features_to_track_option</i>'s default value is CvMat::GOOD_FEATURES_TO_TRACK_OPTION
  3000. */
  3001. VALUE
  3002. rb_good_features_to_track(int argc, VALUE *argv, VALUE self)
  3003. {
  3004. VALUE quality_level, min_distance, good_features_to_track_option;
  3005. CvMat *eigen, *tmp;
  3006. int i;
  3007. rb_scan_args(argc, argv, "21", &quality_level, &min_distance, &good_features_to_track_option);
  3008. good_features_to_track_option = GOOD_FEATURES_TO_TRACK_OPTION(good_features_to_track_option);
  3009. CvMat *src = CVMAT(self);
  3010. CvSize size = cvGetSize(src);
  3011. eigen = cvCreateMat(size.height, size.width, CV_MAKETYPE(CV_32F, 1));
  3012. tmp = cvCreateMat(size.height, size.width, CV_MAKETYPE(CV_32F, 1));
  3013. int np = GF_MAX(good_features_to_track_option);
  3014. if(!(np > 0))
  3015. rb_raise(rb_eArgError, "option :max should be positive value.");
  3016. CvPoint2D32f *p32 = (CvPoint2D32f*)cvAlloc(sizeof(CvPoint2D32f) * np);
  3017. if(!p32)
  3018. rb_raise(rb_eNoMemError, "failed to allocate memory.");
  3019. cvGoodFeaturesToTrack(src, &eigen, &tmp, p32, &np, NUM2DBL(quality_level), NUM2DBL(min_distance),
  3020. GF_MASK(good_features_to_track_option),
  3021. GF_BLOCK_SIZE(good_features_to_track_option),
  3022. GF_USE_HARRIS(good_features_to_track_option),
  3023. GF_K(good_features_to_track_option));
  3024. VALUE corners = rb_ary_new2(np);
  3025. for (i = 0; i < np; i++)
  3026. rb_ary_store(corners, i, cCvPoint2D32f::new_object(p32[i]));
  3027. cvFree(&p32);
  3028. cvReleaseMat(&eigen);
  3029. cvReleaseMat(&tmp);
  3030. return corners;
  3031. }
  3032. /*
  3033. * call-seq:
  3034. * sample_line(p1, p2[,connectivity = 8]) {|pixel| }
  3035. *
  3036. * not yet.
  3037. */
  3038. VALUE
  3039. rb_sample_line(int argc, VALUE *argv, VALUE self)
  3040. {
  3041. /*
  3042. VALUE p1, p2, connectivity;
  3043. if (rb_scan_args(argc, argv, "21", &p1, &p2, &connectivity) < 3)
  3044. connectivity = INT2FIX(8);
  3045. CvPoint point1 = VALUE_TO_CVPOINT(p1), point2 = VALUE_TO_CVPOINT(p2);
  3046. int size;
  3047. switch(FIX2INT(connectivity)) {
  3048. case 4:
  3049. size = abs(point2.x - point1.x) + abs(point2.y - point1.y) + 1;
  3050. break;
  3051. case 8:
  3052. size = maxint(abs(point2.x - point1.x) + 1, abs(point2.y - point1.y) + 1);
  3053. break;
  3054. default:
  3055. rb_raise(rb_eArgError, "argument 3(connectivity) should be 4 or 8. 8 is default.");
  3056. }
  3057. VALUE buf = cCvMat::new_object(1, size, cvGetElemType(CVARR(self)));
  3058. cvSampleLine(CVARR(self), point1, point2, CVMAT(buf)->data.ptr, FIX2INT(connectivity));
  3059. if (rb_block_given_p()) {
  3060. for(int i = 0; i < size; i++) {
  3061. //Data_Wrap_Struct(cCvScalar::rb_class(), 0, 0, CVMAT(buf)->data.ptr[]);
  3062. //rb_yield(cCvScalar::new_object);
  3063. }
  3064. }
  3065. return buf;
  3066. */
  3067. return Qnil;
  3068. }
  3069. /*
  3070. * call-seq:
  3071. * rect_sub_pix(<i>center[, size = self.size]</i>) -> cvmat
  3072. *
  3073. * Retrieves pixel rectangle from image with sub-pixel accuracy.
  3074. * Extracts pixels from <i>self</i>.
  3075. * dst(x,y) = self(x + center.x - (size.width - 1) * 0.5, y + center.y - (size.height - 1) * 0.5)
  3076. * where the values of pixels at non-integer coordinates are retrived using bilinear iterpolation.
  3077. * Every channel of multiple-channel images is processed independently.
  3078. * Whereas the rectangle center must be inside the image, the whole rectangle may be partially occludedl.
  3079. * In this case, the replication border mode is used to get pixel values beyond the image boundaries.
  3080. */
  3081. VALUE
  3082. rb_rect_sub_pix(int argc, VALUE *argv, VALUE self)
  3083. {
  3084. VALUE center, size;
  3085. CvSize _size;
  3086. if (rb_scan_args(argc, argv, "11", &center, &size) < 2)
  3087. _size = cvGetSize(CVARR(self));
  3088. else
  3089. _size = VALUE_TO_CVSIZE(size);
  3090. VALUE dest = new_object(_size, cvGetElemType(CVARR(self)));
  3091. cvGetRectSubPix(CVARR(self), CVARR(dest), VALUE_TO_CVPOINT2D32F(center));
  3092. return dest;
  3093. }
  3094. /*
  3095. * call-seq:
  3096. * quandrangle_sub_pix(<i>map_matrix[, size = self.size]</i>) -> cvmat
  3097. *
  3098. * Retrives pixel quadrangle from image with sub-pixel accuracy.
  3099. * Extracts pixel from <i>self</i> at sub-pixel accuracy and store them:
  3100. */
  3101. VALUE
  3102. rb_quadrangle_sub_pix(int argc, VALUE *argv, VALUE self)
  3103. {
  3104. VALUE map_matrix, size;
  3105. CvSize _size;
  3106. if (rb_scan_args(argc, argv, "11", &map_matrix, &size) < 2)
  3107. _size = cvGetSize(CVARR(self));
  3108. else
  3109. _size = VALUE_TO_CVSIZE(size);
  3110. if (!rb_obj_is_kind_of(map_matrix, cCvMat::rb_class()))
  3111. rb_raise(rb_eTypeError, "argument 1 (map matrix) should be %s (2x3).", rb_class2name(cCvMat::rb_class()));
  3112. VALUE dest = new_object(_size, cvGetElemType(CVARR(self)));
  3113. cvGetQuadrangleSubPix(CVARR(self), CVARR(dest), CVMAT(map_matrix));
  3114. return dest;
  3115. }
  3116. /*
  3117. * call-seq:
  3118. * resize(<i>size[,interpolation = :linear]</i>) -> cvmat
  3119. *
  3120. * Resize image.
  3121. * <i>interpolation</i> is interpolation method:
  3122. * * :nn
  3123. * nearest-neighbor interpolation.
  3124. * * :linear
  3125. * bilinear interpolation (used by default)
  3126. * * :area
  3127. * resampling using pixel area relation. It is preferred method for image decimation that give moire-free results.
  3128. * In case of zooming it is similar to NN method.
  3129. * * :cubic
  3130. * bicubic interpolation.
  3131. * Return <i>self</i> resized image that it fits exactly to <i>size</i>. If ROI is set, the method consideres the ROI as supported as usual.
  3132. */
  3133. VALUE
  3134. rb_resize(int argc, VALUE *argv, VALUE self)
  3135. {
  3136. VALUE size, interpolation;
  3137. rb_scan_args(argc, argv, "11", &size, &interpolation);
  3138. VALUE dest = new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self)));
  3139. cvResize(CVARR(self), CVARR(dest), CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR));
  3140. return dest;
  3141. }
  3142. /*
  3143. * call-seq:
  3144. * warp_affine(<i>map_matrix[,interpolation = :linear][,option = :fill_outliers][,fillval = 0]</i>) -> cvmat
  3145. *
  3146. * Applies affine transformation to the image.
  3147. */
  3148. VALUE
  3149. rb_warp_affine(int argc, VALUE *argv, VALUE self)
  3150. {
  3151. VALUE map_matrix, interpolation, option, fill_value;
  3152. if (rb_scan_args(argc, argv, "13", &map_matrix, &interpolation, &option, &fill_value) < 4)
  3153. fill_value = INT2FIX(0);
  3154. if (!rb_obj_is_kind_of(map_matrix, cCvMat::rb_class()))
  3155. rb_raise(rb_eTypeError, "argument 1 (map matrix) should be %s (2x3).", rb_class2name(cCvMat::rb_class()));
  3156. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3157. cvWarpAffine(CVARR(self), CVARR(dest), CVMAT(map_matrix),
  3158. CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG", option, CV_WARP_FILL_OUTLIERS), VALUE_TO_CVSCALAR(fill_value));
  3159. return dest;
  3160. }
  3161. /*
  3162. * call-seq:
  3163. * CvMat.find_homograpy(<i>src_points, dst_points[,method = :all][,ransac_reproj_threshold = 0][,get_status = nil]</i>) -> cvmat
  3164. *
  3165. * Finds the perspective transformation between two planes.
  3166. * <i>src_points:</i> Coordinates of the points in the original plane, 2xN, Nx2, 3xN or Nx3 1-channel array (the latter two are for representation in homogeneous coordinates), where N is the number of points. 1xN or Nx1 2- or 3-channel array can also be passed.
  3167. * <i>dst_points:</i> Point coordinates in the destination plane, 2xN, Nx2, 3xN or Nx3 1-channel, or 1xN or Nx1 2- or 3-channel array.
  3168. * <i>method:</i> The method used to computed homography matrix; one of the following symbols:
  3169. * :all - a regular method using all the points
  3170. * :ransac - RANSAC-based robust method
  3171. * :lmeds - Least-Median robust method
  3172. * <i>ransac_reproj_threshold:</i> The maximum allowed reprojection error to treat a point pair as an inlier (used in the RANSAC method only). If src_points and dst_points are measured in pixels, it usually makes sense to set this parameter somewhere in the range 1 to 10.
  3173. * <i>get_status</i> If true, the optional output mask set by a robust method (:ransac or :lmeds) is returned additionally.
  3174. */
  3175. VALUE
  3176. rb_find_homograpy(int argc, VALUE *argv, VALUE self)
  3177. {
  3178. VALUE src_points, dst_points, method, ransac_reproj_threshold, get_status;
  3179. rb_scan_args(argc, argv, "23", &src_points, &dst_points, &method, &ransac_reproj_threshold, &get_status);
  3180. VALUE homography = new_object(cvSize(3, 3), CV_32FC1);
  3181. int _method = CVMETHOD("HOMOGRAPHY_CALC_METHOD", method, 0);
  3182. double _ransac_reproj_threshold = NIL_P(ransac_reproj_threshold) ? 0.0 : NUM2DBL(ransac_reproj_threshold);
  3183. if ((_method != 0) && (!NIL_P(get_status)) && IF_BOOL(get_status, 1, 0, 0)) {
  3184. CvMat *src = CVMAT(src_points);
  3185. int num_points = MAX(src->rows, src->cols);
  3186. VALUE status = new_object(cvSize(num_points, 1), CV_8UC1);
  3187. cvFindHomography(src, CVMAT(dst_points), CVMAT(homography),
  3188. _method, _ransac_reproj_threshold, CVMAT(status));
  3189. return rb_assoc_new(homography, status);
  3190. }
  3191. else {
  3192. cvFindHomography(CVMAT(src_points), CVMAT(dst_points), CVMAT(homography),
  3193. _method, _ransac_reproj_threshold, NULL);
  3194. return homography;
  3195. }
  3196. }
  3197. /*
  3198. * call-seq:
  3199. * CvMat.rotation_matrix2D(<i>center,angle,scale</i>) -> cvmat
  3200. *
  3201. * Create new affine matrix of 2D rotation (2x3 32bit floating-point matrix).
  3202. * <i>center</i> is center of rotation (x, y).
  3203. * <i>angle</i> is rotation angle in degrees.
  3204. * Positive values mean counter-clockwise rotation
  3205. * (the coordinate origin is assumed at top-left corner).
  3206. * <i>scale</i> is isotropic scale factor.
  3207. *
  3208. * [ a b | (1 - a) * center.x - b * center.y ]
  3209. * [-b a | (b * center.x + (1 + a) * center.y ]
  3210. * where a = scale * cos(angle), b = scale * sin(angle)
  3211. */
  3212. VALUE
  3213. rb_rotation_matrix2D(VALUE self, VALUE center, VALUE angle, VALUE scale)
  3214. {
  3215. VALUE map_matrix = new_object(cvSize(3,2), CV_MAKETYPE(CV_32F, 1));
  3216. cv2DRotationMatrix(VALUE_TO_CVPOINT2D32F(center), NUM2DBL(angle), NUM2DBL(scale), CVMAT(map_matrix));
  3217. return map_matrix;
  3218. }
  3219. /*
  3220. * call-seq:
  3221. * warp_perspective(<i>map_matrix[,interpolation=:linear][,option =:fill_outliers][,fillval=0])</i>) -> cvmat
  3222. *
  3223. * Applies perspective transformation to the image.
  3224. */
  3225. VALUE
  3226. rb_warp_perspective(int argc, VALUE *argv, VALUE self)
  3227. {
  3228. VALUE map_matrix, interpolation, option, fillval;
  3229. if (rb_scan_args(argc, argv, "13", &map_matrix, &interpolation, &option, &fillval) < 4)
  3230. fillval = INT2FIX(0);
  3231. if (!rb_obj_is_kind_of(map_matrix, cCvMat::rb_class()))
  3232. rb_raise(rb_eTypeError, "argument 1 (map matrix) should be %s (3x3).", rb_class2name(cCvMat::rb_class()));
  3233. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3234. cvWarpPerspective(CVARR(self), CVARR(dest), CVMAT(map_matrix),
  3235. CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG",option, CV_WARP_FILL_OUTLIERS), VALUE_TO_CVSCALAR(fillval));
  3236. return dest;
  3237. }
  3238. /*
  3239. * call-seq:
  3240. * remap(<i>mapx,mapy[,interpolation=:linear][,option=:fill_outliers][,fillval=0]</i>) -> cvmat
  3241. *
  3242. * Applies generic geometrical transformation to the image.
  3243. * Transforms source image using the specified map:
  3244. * dst(x,y)<-src(mapx(x,y),mapy(x,y))
  3245. * Similar to other geometrical transformations, some interpolation method (specified by user) is used to
  3246. * extract pixels with non-integer coordinates.
  3247. */
  3248. VALUE
  3249. rb_remap(int argc, VALUE *argv, VALUE self)
  3250. {
  3251. VALUE mapx, mapy, interpolation, option, fillval;
  3252. if (rb_scan_args(argc, argv, "23", &mapx, &mapy, &interpolation, &option, &fillval) < 5)
  3253. fillval = INT2FIX(0);
  3254. if (!rb_obj_is_kind_of(mapx, cCvMat::rb_class()))
  3255. rb_raise(rb_eTypeError, "argument 1 (map of x-coordinates) should be %s(CV_32F and single-channel).", rb_class2name(cCvMat::rb_class()));
  3256. if (!rb_obj_is_kind_of(mapy, cCvMat::rb_class()))
  3257. rb_raise(rb_eTypeError, "argument 2 (map of y-coordinates) should be %s(CV_32F and single-channel).", rb_class2name(cCvMat::rb_class()));
  3258. VALUE dest = new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3259. cvRemap(CVARR(self), CVARR(dest), CVARR(mapx), CVARR(mapy),
  3260. CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG", option, CV_WARP_FILL_OUTLIERS), VALUE_TO_CVSCALAR(fillval));
  3261. return dest;
  3262. }
  3263. /*
  3264. * call-seq:
  3265. * log_polar(<i>center, magnitude, </i>)
  3266. *
  3267. * Remaps image to log-polar space.
  3268. */
  3269. VALUE
  3270. rb_log_polar(int argc, VALUE *argv, VALUE self)
  3271. {
  3272. /*
  3273. VALUE size, center, m, flags, fillval, dest;
  3274. rb_scan_args(argc, argv, "3*", &size, &center, &m, &flags);
  3275. dest = cCvMat::new_object();
  3276. cvLogPolar(CVARR(self), CVARR(dest),
  3277. VALUE_TO_CVPOINT2D32F(center), NUM2DBL(m),
  3278. CVMETHOD("INTERPOLATION_METHOD", interpolation, CV_INTER_LINEAR) | CVMETHOD("WARP_FLAG", option, CV_WARP_FILL_OUTLIEARS), VALUE_TO_CVSCALAR(fillval));
  3279. return dest;
  3280. */
  3281. return Qnil;
  3282. }
  3283. /*
  3284. * call-seq:
  3285. * erode(<i>[element = nil, iteration = 1]</i>) -> cvmat
  3286. *
  3287. * Create erodes image by using arbitrary structuring element.
  3288. * <i>element</i> is structuring element used for erosion.
  3289. * <i>element</i> should be IplConvKernel. If it is nil, a 3x3 rectangular structuring element is used.
  3290. * <i>iterations</i> is number of times erosion is applied.
  3291. */
  3292. VALUE
  3293. rb_erode(int argc, VALUE *argv, VALUE self)
  3294. {
  3295. return rb_erode_bang(argc, argv, rb_clone(self));
  3296. }
  3297. /*
  3298. * call-seq:
  3299. * erode!(<i>[element = nil][,iteration = 1]</i>) -> self
  3300. *
  3301. * Erodes image by using arbitrary structuring element.
  3302. * see also #erode.
  3303. */
  3304. VALUE
  3305. rb_erode_bang(int argc, VALUE *argv, VALUE self)
  3306. {
  3307. VALUE element, iteration;
  3308. rb_scan_args(argc, argv, "02", &element, &iteration);
  3309. cvErode(CVARR(self), CVARR(self), IPLCONVKERNEL(element), IF_INT(iteration, 1));
  3310. return self;
  3311. }
  3312. /*
  3313. * call-seq:
  3314. * dilate(<i>[element = nil][,iteration = 1]</i>) -> cvmat
  3315. *
  3316. * Create dilates image by using arbitrary structuring element.
  3317. * <i>element</i> is structuring element used for erosion.
  3318. * <i>element</i> should be IplConvKernel. If it is nil, a 3x3 rectangular structuring element is used.
  3319. * <i>iterations</i> is number of times erosion is applied.
  3320. */
  3321. VALUE
  3322. rb_dilate(int argc, VALUE *argv, VALUE self)
  3323. {
  3324. return rb_dilate_bang(argc, argv, rb_clone(self));
  3325. }
  3326. /*
  3327. * call-seq:
  3328. * dilate!(<i>[element = nil][,iteration = 1]</i>) -> self
  3329. *
  3330. * Dilate image by using arbitrary structuring element.
  3331. * see also #dilate.
  3332. */
  3333. VALUE
  3334. rb_dilate_bang(int argc, VALUE *argv, VALUE self)
  3335. {
  3336. VALUE element, iteration;
  3337. rb_scan_args(argc, argv, "02", &element, &iteration);
  3338. cvDilate(CVARR(self), CVARR(self), IPLCONVKERNEL(element), IF_INT(iteration, 1));
  3339. return self;
  3340. }
  3341. VALUE
  3342. rb_morphology_internal(VALUE element, VALUE iteration, int operation, VALUE self)
  3343. {
  3344. CvArr* self_ptr = CVARR(self);
  3345. CvSize size = cvGetSize(self_ptr);
  3346. VALUE dest = new_object(size, cvGetElemType(self_ptr));
  3347. if (operation == CV_MOP_GRADIENT) {
  3348. CvMat* temp = cvCreateMat(size.height, size.width, cvGetElemType(self_ptr));
  3349. cvMorphologyEx(self_ptr, CVARR(dest), temp, IPLCONVKERNEL(element), CV_MOP_GRADIENT, IF_INT(iteration, 1));
  3350. cvReleaseMat(&temp);
  3351. }
  3352. else {
  3353. cvMorphologyEx(self_ptr, CVARR(dest), 0, IPLCONVKERNEL(element), operation, IF_INT(iteration, 1));
  3354. }
  3355. return dest;
  3356. }
  3357. /*
  3358. * call-seq:
  3359. * morpholohy(<i>operation[,element = nil][,iteration = 1]</i>) -> cvmat
  3360. *
  3361. * Performs advanced morphological transformations.
  3362. * <i>operation</i>
  3363. * Type of morphological operation, one of:
  3364. * CV_MOP_OPEN - opening
  3365. * CV_MOP_CLOSE - closing
  3366. * CV_MOP_GRADIENT - morphological gradient
  3367. * CV_MOP_TOPHAT - top hat
  3368. * CV_MOP_BLACKHAT - black hat
  3369. */
  3370. VALUE
  3371. rb_morphology(int argc, VALUE *argv, VALUE self)
  3372. {
  3373. VALUE element, iteration, operation;
  3374. rb_scan_args(argc, argv, "12", &operation, &element, &iteration);
  3375. return rb_morphology_internal(element, iteration, CVMETHOD("MORPHOLOGICAL_OPERATION", operation, -1), self);
  3376. }
  3377. /*
  3378. * call-seq:
  3379. * morpholohy_open(<i>[element = nil][,iteration = 1]</i>) -> cvmat
  3380. *
  3381. * Performs advanced morphological transformations "Opening".
  3382. * dilate(erode(src,element),element)
  3383. */
  3384. VALUE
  3385. rb_morphology_open(int argc, VALUE *argv, VALUE self)
  3386. {
  3387. VALUE element, iteration;
  3388. rb_scan_args(argc, argv, "02", &element, &iteration);
  3389. return rb_morphology_internal(element, iteration, CV_MOP_OPEN, self);
  3390. }
  3391. /*
  3392. * call-seq:
  3393. * morpholohy_close(<i>[element = nil][,iteration = 1]</i>) -> cvmat
  3394. *
  3395. * Performs advanced morphological transformations "Closing".
  3396. * erode(dilate(src,element),element)
  3397. */
  3398. VALUE
  3399. rb_morphology_close(int argc, VALUE *argv, VALUE self)
  3400. {
  3401. VALUE element, iteration;
  3402. rb_scan_args(argc, argv, "02", &element, &iteration);
  3403. return rb_morphology_internal(element, iteration, CV_MOP_CLOSE, self);
  3404. }
  3405. /*
  3406. * call-seq:
  3407. * morpholohy_gradient(<i>[element = nil][,iteration = 1]</i>) -> cvmat
  3408. *
  3409. * Performs advanced morphological transformations "Morphological gradient".
  3410. * dilate(src,element)-erode(src,element)
  3411. */
  3412. VALUE
  3413. rb_morphology_gradient(int argc, VALUE *argv, VALUE self)
  3414. {
  3415. VALUE element, iteration;
  3416. rb_scan_args(argc, argv, "02", &element, &iteration);
  3417. return rb_morphology_internal(element, iteration, CV_MOP_GRADIENT, self);
  3418. }
  3419. /*
  3420. * call-seq:
  3421. * morpholohy_tophat(<i>[element = nil][,iteration = 1]</i>) -> cvmat
  3422. *
  3423. * Performs advanced morphological transformations "tophat".
  3424. * src-open(src,element)
  3425. */
  3426. VALUE
  3427. rb_morphology_tophat(int argc, VALUE *argv, VALUE self)
  3428. {
  3429. VALUE element, iteration;
  3430. rb_scan_args(argc, argv, "02", &element, &iteration);
  3431. return rb_morphology_internal(element, iteration, CV_MOP_TOPHAT, self);
  3432. }
  3433. /*
  3434. * call-seq:
  3435. * morpholohy_blackhat(<i>[element = nil][,iteration = 1]</i>) -> cvmat
  3436. *
  3437. * Performs advanced morphological transformations "blackhat".
  3438. * close(src,element)-src
  3439. */
  3440. VALUE
  3441. rb_morphology_blackhat(int argc, VALUE *argv, VALUE self)
  3442. {
  3443. VALUE element, iteration, dest;
  3444. rb_scan_args(argc, argv, "02", &element, &iteration);
  3445. return rb_morphology_internal(element, iteration, CV_MOP_BLACKHAT, self);
  3446. }
  3447. VALUE
  3448. rb_smooth(int argc, VALUE *argv, VALUE self)
  3449. {
  3450. VALUE smoothtype, p1, p2, p3, p4;
  3451. rb_scan_args(argc, argv, "14", &smoothtype, &p1, &p2, &p3, &p4);
  3452. int _smoothtype = CVMETHOD("SMOOTHING_TYPE", smoothtype, -1);
  3453. VALUE (*smooth_func)(int c, VALUE* v, VALUE s);
  3454. switch (_smoothtype) {
  3455. case CV_BLUR_NO_SCALE:
  3456. smooth_func = rb_smooth_blur_no_scale;
  3457. break;
  3458. case CV_BLUR:
  3459. smooth_func = rb_smooth_blur;
  3460. break;
  3461. case CV_GAUSSIAN:
  3462. smooth_func = rb_smooth_gaussian;
  3463. break;
  3464. case CV_MEDIAN:
  3465. smooth_func = rb_smooth_median;
  3466. break;
  3467. case CV_BILATERAL:
  3468. smooth_func = rb_smooth_bilateral;
  3469. break;
  3470. default:
  3471. smooth_func = rb_smooth_gaussian;
  3472. break;
  3473. }
  3474. return (*smooth_func)(argc - 1, argv + 1, self);
  3475. }
  3476. /*
  3477. * call-seq:
  3478. * smooth_blur_no_scale(<i>[p1 = 3, p2 = 3]</i>) -> cvmat
  3479. *
  3480. * Smooths the image by simple blur with no scaling.
  3481. * * 8bit unsigned -> return 16bit unsigned
  3482. * * 32bit floating point -> return 32bit floating point
  3483. * <b>support single-channel image only.</b>
  3484. */
  3485. VALUE
  3486. rb_smooth_blur_no_scale(int argc, VALUE *argv, VALUE self)
  3487. {
  3488. SUPPORT_C1_ONLY(self);
  3489. VALUE p1, p2, dest;
  3490. rb_scan_args(argc, argv, "02", &p1, &p2);
  3491. int type = cvGetElemType(CVARR(self)), dest_type;
  3492. switch (CV_MAT_DEPTH(type)) {
  3493. case CV_8U:
  3494. dest_type = CV_16U;
  3495. break;
  3496. case CV_32F:
  3497. dest_type = CV_32F;
  3498. break;
  3499. default:
  3500. rb_raise(rb_eNotImpError, "unsupport format. (support 8bit unsigned/signed or 32bit floating point only)");
  3501. }
  3502. dest = new_object(cvGetSize(CVARR(self)), dest_type);
  3503. cvSmooth(CVARR(self), CVARR(dest), CV_BLUR_NO_SCALE, IF_INT(p1, 3), IF_INT(p2, 3));
  3504. return dest;
  3505. }
  3506. /*
  3507. * call-seq:
  3508. * smooth_blur(<i>[p1 = 3, p2 = 3]</i>) -> cvmat
  3509. *
  3510. * Smooths the image by simple blur.
  3511. * Summation over a pixel <i>p1</i> x <i>p2</i> neighborhood with subsequent scaling by 1 / (p1*p2).
  3512. */
  3513. VALUE
  3514. rb_smooth_blur(int argc, VALUE *argv, VALUE self)
  3515. {
  3516. SUPPORT_C1C3_ONLY(self);
  3517. VALUE p1, p2, dest;
  3518. rb_scan_args(argc, argv, "02", &p1, &p2);
  3519. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3520. cvSmooth(CVARR(self), CVARR(dest), CV_BLUR, IF_INT(p1, 3), IF_INT(p2, 3));
  3521. return dest;
  3522. }
  3523. /*
  3524. * call-seq:
  3525. * smooth_gaussian(<i>[p1 = 3, p2 = 3, p3 = 0.0, p4 = 0.0]</i>) -> cvmat
  3526. *
  3527. * Smooths the image by gaussian blur.
  3528. * Convolving image with <i>p1</i> x <i>p2</i> Gaussian kernel.
  3529. *
  3530. * <i>p3</i> may specify Gaussian sigma (standard deviation).
  3531. * If it is zero, it is calculated from the kernel size:
  3532. * sigma = (n/2 - 1)*0.3 + 0.8, where n = p1 for horizontal kernel,
  3533. * n = p2 for vertical kernel.
  3534. *
  3535. * <i>p4</i> is in case of non-square Gaussian kernel the parameter.
  3536. * It may be used to specify a different (from p3) sigma in the vertical direction.
  3537. */
  3538. VALUE
  3539. rb_smooth_gaussian(int argc, VALUE *argv, VALUE self)
  3540. {
  3541. SUPPORT_C1C3_ONLY(self);
  3542. VALUE p1, p2, p3, p4, dest;
  3543. rb_scan_args(argc, argv, "04", &p1, &p2, &p3, &p4);
  3544. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3545. cvSmooth(CVARR(self), CVARR(dest), CV_GAUSSIAN, IF_INT(p1, 3), IF_INT(p2, 3), IF_DBL(p3, 0.0), IF_DBL(p4, 0.0));
  3546. return dest;
  3547. }
  3548. /*
  3549. * call-seq:
  3550. * smooth_median(<i>[p1 = 3]</i>) -> cvmat
  3551. *
  3552. * Smooths the image by median blur.
  3553. * Finding median of <i>p1</i> x <i>p1</i> neighborhood (i.e. the neighborhood is square).
  3554. */
  3555. VALUE
  3556. rb_smooth_median(int argc, VALUE *argv, VALUE self)
  3557. {
  3558. SUPPORT_8U_ONLY(self);
  3559. SUPPORT_C1C3_ONLY(self);
  3560. VALUE p1, dest;
  3561. rb_scan_args(argc, argv, "01", &p1);
  3562. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3563. cvSmooth(CVARR(self), CVARR(dest), CV_MEDIAN, IF_INT(p1, 3));
  3564. return dest;
  3565. }
  3566. /*
  3567. * call-seq:
  3568. * smooth_bilateral(<i>[p1 = 3][p2 = 3]</i>) -> cvmat
  3569. *
  3570. * Smooths the image by bilateral filter.
  3571. * Applying bilateral 3x3 filtering with color sigma=<i>p1</i> and space sigma=<i>p2</i>.
  3572. */
  3573. VALUE
  3574. rb_smooth_bilateral(int argc, VALUE *argv, VALUE self)
  3575. {
  3576. SUPPORT_8U_ONLY(self);
  3577. SUPPORT_C1C3_ONLY(self);
  3578. VALUE p1, p2, dest;
  3579. rb_scan_args(argc, argv, "02", &p1, &p2);
  3580. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3581. cvSmooth(CVARR(self), CVARR(dest), CV_BILATERAL, IF_INT(p1, 3), IF_INT(p2, 3));
  3582. return dest;
  3583. }
  3584. /*
  3585. * call-seq:
  3586. * filter2d(<i>kernel[,anchor]</i>) -> cvmat
  3587. *
  3588. * Convolves image with the kernel.
  3589. * Convolution kernel, single-channel floating point matrix (or same depth of self's).
  3590. * If you want to apply different kernels to different channels,
  3591. * split the image using CvMat#split into separate color planes and process them individually.
  3592. */
  3593. VALUE
  3594. rb_filter2d(int argc, VALUE *argv, VALUE self)
  3595. {
  3596. VALUE kernel, anchor, dest;
  3597. rb_scan_args(argc, argv, "11", &kernel, &anchor);
  3598. if (!rb_obj_is_kind_of(kernel, cCvMat::rb_class()))
  3599. rb_raise(rb_eTypeError, "argument 1 (kernel) should be %s.", rb_class2name(cCvMat::rb_class()));
  3600. int type = cvGetElemType(CVARR(kernel));
  3601. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  3602. cvFilter2D(CVARR(self), CVARR(dest), CVMAT(kernel), NIL_P(anchor) ? cvPoint(-1,-1) : VALUE_TO_CVPOINT(anchor));
  3603. return dest;
  3604. }
  3605. /*
  3606. * call-seq:
  3607. * copy_make_border_constant(<i>size, offset[,value = CvScalar.new(0)]</i>)
  3608. *
  3609. * Copies image and makes border around it.
  3610. * Border is filled with the fixed value, passed as last parameter of the function.
  3611. */
  3612. VALUE
  3613. rb_copy_make_border_constant(int argc, VALUE *argv, VALUE self)
  3614. {
  3615. VALUE size, offset, value, dest;
  3616. rb_scan_args(argc, argv, "21", &size, &offset, &value);
  3617. dest = cCvMat::new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self)));
  3618. cvCopyMakeBorder(CVARR(self), CVARR(dest), VALUE_TO_CVPOINT(offset), IPL_BORDER_CONSTANT, NIL_P(value) ? cvScalar(0) : VALUE_TO_CVSCALAR(value));
  3619. return dest;
  3620. }
  3621. /*
  3622. * call-seq:
  3623. * copy_make_border_replicate(<i>size, offset</i>)
  3624. *
  3625. * Copies image and makes border around it.
  3626. * The pixels from the top and bottom rows,
  3627. * the left-most and right-most columns are replicated to fill the border.
  3628. */
  3629. VALUE
  3630. rb_copy_make_border_replicate(int argc, VALUE *argv, VALUE self)
  3631. {
  3632. VALUE size, offset, dest;
  3633. rb_scan_args(argc, argv, "20", &size, &offset);
  3634. dest = cCvMat::new_object(VALUE_TO_CVSIZE(size), cvGetElemType(CVARR(self)));
  3635. cvCopyMakeBorder(CVARR(self), CVARR(dest), VALUE_TO_CVPOINT(offset), IPL_BORDER_REPLICATE);
  3636. return dest;
  3637. }
  3638. /*
  3639. * call-seq:
  3640. * integral(<i>need_sqsum = false, need_tilted_sum = false</i>) -> [cvmat, cvmat or nil, cvmat or nil]
  3641. *
  3642. * Calculates integral images.
  3643. * If <i>need_sqsum</i> = true, calculate the integral image for squared pixel values.
  3644. * If <i>need_tilted_sum</i> = true, calculate the integral for the image rotated by 45 degrees.
  3645. *
  3646. * sum(X,Y)=sumx<X,y<Yimage(x,y)
  3647. * sqsum(X,Y)=sumx<X,y<Yimage(x,y)2
  3648. * tilted_sum(X,Y)=sumy<Y,abs(x-X)<yimage(x,y)
  3649. *
  3650. * Using these integral images, one may calculate sum, mean, standard deviation over arbitrary up-right or rotated rectangular region of the image in a constant time.
  3651. */
  3652. VALUE
  3653. rb_integral(int argc, VALUE *argv, VALUE self)
  3654. {
  3655. VALUE sum, sqsum, tilted_sum, dest;
  3656. rb_scan_args(argc, argv, "02", &sqsum, &tilted_sum);
  3657. CvSize size = cvSize(cvGetSize(CVARR(self)).width + 1, cvGetSize(CVARR(self)).height + 1);
  3658. int cn = CV_MAT_CN(cvGetElemType(CVARR(self)));
  3659. sum = cCvMat::new_object(size, CV_MAKETYPE(CV_64F, cn));
  3660. sqsum = (sqsum == Qtrue ? cCvMat::new_object(size, CV_MAKETYPE(CV_64F, cn)) : Qnil);
  3661. tilted_sum = (tilted_sum == Qtrue ? cCvMat::new_object(size, CV_MAKETYPE(CV_64F, cn)) : Qnil);
  3662. cvIntegral(CVARR(self), CVARR(sum), NIL_P(sqsum) ? NULL : CVARR(sqsum), NIL_P(tilted_sum) ? NULL : CVARR(tilted_sum));
  3663. dest = rb_ary_new3(1, sum);
  3664. if(sqsum)
  3665. rb_ary_push(dest, sqsum);
  3666. if(tilted_sum)
  3667. rb_ary_push(dest, tilted_sum);
  3668. return dest;
  3669. }
  3670. VALUE
  3671. rb_threshold_internal(int threshold_type, VALUE threshold, VALUE max_value, VALUE use_otsu, VALUE self)
  3672. {
  3673. CvArr* self_ptr = CVARR(self);
  3674. VALUE dest = cCvMat::new_object(cvGetSize(self_ptr), cvGetElemType(self_ptr));
  3675. int otsu = (use_otsu == Qtrue) && ((threshold_type & CV_THRESH_OTSU) == 0);
  3676. int type = threshold_type | (otsu ? CV_THRESH_OTSU : 0);
  3677. double otsu_threshold = cvThreshold(self_ptr, CVARR(dest), NUM2DBL(threshold), NUM2DBL(max_value), type);
  3678. if ((use_otsu == Qtrue) || (threshold_type & CV_THRESH_OTSU))
  3679. return rb_assoc_new(dest, DBL2NUM(otsu_threshold));
  3680. else
  3681. return dest;
  3682. }
  3683. /*
  3684. * call-seq:
  3685. * threshold(<i>threshold, max_value, threshold_type[,use_otsu = false]</i>)
  3686. *
  3687. * Applies fixed-level threshold to array elements.
  3688. *
  3689. */
  3690. VALUE
  3691. rb_threshold(int argc, VALUE *argv, VALUE self)
  3692. {
  3693. VALUE threshold, max_value, threshold_type, use_otsu;
  3694. rb_scan_args(argc, argv, "31", &threshold, &max_value, &threshold_type, &use_otsu);
  3695. const int INVALID_TYPE = -1;
  3696. int type = CVMETHOD("THRESHOLD_TYPE", threshold_type, INVALID_TYPE);
  3697. if (type == INVALID_TYPE)
  3698. rb_raise(rb_eArgError, "Invalid threshold type.");
  3699. return rb_threshold_internal(type, threshold, max_value, use_otsu, self);
  3700. }
  3701. /*
  3702. * call-seq:
  3703. * threshold_binary(<i>threshold, max_value[,use_otsu = false]</i>)
  3704. *
  3705. * Applies fixed-level threshold to array elements.
  3706. *
  3707. * dst(x,y) = max_value, if src(x,y)>threshold
  3708. * 0, otherwise
  3709. */
  3710. VALUE
  3711. rb_threshold_binary(int argc, VALUE *argv, VALUE self)
  3712. {
  3713. VALUE threshold, max_value, use_otsu;
  3714. rb_scan_args(argc, argv, "21", &threshold, &max_value, &use_otsu);
  3715. return rb_threshold_internal(CV_THRESH_BINARY, threshold, max_value, use_otsu, self);
  3716. }
  3717. /*
  3718. * call-seq:
  3719. * threshold_binary_inverse(<i>threshold, max_value[,use_otsu = false]</i>)
  3720. *
  3721. * Applies fixed-level threshold to array elements.
  3722. *
  3723. * dst(x,y) = 0, if src(x,y)>threshold
  3724. * max_value, otherwise
  3725. */
  3726. VALUE
  3727. rb_threshold_binary_inverse(int argc, VALUE *argv, VALUE self)
  3728. {
  3729. VALUE threshold, max_value, use_otsu;
  3730. rb_scan_args(argc, argv, "21", &threshold, &max_value, &use_otsu);
  3731. return rb_threshold_internal(CV_THRESH_BINARY_INV, threshold, max_value, use_otsu, self);
  3732. }
  3733. /*
  3734. * call-seq:
  3735. * threshold_trunc(<i>threshold[,use_otsu = false]</i>)
  3736. *
  3737. * Applies fixed-level threshold to array elements.
  3738. *
  3739. * dst(x,y) = threshold, if src(x,y)>threshold
  3740. * src(x,y), otherwise
  3741. */
  3742. VALUE
  3743. rb_threshold_trunc(int argc, VALUE *argv, VALUE self)
  3744. {
  3745. VALUE threshold, use_otsu;
  3746. rb_scan_args(argc, argv, "11", &threshold, &use_otsu);
  3747. return rb_threshold_internal(CV_THRESH_TRUNC, threshold, INT2NUM(0), use_otsu, self);
  3748. }
  3749. /*
  3750. * call-seq:
  3751. * threshold_to_zero(<i>threshold[,use_otsu = false]</i>)
  3752. *
  3753. * Applies fixed-level threshold to array elements.
  3754. *
  3755. * dst(x,y) = src(x,y), if src(x,y)>threshold
  3756. * 0, otherwise
  3757. */
  3758. VALUE
  3759. rb_threshold_to_zero(int argc, VALUE *argv, VALUE self)
  3760. {
  3761. VALUE threshold, use_otsu;
  3762. rb_scan_args(argc, argv, "11", &threshold, &use_otsu);
  3763. return rb_threshold_internal(CV_THRESH_TOZERO, threshold, INT2NUM(0), use_otsu, self);
  3764. }
  3765. /*
  3766. * call-seq:
  3767. * threshold_to_zero_inverse(<i>threshold[,use_otsu = false]</i>)
  3768. *
  3769. * Applies fixed-level threshold to array elements.
  3770. *
  3771. * dst(x,y) = 0, if src(x,y)>threshold
  3772. * src(x,y), otherwise
  3773. */
  3774. VALUE
  3775. rb_threshold_to_zero_inverse(int argc, VALUE *argv, VALUE self)
  3776. {
  3777. VALUE threshold, use_otsu;
  3778. rb_scan_args(argc, argv, "11", &threshold, &use_otsu);
  3779. return rb_threshold_internal(CV_THRESH_TOZERO_INV, threshold, INT2NUM(0), use_otsu, self);
  3780. }
  3781. /*
  3782. * call-seq:
  3783. * pyr_down(<i>[filter = :gaussian_5x5]</i>) -> cvmat
  3784. *
  3785. * Return downsamples image.
  3786. *
  3787. * This operation performs downsampling step of Gaussian pyramid decomposition.
  3788. * First it convolves source image with the specified filter and then downsamples the image by rejecting even rows and columns.
  3789. *
  3790. * note: filter - only :gaussian_5x5 is currently supported.
  3791. */
  3792. VALUE
  3793. rb_pyr_down(int argc, VALUE *argv, VALUE self)
  3794. {
  3795. VALUE filter_type, dest;
  3796. rb_scan_args(argc, argv, "01", &filter_type);
  3797. int filter = CV_GAUSSIAN_5x5;
  3798. if (argc > 0) {
  3799. switch (TYPE(filter_type)) {
  3800. case T_SYMBOL:
  3801. // currently suport CV_GAUSSIAN_5x5 only.
  3802. break;
  3803. default:
  3804. rb_raise(rb_eArgError, "argument 1 (filter_type) should be Symbol.");
  3805. }
  3806. }
  3807. CvSize size = cvGetSize(CVARR(self));
  3808. dest = cCvMat::new_object(size.height / 2, size.width / 2, cvGetElemType(CVARR(self)));
  3809. cvPyrDown(CVARR(self), CVARR(dest), filter);
  3810. return dest;
  3811. }
  3812. /*
  3813. * call-seq:
  3814. * pyr_up(<i>[filter = :gaussian_5x5]</i>) -> cvmat
  3815. *
  3816. * Return upsamples image.
  3817. *
  3818. * This operation performs up-sampling step of Gaussian pyramid decomposition.
  3819. * First it upsamples the source image by injecting even zero rows and columns and then convolves result with the specified filter multiplied by 4 for interpolation.
  3820. * So the destination image is four times larger than the source image.
  3821. *
  3822. * note: filter - only :gaussian_5x5 is currently supported.
  3823. */
  3824. VALUE
  3825. rb_pyr_up(int argc, VALUE *argv, VALUE self)
  3826. {
  3827. VALUE filter_type, dest;
  3828. rb_scan_args(argc, argv, "01", &filter_type);
  3829. int filter = CV_GAUSSIAN_5x5;
  3830. if (argc > 0) {
  3831. switch (TYPE(filter_type)) {
  3832. case T_SYMBOL:
  3833. // currently suport CV_GAUSSIAN_5x5 only.
  3834. break;
  3835. default:
  3836. rb_raise(rb_eArgError, "argument 1 (filter_type) should be Symbol.");
  3837. }
  3838. }
  3839. CvSize size = cvGetSize(CVARR(self));
  3840. dest = cCvMat::new_object(size.height * 2, size.width * 2, cvGetElemType(CVARR(self)));
  3841. cvPyrUp(CVARR(self), CVARR(dest), filter);
  3842. return dest;
  3843. }
  3844. /*
  3845. * call-seq:
  3846. * flood_fill(<i>seed_point, new_val, lo_diff, up_diff[,flood_fill_option]</i>) -> [cvmat, cvconnectedcomp, iplimage(mask)]
  3847. *
  3848. * Return image filled a connnected compoment with given color.
  3849. * This operation fills a connected component starting from the seed point with the specified color.
  3850. * The connectivity is determined by the closeness of pixel values.
  3851. * The pixel at (x, y) is considered to belong to the repainted domain if:
  3852. *
  3853. * src(x',y')-lo_diff<=src(x,y)<=src(x',y')+up_diff, grayscale image, floating range
  3854. * src(seed.x,seed.y)-lo<=src(x,y)<=src(seed.x,seed.y)+up_diff, grayscale image, fixed range
  3855. * src(x',y')r-lo_diffr<=src(x,y)r<=src(x',y')r+up_diffr and
  3856. * src(x',y')g-lo_diffg<=src(x,y)g<=src(x',y')g+up_diffg and
  3857. * src(x',y')b-lo_diffb<=src(x,y)b<=src(x',y')b+up_diffb, color image, floating range
  3858. * src(seed.x,seed.y)r-lo_diffr<=src(x,y)r<=src(seed.x,seed.y)r+up_diffr and
  3859. * src(seed.x,seed.y)g-lo_diffg<=src(x,y)g<=src(seed.x,seed.y)g+up_diffg and
  3860. * src(seed.x,seed.y)b-lo_diffb<=src(x,y)b<=src(seed.x,seed.y)b+up_diffb, color image, fixed range
  3861. *
  3862. * where src(x',y') is value of one of pixel neighbors.
  3863. * That is, to be added to the connected component, a pixel's color/brightness should be close enough to:
  3864. * * color/brightness of one of its neighbors that are already referred to the connected component in case of floating range
  3865. * * color/brightness of the seed point in case of fixed range.
  3866. *
  3867. * arguments
  3868. * * seed_point -The starting point.
  3869. * * new_val - New value of repainted domain pixels.
  3870. * * lo_diff - Maximal lower brightness/color difference between the currently observed pixel and one of its neighbor belong to the component or seed pixel to add the pixel to component. In case of 8-bit color images it is packed value.
  3871. * * up_diff - Maximal upper brightness/color difference between the currently observed pixel and one of its neighbor belong to the component or seed pixel to add the pixel to component. In case of 8-bit color images it is packed value.
  3872. *
  3873. * and flood_fill_option
  3874. * :connectivity => 4 or 8, 4 default
  3875. * Connectivity determines which neighbors of a pixel are considered.
  3876. * :fixed_range => true or false, false default
  3877. * If set the difference between the current pixel and seed pixel is considered, otherwise difference between neighbor pixels is considered (the range is floating).
  3878. * :mask_only => true or false, false default
  3879. * If set, the function does not fill the image(new_val is ignored), but the fills mask.
  3880. *
  3881. * note: <i>flood_fill_option</i>'s default value is CvMat::FLOOD_FILL_OPTION.
  3882. */
  3883. VALUE
  3884. rb_flood_fill(int argc, VALUE *argv, VALUE self)
  3885. {
  3886. return rb_flood_fill_bang(argc, argv, copy(self));
  3887. }
  3888. /*
  3889. * call-seq:
  3890. * flood_fill!(<i>seed_point, new_val, lo_diff, up_diff[,flood_fill_option]</i>) -> [self, cvconnectedcomp, iplimage(mask)]
  3891. *
  3892. * Fills a connected component with given color.
  3893. * see CvMat#flood_fill
  3894. */
  3895. VALUE
  3896. rb_flood_fill_bang(int argc, VALUE *argv, VALUE self)
  3897. {
  3898. VALUE seed_point, new_val, lo_diff, up_diff, flood_fill_option, mask, comp;
  3899. rb_scan_args(argc, argv, "23", &seed_point, &new_val, &lo_diff, &up_diff, &flood_fill_option);
  3900. flood_fill_option = FLOOD_FILL_OPTION(flood_fill_option);
  3901. int flags = FF_CONNECTIVITY(flood_fill_option);
  3902. if (FF_FIXED_RANGE(flood_fill_option)) {
  3903. flags |= CV_FLOODFILL_FIXED_RANGE;
  3904. }
  3905. if (FF_MASK_ONLY(flood_fill_option)) {
  3906. flags |= CV_FLOODFILL_MASK_ONLY;
  3907. }
  3908. CvSize size = cvGetSize(CVARR(self));
  3909. mask = cIplImage::new_object(size.width + 2, size.height + 2, CV_MAKETYPE(CV_8U, 1));
  3910. comp = cCvConnectedComp::new_object();
  3911. cvFloodFill(CVARR(self),
  3912. VALUE_TO_CVPOINT(seed_point),
  3913. VALUE_TO_CVSCALAR(new_val),
  3914. NIL_P(lo_diff) ? cvScalar(0) : VALUE_TO_CVSCALAR(lo_diff),
  3915. NIL_P(up_diff) ? cvScalar(0) : VALUE_TO_CVSCALAR(up_diff),
  3916. CVCONNECTEDCOMP(comp),
  3917. flags,
  3918. CVARR(mask));
  3919. cvSetImageROI(IPLIMAGE(mask), cvRect(1, 1, size.width, size.height));
  3920. return rb_ary_new3(3, self, comp, mask);
  3921. }
  3922. /*
  3923. * call-seq:
  3924. * find_contours([find_contours_options]) -> cvchain or cvcontour or nil
  3925. *
  3926. * Finds contours in binary image, and return contours as CvContour or CvChain.
  3927. * If contours not found, return nil.
  3928. *
  3929. * <i>flood_fill_option</i> should be Hash include these keys.
  3930. * :mode - Retrieval mode.
  3931. * :external - retrive only the extreme outer contours
  3932. * :list - retrieve all the contours and puts them in the list.(default)
  3933. * :ccomp - retrieve all the contours and organizes them into two-level hierarchy:
  3934. * top level are external boundaries of the components, second level are bounda boundaries of the holes
  3935. * :tree - retrieve all the contours and reconstructs the full hierarchy of nested contours
  3936. * Connectivity determines which neighbors of a pixel are considered.
  3937. * :method - Approximation method.
  3938. * :code - output contours in the Freeman chain code. All other methods output polygons (sequences of vertices).
  3939. * :approx_none - translate all the points from the chain code into points;
  3940. * :approx_simple - compress horizontal, vertical, and diagonal segments, that is, the function leaves only their ending points;(default)
  3941. * :approx_tc89_l1
  3942. * :approx_tc89_kcos - apply one of the flavors of Teh-Chin chain approximation algorithm.
  3943. * If set the difference between the current pixel and seed pixel is considered,
  3944. * otherwise difference between neighbor pixels is considered (the range is floating).
  3945. * :offset - Offset, by which every contour point is shifted.
  3946. * This is useful if the contours are extracted from the image ROI
  3947. * and then they should be analyzed in the whole image context. Should be CvPoint.
  3948. *
  3949. * note: <i>find_contours_option</i>'s default value is CvMat::FIND_CONTOURS_OPTION.
  3950. *
  3951. * <b>support single-channel 8bit unsigned image only.</b>
  3952. *
  3953. * note: Non-zero pixels are treated as 1's, zero pixels remain 0's
  3954. * that is image treated as binary. To get such a binary image from grayscale,
  3955. * one may use threshold, adaptive_threshold or canny.
  3956. */
  3957. VALUE
  3958. rb_find_contours(int argc, VALUE *argv, VALUE self)
  3959. {
  3960. SUPPORT_8UC1_ONLY(self);
  3961. return rb_find_contours_bang(argc, argv, copy(self));
  3962. }
  3963. /*
  3964. * call-seq:
  3965. * find_contours!([find_contours_options]) -> cvchain or chcontour or nil
  3966. *
  3967. * Finds contours in binary image.
  3968. * The function modifies the source image content.
  3969. * (Because the copy is not made, it is slightly faster than find_contours.)
  3970. *
  3971. * see find_contours
  3972. *
  3973. * <b>support single-channel 8bit unsigned image only.</b>
  3974. */
  3975. VALUE
  3976. rb_find_contours_bang(int argc, VALUE *argv, VALUE self)
  3977. {
  3978. SUPPORT_8UC1_ONLY(self);
  3979. VALUE find_contours_option, klass, element_klass, storage;
  3980. rb_scan_args(argc, argv, "01", &find_contours_option);
  3981. CvSeq *contour = NULL;
  3982. find_contours_option = FIND_CONTOURS_OPTION(find_contours_option);
  3983. int mode = FC_MODE(find_contours_option);
  3984. int method = FC_METHOD(find_contours_option);
  3985. int header_size, element_size;
  3986. if (method == CV_CHAIN_CODE) {
  3987. klass = cCvChain::rb_class();
  3988. element_klass = cCvChainCode::rb_class();
  3989. header_size = sizeof(CvChain);
  3990. element_size = sizeof(CvChainCode);
  3991. }
  3992. else {
  3993. klass = cCvContour::rb_class();
  3994. element_klass = cCvPoint::rb_class();
  3995. header_size = sizeof(CvContour);
  3996. element_size = sizeof(CvPoint);
  3997. }
  3998. storage = cCvMemStorage::new_object();
  3999. if(cvFindContours(CVARR(self), CVMEMSTORAGE(storage),
  4000. &contour, header_size, mode, method, FC_OFFSET(find_contours_option)) == 0)
  4001. return Qnil;
  4002. return cCvSeq::new_sequence(klass, contour, element_klass, storage);
  4003. }
  4004. /*
  4005. * call-seq:
  4006. * pyr_segmentation(<i>level, threshold1, threshold2</i>) -> [cvmat, cvseq(include cvconnectedcomp)]
  4007. *
  4008. * Does image segmentation by pyramids.
  4009. * The pyramid builds up to the level <i>level<i>.
  4010. * The links between any pixel a on <i>level<i>i and
  4011. * its candidate father pixel b on the adjacent level are established if
  4012. * p(c(a),c(b)) < threshold1. After the connected components are defined, they are joined into several clusters. Any two segments A and B belong to the same cluster, if
  4013. * p(c(A),c(B)) < threshold2. The input image has only one channel, then
  4014. * p(c^2,c^2)=|c^2-c^2|. If the input image has three channels (red, green and blue), then
  4015. * p(c^2,c^2)=0,3*(c^2 r-c^2 r)+0.59*(c^2 g-c^2 g)+0,11*(c^2 b-c^2 b) . There may be more than one connected component per a cluster.
  4016. *
  4017. * Return segmented image and sequence of connected components.
  4018. * <b>support single-channel or 3-channel 8bit unsigned image only</b>
  4019. */
  4020. VALUE
  4021. rb_pyr_segmentation(int argc, VALUE *argv, VALUE self)
  4022. {
  4023. SUPPORT_8U_ONLY(self);
  4024. SUPPORT_C1C3_ONLY(self);
  4025. VALUE level, threshold1, threshold2, storage, dest;
  4026. rb_scan_args(argc, argv, "30", &level, &threshold1, &threshold2);
  4027. IplImage *src = IPLIMAGE(self);
  4028. int l = FIX2INT(level);
  4029. double t1 = NUM2DBL(threshold1), t2 = NUM2DBL(threshold2);
  4030. CvRect roi = cvGetImageROI(src);
  4031. if (l <= 0)
  4032. rb_raise(rb_eArgError, "argument 1 (level) should be > 0.");
  4033. if(((roi.width | roi.height) & ((1 << l) - 1)) != 0)
  4034. rb_raise(rb_eArgError, "bad image size on level %d.", FIX2INT(level));
  4035. if (t1 < 0)
  4036. rb_raise(rb_eArgError, "argument 2 (threshold for establishing the link) should be >= 0.");
  4037. if (t2 < 0)
  4038. rb_raise(rb_eArgError, "argument 3 (threshold for the segments clustering) should be >= 0.");
  4039. dest = cIplImage::new_object(cvGetSize(src), cvGetElemType(src));
  4040. CvSeq *comp = 0;
  4041. storage = cCvMemStorage::new_object();
  4042. cvPyrSegmentation(src,
  4043. IPLIMAGE(dest),
  4044. CVMEMSTORAGE(storage),
  4045. &comp,
  4046. l, t1, t2);
  4047. if(!comp)
  4048. comp = cvCreateSeq(CV_SEQ_CONNECTED_COMP, sizeof(CvSeq), sizeof(CvConnectedComp), CVMEMSTORAGE(storage));
  4049. return rb_ary_new3(2, dest, cCvSeq::new_sequence(cCvSeq::rb_class(), comp, cCvConnectedComp::rb_class(), storage));
  4050. }
  4051. /*
  4052. * call-seq:
  4053. * pyr_mean_shift_filtering(<i>sp, sr[,max_level = 1][termcrit = CvTermCriteria.new(5,1)]</i>) -> cvmat
  4054. *
  4055. * Does meanshift image segmentation.
  4056. *
  4057. * sp - The spatial window radius.
  4058. * sr - The color window radius.
  4059. * max_level - Maximum level of the pyramid for the segmentation.
  4060. * termcrit - Termination criteria: when to stop meanshift iterations.
  4061. *
  4062. * This method is implements the filtering stage of meanshift segmentation,
  4063. * that is, the output of the function is the filtered "posterized" image with color gradients and fine-grain texture flattened.
  4064. * At every pixel (X,Y) of the input image (or down-sized input image, see below)
  4065. * the function executes meanshift iterations, that is, the pixel (X,Y) neighborhood in the joint space-color hyperspace is considered:
  4066. * {(x,y): X-sp≤x≤X+sp && Y-sp≤y≤Y+sp && ||(R,G,B)-(r,g,b)|| ≤ sr},
  4067. * where (R,G,B) and (r,g,b) are the vectors of color components at (X,Y) and (x,y),
  4068. * respectively (though, the algorithm does not depend on the color space used,
  4069. * so any 3-component color space can be used instead).
  4070. * Over the neighborhood the average spatial value (X',Y')
  4071. * and average color vector (R',G',B') are found and they act as the neighborhood center on the next iteration:
  4072. * (X,Y)~(X',Y'), (R,G,B)~(R',G',B').
  4073. * After the iterations over, the color components of the initial pixel (that is, the pixel from where the iterations started)
  4074. * are set to the final value (average color at the last iteration):
  4075. * I(X,Y) <- (R*,G*,B*).
  4076. * Then max_level > 0, the gaussian pyramid of max_level+1 levels is built,
  4077. * and the above procedure is run on the smallest layer.
  4078. * After that, the results are propagated to the larger layer and the iterations are run again
  4079. * only on those pixels where the layer colors differ much (>sr) from the lower-resolution layer,
  4080. * that is, the boundaries of the color regions are clarified.
  4081. *
  4082. * Note, that the results will be actually different from the ones obtained by running the meanshift procedure on the whole original image (i.e. when max_level==0).
  4083. */
  4084. VALUE
  4085. rb_pyr_mean_shift_filtering(int argc, VALUE *argv, VALUE self)
  4086. {
  4087. VALUE spatial_window_radius, color_window_radius, max_level, termcrit, dest;
  4088. rb_scan_args(argc, argv, "22", &spatial_window_radius, &color_window_radius, &max_level, &termcrit);
  4089. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  4090. cvPyrMeanShiftFiltering(CVARR(self), CVARR(dest),
  4091. NUM2DBL(spatial_window_radius),
  4092. NUM2DBL(color_window_radius),
  4093. IF_INT(max_level, 1),
  4094. NIL_P(termcrit) ? cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 5, 1) : VALUE_TO_CVTERMCRITERIA(termcrit));
  4095. return dest;
  4096. }
  4097. /*
  4098. * call-seq:
  4099. * watershed -> cvmat(mean markers:cv32s)
  4100. *
  4101. * Does watershed segmentation.
  4102. */
  4103. VALUE
  4104. rb_watershed(VALUE self, VALUE markers)
  4105. {
  4106. cvWatershed(CVARR(self), CVARR(markers));
  4107. return markers;
  4108. }
  4109. /*
  4110. * call-seq:
  4111. * moments -> array(include CvMoments)
  4112. *
  4113. * Calculates moments.
  4114. */
  4115. VALUE
  4116. rb_moments(int argc, VALUE *argv, VALUE self)
  4117. {
  4118. VALUE is_binary, moments;
  4119. rb_scan_args(argc, argv, "01", &is_binary);
  4120. IplImage image = *IPLIMAGE(self);
  4121. int cn = CV_MAT_CN(cvGetElemType(CVARR(self)));
  4122. moments = rb_ary_new();
  4123. for(int i = 1; i <= cn; i++) {
  4124. cvSetImageCOI(&image, i);
  4125. rb_ary_push(moments, cCvMoments::new_object(&image, TRUE_OR_FALSE(is_binary, 0)));
  4126. }
  4127. return moments;
  4128. }
  4129. /*
  4130. * call-seq:
  4131. * hough_lines(<i>method, rho, theta, threshold, param1, param2</i>) -> cvseq(include CvLine or CvTwoPoints)
  4132. *
  4133. * Finds lines in binary image using a Hough transform.
  4134. * * method –
  4135. * * The Hough transform variant, one of the following:
  4136. * * - CV_HOUGH_STANDARD - classical or standard Hough transform.
  4137. * * - CV_HOUGH_PROBABILISTIC - probabilistic Hough transform (more efficient in case if picture contains a few long linear segments).
  4138. * * - CV_HOUGH_MULTI_SCALE - multi-scale variant of the classical Hough transform. The lines are encoded the same way as CV_HOUGH_STANDARD.
  4139. * * rho - Distance resolution in pixel-related units.
  4140. * * theta - Angle resolution measured in radians.
  4141. * * threshold - Threshold parameter. A line is returned by the function if the corresponding accumulator value is greater than threshold.
  4142. * * param1 –
  4143. * * The first method-dependent parameter:
  4144. * * For the classical Hough transform it is not used (0).
  4145. * * For the probabilistic Hough transform it is the minimum line length.
  4146. * * For the multi-scale Hough transform it is the divisor for the distance resolution . (The coarse distance resolution will be rho and the accurate resolution will be (rho / param1)).
  4147. * * param2 –
  4148. * * The second method-dependent parameter:
  4149. * * For the classical Hough transform it is not used (0).
  4150. * * For the probabilistic Hough transform it is the maximum gap between line segments lying on the same line to treat them as a single line segment (i.e. to join them).
  4151. * * For the multi-scale Hough transform it is the divisor for the angle resolution. (The coarse angle resolution will be theta and the accurate resolution will be (theta / param2).)
  4152. */
  4153. VALUE
  4154. rb_hough_lines(int argc, VALUE *argv, VALUE self)
  4155. {
  4156. SUPPORT_8UC1_ONLY(self);
  4157. const int INVALID_TYPE = -1;
  4158. VALUE method, rho, theta, threshold, p1, p2;
  4159. rb_scan_args(argc, argv, "42", &method, &rho, &theta, &threshold, &p1, &p2);
  4160. int method_flag = CVMETHOD("HOUGH_TRANSFORM_METHOD", method, INVALID_TYPE);
  4161. VALUE storage = cCvMemStorage::new_object();
  4162. CvSeq *seq = cvHoughLines2(CVARR(copy(self)), CVMEMSTORAGE(storage),
  4163. method_flag, NUM2DBL(rho), NUM2DBL(theta), NUM2INT(threshold),
  4164. IF_DBL(p1, 0), IF_DBL(p2, 0));
  4165. switch (method_flag) {
  4166. case CV_HOUGH_STANDARD:
  4167. case CV_HOUGH_MULTI_SCALE:
  4168. return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvLine::rb_class(), storage);
  4169. break;
  4170. case CV_HOUGH_PROBABILISTIC:
  4171. return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvTwoPoints::rb_class(), storage);
  4172. break;
  4173. default:
  4174. rb_raise(rb_eArgError, "Invalid method: %d", method_flag);
  4175. break;
  4176. }
  4177. return Qnil;
  4178. }
  4179. /*
  4180. * call-seq:
  4181. * hough_lines_standard(<i>rho, theta, threshold</i>) -> cvseq(include CvLine)
  4182. *
  4183. * Finds lines in binary image using standard(classical) Hough transform.
  4184. * * rho - Distance resolution in pixel-related units.
  4185. * * theta - Angle resolution measured in radians.
  4186. * * threshold - Threshold parameter. A line is returned by the function if the corresponding accumulator value is greater than threshold.
  4187. */
  4188. VALUE
  4189. rb_hough_lines_standard(VALUE self, VALUE rho, VALUE theta, VALUE threshold)
  4190. {
  4191. SUPPORT_8UC1_ONLY(self);
  4192. VALUE storage = cCvMemStorage::new_object();
  4193. CvSeq *seq = cvHoughLines2(CVARR(copy(self)), CVMEMSTORAGE(storage),
  4194. CV_HOUGH_STANDARD, NUM2DBL(rho), NUM2DBL(theta), NUM2INT(threshold));
  4195. return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvLine::rb_class(), storage);
  4196. }
  4197. /*
  4198. * call-seq:
  4199. * hough_lines_probabilistic(<i>rho, theta, threshold, min_length, max_gap</i>) -> cvseq(include CvTwoPoints)
  4200. *
  4201. * Finds lines in binary image using probabilistic Hough transform.
  4202. * * rho - Distance resolution in pixel-related units.
  4203. * * theta - Angle resolution measured in radians.
  4204. * * threshold - Threshold parameter. A line is returned by the function if the corresponding accumulator value is greater than threshold.
  4205. * * min_length - The minimum line length.
  4206. * * max_gap - The maximum gap between line segments lieing on the same line to treat them as the single line segment (i.e. to join them).
  4207. */
  4208. VALUE
  4209. rb_hough_lines_probabilistic(VALUE self, VALUE rho, VALUE theta, VALUE threshold, VALUE p1, VALUE p2)
  4210. {
  4211. SUPPORT_8UC1_ONLY(self);
  4212. VALUE storage = cCvMemStorage::new_object();
  4213. CvSeq *seq = cvHoughLines2(CVARR(copy(self)), CVMEMSTORAGE(storage),
  4214. CV_HOUGH_PROBABILISTIC, NUM2DBL(rho), NUM2DBL(theta), NUM2INT(threshold),
  4215. NUM2DBL(p1), NUM2DBL(p2));
  4216. return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvTwoPoints::rb_class(), storage);
  4217. }
  4218. /*
  4219. * call-seq:
  4220. * hough_lines_multi_scale(<i>rho, theta, threshold, div_rho, div_theta</i>) -> cvseq(include CvLine)
  4221. *
  4222. * Finds lines in binary image using multi-scale variant of classical Hough transform.
  4223. * * rho - Distance resolution in pixel-related units.
  4224. * * theta - Angle resolution measured in radians.
  4225. * * threshold - Threshold parameter. A line is returned by the function if the corresponding accumulator value is greater than threshold.
  4226. * * div_rho = divisor for distance resolution rho.
  4227. * * div_theta = divisor for angle resolution theta.
  4228. */
  4229. VALUE
  4230. rb_hough_lines_multi_scale(VALUE self, VALUE rho, VALUE theta, VALUE threshold, VALUE p1, VALUE p2)
  4231. {
  4232. SUPPORT_8UC1_ONLY(self);
  4233. VALUE storage = cCvMemStorage::new_object();
  4234. CvSeq *seq = cvHoughLines2(CVARR(copy(self)), CVMEMSTORAGE(storage),
  4235. CV_HOUGH_MULTI_SCALE, NUM2DBL(rho), NUM2DBL(theta), NUM2INT(threshold),
  4236. NUM2DBL(p1), NUM2DBL(p2));
  4237. return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvLine::rb_class(), storage);
  4238. }
  4239. /*
  4240. * call-seq:
  4241. * hough_circles(<i>method, dp, min_dist, param1, param2, min_radius = 0, max_radius = max(width,height)</i>) -> cvseq(include CvCircle32f)
  4242. *
  4243. * Finds circles in grayscale image using Hough transform.
  4244. */
  4245. VALUE
  4246. rb_hough_circles(int argc, VALUE *argv, VALUE self)
  4247. {
  4248. SUPPORT_8UC1_ONLY(self);
  4249. const int INVALID_TYPE = -1;
  4250. VALUE method, dp, min_dist, param1, param2, min_radius, max_radius, storage;
  4251. rb_scan_args(argc, argv, "52", &method, &dp, &min_dist, &param1, &param2,
  4252. &min_radius, &max_radius);
  4253. storage = cCvMemStorage::new_object();
  4254. int method_flag = CVMETHOD("HOUGH_TRANSFORM_METHOD", method, INVALID_TYPE);
  4255. CvSeq *seq = cvHoughCircles(CVARR(self), CVMEMSTORAGE(storage),
  4256. method_flag, NUM2DBL(dp), NUM2DBL(min_dist),
  4257. NUM2DBL(param1), NUM2DBL(param2),
  4258. IF_INT(min_radius, 0), IF_INT(max_radius, 0));
  4259. return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvCircle32f::rb_class(), storage);
  4260. }
  4261. /*
  4262. * call-seq:
  4263. * hough_circles_gradient(<i>dp, min_dist, threshold_canny, threshold_accumulate, min_radius = 0, max_radius = max(width,height)</i>) -> cvseq(include CvCircle32f)
  4264. *
  4265. * Finds circles in grayscale image using Hough transform.
  4266. */
  4267. VALUE
  4268. rb_hough_circles_gradient(int argc, VALUE *argv, VALUE self)
  4269. {
  4270. SUPPORT_8UC1_ONLY(self);
  4271. VALUE dp, min_dist, threshold_canny, threshold_accumulate, min_radius, max_radius, storage;
  4272. rb_scan_args(argc, argv, "42", &dp, &min_dist, &threshold_canny, &threshold_accumulate, &min_radius, &max_radius);
  4273. storage = cCvMemStorage::new_object();
  4274. CvSeq *seq = cvHoughCircles(CVARR(self), CVMEMSTORAGE(storage),
  4275. CV_HOUGH_GRADIENT, NUM2DBL(dp), NUM2DBL(min_dist),
  4276. NUM2DBL(threshold_canny), NUM2DBL(threshold_accumulate),
  4277. IF_INT(min_radius, 0), IF_INT(max_radius, 0));
  4278. return cCvSeq::new_sequence(cCvSeq::rb_class(), seq, cCvCircle32f::rb_class(), storage);
  4279. }
  4280. /*
  4281. * call-seq:
  4282. * inpaint(<i>inpaint_method, mask, radius</i>) -> cvmat
  4283. *
  4284. * Inpaints the selected region in the image
  4285. * The radius of circlular neighborhood of each point inpainted that is considered by the algorithm.
  4286. */
  4287. VALUE
  4288. rb_inpaint(VALUE self, VALUE inpaint_method, VALUE mask, VALUE radius)
  4289. {
  4290. SUPPORT_8U_ONLY(self);
  4291. SUPPORT_C1C3_ONLY(self);
  4292. const int INVALID_TYPE = -1;
  4293. VALUE dest;
  4294. int method = CVMETHOD("INPAINT_METHOD", inpaint_method, INVALID_TYPE);
  4295. if (!(rb_obj_is_kind_of(mask, cCvMat::rb_class())) || cvGetElemType(CVARR(mask)) != CV_8UC1)
  4296. rb_raise(rb_eTypeError, "argument 1 (mask) should be mask image.");
  4297. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  4298. cvInpaint(CVARR(self), CVARR(mask), CVARR(dest), NUM2DBL(radius), method);
  4299. return dest;
  4300. }
  4301. /*
  4302. * call-seq:
  4303. * inpaint_ns(<i>mask, radius</i>) -> cvmat
  4304. *
  4305. * Inpaints the selected region in the image by Navier-Stokes based method.
  4306. * The radius of circlular neighborhood of each point inpainted that is considered by the algorithm.
  4307. */
  4308. VALUE
  4309. rb_inpaint_ns(VALUE self, VALUE mask, VALUE radius)
  4310. {
  4311. SUPPORT_8U_ONLY(self);
  4312. SUPPORT_C1C3_ONLY(self);
  4313. VALUE dest;
  4314. if (!(rb_obj_is_kind_of(mask, cCvMat::rb_class())) || cvGetElemType(CVARR(mask)) != CV_8UC1)
  4315. rb_raise(rb_eTypeError, "argument 1 (mask) should be mask image.");
  4316. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  4317. cvInpaint(CVARR(self), CVARR(mask), CVARR(dest), NUM2DBL(radius), CV_INPAINT_NS);
  4318. return dest;
  4319. }
  4320. /*
  4321. * call-seq:
  4322. * inpaint_telea(<i>mask, radius</i>) -> cvmat
  4323. *
  4324. * Inpaints the selected region in the image by The method by Alexandru Telea's method.
  4325. * The radius of circlular neighborhood of each point inpainted that is considered by the algorithm.
  4326. */
  4327. VALUE
  4328. rb_inpaint_telea(VALUE self, VALUE mask, VALUE radius)
  4329. {
  4330. SUPPORT_8U_ONLY(self);
  4331. SUPPORT_C1C3_ONLY(self);
  4332. VALUE dest;
  4333. if (!(rb_obj_is_kind_of(mask, cCvMat::rb_class())) || cvGetElemType(CVARR(mask)) != CV_8UC1)
  4334. rb_raise(rb_eTypeError, "argument 1 (mask) should be mask image.");
  4335. dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  4336. cvInpaint(CVARR(self), CVARR(mask), CVARR(dest), NUM2DBL(radius), CV_INPAINT_TELEA);
  4337. return dest;
  4338. }
  4339. /*
  4340. * call-seq:
  4341. * equalize_hist - cvmat
  4342. *
  4343. * Equalize histgram of grayscale of image.
  4344. *
  4345. * equalizes histogram of the input image using the following algorithm:
  4346. * 1. calculate histogram H for src.
  4347. * 2. normalize histogram, so that the sum of histogram bins is 255.
  4348. * 3. compute integral of the histogram:
  4349. * H’(i) = sum0≤j≤iH(j)
  4350. * 4. transform the image using H’ as a look-up table: dst(x,y)=H’(src(x,y))
  4351. * The algorithm normalizes brightness and increases contrast of the image.
  4352. *
  4353. * <b>support single-channel 8bit image (grayscale) only.</b>
  4354. */
  4355. VALUE
  4356. rb_equalize_hist(VALUE self)
  4357. {
  4358. SUPPORT_8UC1_ONLY(self);
  4359. VALUE dest = cCvMat::new_object(cvGetSize(CVARR(self)), cvGetElemType(CVARR(self)));
  4360. cvEqualizeHist(CVARR(self), CVARR(dest));
  4361. return dest;
  4362. }
  4363. /*
  4364. * call-seq:
  4365. * match_template(<i>template[,method = :sqdiff]</i>) -> cvmat(result)
  4366. *
  4367. * Compares template against overlapped image regions.
  4368. * <i>method</i> is specifies the way the template must be compared with image regions.
  4369. * <i>method</i> should be following symbol. (see OpenCV::MATCH_TEMPLATE_METHOD 's key and value.)
  4370. *
  4371. * * :sqdiff
  4372. * R(x,y)=sumx',y'[T(x',y')-I(x+x',y+y')]2
  4373. * * :sqdiff_normed
  4374. * R(x,y)=sumx',y'[T(x',y')-I(x+x',y+y')]2/sqrt[sumx',y'T(x',y')2*sumx',y'I(x+x',y+y')2]
  4375. * * :ccorr
  4376. * R(x,y)=sumx',y'[T(x',y')*I(x+x',y+y')]
  4377. * * :ccorr_normed
  4378. * R(x,y)=sumx',y'[T(x',y')*I(x+x',y+y')]/sqrt[sumx',y'T(x',y')2*sumx',y'I(x+x',y+y')2]
  4379. * * :ccoeff
  4380. * R(x,y)=sumx',y'[T'(x',y')*I'(x+x',y+y')],
  4381. * where T'(x',y')=T(x',y') - 1/(w*h)*sumx",y"T(x",y")
  4382. * I'(x+x',y+y')=I(x+x',y+y') - 1/(w*h)*sumx",y"I(x+x",y+y")
  4383. * * :ccoeff_normed
  4384. * R(x,y)=sumx',y'[T'(x',y')*I'(x+x',y+y')]/sqrt[sumx',y'T'(x',y')2*sumx',y'I'(x+x',y+y')2]
  4385. *
  4386. * After the match_template finishes comparison, the best matches can be found as global
  4387. * minimums (:sqdiff*) or maximums(:ccorr* or :ccoeff*) using minmax function.
  4388. * In case of color image and template summation in both numerator and each sum in denominator
  4389. * is done over all the channels (and separate mean values are used for each channel).
  4390. */
  4391. VALUE
  4392. rb_match_template(int argc, VALUE *argv, VALUE self)
  4393. {
  4394. VALUE templ, method, result;
  4395. int method_flag;
  4396. if (rb_scan_args(argc, argv, "11", &templ, &method) == 1)
  4397. method_flag = CV_TM_SQDIFF;
  4398. else
  4399. method_flag = CVMETHOD("MATCH_TEMPLATE_METHOD", method);
  4400. if (!(rb_obj_is_kind_of(templ, cCvMat::rb_class())))
  4401. rb_raise(rb_eTypeError, "argument 1 (template) should be %s.", rb_class2name(cCvMat::rb_class()));
  4402. if (cvGetElemType(CVARR(self)) != cvGetElemType(CVARR(templ)))
  4403. rb_raise(rb_eTypeError, "template should be same type of self.");
  4404. CvSize src_size = cvGetSize(CVARR(self));
  4405. CvSize template_size = cvGetSize(CVARR(templ));
  4406. result = cCvMat::new_object(src_size.height - template_size.height + 1,
  4407. src_size.width - template_size.width + 1,
  4408. CV_32FC1);
  4409. cvMatchTemplate(CVARR(self), CVARR(templ), CVARR(result), method_flag);
  4410. return result;
  4411. }
  4412. /*
  4413. * call-seq:
  4414. * match_shapes(<i>object, method</i>) -> float
  4415. *
  4416. * Compares two shapes(self and object). <i>object</i> should be CvMat or CvContour.
  4417. *
  4418. * A - object1, B - object2:
  4419. * * method=CV_CONTOUR_MATCH_I1
  4420. * I1(A,B)=sumi=1..7abs(1/mAi - 1/mBi)
  4421. * * method=CV_CONTOUR_MATCH_I2
  4422. * I2(A,B)=sumi=1..7abs(mAi - mBi)
  4423. * * method=CV_CONTOUR_MATCH_I3
  4424. * I3(A,B)=sumi=1..7abs(mAi - mBi)/abs(mAi)
  4425. */
  4426. VALUE
  4427. rb_match_shapes(int argc, VALUE *argv, VALUE self)
  4428. {
  4429. VALUE object, method, param;
  4430. rb_scan_args(argc, argv, "21", &object, &method, &param);
  4431. int method_flag = CVMETHOD("COMPARISON_METHOD", method);
  4432. if (!(rb_obj_is_kind_of(object, cCvMat::rb_class()) || rb_obj_is_kind_of(object, cCvContour::rb_class())))
  4433. rb_raise(rb_eTypeError, "argument 1 (shape) should be %s or %s",
  4434. rb_class2name(cCvMat::rb_class()), rb_class2name(cCvContour::rb_class()));
  4435. return rb_float_new(cvMatchShapes(CVARR(self), CVARR(object), method_flag));
  4436. }
  4437. inline VALUE
  4438. rb_match_shapes_internal(int argc, VALUE *argv, VALUE self, int method)
  4439. {
  4440. VALUE object;
  4441. rb_scan_args(argc, argv, "10", &object);
  4442. if (!(rb_obj_is_kind_of(object, cCvMat::rb_class()) || rb_obj_is_kind_of(object, cCvContour::rb_class())))
  4443. rb_raise(rb_eTypeError, "argument 1 (shape) should be %s or %s",
  4444. rb_class2name(cCvMat::rb_class()), rb_class2name(cCvContour::rb_class()));
  4445. return rb_float_new(cvMatchShapes(CVARR(self), CVARR(object), method));
  4446. }
  4447. /*
  4448. * call-seq:
  4449. * match_shapes_i1(<i>object</i>) -> float
  4450. *
  4451. * Compares two shapes(self and object). <i>object</i> should be CvMat or CvContour.
  4452. *
  4453. * A - object1, B - object2:
  4454. * I1(A,B)=sumi=1..7abs(1/mAi - 1/mBi)
  4455. */
  4456. VALUE
  4457. rb_match_shapes_i1(int argc, VALUE *argv, VALUE self)
  4458. {
  4459. return rb_match_shapes_internal(argc, argv, self, CV_CONTOURS_MATCH_I1);
  4460. }
  4461. /*
  4462. * call-seq:
  4463. * match_shapes_i2(<i>object</i>) -> float
  4464. *
  4465. * Compares two shapes(self and object). <i>object</i> should be CvMat or CvContour.
  4466. *
  4467. * A - object1, B - object2:
  4468. * I2(A,B)=sumi=1..7abs(mAi - mBi)
  4469. */
  4470. VALUE
  4471. rb_match_shapes_i2(int argc, VALUE *argv, VALUE self)
  4472. {
  4473. return rb_match_shapes_internal(argc, argv, self, CV_CONTOURS_MATCH_I2);
  4474. }
  4475. /*
  4476. * call-seq:
  4477. * match_shapes_i3(<i>object</i>) -> float
  4478. *
  4479. * Compares two shapes(self and object). <i>object</i> should be CvMat or CvContour.
  4480. *
  4481. * A - object1, B - object2:
  4482. * I3(A,B)=sumi=1..7abs(mAi - mBi)/abs(mAi)
  4483. */
  4484. VALUE
  4485. rb_match_shapes_i3(int argc, VALUE *argv, VALUE self)
  4486. {
  4487. return rb_match_shapes_internal(argc, argv, self, CV_CONTOURS_MATCH_I3);
  4488. }
  4489. /*
  4490. * call-seq:
  4491. * mean_shift(window, criteria) -> comp
  4492. *
  4493. * Implements CAMSHIFT object tracking algrorithm.
  4494. * First, it finds an object center using mean_shift and, after that,
  4495. * calculates the object size and orientation.
  4496. */
  4497. VALUE
  4498. rb_mean_shift(VALUE self, VALUE window, VALUE criteria)
  4499. {
  4500. VALUE comp = cCvConnectedComp::new_object();
  4501. cvMeanShift(CVARR(self), VALUE_TO_CVRECT(window), VALUE_TO_CVTERMCRITERIA(criteria), CVCONNECTEDCOMP(comp));
  4502. return comp;
  4503. }
  4504. /*
  4505. * call-seq:
  4506. * cam_shift(window, criteria) -> [comp, box]
  4507. *
  4508. * Implements CAMSHIFT object tracking algrorithm. First, it finds an object center using cvMeanShift and,
  4509. * after that, calculates the object size and orientation. The function returns number of iterations made
  4510. * within cvMeanShift.
  4511. */
  4512. VALUE
  4513. rb_cam_shift(VALUE self, VALUE window, VALUE criteria)
  4514. {
  4515. VALUE comp, box;
  4516. comp = cCvConnectedComp::new_object();
  4517. box = cCvBox2D::new_object();
  4518. cvCamShift(CVARR(self), VALUE_TO_CVRECT(window), VALUE_TO_CVTERMCRITERIA(criteria), CVCONNECTEDCOMP(comp), CVBOX2D(box));
  4519. return rb_ary_new3(2, comp, box);
  4520. }
  4521. /*
  4522. * call-seq:
  4523. * snake_image(<i>points, alpha, beta, gamma, window, criteria[, calc_gradient = true]</i>) -> array(pointset)
  4524. *
  4525. * Updates snake in order to minimize its total energy that is a sum of internal energy
  4526. * that depends on contour shape (the smoother contour is, the smaller internal energy is)
  4527. * and external energy that depends on the energy field and reaches minimum at the local energy
  4528. * extremums that correspond to the image edges in case of image gradient.
  4529. * The parameter criteria.epsilon is used to define the minimal number of points that must be moved
  4530. * during any iteration to keep the iteration process running.
  4531. *
  4532. * If at some iteration the number of moved points is less than criteria.epsilon or
  4533. * the function performed criteria.max_iter iterations, the function terminates.
  4534. *
  4535. * points
  4536. * Contour points (snake).
  4537. * alpha
  4538. * Weight[s] of continuity energy, single float or array of length floats, one per each contour point.
  4539. * beta
  4540. * Weight[s] of curvature energy, similar to alpha.
  4541. * gamma
  4542. * Weight[s] of image energy, similar to alpha.
  4543. * window
  4544. * Size of neighborhood of every point used to search the minimum, both win.width and win.height must be odd.
  4545. * criteria
  4546. * Termination criteria.
  4547. * calc_gradient
  4548. * Gradient flag. If not 0, the function calculates gradient magnitude for every image pixel and consideres
  4549. * it as the energy field, otherwise the input image itself is considered.
  4550. */
  4551. VALUE
  4552. rb_snake_image(int argc, VALUE *argv, VALUE self)
  4553. {
  4554. VALUE points, alpha, beta, gamma, window, criteria, calc_gradient;
  4555. rb_scan_args(argc, argv, "61", &points, &alpha, &beta, &gamma, &window, &criteria, &calc_gradient);
  4556. CvPoint *pointset = 0;
  4557. int length = CVPOINTS_FROM_POINT_SET(points, &pointset);
  4558. int coeff = (TYPE(alpha) == T_ARRAY && TYPE(beta) == T_ARRAY && TYPE(gamma) == T_ARRAY) ? CV_ARRAY : CV_VALUE;
  4559. float *a = 0, *b = 0, *c = 0;
  4560. IplImage stub;
  4561. int i;
  4562. if (coeff == CV_VALUE) {
  4563. float buff_a, buff_b, buff_c;
  4564. buff_a = (float)NUM2DBL(alpha);
  4565. buff_b = (float)NUM2DBL(beta);
  4566. buff_c = (float)NUM2DBL(gamma);
  4567. a = &buff_a;
  4568. b = &buff_b;
  4569. c = &buff_c;
  4570. }
  4571. else { // CV_ARRAY
  4572. if ((RARRAY_LEN(alpha) != length) ||
  4573. (RARRAY_LEN(beta) != length) ||
  4574. (RARRAY_LEN(gamma) != length))
  4575. rb_raise(rb_eArgError, "alpha, beta, gamma should be same size of points");
  4576. a = ALLOCA_N(float, length);
  4577. b = ALLOCA_N(float, length);
  4578. c = ALLOCA_N(float, length);
  4579. for (i = 0; i < length; ++i) {
  4580. a[i] = (float)NUM2DBL(RARRAY_PTR(alpha)[i]);
  4581. b[i] = (float)NUM2DBL(RARRAY_PTR(beta)[i]);
  4582. c[i] = (float)NUM2DBL(RARRAY_PTR(gamma)[i]);
  4583. }
  4584. }
  4585. CvSize win = VALUE_TO_CVSIZE(window);
  4586. CvTermCriteria tc = VALUE_TO_CVTERMCRITERIA(criteria);
  4587. cvSnakeImage(cvGetImage(CVARR(self), &stub), pointset, length,
  4588. a, b, c, coeff, win, tc, IF_BOOL(calc_gradient, 1, 0, 1));
  4589. VALUE result = rb_ary_new2(length);
  4590. for (i = 0; i < length; ++i)
  4591. rb_ary_push(result, cCvPoint::new_object(pointset[i]));
  4592. cvFree(&pointset);
  4593. return result;
  4594. }
  4595. /*
  4596. * call-seq:
  4597. * optical_flow_hs(<i>prev[,velx = nil][,vely = nil][,options]</i>) -> [cvmat, cvmat]
  4598. *
  4599. * Calculates optical flow for two images (previous -> self) using Horn & Schunck algorithm.
  4600. * Return horizontal component of the optical flow and vertical component of the optical flow.
  4601. * <i>prev</i> is previous image
  4602. * <i>velx</i> is previous velocity field of x-axis, and <i>vely</i> is previous velocity field of y-axis.
  4603. *
  4604. * options
  4605. * * :lambda -> should be Float (default is 0.0005)
  4606. * Lagrangian multiplier.
  4607. * * :criteria -> should be CvTermCriteria object (default is CvTermCriteria(1, 0.001))
  4608. * Criteria of termination of velocity computing.
  4609. * note: <i>option</i>'s default value is CvMat::OPTICAL_FLOW_HS_OPTION.
  4610. *
  4611. * sample code
  4612. * velx, vely = nil, nil
  4613. * while true
  4614. * current = capture.query
  4615. * velx, vely = current.optical_flow_hs(prev, velx, vely) if prev
  4616. * prev = current
  4617. * end
  4618. */
  4619. VALUE
  4620. rb_optical_flow_hs(int argc, VALUE *argv, VALUE self)
  4621. {
  4622. SUPPORT_8UC1_ONLY(self);
  4623. VALUE prev, velx, vely, options;
  4624. int use_previous = 0;
  4625. rb_scan_args(argc, argv, "13", &prev, &velx, &vely, &options);
  4626. options = OPTICAL_FLOW_HS_OPTION(options);
  4627. if (!rb_obj_is_kind_of(prev, cCvMat::rb_class()))
  4628. rb_raise(rb_eTypeError, "argument 1 (previous image) should be %s", rb_class2name(cCvMat::rb_class()));
  4629. if (NIL_P(velx) && NIL_P(vely)) {
  4630. velx = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  4631. vely = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  4632. } else {
  4633. if (rb_obj_is_kind_of(velx, cCvMat::rb_class()) && rb_obj_is_kind_of(vely, cCvMat::rb_class()))
  4634. use_previous = 1;
  4635. else
  4636. rb_raise(rb_eArgError, "Necessary to give both argument 2(previous velocity field x) and argument 3(previous velocity field y)");
  4637. }
  4638. cvCalcOpticalFlowHS(CVARR(prev), CVARR(self), use_previous, CVARR(velx), CVARR(vely),
  4639. HS_LAMBDA(options), HS_CRITERIA(options));
  4640. return rb_ary_new3(2, velx, vely);
  4641. }
  4642. /*
  4643. * call-seq:
  4644. * optical_flow_lk(<i>prev, win_size</i>) -> [cvmat, cvmat]
  4645. *
  4646. * Calculates optical flow for two images (previous -> self) using Lucas & Kanade algorithm
  4647. * Return horizontal component of the optical flow and vertical component of the optical flow.
  4648. *
  4649. * <i>win_size</i> is size of the averaging window used for grouping pixels.
  4650. */
  4651. VALUE
  4652. rb_optical_flow_lk(VALUE self, VALUE prev, VALUE win_size)
  4653. {
  4654. SUPPORT_8UC1_ONLY(self);
  4655. VALUE velx, vely;
  4656. if (!rb_obj_is_kind_of(prev, cCvMat::rb_class()))
  4657. rb_raise(rb_eTypeError, "argument 1 (previous image) should be %s", rb_class2name(cCvMat::rb_class()));
  4658. velx = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  4659. vely = cCvMat::new_object(cvGetSize(CVARR(self)), CV_MAKETYPE(CV_32F, 1));
  4660. cvCalcOpticalFlowLK(CVARR(prev), CVARR(self), VALUE_TO_CVSIZE(win_size), CVARR(velx), CVARR(vely));
  4661. return rb_ary_new3(2, velx, vely);
  4662. }
  4663. /*
  4664. * call-seq:
  4665. * optical_flow_bm(<i>prev[,velx = nil][,vely = nil][,option]</i>) -> [cvmat, cvmat]
  4666. *
  4667. * Calculates optical flow for two images (previous -> self) using block matching method.
  4668. * Return horizontal component of the optical flow and vertical component of the optical flow.
  4669. * <i>prev</i> is previous image.
  4670. * <i>velx</i> is previous velocity field of x-axis, and <i>vely</i> is previous velocity field of y-axis.
  4671. *
  4672. * options
  4673. * * :block_size -> should be CvSize (default is CvSize(4,4))
  4674. * Size of basic blocks that are compared.
  4675. * * :shift_size -> should be CvSize (default is CvSize(1,1))
  4676. * Block coordinate increments.
  4677. * * :max_range -> should be CvSize (default is CVSize(4,4))
  4678. * Size of the scanned neighborhood in pixels around block.
  4679. * note: <i>option</i>'s default value is CvMat::OPTICAL_FLOW_BM_OPTION.
  4680. *
  4681. * Velocity is computed for every block, but not for every pixel,
  4682. * so velocity image pixels correspond to input image blocks.
  4683. * input/output velocity field's size should be (self.width / block_size.width)x(self.height / block_size.height).
  4684. * e.g. image.size is 320x240 and block_size is 4x4, velocity field's size is 80x60.
  4685. *
  4686. */
  4687. VALUE
  4688. rb_optical_flow_bm(int argc, VALUE *argv, VALUE self)
  4689. {
  4690. SUPPORT_8UC1_ONLY(self);
  4691. VALUE prev, velx, vely, options;
  4692. int use_previous = 0;
  4693. rb_scan_args(argc, argv, "13", &prev, &velx, &vely, &options);
  4694. options = OPTICAL_FLOW_BM_OPTION(options);
  4695. CvSize
  4696. image_size = cvGetSize(CVARR(self)),
  4697. block_size = BM_BLOCK_SIZE(options),
  4698. shift_size = BM_SHIFT_SIZE(options),
  4699. max_range = BM_MAX_RANGE(options),
  4700. velocity_size = cvSize((image_size.width - block_size.width) / shift_size.width,
  4701. (image_size.height - block_size.height) / shift_size.height);
  4702. if (NIL_P(velx) && NIL_P(vely)) {
  4703. velx = cCvMat::new_object(velocity_size, CV_MAKETYPE(CV_32F, 1));
  4704. vely = cCvMat::new_object(velocity_size, CV_MAKETYPE(CV_32F, 1));
  4705. }
  4706. else {
  4707. if (rb_obj_is_kind_of(velx, cCvMat::rb_class()) && rb_obj_is_kind_of(vely, cCvMat::rb_class()))
  4708. use_previous = 1;
  4709. else
  4710. rb_raise(rb_eArgError, "Necessary to give both argument 2(previous velocity field x) and argument 3(previous velocity field y)");
  4711. }
  4712. cvCalcOpticalFlowBM(CVARR(prev), CVARR(self),
  4713. block_size, shift_size, max_range, use_previous,
  4714. CVARR(velx), CVARR(vely));
  4715. return rb_ary_new3(2, velx, vely);
  4716. }
  4717. /*
  4718. * call-seq:
  4719. * CvMat.find_fundamental_mat_7point(<i>points1, points2</i>) -> fundamental_matrix(cvmat) or nil
  4720. *
  4721. * Calculates fundamental matrix from corresponding points, use for 7-point algorism. Return fundamental matrix(9x3).
  4722. * <i>points1</i> and <i>points2</i> should be 2x7 or 3x7 single-channel, or 1x7 multi-channel matrix.
  4723. *
  4724. * note: 9x3 fundamental matrix means 3x3 three fundamental matrices.
  4725. */
  4726. VALUE
  4727. rb_find_fundamental_mat_7point(VALUE klass, VALUE points1, VALUE points2)
  4728. {
  4729. VALUE fundamental_matrix = cCvMat::new_object(9, 3, CV_MAT_DEPTH(CVMAT(points1)->type));
  4730. int num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix),
  4731. CV_FM_7POINT, 0, 0, NULL);
  4732. return (num == 0) ? Qnil : fundamental_matrix;
  4733. }
  4734. /*
  4735. * call-seq:
  4736. * CvMat.find_fundamental_mat_8point(<i>points1, points2</i>) -> fundamental_matrix(cvmat) or nil
  4737. *
  4738. * Calculates fundamental matrix from corresponding points, use for 8-point algorism.
  4739. * <i>points1</i> and <i>points2</i> should be 2x8 or 3x8 single-channel, or 1x8 multi-channel matrix.
  4740. *
  4741. */
  4742. VALUE
  4743. rb_find_fundamental_mat_8point(VALUE klass, VALUE points1, VALUE points2)
  4744. {
  4745. VALUE fundamental_matrix = cCvMat::new_object(3, 3, CV_MAT_DEPTH(CVMAT(points1)->type));
  4746. int num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix),
  4747. CV_FM_8POINT, 0, 0, NULL);
  4748. return (num == 0) ? Qnil : fundamental_matrix;
  4749. }
  4750. /*
  4751. * call-seq:
  4752. * CvMat.find_fundamental_mat_ransac(<i>points1, points2[,options = {}]</i>) -> fundamental_matrix(cvmat) or nil
  4753. *
  4754. * Calculates fundamental matrix from corresponding points, use for RANSAC algorism.
  4755. * <i>points1</i> and <i>points2</i> should be 2xN, Nx2, 3xN or Nx3 1-channel, or 1xN or Nx1 multi-channel matrix (N >= 8).
  4756. * <i>option</i> should be Hash include these keys.
  4757. * :with_status (true or false)
  4758. * If set true, return fundamental_matrix and status. [fundamental_matrix, status]
  4759. * Otherwise return fundamental matrix only(default).
  4760. * :maximum_distance
  4761. * The maximum distance from point to epipolar line in pixels, beyond which the point is considered an outlier
  4762. * and is not used for computing the final fundamental matrix. Usually it is set to 0.5 or 1.0.
  4763. * :desirable_level
  4764. * It denotes the desirable level of confidence that the matrix is correct.
  4765. *
  4766. * note: <i>option</i>'s default value is CvMat::FIND_FUNDAMENTAL_MAT_OPTION.
  4767. */
  4768. VALUE
  4769. rb_find_fundamental_mat_ransac(int argc, VALUE *argv, VALUE klass)
  4770. {
  4771. VALUE points1, points2, option, fundamental_matrix, status;
  4772. int num = 0;
  4773. rb_scan_args(argc, argv, "21", &points1, &points2, &option);
  4774. option = FIND_FUNDAMENTAL_MAT_OPTION(option);
  4775. fundamental_matrix = cCvMat::new_object(3, 3, CV_MAT_DEPTH(CVMAT(points1)->type));
  4776. if(FFM_WITH_STATUS(option)){
  4777. CvMat *points1_ptr = CVMAT(points1);
  4778. int status_len = (points1_ptr->rows > points1_ptr->cols) ? points1_ptr->rows : points1_ptr->cols;
  4779. status = cCvMat::new_object(1, status_len, CV_8UC1);
  4780. num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_RANSAC,
  4781. FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), CVMAT(status));
  4782. return num == 0 ? Qnil : rb_ary_new3(2, fundamental_matrix, status);
  4783. }else{
  4784. num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_RANSAC,
  4785. FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), NULL);
  4786. return num == 0 ? Qnil : fundamental_matrix;
  4787. }
  4788. }
  4789. /*
  4790. * call-seq:
  4791. * CvMat.find_fundamental_mat_lmeds(<i>points1, points2[,options = {}]</i>) -> fundamental_matrix(cvmat) or nil
  4792. *
  4793. * Calculates fundamental matrix from corresponding points, use for LMedS algorism.
  4794. * <i>points1</i> and <i>points2</i> should be 2xN, Nx2, 3xN or Nx3 1-channel, or 1xN or Nx1 multi-channel matrix (N >= 8).
  4795. * <i>option</i> should be Hash include these keys.
  4796. * :with_status (true or false)
  4797. * If set true, return fundamental_matrix and status. [fundamental_matrix, status]
  4798. * Otherwise return fundamental matrix only(default).
  4799. * :desirable_level
  4800. * It denotes the desirable level of confidence that the matrix is correct.
  4801. *
  4802. * note: <i>option</i>'s default value is CvMat::FIND_FUNDAMENTAL_MAT_OPTION.
  4803. */
  4804. VALUE
  4805. rb_find_fundamental_mat_lmeds(int argc, VALUE *argv, VALUE klass)
  4806. {
  4807. VALUE points1, points2, option, fundamental_matrix, status;
  4808. int num = 0;
  4809. rb_scan_args(argc, argv, "21", &points1, &points2, &option);
  4810. option = FIND_FUNDAMENTAL_MAT_OPTION(option);
  4811. fundamental_matrix = cCvMat::new_object(3, 3, CV_MAT_DEPTH(CVMAT(points1)->type));
  4812. if(FFM_WITH_STATUS(option)){
  4813. CvMat *points1_ptr = CVMAT(points1);
  4814. int status_len = (points1_ptr->rows > points1_ptr->cols) ? points1_ptr->rows : points1_ptr->cols;
  4815. status = cCvMat::new_object(1, status_len, CV_8UC1);
  4816. num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_LMEDS,
  4817. 0, FFM_DESIRABLE_LEVEL(option), CVMAT(status));
  4818. return num == 0 ? Qnil : rb_ary_new3(2, fundamental_matrix, status);
  4819. }else{
  4820. num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), CV_FM_LMEDS,
  4821. 0, FFM_DESIRABLE_LEVEL(option), NULL);
  4822. return num == 0 ? Qnil : fundamental_matrix;
  4823. }
  4824. }
  4825. /*
  4826. * call-seq:
  4827. * CvMat.find_fundamental_mat(<i>points1, points2[,options = {}]</i>) -> fundamental_matrix(cvmat) or nil
  4828. *
  4829. * Calculates fundamental matrix from corresponding points.
  4830. * Size of the output fundamental matrix is 3x3 or 9x3 (7-point method may return up to 3 matrices)
  4831. *
  4832. * <i>points1</i> and <i>points2</i> should be 2xN, Nx2, 3xN or Nx3 1-channel, or 1xN or Nx1 multi-channel matrix.
  4833. * <i>method<i> is method for computing the fundamental matrix
  4834. * - CV_FM_7POINT for a 7-point algorithm. (N = 7)
  4835. * - CV_FM_8POINT for an 8-point algorithm. (N >= 8)
  4836. * - CV_FM_RANSAC for the RANSAC algorithm. (N >= 8)
  4837. * - CV_FM_LMEDS for the LMedS algorithm. (N >= 8)
  4838. * <i>option</i> should be Hash include these keys.
  4839. * :with_status (true or false)
  4840. * If set true, return fundamental_matrix and status. [fundamental_matrix, status]
  4841. * Otherwise return fundamental matrix only(default).
  4842. * :maximum_distance
  4843. * The parameter is used for RANSAC. It is the maximum distance from point to epipolar line in pixels, beyond which the point is considered an outlier and is not used for computing the final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the point localization, image resolution and the image noise.
  4844. * :desirable_level
  4845. * The optional output array of N elements, every element of which is set to 0 for outliers and to 1 for the other points. The array is computed only in RANSAC and LMedS methods. For other methods it is set to all 1's.
  4846. *
  4847. * note: <i>option</i>'s default value is CvMat::FIND_FUNDAMENTAL_MAT_OPTION.
  4848. */
  4849. VALUE
  4850. rb_find_fundamental_mat(int argc, VALUE *argv, VALUE klass)
  4851. {
  4852. VALUE points1, points2, method, option, fundamental_matrix, status;
  4853. int num = 0;
  4854. rb_scan_args(argc, argv, "31", &points1, &points2, &method, &option);
  4855. option = FIND_FUNDAMENTAL_MAT_OPTION(option);
  4856. int fm_method = FIX2INT(method);
  4857. if (fm_method == CV_FM_7POINT)
  4858. fundamental_matrix = cCvMat::new_object(9, 3, CV_MAT_DEPTH(CVMAT(points1)->type));
  4859. else
  4860. fundamental_matrix = cCvMat::new_object(3, 3, CV_MAT_DEPTH(CVMAT(points1)->type));
  4861. if (FFM_WITH_STATUS(option)) {
  4862. CvMat *points1_ptr = CVMAT(points1);
  4863. int status_len = (points1_ptr->rows > points1_ptr->cols) ? points1_ptr->rows : points1_ptr->cols;
  4864. status = cCvMat::new_object(1, status_len, CV_8UC1);
  4865. num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), fm_method,
  4866. FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), CVMAT(status));
  4867. return num == 0 ? Qnil : rb_ary_new3(2, fundamental_matrix, status);
  4868. }
  4869. else {
  4870. num = cvFindFundamentalMat(CVMAT(points1), CVMAT(points2), CVMAT(fundamental_matrix), fm_method,
  4871. FFM_MAXIMUM_DISTANCE(option), FFM_DESIRABLE_LEVEL(option), NULL);
  4872. return num == 0 ? Qnil : fundamental_matrix;
  4873. }
  4874. }
  4875. /*
  4876. * call-seq:
  4877. * CvMat.compute_correspond_epilines(<i>points, which_image, fundamental_matrix</i>) -> correspondent_lines(cvmat)
  4878. *
  4879. * For points in one image of stereo pair computes the corresponding epilines in the other image.
  4880. * Finds equation of a line that contains the corresponding point (i.e. projection of the same 3D point)
  4881. * in the other image. Each line is encoded by a vector of 3 elements l=[a,b,c]T, so that:
  4882. * lT*[x, y, 1]T=0,
  4883. * or
  4884. * a*x + b*y + c = 0
  4885. * From the fundamental matrix definition (see cvFindFundamentalMatrix discussion), line l2 for a point p1 in the first image (which_image=1) can be computed as:
  4886. * l2=F*p1
  4887. * and the line l1 for a point p2 in the second image (which_image=1) can be computed as:
  4888. * l1=FT*p2
  4889. * Line coefficients are defined up to a scale. They are normalized (a2+b2=1) are stored into correspondent_lines.
  4890. */
  4891. VALUE
  4892. rb_compute_correspond_epilines(VALUE klass, VALUE points, VALUE which_image, VALUE fundamental_matrix)
  4893. {
  4894. VALUE correspondent_lines;
  4895. CvMat* points_ptr = CVMAT(points);
  4896. int n;
  4897. if(points_ptr->cols <= 3 && points_ptr->rows >= 7)
  4898. n = points_ptr->rows;
  4899. else if(points_ptr->rows <= 3 && points_ptr->cols >= 7)
  4900. n = points_ptr->cols;
  4901. else
  4902. rb_raise(rb_eArgError, "input points should 2xN, Nx2 or 3xN, Nx3 matrix(N >= 7).");
  4903. correspondent_lines = cCvMat::new_object(n, 3, CV_MAT_DEPTH(points_ptr->type));
  4904. cvComputeCorrespondEpilines(points_ptr, FIX2INT(which_image), CVMAT(fundamental_matrix),
  4905. CVMAT(correspondent_lines));
  4906. return correspondent_lines;
  4907. }
  4908. VALUE
  4909. new_object(int rows, int cols, int type)
  4910. {
  4911. return OPENCV_OBJECT(rb_klass, cvCreateMat(rows, cols, type));
  4912. }
  4913. VALUE
  4914. new_object(CvSize size, int type)
  4915. {
  4916. return OPENCV_OBJECT(rb_klass, cvCreateMat(size.height, size.width, type));
  4917. }
  4918. __NAMESPACE_END_OPENCV
  4919. __NAMESPACE_END_CVMAT