]> SALOME platform Git repositories - modules/geom.git/blob - src/ShapeRecognition/ShapeRec_FeatureDetector.cxx
Salome HOME
b452a9c67933be5aa9fde269501e7c93bc145bfd
[modules/geom.git] / src / ShapeRecognition / ShapeRec_FeatureDetector.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File   : ShapeRec_FeatureDetector.cxx
24 // Author : Renaud NEDELEC, Open CASCADE S.A.S.
25
26 #include "ShapeRec_FeatureDetector.hxx"
27 #include <stdio.h>
28 #include "utilities.h"
29
30 // TODO : All the following methods but ComputeContours use the C API of OpenCV while ComputContours
31 // uses the C++ API of the library.
32 // This should be homogenized and preferably by using the C++ API (which is more recent for all the methods
33
34 // The code has to be "cleaned up" too
35
36 /*!
37   Constructor
38   \param theFilename - image to process
39 */
40 ShapeRec_FeatureDetector::ShapeRec_FeatureDetector(): 
41   corners()
42 {
43   cornerCount = 2000;
44   rect=cvRect(0,0,0,0);
45   imagePath = ""; //theFilename;
46   // Store the dimensions of the picture
47   imgHeight = 0;
48   imgWidth  = 0;
49 }
50
51 /*!
52   Sets the path of the image file to be processed
53   \param thePath - Location of the image file 
54 */
55 void ShapeRec_FeatureDetector::SetPath( const std::string& thePath )
56 {
57   imagePath = thePath; 
58   if (imagePath != "")
59   {
60     IplImage* src = cvLoadImage(imagePath.c_str(),CV_LOAD_IMAGE_COLOR);
61     imgHeight = src->height;
62     imgWidth = src->width; 
63   }
64 }
65
66 /*!
67   Computes the corners of the image located at imagePath
68 */
69 void ShapeRec_FeatureDetector::ComputeCorners( bool useROI, ShapeRec_Parameters* parameters ){
70   ShapeRec_CornersParameters* aCornersParameters = dynamic_cast<ShapeRec_CornersParameters*>( parameters );
71   if ( !aCornersParameters ) aCornersParameters = new  ShapeRec_CornersParameters();
72
73   // Images to be used for detection
74   IplImage *eig_img, *temp_img, *src_img_gray;
75   
76   // Load image
77   src_img_gray = cvLoadImage (imagePath.c_str(), CV_LOAD_IMAGE_GRAYSCALE);
78   
79   if ( useROI )
80   {
81     // If a ROI as been set use it for detection
82     cvSetImageROI( src_img_gray, rect );
83   }
84   
85   eig_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
86   temp_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
87   corners = (CvPoint2D32f *) cvAlloc (cornerCount * sizeof (CvPoint2D32f));
88   
89   // image height and width
90   imgHeight = src_img_gray->height;
91   imgWidth  = src_img_gray->width;
92
93   // Corner detection using cvCornerMinEigenVal 
94   // (one of the methods available inOpenCV, there is also a cvConerHarris method that can be used by setting a flag in cvGoodFeaturesToTrack)
95   cvGoodFeaturesToTrack (src_img_gray, eig_img, temp_img, corners, &cornerCount, aCornersParameters->qualityLevel, aCornersParameters->minDistance);
96   cvFindCornerSubPix (src_img_gray, corners, cornerCount, cvSize (aCornersParameters->kernelSize, aCornersParameters->kernelSize), cvSize (-1, -1),
97                       cvTermCriteria (aCornersParameters->typeCriteria, aCornersParameters->maxIter, aCornersParameters->epsilon));
98
99   cvReleaseImage (&eig_img);
100   cvReleaseImage (&temp_img);
101   cvReleaseImage (&src_img_gray);
102
103 }
104
105 /*!
106   Computes the contours of the image located at imagePath
107 */
108 bool ShapeRec_FeatureDetector::ComputeContours( bool useROI, ShapeRec_Parameters* parameters ){
109  
110   // Initialising images
111   cv::Mat src, src_gray;
112   cv::Mat detected_edges;
113   
114   // Read image
115   src = cv::imread( imagePath.c_str() );
116   if( !src.data )
117     return false; 
118   
119   if ( !useROI )   // CANNY: The problem is that with that filter the detector detects double contours
120   {   
121     // Convert the image to grayscale
122     if (src.channels() == 3)
123       cv::cvtColor( src, src_gray, CV_BGR2GRAY );
124     else if (src.channels() == 1)
125       src_gray = src;
126
127     ShapeRec_CannyParameters* aCannyParameters = dynamic_cast<ShapeRec_CannyParameters*>( parameters );
128     if ( !aCannyParameters ) aCannyParameters = new ShapeRec_CannyParameters();
129
130     // Reduce noise              
131     blur( src_gray, detected_edges, cv::Size( aCannyParameters->kernelSize, aCannyParameters->kernelSize ) );
132     // Canny detector
133     Canny( detected_edges, detected_edges, aCannyParameters->lowThreshold, aCannyParameters->lowThreshold * aCannyParameters->ratio,
134            aCannyParameters->kernelSize, aCannyParameters->L2gradient );
135   }
136   else //COLORFILTER
137   {
138     IplImage* find_image = cvLoadImage(imagePath.c_str(),CV_LOAD_IMAGE_COLOR);
139
140     ShapeRec_ColorFilterParameters* aColorFilterParameters = dynamic_cast<ShapeRec_ColorFilterParameters*>( parameters );
141     if ( !aColorFilterParameters ) aColorFilterParameters = new ShapeRec_ColorFilterParameters();
142
143     // Reduce noise
144     cvSmooth( find_image, find_image, CV_GAUSSIAN, aColorFilterParameters->smoothSize, aColorFilterParameters->smoothSize );
145   
146     // Crop the image to build an histogram from the selected part
147     cvSetImageROI(find_image, rect);
148     IplImage* test_image = cvCreateImage(cvGetSize(find_image),
149                                          find_image->depth,
150                                          find_image->nChannels);
151     cvCopy(find_image, test_image, NULL);
152     cvResetImageROI(find_image);
153   
154     IplImage* test_hsv = cvCreateImage(cvGetSize(test_image),8,3);
155     IplImage* h_plane = cvCreateImage( cvGetSize(test_image), 8, 1 );
156     IplImage* s_plane = cvCreateImage( cvGetSize(test_image), 8, 1 );
157     CvHistogram* hist;
158
159     cvCvtColor(test_image, test_hsv, CV_BGR2HSV);
160   
161     cvCvtPixToPlane(test_hsv, h_plane, s_plane, 0, 0);
162     IplImage* planes[] = { h_plane, s_plane };
163   
164     //create hist
165     float hranges[] = { 0, 180 };
166     float sranges[] = { 0, 256 };
167     float* ranges[] = { hranges, sranges };
168     hist = cvCreateHist( 2, aColorFilterParameters->histSize, aColorFilterParameters->histType, ranges );
169   
170     //calculate hue /saturation histogram
171     cvCalcHist(planes, hist, 0 ,0);
172
173 //   // TEST print of the histogram for debugging
174 //   IplImage* hist_image = cvCreateImage(cvSize(320,300),8,3);
175 //   
176 //   //draw hist on hist_test image.
177 //   cvZero(hist_image);
178 //   float max_value = 0;
179 //   cvGetMinMaxHistValue(hist, 0 , &max_value, 0, 0);
180 //   int bin_w = hist_image->width/size_hist;
181 //   for(int i = 0; i < size_hist; i++ )
182 //   {
183 //     //prevent overflow
184 //     int val = cvRound( cvGetReal1D(hist->bins,i)*hist_image->
185 //     height/max_value);
186 //     CvScalar color = CV_RGB(200,0,0);
187 //     //hsv2rgb(i*180.f/size_hist);
188 //     cvRectangle( hist_image, cvPoint(i*bin_w,hist_image->height),
189 //     cvPoint((i+1)*bin_w,hist_image->height - val),
190 //     color, -1, 8, 0 );
191 //   }
192 //  
193 //    
194 //   cvNamedWindow("hist", 1); cvShowImage("hist",hist_image);
195   
196   
197     //calculate back projection of hue and saturation planes of input image
198     IplImage* backproject = cvCreateImage(cvGetSize(test_image), 8, 1);
199     IplImage* binary_backproject = cvCreateImage(cvGetSize(test_image), 8, 1);
200     cvCalcBackProject(planes, backproject, hist);
201   
202     // Threshold in order to obtain binary image
203     cvThreshold(backproject, binary_backproject, aColorFilterParameters->threshold, aColorFilterParameters->maxThreshold, CV_THRESH_BINARY);
204     cvReleaseImage(&test_image);
205     cvReleaseImage(&test_hsv);
206     cvReleaseImage(&h_plane);
207     cvReleaseImage(&s_plane);
208     cvReleaseImage(&find_image);
209     cvReleaseImage(&backproject);
210   
211     detected_edges = cv::Mat(binary_backproject);
212   }
213   // else if ( detection_method == RIDGE_DETECTOR )  // Method adapted for engineering drawings (e.g. watershed functionnality could be used here cf.OpenCV documentation and samples)
214   // {
215   //   // TODO
216   //   return false;
217   // }
218
219   //  _detectAndRetrieveContours( detected_edges, parameters->findContoursMethod );
220   detected_edges = detected_edges > 1;
221   findContours( detected_edges, contours, hierarchy, CV_RETR_CCOMP, parameters->findContoursMethod, useROI ? cvPoint(rect.x,rect.y) : cvPoint(0,0) );
222
223   return true;
224   
225 }
226
227 /*!
228   Computes the lines in the image located at imagePath
229 */
230 bool ShapeRec_FeatureDetector::ComputeLines(){
231   MESSAGE("ShapeRec_FeatureDetector::ComputeLines()")
232   // Initialising images
233   cv::Mat src, src_gray, detected_edges, dst;
234   
235   src=cv::imread(imagePath.c_str(), 0);
236   
237   Canny( src, dst, 50, 200, 3 );
238   HoughLinesP( dst, lines, 1, CV_PI/180, 80, 30, 10 );
239   return true;
240   
241 }
242
243 /*!
244   Stores a region of interest given by user in rect
245   \param theRect - Region Of Interest of the image located at imagePath 
246 */
247 void ShapeRec_FeatureDetector::SetROI( const QRect& theRect )
248 {
249   if (!theRect.isEmpty()){
250     rect = cvRect(theRect.x(),theRect.y(),theRect.width(),theRect.height());
251   }
252 }
253
254 /*!
255   Crops the image located at imagePath to the region of interest given by the user via SetROI
256   and stores the result in /tmp
257   \param theRect - Region Of Interest of the image located at imagePath 
258 */
259 std::string ShapeRec_FeatureDetector::CroppImage()
260 {
261   IplImage* src = cvLoadImage(imagePath.c_str(),CV_LOAD_IMAGE_COLOR);
262  
263   cvSetImageROI(src, rect);
264   IplImage* cropped_image = cvCreateImage(cvGetSize(src),
265                                           src->depth,
266                                           src->nChannels);
267   cvCopy(src, cropped_image, NULL);
268   cvResetImageROI(src);
269   
270   cvSaveImage ("/tmp/cropped_image.bmp", cropped_image);
271   
272   return "/tmp/cropped_image.bmp";
273 }
274
275 /*!
276   \class ShapeRec_CornersParameters
277   \brief Parameters for the corners detection 
278 */
279 ShapeRec_CornersParameters::ShapeRec_CornersParameters()
280 {
281   qualityLevel = 0.2;
282   minDistance = 1;
283   typeCriteria = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS;
284   maxIter = 20;
285   epsilon = 0.03;
286 }
287 ShapeRec_CornersParameters::~ShapeRec_CornersParameters()
288 {
289 }
290
291 /*!
292   \class ShapeRec_Parameters
293   \brief Parameters for the contour/corners detection 
294 */
295 ShapeRec_Parameters::ShapeRec_Parameters()
296 {
297   kernelSize = 3;
298   findContoursMethod = CV_CHAIN_APPROX_NONE;
299 }
300 ShapeRec_Parameters::~ShapeRec_Parameters()
301 {
302 }
303
304 /*!
305   \class ShapeRec_CannyParameters
306   \brief Parameters for the contour detection 
307 */
308 ShapeRec_CannyParameters::ShapeRec_CannyParameters()
309 {
310   lowThreshold = 100; // is used for edge linking.
311   ratio = 3;          // lowThreshold*ratio is used to find initial segments of strong edges
312   L2gradient = true;  // norm L2 or L1
313 }
314
315 ShapeRec_CannyParameters::~ShapeRec_CannyParameters()
316 {
317 }
318
319 /*!
320   \class ShapeRec_ColorFilterParameters
321   \brief Parameters for the contour detection 
322 */
323 ShapeRec_ColorFilterParameters::ShapeRec_ColorFilterParameters()
324 {
325   smoothSize = 3;           // The parameter of the smoothing operation, the aperture width. Must be a positive odd number
326   histSize = new int[2];    // array of the histogram dimension sizes
327   histSize[0] = 30;         // hbins
328   histSize[1] = 32;         // sbins
329   histType = CV_HIST_ARRAY; // histogram representation format
330   threshold = 128;          // threshold value
331   maxThreshold = 255;       // maximum value to use with the THRESH_BINARY thresholding types
332 }
333
334 ShapeRec_ColorFilterParameters::~ShapeRec_ColorFilterParameters()
335 {
336 }