aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Villeret <avilleret@users.sourceforge.net>2012-09-22 15:09:44 +0000
committerAntoine Villeret <avilleret@users.sourceforge.net>2012-09-22 15:09:44 +0000
commit841e92c1821ee54a92597ede38182565f24f2a87 (patch)
tree87653468bb01067d7c4819116077be66cd844cb3
parent221b44fc5ef260674bf856e02a1b0a33403794f6 (diff)
add a shape matcher for shape recognition
svn path=/trunk/externals/pix_opencv/; revision=16266
-rw-r--r--pix_opencv_matchshape-help.pd103
-rw-r--r--pix_opencv_matchshape.cpp221
-rw-r--r--pix_opencv_matchshape.h73
3 files changed, 397 insertions, 0 deletions
diff --git a/pix_opencv_matchshape-help.pd b/pix_opencv_matchshape-help.pd
new file mode 100644
index 0000000..be53c23
--- /dev/null
+++ b/pix_opencv_matchshape-help.pd
@@ -0,0 +1,103 @@
+#N canvas 216 165 968 473 10;
+#X obj 477 6 cnv 15 480 460 empty empty empty 20 12 0 14 -228992 -66577
+0;
+#X obj 20 75 cnv 15 450 200 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#X obj 21 326 cnv 15 450 140 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#X text 22 331 Inlets:;
+#X obj 21 286 cnv 15 450 30 empty empty empty 20 12 0 14 -195568 -66577
+0;
+#X text 30 285 Arguments:;
+#X text 22 400 Outlets:;
+#X obj 491 41 cnv 15 460 310 empty empty empty 20 12 0 14 -24198 -66577
+0;
+#X obj 501 326 pix_opencv_matchshape;
+#X obj 501 14 gemhead;
+#X obj 501 377 pix_texture;
+#X obj 501 398 rectangle 4 3;
+#X msg 570 103 contour 4 2 0 0 0 1 1 1 1 0;
+#X msg 556 239 method \$1;
+#X floatatom 556 217 5 0 0 0 - - -;
+#X msg 580 153 template 4 2 0 0 0 1 1 1 1 0;
+#X msg 590 173 template 4 2 2 0 4 1 1 1 1 0;
+#X msg 560 83 contour 6 2 0 0 0 1 1 1 1 0 -0.5 -0.5;
+#X floatatom 556 267 5 0 0 0 - - -;
+#X msg 556 287 threshold \$1;
+#X msg 550 64 contour 4 2 2 0 4 1 1 1 1 0;
+#X obj 624 357 route match_vec template_vec;
+#X obj 624 407 unpack;
+#X text 631 390 found corresponding contour;
+#X floatatom 624 435 5 0 0 0 - - -;
+#X floatatom 659 435 5 0 0 0 - - -;
+#X text 623 448 id;
+#X text 659 448 absolute difference from template;
+#X floatatom 706 378 5 0 0 0 - - -;
+#X text 740 375 number of loaded contour;
+#X text 593 213 method to compare shape (1 \, 2 or 3 \, please refer
+to OpenCV doc for details);
+#X text 37 193 This external uses cv::matchShapes function. Documentation
+is here : http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=matchshapes#matchshapes
+;
+#X text 588 266 threshold behind wich a shape is recognized;
+#X text 575 135 template message add a template to library;
+#X text 549 46 contour message compare the contour to each loaded contour
+;
+#X text 37 103 [pix_opencv_matchshape] compares input images or input
+contours to a library of images (or contours). It sends out the id
+of the closest found behind a threshold.;
+#X text 37 143 You can use pix_opencv_contour_convexhull2 to find all
+contours in the image and send them to pix_opencv_matchshape to recognize
+it.;
+#X text 20 79 Description: compares shapes;
+#X text 45 24 Synopsis: [pix_opencv_matchshape];
+#X text 67 40 Class: pix_opencv;
+#X text 76 296 none;
+#X text 40 353 Inlet 1: message: template <list of points>;
+#X text 40 363 Inlet 1: message: contour <list of points>;
+#X text 40 373 Inlet 1: message: method <float>;
+#X text 40 383 Inlet 1: message: threshold <float>;
+#X text 34 413 Outlet 1: input image;
+#X text 40 343 Inlet 1: image;
+#X obj 364 368 cnv 15 100 60 empty empty empty 20 12 0 14 -195568 -66577
+0;
+#N canvas 0 0 450 300 gemwin 0;
+#X obj 132 136 gemwin;
+#X obj 67 89 outlet;
+#X obj 67 10 inlet;
+#X obj 67 41 route create;
+#X msg 67 70 set destroy;
+#X msg 142 68 set create;
+#X msg 198 112 destroy;
+#X msg 132 112 create \, 1;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 3 0 7 0;
+#X connect 3 1 5 0;
+#X connect 3 1 6 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X restore 369 407 pd gemwin;
+#X msg 369 388 create;
+#X text 365 367 Create window:;
+#X connect 8 0 10 0;
+#X connect 8 1 21 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 12 0 8 0;
+#X connect 13 0 8 0;
+#X connect 14 0 13 0;
+#X connect 15 0 8 0;
+#X connect 16 0 8 0;
+#X connect 17 0 8 0;
+#X connect 18 0 19 0;
+#X connect 19 0 8 0;
+#X connect 20 0 8 0;
+#X connect 21 0 22 0;
+#X connect 21 1 28 0;
+#X connect 22 0 24 0;
+#X connect 22 1 25 0;
+#X connect 48 0 49 0;
+#X connect 49 0 48 0;
diff --git a/pix_opencv_matchshape.cpp b/pix_opencv_matchshape.cpp
new file mode 100644
index 0000000..75dc910
--- /dev/null
+++ b/pix_opencv_matchshape.cpp
@@ -0,0 +1,221 @@
+////////////////////////////////////////////////////////
+//
+// GEM - Graphics Environment for Multimedia
+//
+// zmoelnig@iem.kug.ac.at
+//
+// Implementation file
+//
+// Copyright (c) 1997-2000 Mark Danks.
+// Copyright (c) Günther Geiger.
+// Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM
+// Copyright (c) 2002 James Tittle & Chris Clepper
+// For information on usage and redistribution, and for a DISCLAIMER OF ALL
+// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
+//
+/////////////////////////////////////////////////////////
+// based on code written by Lluis Gomez i Bigorda ( lluisgomez _at_ hangar _dot_ org ) (pix_opencv)
+// Template for pix_opencv class
+
+#include "pix_opencv_matchshape.h"
+#include <stdio.h>
+#include <RTE/MessageCallbacks.h>
+
+using namespace std;
+
+
+CPPEXTERN_NEW(pix_opencv_matchshape)
+
+/////////////////////////////////////////////////////////
+//
+// pix_opencv_matchshape
+//
+/////////////////////////////////////////////////////////
+// Constructor
+//
+/////////////////////////////////////////////////////////
+pix_opencv_matchshape :: pix_opencv_matchshape() : m_threshold(2), m_method(CV_CONTOURS_MATCH_I1)
+{
+ m_dataout = outlet_new(this->x_obj, 0);
+ m_template_vec_vec.clear();
+ m_template_vec_mat.clear();
+}
+
+/////////////////////////////////////////////////////////
+// Destructor
+//
+/////////////////////////////////////////////////////////
+pix_opencv_matchshape :: ~pix_opencv_matchshape()
+{
+}
+
+/////////////////////////////////////////////////////////
+// processImage
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_matchshape :: processRGBAImage(imageStruct &image)
+{
+ error( "pix_opencv_matchshape : rgba format not supported" );
+}
+
+void pix_opencv_matchshape :: processRGBImage(imageStruct &image) {
+ error( "pix_opencv_matchshape : rgb format not supported");
+}
+
+void pix_opencv_matchshape :: processYUVImage(imageStruct &image)
+{
+ error( "pix_opencv_matchshape : yuv format not supported" );
+}
+
+void pix_opencv_matchshape :: processGrayImage(imageStruct &image)
+{
+ error( "pix_opencv_matchshape : gray format not supported" );
+ error( "pix_opencv_matchshape only works on pd lists" );
+
+ // TODO add support to compare grayscale images
+}
+
+/////////////////////////////////////////////////////////
+// static member function
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_matchshape :: obj_setupCallback(t_class *classPtr)
+{
+ CPPEXTERN_MSG0(classPtr, "clear", clearMess);
+ CPPEXTERN_MSG(classPtr, "template", templateMess);
+ CPPEXTERN_MSG(classPtr, "contour", contourMess);
+ CPPEXTERN_MSG1(classPtr, "threshold", thresholdMess, float);
+ CPPEXTERN_MSG1(classPtr, "method", methodMess, int);
+}
+
+void pix_opencv_matchshape :: clearMess(void)
+{
+ for ( vector<vector<cv::Point2f> >::iterator it=m_template_vec_vec.end(); it!=m_template_vec_vec.begin(); it--)
+ {
+ (*it).clear();
+ }
+ m_template_vec_vec.clear();
+ m_template_vec_mat.clear();
+
+ t_atom data;
+ SETFLOAT(&data, (float)m_template_vec_vec.size());
+ outlet_anything(m_dataout, gensym("template_vec"), 1, &data);
+
+ SETFLOAT(&data, (float)m_template_vec_mat.size());
+ outlet_anything(m_dataout, gensym("template_mat"), 1, &data);
+}
+
+
+void pix_opencv_matchshape :: contourMess(t_symbol*s, int argc, t_atom*argv)
+{
+ if ( m_template_vec_vec.empty() ){
+ error("no template to match, please load a template before matching");
+ return;
+ }
+
+ if ( (argc%2)!=0 ) {
+ error("template message argument should be multiple of 2");
+ return;
+ }
+
+ for (int i=0;i<argc;i++){
+ if(argv[i].a_type!=A_FLOAT){
+ error("template message should have only float arguments");
+ return;
+ }
+ }
+
+ vector<cv::Point2f> tmp_contour;
+ for (int i=2;i<argc;i+=2){ // start at index 2, first two elements are reserved (for compatibility)
+ cv::Point2f pt;
+ pt.x = atom_getfloat(argv+i);
+ pt.y = atom_getfloat(argv+i+1);
+ tmp_contour.push_back(pt);
+ }
+
+ double comp, min(99999999999.);
+ int id(0),i(0);
+ for ( vector<vector<cv::Point2f> >::iterator it=m_template_vec_vec.begin(); it!=m_template_vec_vec.end(); ++it){
+ comp = cv::matchShapes(tmp_contour, *it, m_method, 0.);
+ if ( comp < min ){
+ min=comp;
+ id=i;
+ }
+ i++;
+ }
+
+ if ( min < m_threshold )
+ {
+ t_atom data[2];
+ SETFLOAT(data,id);
+ SETFLOAT(data+1, min);
+ outlet_anything(m_dataout, gensym("match_vec"), 2, data);
+ }
+}
+
+void pix_opencv_matchshape :: templateMess(t_symbol*s, int argc, t_atom*argv)
+{
+ if ( (argc%2)!=0 ) {
+ error("template message argument should be multiple of 2");
+ return;
+ }
+ for (int i=0;i<argc;i++){
+ if(argv[i].a_type!=A_FLOAT){
+ error("template message should have only float arguments");
+ return;
+ }
+ }
+
+ vector<cv::Point2f> tmp_contour;
+ tmp_contour.clear();
+ for (int i=2;i<argc;i+=2){ // start at index 2, first two elements are reserved (for compatibility)
+ cv::Point2f pt;
+ pt.x = atom_getfloat(argv+i);
+ pt.y = atom_getfloat(argv+i+1);
+ tmp_contour.push_back(pt);
+ }
+ m_template_vec_vec.push_back(tmp_contour);
+
+ t_atom data;
+ SETFLOAT(&data, (int)m_template_vec_vec.size());
+ outlet_anything(m_dataout, gensym("template_vec"), 1, &data);
+}
+
+void pix_opencv_matchshape :: thresholdMess(float arg)
+{
+ m_threshold=(double)(arg>0.?arg:0.);
+ t_atom data;
+ SETFLOAT(&data, m_threshold);
+ outlet_anything(m_dataout, gensym("threshold"), 1, &data);
+}
+
+void pix_opencv_matchshape :: methodMess(int arg)
+{
+ switch (arg) {
+ case 1:
+ m_method=CV_CONTOURS_MATCH_I1;
+ break;
+ case 2:
+ m_method=CV_CONTOURS_MATCH_I2;
+ break;
+ case 3:
+ m_method=CV_CONTOURS_MATCH_I3;
+ break;
+ default:
+ error("method should be 1, 2 or 3");
+ m_method=CV_CONTOURS_MATCH_I1;
+ }
+ t_atom data;
+ switch (m_method) {
+ case CV_CONTOURS_MATCH_I1:
+ SETFLOAT(&data, 1);
+ break;
+ case CV_CONTOURS_MATCH_I2:
+ SETFLOAT(&data, 2);
+ break;
+ case CV_CONTOURS_MATCH_I3:
+ SETFLOAT(&data, 3);
+ break;
+ }
+ outlet_anything(m_dataout, gensym("method"), 1, &data);
+}
diff --git a/pix_opencv_matchshape.h b/pix_opencv_matchshape.h
new file mode 100644
index 0000000..9fc971b
--- /dev/null
+++ b/pix_opencv_matchshape.h
@@ -0,0 +1,73 @@
+/*-----------------------------------------------------------------
+LOG
+ GEM - Graphics Environment for Multimedia
+
+ Threshold filter
+
+ Copyright (c) 1997-1999 Mark Danks. mark@danks.org
+ Copyright (c) Günther Geiger. geiger@epy.co.at
+ Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM. zmoelnig@iem.kug.ac.at
+ Copyright (c) 2002 James Tittle & Chris Clepper
+ For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
+
+-----------------------------------------------------------------*/
+
+#ifndef INCLUDE_PIX_OPENCV_MATCHSHAPE_H_
+#define INCLUDE_PIX_OPENCV_MATCHSHAPE_H_
+
+#ifndef _EiC
+#include "cv.h"
+#endif
+
+#include "Base/GemPixObj.h"
+
+/*-----------------------------------------------------------------
+-------------------------------------------------------------------
+CLASS
+ pix_opencv_matchshape
+
+ square pattern detector
+
+KEYWORDS
+ pix
+
+DESCRIPTION
+
+-----------------------------------------------------------------*/
+class GEM_EXTERN pix_opencv_matchshape : public GemPixObj
+{
+ CPPEXTERN_HEADER(pix_opencv_matchshape, GemPixObj)
+
+ public:
+
+ // Constructor
+ pix_opencv_matchshape();
+
+ protected:
+ // process messages
+ void clearMess(void);
+ void templateMess(t_symbol*s, int argc, t_atom*argv);
+ void contourMess(t_symbol*s, int argc, t_atom*argv);
+ void thresholdMess(float arg);
+ void methodMess(int arg);
+
+ // Destructor
+ virtual ~pix_opencv_matchshape();
+
+ // Do the processing
+ virtual void processRGBAImage(imageStruct &image);
+ virtual void processRGBImage(imageStruct &image);
+ virtual void processYUVImage(imageStruct &image);
+ virtual void processGrayImage(imageStruct &image);
+
+ private:
+
+ t_outlet *m_dataout; // info outlet
+ double m_threshold;
+ int m_method;
+ std::vector<std::vector<cv::Point2f> > m_template_vec_vec;
+ std::vector<cv::Mat> m_template_vec_mat;
+
+};
+#endif // for header file