source: level2/competencies/FacET/src/image_processing.cpp @ 234

Revision 74, 11.7 KB checked in by nik, 11 years ago (diff)

FacET import

Line 
1/* $Id: image_processing.cpp 5 2009-03-12 22:30:56Z mw $
2 * +-------------------------------------------------------------------+
3 * | This file contains parts of code from the application created for |
4 * | the Master thesis supervised by Marek Wnuk (Wroclaw University of |
5 * | Technology):  "Wykorzystanie systemu wizyjnego do rozpoznawania   |
6 * | emocji czlowieka" ("Vision system in human emotions recognition") |
7 * | by Marcin Namysl in June 2008.                                    |
8 * +-------------------------------------------------------------------+
9 *
10 * \author Marek Wnuk
11 * \date 2009.03.03
12 * \version 1.00.00
13 */
14
15/*
16    FacET is a library for detecting and parameterising face components.
17    Copyright (C) 2009  Marek Wnuk <marek.wnuk@pwr.wroc.pl>
18
19    This program is free software: you can redistribute it and/or modify
20    it under the terms of the GNU General Public License as published by
21    the Free Software Foundation, either version 3 of the License, or
22    (at your option) any later version.
23
24    This program is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27    GNU General Public License for more details.
28
29    You should have received a copy of the GNU General Public License
30    along with this program.  If not, see <http://www.gnu.org/licenses/>.
31*/
32
33/*! \file image_processing.cpp
34 *
35 * File defines class implementing image processing methods:
36 * \link ImgProcMethods::hysteresisThresholding hysteresis thresholding\endlink,
37 * \link ImgProcMethods::createOutline silhouette outline creation\endlink,
38 * \link ImgProcMethods::doHoughTransform Hough transform\endlink, etc.
39 *
40 */
41
42#include "facet.h"
43
44using std::bitset;
45using std::list;
46using std::cerr;
47
48
49/********************** IMAGE PROCESSING METHODS *************************/
50
51int ImgProcMethods::findConnectedRegions(IplImage *src, bool draw,
52                                                  IplImage *dst)
53{
54  CvSeq* contour = 0;
55  IplImage *src_copy = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
56  cvCopy(src, src_copy);
57 
58  cvClearMemStorage( contours_storage );
59
60  cvFindContours( src_copy, contours_storage, &contour, sizeof(CvContour),
61                  CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
62
63  int cont_ctr = 0;
64  for( ; contour != 0; contour = contour->h_next ){
65
66    if (draw) {
67      cvZero(dst);
68      cvDrawContours(dst,contour,CV_RGB(rand()&255,rand()&255,rand()&255),
69                     CV_RGB(rand()&255,rand()&255,rand()&255),-1,CV_FILLED,8);
70    }
71    cont_ctr++;
72  }
73  cvReleaseImage( &src_copy );
74  return cont_ctr;
75}
76
77void
78ImgProcMethods::detectObjectHaar(IplImage *src,
79                                         CvHaarClassifierCascade* cascade,
80                                         FaceComponent &element, double scale,
81                                         double scale_factor,
82                                         int min_neighbors)
83{
84
85  CvSize object_size = cvSize(cvRound(cvGetSize(src).width/3),
86                              cvRound(cvGetSize(src).height/4));
87 
88  element = FaceComponent(cvPoint(1,1),cvPoint(2,2));
89  if( !cascade )
90    {
91      cerr << "ERROR: Loading the object cascade file failed\n";
92      return;
93    }
94
95  cvClearMemStorage( storage );
96 
97
98  if( cascade )
99    {
100      CvSeq* objects =
101        cvHaarDetectObjects(src, cascade, storage, scale_factor, min_neighbors,
102                            CV_HAAR_DO_CANNY_PRUNING, object_size);
103
104      for(int i = 0; i < (objects ? objects->total : 0); i++ )
105        {
106          CvRect* r = (CvRect*)cvGetSeqElem( objects, i );
107
108          double W = r->width - r->width*scale;
109          double H = r->height - r->height*scale;
110
111          CvPoint pt1, pt2;
112
113          pt1.x = (r->x + cvRound(W/2));
114          pt2.x = (r->x + r->width - cvRound(W/2));
115          pt1.y = (r->y + cvRound(H/2));
116          pt2.y = (r->y + r->height - cvRound(H/2));
117       
118          element = FaceComponent(pt1, pt2);
119        }
120    }
121  return;
122}
123
124/* left = 1000 (8)
125 * right = 0100 (4)
126 * top = 0010 (2)
127 * bottom = 0001 (1)
128 *
129 * top&bottom = 0011 (3)
130 * left&right = 1100 (12)
131 * top&left = 1010 (10)
132 * top&right = 0110 (6)
133 * top&left = 1001 (9)
134 * bottom&right = 0101 (5)
135 *
136 * left&right&top = 1110 (14)
137 * left&right&bottom = 1101 (13)
138 * top&bottom&left = 1011 (11)
139 * top&bottom&right = 0111 (7)
140 *
141 * all = 1111 (15)
142 */
143void ImgProcMethods::removeBoundaryBlobs(IplImage *src, IplImage *dst,
144                                               bitset<4> flag)
145{
146  int border = 1;
147
148  int left   = flag[3]*border;
149  int right  = flag[2]*border;
150  int up     = flag[1]*border;
151  int bottom = flag[0]*border;
152
153  IplImage *temp = cvCreateImage(cvGetSize(src), 8, 1);
154  IplImage *tmp = cvCreateImage(cvGetSize(src), 8, 1);
155  cvSet(temp, cvScalar(255));
156
157  cvSetImageROI(temp, cvRect(left, up, temp->width-right-left,
158                             temp->height-bottom-up));
159  cvZero(temp);
160  cvResetImageROI(temp);
161
162  IplImage *dst_copy=cvCreateImage(cvGetSize(dst), dst->depth, dst->nChannels);
163
164  do {
165    cvDilate(temp, dst_copy);
166    cvAnd(dst_copy, src, dst_copy);
167    cvXor(dst_copy, temp, tmp);
168    cvCopy(dst_copy, temp);
169  } while (cvCountNonZero(tmp));
170  cvSub(src, dst_copy, dst_copy);
171  cvCopy(dst_copy,dst);
172  cvReleaseImage( &dst_copy );
173  cvReleaseImage( &temp );
174  cvReleaseImage( &tmp );
175}
176
177void ImgProcMethods::removeSmallBlobs(IplImage *src, IplImage *dst,
178                                           int iter)
179{
180  IplImage *tmp = cvCreateImage(cvGetSize(src), 8, 1);
181  cvCopy(src, tmp);
182
183  //remove small objects
184  for (int i=0;i<iter;i++) cvErode(tmp,tmp);
185  for (int i=0;i<iter;i++){
186    cvDilate(tmp,tmp);
187    //cvAnd(src,dst,src);
188  }
189  cvCopy(tmp,dst);
190  cvReleaseImage( &tmp );
191}
192
193
194void ImgProcMethods::createOutline(IplImage *src, IplImage *dst)
195{
196  IplImage *dst_copy = cvCreateImage(cvGetSize(dst),dst->depth,dst->nChannels);
197  cvCopy(dst, dst_copy);
198
199  cvErode(src, dst_copy);
200  cvSub(src, dst_copy, dst);                           
201
202  cvReleaseImage( &dst_copy);
203}
204
205
206void ImgProcMethods::findContours(IplImage *src, CvSeq *&contours)
207{   
208  cvClearMemStorage( contours_storage );
209
210  cvFindContours( src, contours_storage, &contours, sizeof(CvContour),
211                  CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
212}
213
214int ImgProcMethods::doHoughTransform(IplImage *src,
215                                             list<CvPoint> &linesList) {
216  IplImage *image = cvCreateImage(cvGetSize(src),8,1);
217 
218  if (image->nChannels > 1) cvCvtColor(src, image, CV_BGR2GRAY);
219  else cvCopy(src, image);
220   
221  cvClearMemStorage( storage );
222  stretchHistogram(image, image);
223  int average = cvRound(cvAvg(image).val[0]);
224  if (!average) average=1;
225
226  int width = image->width/3;
227  if (!width) average=1;
228
229  CvSeq* lines = cvHoughLines2( image, storage, CV_HOUGH_PROBABILISTIC, 1,
230                                CV_PI/360, average, image->width/3, 1 );
231
232  int wrinkles_counter = 0;
233
234  for(int i = 0; i < lines->total; i++ ){
235   
236    CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
237
238    double A,B,C;
239    drawStrLine(line[0],line[1],A,B,C);
240    double kat = -rad2deg(calcAngleOX(A,B));
241
242    if ((kat < 30) & (kat > -30)){
243      linesList.push_front(line[0]);
244      linesList.push_front(line[1]);
245      wrinkles_counter++;
246    }
247  }
248  cvReleaseImage( &image );
249  return wrinkles_counter;
250}
251
252bool ImgProcMethods::checkPixelNeighbourhood(IplImage *src, int y, int x,
253                                                  int R)
254{
255  for (int i=y-1; i<=y+1; i++)
256    for (int j=x-1; j<=x+1; j++)
257      if ((i>=0) & (j>=0) & (i<src->height) & (j<src->width))
258        if ((int)CV_IMAGE_ELEM(src,uchar,i,j)<R)
259          return true;
260  return false;
261}
262
263void ImgProcMethods::hysteresisThresholding(IplImage *src, IplImage *dst,
264                                             int R, int L)
265{
266  IplImage *temp = cvCreateImage(cvGetSize(dst), dst->depth, dst->nChannels);
267  cvZero(temp);
268
269  for (int i=0; i<(src->height); i++){
270    for (int j=0; j<(src->width); j++){
271      int w = (int)CV_IMAGE_ELEM(src,uchar,i,j);
272      if (w<R)
273        CV_IMAGE_ELEM(temp,uchar,i,j)= 255;
274      else if (w<L){
275        if (checkPixelNeighbourhood(src,i,j,R))
276          CV_IMAGE_ELEM(temp,uchar,i,j)= 255;
277        else
278          CV_IMAGE_ELEM(temp,uchar,i,j)= 0;
279      }
280      else
281        CV_IMAGE_ELEM(temp,uchar,i,j)= 0;
282    }
283  }
284  cvCopy(temp,dst);
285  cvReleaseImage( &temp );
286}
287
288IplImage *ImgProcMethods::showHistogram(const IplImage *src, bool display, CvSize size)
289{
290  IplImage *dst=cvCloneImage(src);
291  IplImage *hist_image;
292  CvHistogram *hist;
293
294  int hist_size = 256;
295  float range_0[]={0,256};
296  float* ranges[] = { range_0 };
297  CvMat *lut_mat;
298  uchar lut[256];
299  float max_value = 0.f, min_value = 0.f;
300  int bin_w;
301  CvFont font;
302  double hScale = 0.8;
303  double vScale = 0.8;
304  int lineWidth = 1;
305  int offset=80;
306  int xsize=size.width;
307  int ysize=size.height;
308  char buffer[4];
309
310  hist_image=cvCreateImage(cvSize(xsize+offset,ysize+2*offset), 8, 3);
311  hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);
312  lut_mat = cvCreateMatHeader( 1, 256, CV_8UC1 );
313  cvSetData( lut_mat, lut, 0 );
314
315  cvCalcHist(&dst,hist,0);
316  cvGetMinMaxHistValue(hist,&min_value,&max_value);
317  cvScale( hist->bins, hist->bins, ((double)ysize)/max_value, 0 );
318
319  cvSet( hist_image, cvScalarAll(255), 0 );
320  bin_w = cvRound((double)xsize/hist_size);
321
322  cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, hScale, vScale,
323             0, lineWidth);
324
325  cvPutText (hist_image, "some text", cvPoint(90, 90),
326             &font, cvScalar(0,0,0));
327
328  cvRectangle(hist_image,cvPoint(offset/2,offset),
329              cvPoint(xsize+offset/2,ysize+offset),cvScalar(255,248,240),-1);
330 
331  for (int i=0; i<ysize; i+=20){
332    if ((i%100==0)&(i!=0)){
333      cvLine(hist_image,cvPoint(offset/2-5,ysize+offset-i),
334             cvPoint(xsize+offset/2,ysize+offset-i),cvScalar(0,0,0),1);
335
336      sprintf (buffer, "%d", i); // i -> char buffer
337
338      cvPutText(hist_image,buffer,cvPoint(offset/2-15*bin_w,ysize+offset-i),
339                &font , cvScalar(0,0,0));
340     
341    }
342    else{
343      cvLine(hist_image,cvPoint(offset/2,ysize+offset-i),
344             cvPoint(xsize+offset/2,ysize+offset-i),cvScalar(0,0,0),1);
345    }
346  }
347
348  for (int i=0; i<ysize; i+=100){
349    cvLine(hist_image,cvPoint(offset/2-5,ysize+offset-i),
350           cvPoint(xsize+offset/2,ysize+offset-i),cvScalar(0,0,0),1);
351  }
352
353  for(int i = 0; i < hist_size; i++ ){
354
355    int y= cvRound(cvGetReal1D(hist->bins,i));
356    int x=bin_w;
357
358    cvRectangle( hist_image, cvPoint(i*x+offset/2, ysize+offset),
359                 cvPoint((i+1)*x+offset/2, ysize - y+offset),
360                 cvScalar(131,139,139), -1, 8, 0 );
361
362    sprintf (buffer, "%d", i); // i -> char buffer
363
364    if (i%50==0){
365 
366      cvPutText(hist_image,buffer,cvPoint(i*x+offset/2-5*x,
367                                          cvRound(ysize+offset*1.8)),
368                &font, cvScalar(0,0,0));
369      cvLine(hist_image,cvPoint(i*x+offset/2,cvRound(ysize+offset*1.3)),
370             cvPoint(i*x+offset/2,offset),cvScalar(255,255,255),2,CV_AA);
371     
372      cvLine(hist_image,cvPoint(i*x+offset/2,cvRound(ysize+offset*1.3)),
373             cvPoint(i*x+offset/2,offset),cvScalar(0,0,255),1);
374     
375    }
376    else if (i%10==0){
377      cvLine(hist_image,cvPoint(i*x+offset/2,cvRound(ysize+offset*1.3)),
378             cvPoint(i*x+offset/2,offset),cvScalar(0,0,0));
379
380    }
381  }
382         
383  cvLine(hist_image,cvPoint(offset/2,offset),
384         cvPoint(xsize+offset/2,offset), cvScalar(0,0,0));
385
386  // display histogram image
387  if (display){
388    cvNamedWindow("histogram", 1);
389    cvShowImage( "histogram", hist_image );
390    cvWaitKey(0);
391  }
392
393  cvReleaseImage( &dst );
394  cvReleaseMat( &lut_mat );
395
396  return hist_image;
397}
398
399void ImgProcMethods::stretchHistogram(const IplImage* src, IplImage *dst)
400{
401  double min,max;
402 
403  cvMinMaxLoc ( src, &min, &max );
404
405  if( min != max )
406    cvConvertScaleAbs ( src, dst, 255/(max-min), -min );
407  else
408    cvZero ( dst );
409}
410
411int ImgProcMethods::findThresholdByHist(IplImage *src, int factor)
412{
413  int size=256;
414  float range[2] = {0, size};
415  float *ranges[] = {range};
416 
417  CvHistogram *histogram = cvCreateHist(1, &size, CV_HIST_ARRAY, ranges, 1);
418 
419  cvCalcHist(&src, histogram, 0);
420 
421  int intensity_sum = 0;
422  int current_sum = 0;
423
424  intensity_sum = src->width * src->height;
425
426  for(int i = 0; i < size; i++ ){
427
428    current_sum += cvRound(cvGetReal1D(histogram->bins,i));
429
430    if (current_sum >= ((intensity_sum * factor)/100) ) {
431      cvReleaseHist( &histogram );
432      return i;
433    }
434  }
435
436  cvReleaseHist( &histogram );
437  std::cerr << "Error in function 'findThresholdByHist()' \n";
438
439  return -1;
440}
441
Note: See TracBrowser for help on using the repository browser.