ext/spyglass/contour.cc in spyglass-0.0.2 vs ext/spyglass/contour.cc in spyglass-0.0.3
- old
+ new
@@ -9,11 +9,16 @@
ContourClass = rb_define_class_under(Spyglass::get_ruby_module(), "Contour", rb_cObject);
rb_define_alloc_func(ContourClass, rb_alloc);
rb_define_method(ContourClass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1);
// Instance methods
+ rb_define_method(ContourClass, "corners", RUBY_METHOD_FUNC(rb_get_corners), 0);
+ rb_define_method(ContourClass, "convex?", RUBY_METHOD_FUNC(rb_is_convex), 0);
rb_define_method(ContourClass, "rect", RUBY_METHOD_FUNC(rb_get_rect), 0);
+
+ // Aliases
+ rb_define_alias(ContourClass, "closed?", "convex?");
}
VALUE get_ruby_class() {
return ContourClass;
}
@@ -48,9 +53,60 @@
cv::Point *_point = new cv::Point(* SG_GET_POINT(point));
contour->push_back(_point);
}
return self;
+ }
+
+ static VALUE rb_get_corners(VALUE self) {
+ // This method is a bit of a misnomer in terms of how OpenCV works,
+ // seen as it's not a simple getter. It's implemented for ease of
+ // use. This code was blatantly based on:
+ //
+ // http://opencv-code.com/tutorials/automatic-perspective-correction-for-quadrilateral-objects/
+ std::vector<cv::Point> contour = to_value_vector(SG_GET_CONTOUR(self));
+ cv::approxPolyDP(contour, contour, cv::arcLength(cv::Mat(contour), true) * 0.02, true);
+ if (contour.size() != 4) {
+ // TODO: Throw exception here?
+ std::cout << "The object is not quadrilateral!" << std::endl;
+ return Qnil;
+ }
+
+ // Get mass center
+ cv::Point center(0,0);
+ for (int i = 0; i < contour.size(); i++)
+ center += contour[i];
+ center *= (1. / contour.size());
+
+ // Grab TL, TR, BL, and BR corners.
+ std::vector<cv::Point> top, bot;
+ for (int i = 0; i < contour.size(); i++) {
+ if (contour[i].y < center.y)
+ top.push_back(contour[i]);
+ else
+ bot.push_back(contour[i]);
+ }
+
+ cv::Point tl = top[0].x > top[1].x ? top[1] : top[0];
+ cv::Point tr = top[0].x > top[1].x ? top[0] : top[1];
+ cv::Point bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
+ cv::Point br = bot[0].x > bot[1].x ? bot[0] : bot[1];
+
+ contour.clear();
+ contour.push_back(tl);
+ contour.push_back(tr);
+ contour.push_back(br);
+ contour.push_back(bl);
+
+ return from_cvpoint_vector(contour);
+ }
+
+ static VALUE rb_is_convex(VALUE self) {
+ std::vector<cv::Point> contour = to_value_vector(SG_GET_CONTOUR(self));
+ std::vector<cv::Point> simplified;
+ cv::approxPolyDP(contour, simplified, cv::arcLength(cv::Mat(contour), true) * 0.02, true);
+
+ return cv::isContourConvex(simplified) ? Qtrue : Qfalse;
}
static VALUE rb_get_rect(VALUE self) {
std::vector<cv::Point *> *contour = SG_GET_CONTOUR(self);
cv::Rect rect = cv::boundingRect(to_value_vector(contour));