v0.3.9b:
[mldemos:baraks-mldemos.git] / _IOPlugins / CSVImport / basicOpenCV.h
1 /*********************************************************************\r
2 MLDemos: A User-Friendly visualization toolkit for machine learning\r
3 Copyright (C) 2010  Basilio Noris\r
4 Contact: mldemos@b4silio.com\r
5 \r
6 This library is free software; you can redistribute it and/or\r
7 modify it under the terms of the GNU Lesser General Public License,\r
8 version 3 as published by the Free Software Foundation.\r
9 \r
10 This library is distributed in the hope that it will be useful, but\r
11 WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
13 Lesser General Public License for more details.\r
14 \r
15 You should have received a copy of the GNU Lesser General Public\r
16 License along with this library; if not, write to the Free\r
17 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
18 *********************************************************************/\r
19 #ifndef _BASICOPENCV_H_\r
20 #define _BASICOPENCV_H_\r
21 \r
22 #include "public.h"\r
23 #include <vector>\r
24 #ifdef OPENCV22\r
25 #include <opencv2/imgproc/imgproc.hpp>\r
26 #include <opencv2/features2d/features2d.hpp>\r
27 #include <opencv2/video/tracking.hpp>\r
28 #include <opencv2/ml/ml.hpp>\r
29 #include <opencv2/highgui/highgui.hpp>\r
30 #include <opencv2/legacy/legacy.hpp>\r
31 #include <opencv2/legacy/compat.hpp>\r
32 #else\r
33 #include <opencv/cv.h>\r
34 #include <opencv/cxcore.h>\r
35 #include <opencv/cvaux.h>\r
36 #include <opencv/ml.h>\r
37 #include <opencv/highgui.h>\r
38 #endif\r
39 \r
40 /* computes the point corresponding to a certain angle on an input image */\r
41 #define calc_point(img, angle)                                      \\r
42     cvPoint( cvRound(img->width/2 + img->width/3*cos(angle)),           \\r
43                 cvRound(img->height/2 - img->width/3*sin(angle)))\r
44 \r
45 /* plot points */\r
46 #define draw_cross(img, center, color, d )                                                                              \\r
47     cvLine( img, cvPoint( center.x - d, center.y - d ),                                                 \\r
48                     cvPoint( center.x + d, center.y + d ), color, 1, CV_AA, 0); \\r
49     cvLine( img, cvPoint( center.x + d, center.y - d ),                                                 \\r
50                     cvPoint( center.x - d, center.y + d ), color, 1, CV_AA, 0 )\r
51 /* draws a plus */\r
52 #define draw_plus(img, center, color, d )                                       \\r
53         cvLine( img, cvPoint( center.x - d, center.y),                  \\r
54                 cvPoint( center.x + d, center.y), color, 1, 0 );        \\r
55         cvLine( img, cvPoint( center.x, center.y - d ),                 \\r
56                 cvPoint( center.x, center.y + d ), color, 1, 0 )\r
57 \r
58 void cvDrawRect(IplImage *img, CvRect rect, CvScalar color=CV_RGB(0,0,255), int thickness=1, int line_type=8, int shift=0);\r
59 void cvDrawGradient(IplImage *image, CvRect rect, CvScalar color1, CvScalar color2, bool vertical=true);\r
60 \r
61 class BasicOpenCV\r
62 {\r
63 public:\r
64         static const CvScalar color [22];\r
65         static const u32 colorCnt = 22;\r
66 \r
67         static IplImage *Rotate(IplImage *src, float angle);\r
68         static IplImage *Rotate90(IplImage *src, u32 direction=0);\r
69         static void integralImage(const IplImage *image, IplImage **intimage);\r
70         static u32 GetSum(IplImage *integral, CvRect rect);\r
71         static u32 GetSum(IplImage *integral, int x, int y, int w, int h);\r
72         static void cvCopyFlipped(IplImage *src, IplImage *dst);\r
73         static void DisplayHueSatHist(IplImage* src);\r
74         static void CreateHistogramImage(IplImage *src, IplImage *dst, int bins=256, int channels=0);\r
75         static void RGB2NCC(IplImage *image, IplImage *red, IplImage *green);\r
76         static void BinaryMedian(IplImage *src, IplImage *dst);\r
77         static void RemoveNoise(IplImage * src);\r
78         static IplImage *Deinterlace(IplImage *image);\r
79         static IplImage *GetField(IplImage *image, u32 field);\r
80         static IplImage *Half2Full(IplImage *image);\r
81         static void Half2Full(IplImage *src, IplImage *dst);\r
82         static IplImage *Half2Demi(IplImage *image);\r
83         static void Half2Demi(IplImage *src, IplImage *dst);\r
84         static IplImage *Half(IplImage *src);\r
85         static void Half(IplImage **src);\r
86         static IplImage *Resize(IplImage *src, CvSize size);\r
87         static void Resize(IplImage **src,CvSize size);\r
88         static void ChannelSubtraction(IplImage *src , IplImage *dst, u32 first, u32 second);\r
89         static void Divide(IplImage *img1, IplImage *img2 );\r
90         static IplImage *Crop(IplImage *image,CvRect selection);\r
91         static int otsuThreshold(CvMat* prob, CvHistogram* hist);\r
92         static float MaximizeSquare(IplImage *image, int *x, int *y, int *s);\r
93 \r
94         static IplImage *BoxPlot(std::vector<float> data, float maxVal=-FLT_MAX, float minVal=FLT_MAX);\r
95         static IplImage *BoxPlot(std::vector<std::vector<float> > data, float maxVal=-FLT_MAX, float minVal=FLT_MAX);\r
96 };\r
97 \r
98 typedef BasicOpenCV CV;\r
99 \r
100 namespace BasicML\r
101 {\r
102         //returns the index corresponding to the minimal value \r
103         static int smallest(s32 values[], u32 length){\r
104                 s32 minValue = values[0];\r
105                 u32 minIndex = 0;\r
106                 FOR(i, length){\r
107                         if (values[i] < minValue){\r
108                                 minIndex = i;\r
109                                 minValue = values[i];\r
110                         }\r
111                 }\r
112                 return minIndex;\r
113         }\r
114 \r
115         // returns the mean for the specified cluster\r
116         static CvPoint mean(CvPoint3D32f points[], int length, int cluster){\r
117                 CvPoint mean = cvPoint(0,0);\r
118                 int nbPointInCluster = 0;\r
119                 for (int i=0; i<length; i++){\r
120                         if((int)points[i].z == cluster){\r
121                                 mean.x += (int)points[i].x;\r
122                                 mean.y += (int)points[i].y;\r
123                                 nbPointInCluster++;\r
124                         }\r
125                 }\r
126 \r
127                 // if a cluster has one or more point(s), change the cluster's mean\r
128                 if (nbPointInCluster){\r
129                         mean.x /= nbPointInCluster;\r
130                         mean.y /= nbPointInCluster;\r
131                 }\r
132                 return mean;\r
133         }\r
134 \r
135         /**\r
136           * performs the K-mean clustering algorithm\r
137           *\r
138           * @param points[] : each element of this array is a 3-uple (x,y,c), where\r
139           *                   x,y are the coordinate of the point, and c the cluster\r
140           *                   the point belongs to.\r
141           *                   the c component can be initialized randomly and will be changed by the algo\r
142           * @param numberOfPoints : number of point to be clustered (i.e number of points\r
143           *                         corresponding to skin color (in our case)\r
144           * @param nbCluster :      number of clusters. Min 1, Max 3\r
145           * @param xmax :           max value for the x coordinate (i.e image's width)\r
146           * @param ymax :           max value for the y coordinate (i.e image's height)\r
147           *\r
148           */\r
149         #define squareNorm(p1, p2) ((int)p1.x-p2.x)*((int)p1.x-p2.x) + ((int)p1.y-p2.y)*((int)p1.y-p2.y)\r
150 \r
151         static CvPoint *KmeansClustering(CvPoint3D32f points[],u32 length, u32 nbCluster, s32 xmax, s32 ymax){\r
152                 const s32 maxInt = 2^32-1;\r
153 \r
154                 // contains the means for each cluster\r
155                 CvPoint *means = new CvPoint[nbCluster];\r
156 \r
157                 // mean of the current cluster\r
158                 CvPoint currentMean;\r
159 \r
160                 // has one point moved from one cluster to another ?\r
161                 bool atLeastOneChange=true;\r
162 \r
163                 // contains the "distance" (i.e d*d) from the current point to each cluster\r
164                 s32 *currentSquareDistance = new s32[nbCluster];\r
165 \r
166 \r
167                 // Random number generation for initial means of clusters\r
168                 srand((u32)(cvGetTickCount()/cvGetTickFrequency()/10000000.0));\r
169 \r
170                 //initialize the means randomly\r
171                 \r
172                 FOR(i, nbCluster){\r
173                         currentMean.x=rand()%xmax;\r
174                         currentMean.y=rand()%ymax;\r
175                         means[i]=(currentMean);\r
176                 }\r
177 \r
178                 FOR(k, nbCluster){\r
179                         currentSquareDistance[k]=maxInt;\r
180                 }\r
181 \r
182                 while(atLeastOneChange){\r
183                         atLeastOneChange=false;\r
184                         //classify the points into clusters\r
185                         FOR(i, length){\r
186                                 FOR(j,nbCluster){\r
187                                         currentSquareDistance[j]=squareNorm(points[i], means[j]);\r
188                                 }\r
189                                 if (points[i].z != (f32)smallest(currentSquareDistance,nbCluster)){\r
190                                         atLeastOneChange=true;\r
191                                         points[i].z = (f32)smallest(currentSquareDistance,nbCluster);\r
192                                 }\r
193                         }\r
194                         //calculate the mean of each cluster\r
195                         FOR(k,nbCluster){\r
196                                 means[k]=mean(points, length,k);\r
197                         }\r
198                 }\r
199                 return means;\r
200         }\r
201 \r
202         static CvPoint *KMeans(IplImage *image, u32 clusterCount)\r
203         {\r
204                 if(!image ||image->nChannels != 1) return NULL;\r
205 \r
206                 cvMorphologyEx(image, image, 0, 0, CV_MOP_CLOSE,2);\r
207                 u32 width = image->width;\r
208                 u32 height = image->height;\r
209                 CvPoint3D32f *points = new CvPoint3D32f[width*height];\r
210                 u32 pointsCount = 0;\r
211 \r
212                 FOR(i,height){\r
213                         FOR(j,width){\r
214                                 if ((uchar)image->imageData[i*width+j]){\r
215                                         points[pointsCount++] = cvPoint3D32f(j,i,0);\r
216                                 }\r
217                         }\r
218                 }\r
219                 CvPoint *clusters = KmeansClustering(points, pointsCount, clusterCount, width, height);\r
220                 //FOR(i,pointsCount)\r
221                         //RGB(image, u32(points[i].y*width + points[i].x)) = ((u32)points[i].z + 1)*255/(clusterCount+1);\r
222                 delete points;\r
223                 return clusters;\r
224         }\r
225 \r
226         #ifndef EIGEN_STRUCT\r
227         #define EIGEN_STRUCT\r
228         typedef struct{\r
229                  CvPoint2D32f e1;\r
230                  CvPoint2D32f e2;\r
231                  CvPoint2D32f lambda;\r
232                  CvPoint2D32f mean;\r
233                  //f32 l1;\r
234                  //f32 l2;\r
235                  //f32 mean.x;\r
236                  //f32 mean.y;\r
237         } Eigen;\r
238         #endif // EIGEN_STRUCT\r
239 \r
240         /**\r
241           *   PCA over the CbCr space using calibration data.\r
242           *\r
243           *       @return :          eigenvectors (e1 & e2), cooresponding eigenvalues (l1 & l2) \r
244           *                      and the center of mass of distribution (mean.x & mean.y)\r
245           */\r
246 \r
247         static Eigen PCA(CvPoint2D32f points[], u32 nbPoints){\r
248                 CvPoint2D32f mean = cvPoint2D32f(0,0);\r
249 \r
250                 //the covariance matrix\r
251                 f32 c0[2][2];   \r
252 \r
253                 FOR(i, nbPoints){\r
254                         mean.y+=points[i].x;\r
255                         mean.x+=points[i].y;\r
256                 }\r
257                 mean.y/=(f32)nbPoints;\r
258                 mean.x/=(f32)nbPoints;\r
259 \r
260                 //initialisation\r
261                 FOR(i,2)\r
262                         FOR(j,2)\r
263                                 c0[i][j]=0.0;\r
264 \r
265                 //CbCb (variance of Cb)\r
266                 FOR(i,nbPoints)\r
267                         c0[0][0]+=(points[i].x-mean.x)*(points[i].x-mean.x);\r
268                 c0[0][0]/=(f32)nbPoints;\r
269 \r
270                 //CbCr (covariance of Cb-Cr = covariance Cr-Cb)\r
271                 c0[0][1] = 0.0;\r
272                 FOR(i, nbPoints)\r
273                         c0[0][1]+=(points[i].x-mean.x)*(points[i].y-mean.y);\r
274                 c0[0][1]/=(f32)nbPoints;\r
275 \r
276                 c0[1][0] = c0[0][1];\r
277 \r
278                 //CrCr (variance of Cr)\r
279                 FOR(i, nbPoints)\r
280                         c0[1][1]+=(points[i].y-mean.y)*(points[i].y-mean.y);\r
281                 c0[1][1]/=(f32)nbPoints;\r
282 \r
283                 f32 determinant = (c0[1][1]+c0[0][0])*(c0[1][1]+c0[0][0])-4.0f*(c0[0][0]*c0[1][1]-c0[1][0]*c0[0][1]);\r
284                 CvPoint2D32f eig = cvPoint2D32f(0,0);\r
285 \r
286                 if (determinant > 0){\r
287                         eig.x= (c0[1][1]+c0[0][0]+sqrtf(determinant))/2.0f;\r
288                         eig.y= (c0[1][1]+c0[0][0]-sqrtf(determinant))/2.0f;\r
289                 }else{\r
290                         //printf("determinant is not positive during calculation of eigenvalues !!");\r
291                 }\r
292 \r
293                 CvPoint2D32f e1;\r
294                 e1.x=-c0[0][1]/(c0[0][0]-eig.x);\r
295                 e1.y=1.0;\r
296 \r
297                 //f32 norm = sqrtf(e1.x*e1.x+e1.y*e1.y);\r
298 \r
299                 CvPoint2D32f e2;\r
300                 e2.x=-c0[0][1]/(c0[0][0]-eig.y);\r
301                 e2.y=1.0;\r
302 \r
303                 Eigen result;\r
304 \r
305                 result.e1=e1;\r
306                 result.e2=e2;\r
307                 result.lambda = eig;\r
308                 result.mean = mean;\r
309 \r
310                 return result;\r
311 \r
312         }\r
313 \r
314         static Eigen PCA(IplImage *x, IplImage *y){\r
315                 Eigen eig;\r
316                 eig.e1 = cvPoint2D32f(0,0);\r
317                 if(!x || !y) return eig;\r
318                 u32 length = x->widthStep*x->height;\r
319                 if(length != (u32)(y->widthStep*y->height)) return eig;\r
320                 CvPoint2D32f *points = new CvPoint2D32f[length];\r
321                 FOR(i, length){\r
322                         points[i].x = x->imageData[i]/255.f;\r
323                         points[i].y = y->imageData[i]/255.f;\r
324                 }\r
325                 eig = PCA(points, length);\r
326                 delete[] points;\r
327                 return eig;\r
328         }\r
329 \r
330         /**\r
331           *   determines if a point is inside a ellipse given by the eigenvalues (radius), eigenvectors (direction) and center.\r
332           *\r
333           *   @param point        : is the CbCr **point** into the ellipse  \r
334           *       @param eigenValVect : eigenvalues, corresp. eigenvectors, center of mass\r
335 \r
336           *       @return : true if the *point* is inside the ellipse (i.e this point corresponds to skin color)\r
337           */\r
338 \r
339         static bool isInsideEllipse(CvPoint2D32f point, Eigen eigenValVect, f32 proportionFactor){\r
340 \r
341                 //translate the coordinate system to the center of mass of points\r
342                 CvPoint2D32f newPoint;\r
343                 newPoint.x = point.x - eigenValVect.mean.x;\r
344                 newPoint.y = point.y - eigenValVect.mean.y;\r
345 \r
346                 f32 theta;\r
347                 \r
348                 if (eigenValVect.e1.x >= 0)\r
349                         theta = atanf(eigenValVect.e1.y/eigenValVect.e1.x);\r
350                 else if(eigenValVect.e2.x >= 0)\r
351                         theta = atanf(eigenValVect.e2.y/eigenValVect.e2.x);\r
352                 else{\r
353                         //printf("\n*** ERROR - NON ORTHOGONAL VECTORS ***\n");\r
354                 }\r
355 \r
356                 // rotation\r
357                 newPoint.x=newPoint.x*cosf(theta)-point.y*sinf(theta);\r
358                 newPoint.y=newPoint.x*sinf(theta)+point.y*cosf(theta);\r
359 \r
360                 return ((((newPoint.x*newPoint.x)/(eigenValVect.lambda.x*proportionFactor*eigenValVect.lambda.x*proportionFactor))\r
361                         +((newPoint.y*newPoint.y)/(eigenValVect.lambda.y*proportionFactor*eigenValVect.lambda.y*proportionFactor))) < 1.0f);\r
362         }\r
363 \r
364         static void SelectPCA(IplImage *x, IplImage *y, IplImage *dst, Eigen eig, f32 ratio)\r
365         {\r
366                 if(!x || !y) return;\r
367                 if(!dst) dst = cvCreateImage(cvGetSize(x),8,1);\r
368                 else if (dst->width != x->width && dst->height != x->height){\r
369                         cvReleaseImage(&dst);\r
370                         dst = NULL;\r
371                         cvCreateImage(cvGetSize(x),8,1);\r
372                 }\r
373                 u32 width = x->width;\r
374                 u32 height = x->height;\r
375                 FOR(i,height){\r
376                         FOR(j, width){\r
377                                 dst->imageData[i*width + j] = isInsideEllipse(cvPoint2D32f((unsigned char)(x->imageData[i*width+j])/255.f, ((unsigned char)y->imageData[i*width+j])/255.f), eig, ratio) ? 255 : 0;\r
378                         }\r
379                 }\r
380         }\r
381 }\r
382 #endif //_BASICOPENCV_H_\r