aboutsummaryrefslogtreecommitdiff
path: root/pix_opencv_contours.cpp
blob: 0632c57d50bbf6c5e449ae7b13474d1652cf85a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
////////////////////////////////////////////////////////
//
// 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_contours.h"
#include <stdio.h>
#include <RTE/MessageCallbacks.h>


CPPEXTERN_NEW(pix_opencv_contours)

/////////////////////////////////////////////////////////
//
// pix_opencv_contours
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
pix_opencv_contours :: pix_opencv_contours() : m_area_threshold(30)
{ 
	m_dataout_middle = outlet_new(this->x_obj, 0);
	m_dataout_right = outlet_new(this->x_obj, 0);

	//~ post("build on %s at %s", __DATE__, __TIME__);
}

/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
pix_opencv_contours :: ~pix_opencv_contours()
{ 
}

/////////////////////////////////////////////////////////
// processImage
//
/////////////////////////////////////////////////////////
void pix_opencv_contours :: processRGBAImage(imageStruct &image)
{ 
	error( "pix_opencv_contours : rgba format not supported" );
}

void pix_opencv_contours :: processRGBImage(imageStruct &image) {
	error( "pix_opencv_contours : rgb format not supported");
}

void pix_opencv_contours :: processYUVImage(imageStruct &image) {
	error( "pix_opencv_contours : yuv format not supported" );
}
    	
void pix_opencv_contours :: processGrayImage(imageStruct &image)
{ 
	if ( image.xsize < 0 || image.ysize < 0 ) return;

	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();
		
	std::vector<std::vector<cv::Point> > contours;
	std::vector<cv::Point> one_contour;		

	contours.clear();
	m_contours.clear();

	cv::findContours(imgMat, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
		
	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);
		}
	}
	//~ cv::drawContours(imgMat2, m_contours, -1, cv::Scalar(128,255,255), 3);

	t_atom*info;
	info = new t_atom[(int) m_contours.size()*14+2];
	// info : 14x(contour_nb) matrix
	// info for each contour : area, rotrect corner (8 float), rotrect center, rotrect size, rotation angle
	int count(0);
	SETFLOAT(info+1, 14.);
	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));
			
			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);
			}

			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);
			
			info_offset+=14;
			count++;
		}
	}
	SETFLOAT(info, (float) count);
	if (count) outlet_anything(m_dataout_right, gensym("info"), count*14+2, info);
	else outlet_list(m_dataout_right, gensym("info"), 1, 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);
			
			int offset(2);
			
			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;
			}
			outlet_anything(m_dataout_middle, gensym("contour"), size, ap);
			if(ap)delete[]ap;ap=NULL;	
			
		}
	}
	
	if (info) delete info;
	info = NULL;
}

/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void pix_opencv_contours :: obj_setupCallback(t_class *classPtr)
{
	CPPEXTERN_MSG1(classPtr, "epsilon",	epsilonMess, 		double);		    		  	  
	CPPEXTERN_MSG1(classPtr, "area",	areaMess, 			double);		    		  	  
}

/////////////////////////////////////////////////////////
// messages handling
//
/////////////////////////////////////////////////////////
void pix_opencv_contours :: epsilonMess(double arg)
{
	m_epsilon = arg > 0 ? arg : 3.;
	t_atom data_out;
	SETFLOAT(&data_out, (float) m_epsilon);
	outlet_anything( m_dataout_right, gensym("epsilon"), 1, &data_out);
}
void pix_opencv_contours :: areaMess(double arg)
{
	m_area_threshold = arg > 0 ? arg : 30.;
	t_atom data_out;
	SETFLOAT(&data_out, (float) m_area_threshold);
	outlet_anything( m_dataout_right, gensym("area"), 1, &data_out);
}