1
0
Fork 0
mirror of https://github.com/ruby-opencv/ruby-opencv synced 2023-03-27 23:22:12 -04:00
ruby-opencv/ext/opencv/cvcontour.cpp
2012-05-31 02:38:41 +09:00

333 lines
9.6 KiB
C++

/************************************************************
cvcontour.cpp -
$Author: lsxi $
Copyright (C) 2007 Masakazu Yonekura
************************************************************/
#include "cvcontour.h"
/*
* Document-class: OpenCV::CvContour
*
* Contour
*
* @see CvMat#find_contours
*/
__NAMESPACE_BEGIN_OPENCV
__NAMESPACE_BEGIN_CVCONTOUR
#define APPROX_POLY_OPTION(op) rb_get_option_table(rb_klass, "APPROX_OPTION", op)
#define APPROX_POLY_METHOD(op) CVMETHOD("APPROX_POLY_METHOD", LOOKUP_CVMETHOD(op, "method"), CV_POLY_APPROX_DP)
#define APPROX_POLY_ACCURACY(op) NUM2DBL(LOOKUP_CVMETHOD(op, "accuracy"))
#define APPROX_POLY_RECURSIVE(op) TRUE_OR_FALSE(LOOKUP_CVMETHOD(op, "recursive"))
VALUE rb_allocate(VALUE klass);
void cvcontour_free(void *ptr);
VALUE rb_klass;
VALUE
rb_class()
{
return rb_klass;
}
VALUE
rb_allocate(VALUE klass)
{
CvContour *ptr;
return Data_Make_Struct(klass, CvContour, mark_root_object, unregister_object, ptr);
}
/*
* Constructor
* @overload new(storage = nil)
* @param [CvMemStorage] storage Sequence location
* @return [CvContour] self
* @opencv_func cvCreateSeq
*/
VALUE
rb_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE storage;
rb_scan_args(argc, argv, "01", &storage);
if (NIL_P(storage))
storage = cCvMemStorage::new_object(0);
else
storage = CHECK_CVMEMSTORAGE(storage);
CvContour* contour = (CvContour*)DATA_PTR(self);
try {
contour = (CvContour*)cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvContour),
sizeof(CvPoint), CVMEMSTORAGE(storage));
}
catch (cv::Exception& e) {
raise_cverror(e);
}
register_root_object((CvSeq*)contour, storage);
return self;
}
/*
* Returns bounding box of the contour
* @overload rect
* @return [CvRect] Bounding box of the contour
*/
VALUE
rb_rect(VALUE self)
{
return cCvRect::new_object(CVCONTOUR(self)->rect);
}
/*
* Returns color of the contour
* @overload color
* @return [Number] Color of the contour
*/
VALUE
rb_color(VALUE self)
{
return INT2NUM(CVCONTOUR(self)->color);
}
/*
* Set color of the contour
* @overload color=value
* @param value [Number] Color of the contour
*/
VALUE
rb_set_color(VALUE self, VALUE color)
{
CVCONTOUR(self)->color = NUM2INT(color);
return self;
}
/*
* Returns reserved region values of the contour
* @overload reserved
* @return [Array<Number>] Reserved region values of the contour
*/
VALUE
rb_reserved(VALUE self)
{
return rb_ary_new3(3,
INT2NUM(CVCONTOUR(self)->reserved[0]),
INT2NUM(CVCONTOUR(self)->reserved[1]),
INT2NUM(CVCONTOUR(self)->reserved[2]));
}
/*
* Approximates polygonal curves with desired precision
* @overload approx_poly(options)
* @param options [Hash] Parameters
* @option options [Symbol] :method Approximation method (default :dp)
* * :dp - Douglas-Peucker algorithm.
* @option options [Number] :accuracy Parameter specifying the approximation accuracy.
* This is the maximum distance between the original curve and its approximation.
* @option options [Boolean] :recursive Recursion flag. If true, the function approximates
* all the contours accessible from curve by h_next and v_next links.
* @return [CvContour] Result of the approximation
* @return [nil] Approximation faied
* @opencv_func cvApproxPoly
*/
VALUE
rb_approx_poly(int argc, VALUE *argv, VALUE self)
{
VALUE approx_poly_option;
rb_scan_args(argc, argv, "01", &approx_poly_option);
approx_poly_option = APPROX_POLY_OPTION(approx_poly_option);
VALUE storage = cCvMemStorage::new_object();
CvSeq *contour = cvApproxPoly(CVCONTOUR(self), sizeof(CvContour), CVMEMSTORAGE(storage),
APPROX_POLY_METHOD(approx_poly_option),
APPROX_POLY_ACCURACY(approx_poly_option),
APPROX_POLY_RECURSIVE(approx_poly_option));
if (contour && contour->total > 0) {
return cCvSeq::new_sequence(cCvContour::rb_class(), contour, cCvPoint::rb_class(), storage);
}
return Qnil;
}
/*
* Calculates up-right bounding rectangle of point set.
* @overload bounding_rect
* @return [CvRect] Bounding rectangle
* @opencv_func cvBoundingRect
*/
VALUE
rb_bounding_rect(VALUE self)
{
CvRect rect;
try {
rect = cvBoundingRect(CVCONTOUR(self), 1);
}
catch (cv::Exception& e) {
raise_cverror(e);
}
return cCvRect::new_object(rect);
}
/*
* Creates hierarchical representation of contour
* @overload create_tree(threshold = 0.0)
* @param threshold [Number] If <= 0, the method creates full binary tree representation.
* If > 0, the method creates representation with the precision threshold.
* @return [CvContourTree] Hierarchical representation of the contour
* @opencv_func cvCreateContourTree
*/
VALUE
rb_create_tree(int argc, VALUE *argv, VALUE self)
{
VALUE threshold, storage;
rb_scan_args(argc, argv, "01", &threshold);
storage = cCvMemStorage::new_object();
CvContourTree *tree = NULL;
try {
tree = cvCreateContourTree(CVSEQ(self), CVMEMSTORAGE(storage), IF_DBL(threshold, 0.0));
}
catch (cv::Exception& e) {
raise_cverror(e);
}
return cCvSeq::new_sequence(cCvContourTree::rb_class(), (CvSeq*)tree, cCvPoint::rb_class(), storage);
}
/*
* Performs a point-in-contour test.
* The method determines whether the point is inside a contour, outside,
* or lies on an edge (or coincides with a vertex).
* @overload in?(point)
* @param point [CvPoint2D32f] Point tested against the contour
* @return [Boolean] If the point is inside, returns true. If outside, returns false.
* If lies on an edge, returns nil.
* @opencv_func cvPointPolygonTest
*/
VALUE
rb_in_q(VALUE self, VALUE point)
{
double n = 0;
try {
n = cvPointPolygonTest(CVARR(self), VALUE_TO_CVPOINT2D32F(point), 0);
}
catch (cv::Exception& e) {
raise_cverror(e);
}
return n == 0 ? Qnil : n > 0 ? Qtrue : Qfalse;
}
/*
* Calculates distance between a point and the nearest contour edgex
* @overload measure_distance(point)
* @param point [CvPoint2D32f] Point tested against the contour
* @return Signed distance between the point and the nearest contour edge
* @opencv_func cvPointPolygonTest
*/
VALUE
rb_measure_distance(VALUE self, VALUE point)
{
double distance = 0;
try {
distance = cvPointPolygonTest(CVARR(self), VALUE_TO_CVPOINT2D32F(point), 1);
}
catch (cv::Exception& e) {
raise_cverror(e);
}
return rb_float_new(distance);
}
/*
* Determines whether the point is inside a contour, outside, or lies on an edge (or coinsides with a vertex).
* @overload point_polygon_test(point, measure_dist)
* @param point [CvPoint2D32f] Point tested against the contour
* @param measure_dist [Boolean] If true, the method estimates the signed distance from the point to
* the nearest contour edge. Otherwise, the function only checks if the point is inside a contour or not.
* @return [Number] When measure_dist = false, the return value is +1, -1 and 0, respectively.
* When measure_dist = true, it is a signed distance between the point and the nearest contour edge.
* @opencv_func cvPointPolygonTest
*/
VALUE
rb_point_polygon_test(VALUE self, VALUE point, VALUE measure_dist)
{
int measure_dist_flag;
if (measure_dist == Qtrue)
measure_dist_flag = 1;
else if (measure_dist == Qfalse)
measure_dist_flag = 0;
else
measure_dist_flag = NUM2INT(measure_dist);
double dist = Qnil;
try {
dist = cvPointPolygonTest(CVARR(self), VALUE_TO_CVPOINT2D32F(point), measure_dist_flag);
}
catch (cv::Exception& e) {
raise_cverror(e);
}
/* cvPointPolygonTest returns 100, -100 or 0 when measure_dist = 0 */
if ((!measure_dist_flag) && ((int)dist) != 0)
dist = (dist > 0) ? 1 : -1;
return rb_float_new(dist);
}
VALUE new_object()
{
VALUE object = rb_allocate(rb_klass);
rb_initialize(0, NULL, object);
return object;
}
void
init_ruby_class()
{
#if 0
// For documentation using YARD
VALUE opencv = rb_define_module("OpenCV");
VALUE cvseq = rb_define_class_under(opencv, "CvSeq");
VALUE curve = rb_define_module_under(opencv, "Curve");
VALUE pointset = rb_define_module_under(opencv, "PointSet");
#endif
if (rb_klass)
return;
VALUE opencv = rb_module_opencv();
VALUE cvseq = cCvSeq::rb_class();
VALUE curve = mCurve::rb_module();
VALUE pointset = mPointSet::rb_module();
rb_klass = rb_define_class_under(opencv, "CvContour", cvseq);
rb_include_module(rb_klass, curve);
rb_include_module(rb_klass, pointset);
rb_define_alloc_func(rb_klass, rb_allocate);
VALUE approx_option = rb_hash_new();
rb_define_const(rb_klass, "APPROX_OPTION", approx_option);
rb_hash_aset(approx_option, ID2SYM(rb_intern("method")), INT2FIX(CV_POLY_APPROX_DP));
rb_hash_aset(approx_option, ID2SYM(rb_intern("accuracy")), rb_float_new(1.0));
rb_hash_aset(approx_option, ID2SYM(rb_intern("recursive")), Qfalse);
rb_define_private_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1);
rb_define_method(rb_klass, "rect", RUBY_METHOD_FUNC(rb_rect), 0);
rb_define_method(rb_klass, "color", RUBY_METHOD_FUNC(rb_color), 0);
rb_define_method(rb_klass, "color=", RUBY_METHOD_FUNC(rb_set_color), 1);
rb_define_method(rb_klass, "reserved", RUBY_METHOD_FUNC(rb_reserved), 0);
rb_define_method(rb_klass, "approx_poly", RUBY_METHOD_FUNC(rb_approx_poly), -1);
rb_define_alias(rb_klass, "approx", "approx_poly");
rb_define_method(rb_klass, "bounding_rect", RUBY_METHOD_FUNC(rb_bounding_rect), 0);
rb_define_method(rb_klass, "create_tree", RUBY_METHOD_FUNC(rb_create_tree), -1);
rb_define_method(rb_klass, "in?", RUBY_METHOD_FUNC(rb_in_q), 1);
rb_define_method(rb_klass, "measure_distance", RUBY_METHOD_FUNC(rb_measure_distance), 1);
rb_define_method(rb_klass, "point_polygon_test", RUBY_METHOD_FUNC(rb_point_polygon_test), 2);
}
__NAMESPACE_END_CVCONTOUR
__NAMESPACE_END_OPENCV