aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Villeret <avilleret@users.sourceforge.net>2012-12-26 19:54:45 +0000
committerAntoine Villeret <avilleret@users.sourceforge.net>2012-12-26 19:54:45 +0000
commit15c02439915a7a8757e8520b6a610163a72d6a80 (patch)
tree35c74b71fd125ec648ce2fca607f0cf5b3793516
parentad4e1e117491f61dafc998c47fb7ca3997990436 (diff)
add convexity defects ouput
add convexhull output add contours hierarchy svn path=/trunk/externals/pix_opencv/; revision=16759
-rw-r--r--pix_opencv_contours.cc304
-rw-r--r--pix_opencv_contours.h10
2 files changed, 252 insertions, 62 deletions
diff --git a/pix_opencv_contours.cc b/pix_opencv_contours.cc
index 2697fcb..6032d1b 100644
--- a/pix_opencv_contours.cc
+++ b/pix_opencv_contours.cc
@@ -33,7 +33,12 @@ CPPEXTERN_NEW(pix_opencv_contours)
// Constructor
//
/////////////////////////////////////////////////////////
-pix_opencv_contours :: pix_opencv_contours() : m_area_threshold(30)
+pix_opencv_contours :: pix_opencv_contours() : m_area_threshold(30), \
+ m_epsilon(2), \
+ m_enable_contours(1), \
+ m_enable_hulls(1), \
+ m_enable_defects(1), \
+ m_hierarchy_level(-1)
{
m_dataout_middle = outlet_new(this->x_obj, 0);
m_dataout_right = outlet_new(this->x_obj, 0);
@@ -72,87 +77,243 @@ void pix_opencv_contours :: processGrayImage(imageStruct &image)
cv::Mat imgMat2( image.ysize, image.xsize, CV_8UC1, image.data, image.csize*image.xsize); // just transform imageStruct to IplImage without copying data
- cv::Mat imgMat = imgMat2.clone();
+ cv::Mat imgMat = imgMat2.clone(); // copy data because findContours need it...
+
+ m_contours.clear();
+ m_convexhulls.clear();
+
+ /*****************/
+ /* Find Contours */
+ /*****************/
std::vector<std::vector<cv::Point> > contours;
- std::vector<cv::Point> one_contour;
+ std::vector<cv::Vec4i> hierarchy;
- contours.clear();
- m_contours.clear();
+ cv::findContours(imgMat, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
+
+ /*
+ std::cout << "hierarchy : \n" << std::endl;
+ std::cout << "id\tnext\tprev\tchild\tparent" << std::endl;
+ for ( size_t i = 0; i < contours.size(); i++ )
+ {
+ std::cout << i << "\t" << hierarchy[i][0] << "\t" << hierarchy[i][1] << "\t" << hierarchy[i][2] << "\t" << hierarchy[i][3] << std::endl;
+ }
+ */
+
+ if ( m_hierarchy_level != -1 )
+ {
+ int i=0;
+ int hierarchy_level=0;
+
+ while ( i < (int) contours.size() && i!=-1 && hierarchy_level != -1 )
+ {
+ if ( cv::contourArea(contours[i], false) > m_area_threshold && hierarchy_level == m_hierarchy_level )
+ {
+ std::vector<cv::Point> one_contour;
+ cv::approxPolyDP(contours[i], one_contour, m_epsilon, true);
+ m_contours.push_back(one_contour); // push contour if it's big enough
+ }
+ if ( hierarchy_level < m_hierarchy_level && hierarchy[i][2] != -1 ){ // si on n'a pas atteint le niveau choisi et qu'il y a un enfant on le prend
+ hierarchy_level++;
+ int j = i;
+ i=hierarchy[j][2]; // get the first child
+ } else if ( hierarchy[i][0] != -1 ) {
+ i=hierarchy[i][0]; // get the next contour at this hierarchy level if it exists
+ } else {
+ while ( hierarchy_level != -1 )
+ {
+ hierarchy_level--;
+ i=hierarchy[i][3];
+ if ( i < 0 ) break; // pas de parent...
+ if ( hierarchy[i][0] != -1 ) {
+ i=hierarchy[i][0]; // next du parent
+ break;
+ }
+ }
- cv::findContours(imgMat, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
+ }
+ }
+ } else {
+ for ( size_t i = 0; i < contours.size(); i++ )
+ {
+ if ( cv::contourArea(contours[i], false) > m_area_threshold ){
+ std::vector<cv::Point> one_contour;
+ cv::approxPolyDP(contours[i], one_contour, m_epsilon, true);
+ m_contours.push_back(one_contour);
+ }
+ }
+ }
+
+ if ( m_enable_contours )
+ {
+ t_atom*info;
+ info = new t_atom[(int) m_contours.size()*20+2];
+ // info : 20x(contour_nb) matrix
+ // info for each contour : area, rotrect corner (8 float), rotrect center, rotrect size, rotation angle, segments number, other are reserved for future use
+ int count(0);
+ SETFLOAT(info+1, 20.);
+ int info_offset(2);
- for( size_t i = 0; i < contours.size(); i++ ) {
- if ( cv::contourArea(contours[i], false) > m_area_threshold ){
- one_contour.clear();
- cv::approxPolyDP(contours[i], one_contour, m_epsilon, true);
- m_contours.push_back(one_contour);
+ for( size_t i = 0 ; i < m_contours.size(); i++ )
+ {
+ if (!m_contours[i].empty() && m_contours[i].size() > 2) {
+ SETFLOAT(info+info_offset, (float) cv::contourArea(m_contours[i]));
+
+ cv::RotatedRect rot_rect = cv::minAreaRect(m_contours[i]);
+ cv::Point2f corners[4];
+ rot_rect.points(corners);
+ for (int j=0;j<4;j++) {
+ SETFLOAT(info+info_offset+j*2+1, corners[j].x/image.xsize);
+ SETFLOAT(info+info_offset+j*2+2, corners[j].y/image.ysize);
+ }
+
+ SETFLOAT(info+info_offset+9, rot_rect.center.x/image.xsize);
+ SETFLOAT(info+info_offset+10, rot_rect.center.y/image.ysize);
+ SETFLOAT(info+info_offset+11, rot_rect.size.width/image.xsize);
+ SETFLOAT(info+info_offset+12, rot_rect.size.height/image.xsize);
+ SETFLOAT(info+info_offset+13, rot_rect.angle);
+ SETFLOAT(info+info_offset+14, m_contours[i].size()); // number of points in segment
+ SETFLOAT(info+info_offset+15, 0);
+ SETFLOAT(info+info_offset+16, 0);
+ SETFLOAT(info+info_offset+17, 0);
+ SETFLOAT(info+info_offset+18, 0);
+ SETFLOAT(info+info_offset+19, 0);
+
+ info_offset+=20;
+ count++;
+ }
}
+ SETFLOAT(info, (float) count);
+ if (count) outlet_anything(m_dataout_right, gensym("info"), count*20+2, info);
+ else outlet_float(m_dataout_right, 0);
+
+ for( size_t i = 0 ; i < m_contours.size() ; i++ )
+ {
+ if (!m_contours[i].empty() && m_contours[i].size() > 2) {
+ int size = 2+m_contours[i].size()*2;
+ t_atom*ap = new t_atom[size];
+ SETFLOAT(ap, static_cast<t_float>(m_contours[i].size()));
+ SETFLOAT(ap+1, 2.0);
+
+ int offset(2);
+
+ for ( size_t j = 0 ; j < m_contours[i].size() ; j++){
+ cv::Point pt = m_contours[i][j];
+ SETFLOAT(ap+offset,(float) pt.x/image.xsize);
+ SETFLOAT(ap+offset+1,(float) pt.y/image.ysize);
+ offset+=2;
+ }
+ outlet_anything(m_dataout_middle, gensym("contour"), size, ap);
+ if(ap)delete[]ap;ap=NULL;
+
+ }
+ }
+
+ if (info) delete info;
+ info = NULL;
}
+
//~ cv::drawContours(imgMat2, m_contours, -1, cv::Scalar(128,255,255), 3);
-
- t_atom*info;
- info = new t_atom[(int) m_contours.size()*20+2];
- // info : 20x(contour_nb) matrix
- // info for each contour : area, rotrect corner (8 float), rotrect center, rotrect size, rotation angle, segments number, other are reserved for future use
- int count(0);
- SETFLOAT(info+1, 20.);
- int info_offset(2);
- for( std::vector<std::vector<cv::Point> >::iterator it = m_contours.begin(); it != m_contours.end(); ++it ) {
- if (!it->empty() && it->size() > 2) {
- SETFLOAT(info+info_offset, (float) cv::contourArea(*it));
+ /**********************/
+ /* Compute Convexhull */
+ /**********************/
+ if ( m_enable_defects || m_enable_hulls )
+ {
+ for ( size_t i = 0; i < m_contours.size(); i++ )
+ {
+ std::vector<int> convexhull;
+ cv::convexHull(m_contours[i], convexhull);
+ m_convexhulls.push_back(convexhull);
+ }
+ }
+
+ if ( m_enable_hulls )
+ {
+ for ( size_t i = 0 ; i < m_convexhulls.size() ; i++ )
+ {
+ int list_size=(int) m_convexhulls[i].size()*2+2;
- cv::RotatedRect rot_rect = cv::minAreaRect(*it);
- cv::Point2f corners[4];
- rot_rect.points(corners);
- for (int j=0;j<4;j++) {
- SETFLOAT(info+info_offset+j*2+1, corners[j].x/image.xsize);
- SETFLOAT(info+info_offset+j*2+2, corners[j].y/image.ysize);
- }
+ t_atom* data = new t_atom[list_size];
+
+ SETFLOAT(data,m_convexhulls[i].size()); // nb of points for current convexhull
+ SETFLOAT(data+1, 2); // each point is represented by 2 values
+
+ t_atom* apt=data+2;
- SETFLOAT(info+info_offset+9, rot_rect.center.x/image.xsize);
- SETFLOAT(info+info_offset+10, rot_rect.center.y/image.ysize);
- SETFLOAT(info+info_offset+11, rot_rect.size.width/image.xsize);
- SETFLOAT(info+info_offset+12, rot_rect.size.height/image.xsize);
- SETFLOAT(info+info_offset+13, rot_rect.angle);
- SETFLOAT(info+info_offset+14, it->size()); // number of points in segment
- SETFLOAT(info+info_offset+15, 0);
- SETFLOAT(info+info_offset+16, 0);
- SETFLOAT(info+info_offset+17, 0);
- SETFLOAT(info+info_offset+18, 0);
- SETFLOAT(info+info_offset+19, 0);
+ for ( size_t j = 0 ; j < m_convexhulls[i].size() ; j++){
+ int k = m_convexhulls[i][j];
+ cv::Point pt = m_contours[i][k];
+ SETFLOAT(apt, (float) pt.x/image.xsize);
+ SETFLOAT(apt+1, (float) pt.y/image.ysize);
+ apt+=2;
+ }
+ outlet_anything(m_dataout_middle, gensym("convexhull"), list_size, data);
- info_offset+=20;
- count++;
+ if (data) delete data;
+ data = NULL;
}
}
- SETFLOAT(info, (float) count);
- if (count) outlet_anything(m_dataout_right, gensym("info"), count*20+2, info);
- else outlet_float(m_dataout_right, 0);
- for( std::vector<std::vector<cv::Point> >::iterator it = m_contours.begin(); it != m_contours.end(); ++it ) {
- if (!it->empty() && it->size() > 2) {
- int size = 2+it->size()*2;
- t_atom*ap = new t_atom[size];
- SETFLOAT(ap, static_cast<t_float>(it->size()));
- SETFLOAT(ap+1, 2.0);
+ /*****************************/
+ /* Compute convexity defects */
+ /*****************************/
+ if ( m_enable_defects )
+ {
+ for ( size_t i = 0 ; i < m_contours.size() ; i++ )
+ {
+ std::vector<cv::Vec4i> defects(m_convexhulls[i].size());
+
+ cv::Ptr<CvMemStorage> storage = cvCreateMemStorage();
+ cv::InputArray _points = m_contours[i];
+ cv::InputArray _hull = m_convexhulls[i];
+
+ cv::Mat points = _points.getMat();
+ cv::Mat hull = _hull.getMat();
- int offset(2);
+ CvMat c_points = points, c_hull = hull;
- for ( std::vector<cv::Point>::iterator ite=it->begin(); ite!=it->end(); ++ite){
- SETFLOAT(ap+offset,(float) (*ite).x/image.xsize);
- SETFLOAT(ap+offset+1,(float) (*ite).y/image.ysize);
- offset+=2;
+ CvSeq* seq = cvConvexityDefects(&c_points, &c_hull, storage);
+
+ double norm = sqrtf( image.xsize*image.ysize );
+
+ if ( !seq ) {
+ error("seq undefined...");
+ continue;
}
- outlet_anything(m_dataout_middle, gensym("contour"), size, ap);
- if(ap)delete[]ap;ap=NULL;
+ int list_size=(int) seq->total*7+2;
+
+ if (seq->total > 0)
+ {
+ t_atom* data = new t_atom[list_size];
+
+ SETFLOAT(data, seq->total); // number of defect for current contour
+ SETFLOAT(data+1, 7); // a defect is represented by 7 values : start point (x,y), end point (x,y), farthest point (x,y) and defect depth
+
+ cv::SeqIterator<CvConvexityDefect> it = cv::Seq<CvConvexityDefect>(seq).begin(); // TODO : crash sometimes but don't know why yet...
+ t_atom* apt = data+2;
+
+ for ( int j = 0 ; j < seq->total ; j++, ++it )
+ {
+ CvConvexityDefect& defect = *it;
+ SETFLOAT(apt, (float) defect.start->x/image.xsize);
+ SETFLOAT(apt+1, (float) defect.start->y/image.ysize);
+ SETFLOAT(apt+2, (float) defect.end->x/image.xsize);
+ SETFLOAT(apt+3, (float) defect.end->y/image.ysize);
+ SETFLOAT(apt+4, (float) defect.depth_point->x/image.xsize);
+ SETFLOAT(apt+5, (float) defect.depth_point->y/image.ysize);
+ SETFLOAT(apt+6, (float) defect.depth/norm);
+ apt+=7;
+ }
+
+ outlet_anything(m_dataout_middle, gensym("convexitydefects"), list_size, data);
+
+ if (data) delete data;
+ data = NULL;
+ }
}
}
-
- if (info) delete info;
- info = NULL;
}
/////////////////////////////////////////////////////////
@@ -163,6 +324,10 @@ void pix_opencv_contours :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG1(classPtr, "epsilon", epsilonMess, double);
CPPEXTERN_MSG1(classPtr, "area", areaMess, double);
+ CPPEXTERN_MSG1(classPtr, "contours", contoursMess, double);
+ CPPEXTERN_MSG1(classPtr, "convexhulls", convexhullsMess, double);
+ CPPEXTERN_MSG1(classPtr, "convexitydefects", convexitydefectsMess, double);
+ CPPEXTERN_MSG1(classPtr, "hierarchy_level", hierarchyMess, double);
}
/////////////////////////////////////////////////////////
@@ -183,3 +348,20 @@ void pix_opencv_contours :: areaMess(double arg)
SETFLOAT(&data_out, (float) m_area_threshold);
outlet_anything( m_dataout_right, gensym("area"), 1, &data_out);
}
+void pix_opencv_contours :: contoursMess(double arg)
+{
+ m_enable_contours = arg > 0;
+}
+void pix_opencv_contours :: convexhullsMess(double arg)
+{
+ m_enable_hulls = arg > 0;
+}
+void pix_opencv_contours :: convexitydefectsMess(double arg)
+{
+ m_enable_defects = arg > 0;
+}
+void pix_opencv_contours :: hierarchyMess(double arg)
+{
+ m_hierarchy_level = arg < -1 ? -1 : arg;
+ m_mode = m_hierarchy_level == -1 ? CV_RETR_LIST : CV_RETR_TREE;
+}
diff --git a/pix_opencv_contours.h b/pix_opencv_contours.h
index 5882b5a..fb1ebe1 100644
--- a/pix_opencv_contours.h
+++ b/pix_opencv_contours.h
@@ -61,14 +61,22 @@ class GEM_EXTERN pix_opencv_contours : public GemPixObj
// Messages handling
void epsilonMess(double arg);
void areaMess(double arg);
+ void contoursMess(double arg);
+ void convexhullsMess(double arg);
+ void convexitydefectsMess(double arg);
+ void hierarchyMess(double arg);
private:
t_outlet *m_dataout_middle; // contour outlet
t_outlet *m_dataout_right; // info outlet
- std::vector<std::vector<cv::Point> > m_contours;
+ std::vector<std::vector<cv::Point> > m_contours;
+ std::vector<std::vector<int> > m_convexhulls;
+ //~ std::vector<cv::Vec4i> m_hierarchy;
double m_area_threshold; // min area for contour
double m_epsilon;
+
+ int m_enable_contours, m_enable_hulls, m_enable_defects, m_hierarchy_level, m_mode;
};
#endif // for header file