Salome HOME
Mantis issue 0021432: EDF GEOM: Faces with huge tolerance can be built in GEOM.
[modules/geom.git] / src / ShapeRecognition / ShapeRec_FeatureDetector.cxx
1 // Copyright (C) 2007-2011  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 // File   : ShapeRec_FeatureDetector.cxx
23 // Author : Renaud NEDELEC, Open CASCADE S.A.S.
24
25 #include "ShapeRec_FeatureDetector.hxx"
26 #include <stdio.h>
27 #include "utilities.h"
28
29 using namespace cv;
30
31 //TODO : All the following methods but ComputeContours use the C API of OpenCV while ComputContours
32 // uses the C++ API of the library.
33 // This should be homogenized and preferably by using the C++ API (which is more recent for all the methods
34
35 // The code has to be "cleaned up" too
36
37 /*!
38   Constructor
39   \param theFilename - image to process
40 */
41 ShapeRec_FeatureDetector::ShapeRec_FeatureDetector(): 
42   corners()
43 {
44   cornerCount = 2000;
45   rect=cvRect(0,0,0,0);
46   imagePath = ""; //theFilename;
47   // Store the dimensions of the picture
48   imgHeight = 0;
49   imgWidth  = 0;
50 }
51
52 /*!
53   Sets the path of the image file to be proccesed
54   \param thePath - Location of the image file 
55 */
56 void ShapeRec_FeatureDetector::SetPath( const std::string& thePath )
57 {
58   imagePath = thePath; 
59   if (imagePath != "")
60   {
61     IplImage* src = cvLoadImage(imagePath.c_str(),CV_LOAD_IMAGE_COLOR);
62     imgHeight = src->height;
63     imgWidth = src->width; 
64   }
65 }
66
67 /*!
68   Computes the corners of the image located at imagePath
69 */
70 void ShapeRec_FeatureDetector::ComputeCorners(){
71   
72   // Parameters for the corner detection
73   double qualityLevel = 0.2;
74   double minDistance = 1;
75  
76   // Images to be used for detection
77   IplImage *eig_img, *temp_img, *src_img_gray;
78   
79   // Load image
80   src_img_gray = cvLoadImage (imagePath.c_str(), CV_LOAD_IMAGE_GRAYSCALE);
81   
82   if ( rect.width > 1 )
83   {
84     // If a ROI as been set use it for detection
85     cvSetImageROI( src_img_gray, rect );
86   }
87   
88   eig_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
89   temp_img = cvCreateImage (cvGetSize (src_img_gray), IPL_DEPTH_32F, 1);
90   corners = (CvPoint2D32f *) cvAlloc (cornerCount * sizeof (CvPoint2D32f));
91   
92   // image height and width
93   imgHeight = src_img_gray->height;
94   imgWidth  = src_img_gray->width;
95
96   // Corner detection using cvCornerMinEigenVal 
97   // (one of the methods available inOpenCV, there is also a cvConerHarris method that can be used by setting a flag in cvGoodFeaturesToTrack)
98   cvGoodFeaturesToTrack (src_img_gray, eig_img, temp_img, corners, &cornerCount, /*quality-level=*/qualityLevel, /*min-distance=*/minDistance);
99   cvFindCornerSubPix (src_img_gray, corners, cornerCount,
100                     cvSize (3, 3), cvSize (-1, -1), cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03));
101
102   cvReleaseImage (&eig_img);
103   cvReleaseImage (&temp_img);
104   cvReleaseImage (&src_img_gray);
105
106 }
107
108 /*!
109   Computes the contours of the image located at imagePath
110 */
111 bool ShapeRec_FeatureDetector::ComputeContours( int detection_method ){
112  
113   // Initialising images
114   Mat src, src_gray;
115   Mat detected_edges;
116   
117   // Read image
118   src = imread( imagePath.c_str() );
119   if( !src.data )
120     return false; 
121   
122   if ( detection_method == CANNY )   // The problem is that with that filter the detector detects double contours
123   {   
124     // Thresholds for Canny detector
125     int lowThreshold = 100;
126     int ratio = 3;
127     int kernel_size = 3; // 3,5 or 7
128     
129     // Convert the image to grayscale
130     if (src.channels() == 3)
131       cvtColor( src, src_gray, CV_BGR2GRAY );
132     else if (src.channels() == 1)
133       src_gray = src;
134   
135     // Reduce noise with a kernel 3x3               
136     blur( src_gray, detected_edges, Size(3,3) );
137     // Canny detector
138     Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size, /*L2gradient =*/true );      
139   }
140   else if ( detection_method == COLORFILTER )
141   {
142     if ( !rect.width > 1 )
143       return false;
144     detected_edges = _colorFiltering();
145   }
146   else if ( detection_method == RIDGE_DETECTOR )  // Method adapted for engineering drawings (e.g. watershed functionnality could be used here cf.OpenCV documentation and samples)
147   {
148     // TODO
149     return false;
150   }
151   _detectAndRetrieveContours( detected_edges );
152   
153   return true;
154   
155 }
156
157 /*!
158   Computes the lines in the image located at imagePath
159 */
160 bool ShapeRec_FeatureDetector::ComputeLines(){
161   MESSAGE("ShapeRec_FeatureDetector::ComputeLines()")
162   // Initialising images
163   Mat src, src_gray, detected_edges, dst;
164   
165   src=imread(imagePath.c_str(), 0);
166   
167   Canny( src, dst, 50, 200, 3 );
168   HoughLinesP( dst, lines, 1, CV_PI/180, 80, 30, 10 );
169   return true;
170   
171 }
172
173 /*!
174   Stores a region of interest given by user in rect
175   \param theRect - Region Of Interest of the image located at imagePath 
176 */
177 void ShapeRec_FeatureDetector::SetROI( const QRect& theRect )
178 {
179   if (!theRect.isEmpty()){
180     rect = cvRect(theRect.x(),theRect.y(),theRect.width(),theRect.height());
181   }
182 }
183
184 /*!
185   Crops the image located at imagePath to the region of interest given by the user via SetROI
186   and stores the result in /tmp
187   \param theRect - Region Of Interest of the image located at imagePath 
188 */
189 std::string ShapeRec_FeatureDetector::CroppImage()
190 {
191   IplImage* src = cvLoadImage(imagePath.c_str(),CV_LOAD_IMAGE_COLOR);
192  
193   cvSetImageROI(src, rect);
194   IplImage* cropped_image = cvCreateImage(cvGetSize(src),
195                                           src->depth,
196                                           src->nChannels);
197   cvCopy(src, cropped_image, NULL);
198   cvResetImageROI(src);
199   
200   cvSaveImage ("/tmp/cropped_image.bmp", cropped_image);
201   
202   return "/tmp/cropped_image.bmp";
203 }
204
205
206 /*!
207   Performs contours detection and store them in contours 
208   \param src - src image to find contours of 
209 */
210 void ShapeRec_FeatureDetector::_detectAndRetrieveContours( Mat src )
211 {
212   src = src > 1; 
213   int method = CV_CHAIN_APPROX_NONE;
214   findContours( src, contours, hierarchy,CV_RETR_CCOMP, method);
215   // Other possible approximations CV_CHAIN_APPROX_TC89_KCOS, CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_SIMPLE cf. OpenCV documentation 
216   // for precise information
217 }
218
219 /*!
220   Performs color filtering from the image sample contained in the ROI rect of the image 
221   located at imagePath
222   Thresholds the result in order ot obtain a binary image
223   \return binary image resulting from filtering and thersholding
224 */
225 Mat ShapeRec_FeatureDetector::_colorFiltering()
226 {  
227   IplImage* find_image = cvLoadImage(imagePath.c_str(),CV_LOAD_IMAGE_COLOR);
228   // Reduce noise with a kernel 3x3               
229   cvSmooth( find_image, find_image, CV_GAUSSIAN, 3, 3 );
230   
231   if ( !rect.width > 1 )
232     return Mat(find_image);
233   
234   // Crop the image to build an histogram from the selected part
235   cvSetImageROI(find_image, rect);
236   IplImage* test_image = cvCreateImage(cvGetSize(find_image),
237                                        find_image->depth,
238                                        find_image->nChannels);
239   cvCopy(find_image, test_image, NULL);
240   cvResetImageROI(find_image);
241   
242   IplImage* test_hsv = cvCreateImage(cvGetSize(test_image),8,3);
243   IplImage* test_hue = cvCreateImage(cvGetSize(test_image),8,1);
244   CvHistogram* hist;
245
246   cvCvtColor(test_image, test_hsv, CV_BGR2HSV);
247   cvCvtPixToPlane(test_hsv, test_hue, 0, 0, 0);
248   
249   //create hist
250   int size_hist = 10;
251   float hranges[] = {0, 180};
252   float* ranges = hranges;
253   hist = cvCreateHist(1, &size_hist, CV_HIST_ARRAY, &ranges, 1);
254   
255   //calculate hue` histogram
256   cvCalcHist(&test_hue, hist, 0 ,0);
257
258 //   // TEST print of the histogram for debugging
259 //   IplImage* hist_image = cvCreateImage(cvSize(320,300),8,3);
260 //   
261 //   //draw hist on hist_test image.
262 //   cvZero(hist_image);
263 //   float max_value = 0;
264 //   cvGetMinMaxHistValue(hist, 0 , &max_value, 0, 0);
265 //   int bin_w = hist_image->width/size_hist;
266 //   for(int i = 0; i < size_hist; i++ )
267 //   {
268 //     //prevent overflow
269 //     int val = cvRound( cvGetReal1D(hist->bins,i)*hist_image->
270 //     height/max_value);
271 //     CvScalar color = CV_RGB(200,0,0);
272 //     //hsv2rgb(i*180.f/size_hist);
273 //     cvRectangle( hist_image, cvPoint(i*bin_w,hist_image->height),
274 //     cvPoint((i+1)*bin_w,hist_image->height - val),
275 //     color, -1, 8, 0 );
276 //   }
277 //  
278 //    
279 //   cvNamedWindow("hist", 1); cvShowImage("hist",hist_image);
280   
281   
282   //calculate back projection of hue plane of input image
283   IplImage* backproject = cvCreateImage(cvGetSize(find_image), 8, 1);
284   IplImage* binary_backproject = cvCreateImage(cvGetSize(find_image), 8, 1);
285   IplImage* find_hsv = cvCreateImage(cvGetSize(find_image),8,3);
286   IplImage* find_hue = cvCreateImage(cvGetSize(find_image),8,1);
287   
288   cvCvtColor(find_image, find_hsv, CV_BGR2HSV);
289   cvCvtPixToPlane(find_hsv, find_hue, 0, 0, 0);
290   cvCalcBackProject(&find_hue, backproject, hist);
291   
292   // Threshold in order to obtain binary image
293   cvThreshold(backproject, binary_backproject, 1, 255, CV_THRESH_BINARY);  // NOTE it would be good to think about the best threshold to use (it's 1 for now)
294   cvReleaseImage(&test_image);
295   cvReleaseImage(&test_hsv);
296   cvReleaseImage(&test_hue);
297   cvReleaseImage(&backproject);
298   
299   return Mat(binary_backproject);
300 }