2021-03-22 19:09:08 +03:00
// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
2012-08-09 07:58:02 +00:00
//
// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
2014-02-18 10:44:41 +04:00
// version 2.1 of the License, or (at your option) any later version.
2012-08-09 07:58:02 +00:00
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
// File : ShapeRec_FeatureDetector.cxx
// Author : Renaud NEDELEC, Open CASCADE S.A.S.
# include "ShapeRec_FeatureDetector.hxx"
# include <stdio.h>
# include "utilities.h"
2013-10-22 11:33:32 +00:00
// TODO : All the following methods but ComputeContours use the C API of OpenCV while ComputContours
2012-08-09 07:58:02 +00:00
// uses the C++ API of the library.
// This should be homogenized and preferably by using the C++ API (which is more recent for all the methods
// The code has to be "cleaned up" too
/*!
Constructor
*/
ShapeRec_FeatureDetector : : ShapeRec_FeatureDetector ( ) :
corners ( )
{
cornerCount = 2000 ;
rect = cvRect ( 0 , 0 , 0 , 0 ) ;
imagePath = " " ; //theFilename;
// Store the dimensions of the picture
imgHeight = 0 ;
imgWidth = 0 ;
}
/*!
Sets the path of the image file to be processed
\ param thePath - Location of the image file
*/
void ShapeRec_FeatureDetector : : SetPath ( const std : : string & thePath )
{
imagePath = thePath ;
if ( imagePath ! = " " )
{
IplImage * src = cvLoadImage ( imagePath . c_str ( ) , CV_LOAD_IMAGE_COLOR ) ;
imgHeight = src - > height ;
2013-12-18 14:23:59 +00:00
imgWidth = src - > width ;
cvReleaseImage ( & src ) ;
2012-08-09 07:58:02 +00:00
}
}
/*!
Computes the corners of the image located at imagePath
*/
2013-12-18 14:23:59 +00:00
void ShapeRec_FeatureDetector : : ComputeCorners ( bool useROI , ShapeRec_Parameters * parameters )
{
2013-10-22 11:33:32 +00:00
ShapeRec_CornersParameters * aCornersParameters = dynamic_cast < ShapeRec_CornersParameters * > ( parameters ) ;
if ( ! aCornersParameters ) aCornersParameters = new ShapeRec_CornersParameters ( ) ;
2012-08-09 07:58:02 +00:00
// Images to be used for detection
IplImage * eig_img , * temp_img , * src_img_gray ;
// Load image
src_img_gray = cvLoadImage ( imagePath . c_str ( ) , CV_LOAD_IMAGE_GRAYSCALE ) ;
2013-10-22 11:33:32 +00:00
if ( useROI )
2012-08-09 07:58:02 +00:00
{
// If a ROI as been set use it for detection
cvSetImageROI ( src_img_gray , rect ) ;
}
eig_img = cvCreateImage ( cvGetSize ( src_img_gray ) , IPL_DEPTH_32F , 1 ) ;
temp_img = cvCreateImage ( cvGetSize ( src_img_gray ) , IPL_DEPTH_32F , 1 ) ;
corners = ( CvPoint2D32f * ) cvAlloc ( cornerCount * sizeof ( CvPoint2D32f ) ) ;
// image height and width
imgHeight = src_img_gray - > height ;
imgWidth = src_img_gray - > width ;
// Corner detection using cvCornerMinEigenVal
// (one of the methods available inOpenCV, there is also a cvConerHarris method that can be used by setting a flag in cvGoodFeaturesToTrack)
2013-10-22 11:33:32 +00:00
cvGoodFeaturesToTrack ( src_img_gray , eig_img , temp_img , corners , & cornerCount , aCornersParameters - > qualityLevel , aCornersParameters - > minDistance ) ;
cvFindCornerSubPix ( src_img_gray , corners , cornerCount , cvSize ( aCornersParameters - > kernelSize , aCornersParameters - > kernelSize ) , cvSize ( - 1 , - 1 ) ,
cvTermCriteria ( aCornersParameters - > typeCriteria , aCornersParameters - > maxIter , aCornersParameters - > epsilon ) ) ;
2012-08-09 07:58:02 +00:00
cvReleaseImage ( & eig_img ) ;
cvReleaseImage ( & temp_img ) ;
cvReleaseImage ( & src_img_gray ) ;
}
/*!
Computes the contours of the image located at imagePath
*/
2013-12-18 14:23:59 +00:00
bool ShapeRec_FeatureDetector : : ComputeContours ( bool useROI , ShapeRec_Parameters * parameters )
{
2012-08-09 07:58:02 +00:00
// Initialising images
2013-10-22 11:33:32 +00:00
cv : : Mat src , src_gray ;
cv : : Mat detected_edges ;
2012-08-09 07:58:02 +00:00
// Read image
2013-10-22 11:33:32 +00:00
src = cv : : imread ( imagePath . c_str ( ) ) ;
2012-08-09 07:58:02 +00:00
if ( ! src . data )
return false ;
2013-10-22 11:33:32 +00:00
if ( ! useROI ) // CANNY: The problem is that with that filter the detector detects double contours
2012-08-09 07:58:02 +00:00
{
// Convert the image to grayscale
if ( src . channels ( ) = = 3 )
2013-10-22 11:33:32 +00:00
cv : : cvtColor ( src , src_gray , CV_BGR2GRAY ) ;
2012-08-09 07:58:02 +00:00
else if ( src . channels ( ) = = 1 )
src_gray = src ;
2013-10-22 11:33:32 +00:00
ShapeRec_CannyParameters * aCannyParameters = dynamic_cast < ShapeRec_CannyParameters * > ( parameters ) ;
if ( ! aCannyParameters ) aCannyParameters = new ShapeRec_CannyParameters ( ) ;
// Reduce noise
blur ( src_gray , detected_edges , cv : : Size ( aCannyParameters - > kernelSize , aCannyParameters - > kernelSize ) ) ;
2012-08-09 07:58:02 +00:00
// Canny detector
2013-10-22 11:33:32 +00:00
Canny ( detected_edges , detected_edges , aCannyParameters - > lowThreshold , aCannyParameters - > lowThreshold * aCannyParameters - > ratio ,
aCannyParameters - > kernelSize , aCannyParameters - > L2gradient ) ;
2012-08-09 07:58:02 +00:00
}
2013-10-22 11:33:32 +00:00
else //COLORFILTER
2012-08-09 07:58:02 +00:00
{
2013-12-18 14:23:59 +00:00
// Load the input image where we want to detect contours
IplImage * input_image = cvLoadImage ( imagePath . c_str ( ) , CV_LOAD_IMAGE_COLOR ) ;
2013-10-22 11:33:32 +00:00
ShapeRec_ColorFilterParameters * aColorFilterParameters = dynamic_cast < ShapeRec_ColorFilterParameters * > ( parameters ) ;
if ( ! aColorFilterParameters ) aColorFilterParameters = new ShapeRec_ColorFilterParameters ( ) ;
// Reduce noise
2013-12-18 14:23:59 +00:00
cvSmooth ( input_image , input_image , CV_GAUSSIAN , aColorFilterParameters - > smoothSize , aColorFilterParameters - > smoothSize ) ;
2013-10-22 11:33:32 +00:00
2013-12-18 14:23:59 +00:00
// Crop the image to the selected part only (sample_image)
cvSetImageROI ( input_image , rect ) ;
IplImage * sample_image = cvCreateImage ( cvGetSize ( input_image ) ,
input_image - > depth ,
input_image - > nChannels ) ;
cvCopy ( input_image , sample_image , NULL ) ;
cvResetImageROI ( input_image ) ;
2012-08-09 07:58:02 +00:00
2013-12-18 14:23:59 +00:00
IplImage * sample_hsv = cvCreateImage ( cvGetSize ( sample_image ) , 8 , 3 ) ;
IplImage * sample_h_plane = cvCreateImage ( cvGetSize ( sample_image ) , 8 , 1 ) ;
IplImage * sample_s_plane = cvCreateImage ( cvGetSize ( sample_image ) , 8 , 1 ) ;
CvHistogram * sample_hist ;
2013-10-22 11:33:32 +00:00
2013-12-18 14:23:59 +00:00
cvCvtColor ( sample_image , sample_hsv , CV_BGR2HSV ) ;
2013-10-22 11:33:32 +00:00
2021-03-16 14:26:59 +03:00
cvSplit ( sample_hsv , sample_h_plane , sample_s_plane , 0 , 0 ) ;
2013-12-18 14:23:59 +00:00
IplImage * sample_planes [ ] = { sample_h_plane , sample_s_plane } ;
2013-10-22 11:33:32 +00:00
2013-12-18 14:23:59 +00:00
// Create the hue / saturation histogram of the SAMPLE image.
// This histogramm will be representative of what is the zone
// we want to find the frontier of. Indeed, the sample image is meant to
// be representative of this zone
2013-10-22 11:33:32 +00:00
float hranges [ ] = { 0 , 180 } ;
float sranges [ ] = { 0 , 256 } ;
float * ranges [ ] = { hranges , sranges } ;
2013-12-18 14:23:59 +00:00
sample_hist = cvCreateHist ( 2 , aColorFilterParameters - > histSize , aColorFilterParameters - > histType , ranges ) ;
2013-10-22 11:33:32 +00:00
//calculate hue /saturation histogram
2013-12-18 14:23:59 +00:00
cvCalcHist ( sample_planes , sample_hist , 0 , 0 ) ;
2013-10-22 11:33:32 +00:00
// // TEST print of the histogram for debugging
// IplImage* hist_image = cvCreateImage(cvSize(320,300),8,3);
//
// //draw hist on hist_test image.
// cvZero(hist_image);
// float max_value = 0;
// cvGetMinMaxHistValue(hist, 0 , &max_value, 0, 0);
// int bin_w = hist_image->width/size_hist;
// for(int i = 0; i < size_hist; i++ )
// {
// //prevent overflow
// int val = cvRound( cvGetReal1D(hist->bins,i)*hist_image->
// height/max_value);
// CvScalar color = CV_RGB(200,0,0);
// //hsv2rgb(i*180.f/size_hist);
// cvRectangle( hist_image, cvPoint(i*bin_w,hist_image->height),
// cvPoint((i+1)*bin_w,hist_image->height - val),
// color, -1, 8, 0 );
// }
//
//
// cvNamedWindow("hist", 1); cvShowImage("hist",hist_image);
2013-12-18 14:23:59 +00:00
// Calculate the back projection of hue and saturation planes of the INPUT image
// by mean of the histogram of the SAMPLE image.
//
// The pixels which (h,s) coordinates correspond to high values in the histogram
// will have high values in the grey image result. It means that a pixel of the INPUT image
// which is more probably in the zone represented by the SAMPLE image, will be whiter
// in the back projection.
IplImage * backproject = cvCreateImage ( cvGetSize ( input_image ) , 8 , 1 ) ;
IplImage * binary_backproject = cvCreateImage ( cvGetSize ( input_image ) , 8 , 1 ) ;
IplImage * input_hsv = cvCreateImage ( cvGetSize ( input_image ) , 8 , 3 ) ;
IplImage * input_hplane = cvCreateImage ( cvGetSize ( input_image ) , 8 , 1 ) ;
IplImage * input_splane = cvCreateImage ( cvGetSize ( input_image ) , 8 , 1 ) ;
2013-10-22 11:33:32 +00:00
2013-12-18 14:23:59 +00:00
// Get hue and saturation planes of the INPUT image
cvCvtColor ( input_image , input_hsv , CV_BGR2HSV ) ;
2021-03-16 14:26:59 +03:00
cvSplit ( input_hsv , input_hplane , input_splane , 0 , 0 ) ;
2013-12-18 14:23:59 +00:00
IplImage * input_planes [ ] = { input_hplane , input_splane } ;
// Compute the back projection
cvCalcBackProject ( input_planes , backproject , sample_hist ) ;
// Threshold in order to obtain a binary image
2013-10-22 11:33:32 +00:00
cvThreshold ( backproject , binary_backproject , aColorFilterParameters - > threshold , aColorFilterParameters - > maxThreshold , CV_THRESH_BINARY ) ;
2013-12-18 14:23:59 +00:00
cvReleaseImage ( & sample_image ) ;
cvReleaseImage ( & sample_hsv ) ;
cvReleaseImage ( & sample_h_plane ) ;
cvReleaseImage ( & sample_s_plane ) ;
cvReleaseImage ( & input_image ) ;
cvReleaseImage ( & input_hsv ) ;
cvReleaseImage ( & input_hplane ) ;
cvReleaseImage ( & input_splane ) ;
2013-10-22 11:33:32 +00:00
cvReleaseImage ( & backproject ) ;
2019-09-02 20:31:02 +03:00
# if CV_MAJOR_VERSION == 3
detected_edges = cv : : cvarrToMat ( binary_backproject ) ;
# else
2013-10-22 11:33:32 +00:00
detected_edges = cv : : Mat ( binary_backproject ) ;
2019-09-02 20:31:02 +03:00
# endif
2013-10-22 11:33:32 +00:00
}
2017-12-04 14:42:45 +03:00
// else if ( detection_method == RIDGE_DETECTOR ) // Method adapted for engineering drawings (e.g. watershed functionality could be used here cf.OpenCV documentation and samples)
2013-10-22 11:33:32 +00:00
// {
// // TODO
// return false;
// }
// _detectAndRetrieveContours( detected_edges, parameters->findContoursMethod );
detected_edges = detected_edges > 1 ;
2013-12-18 14:23:59 +00:00
findContours ( detected_edges , contours , hierarchy , CV_RETR_CCOMP , parameters - > findContoursMethod ) ;
2013-10-22 11:33:32 +00:00
2012-08-09 07:58:02 +00:00
return true ;
}
/*!
Computes the lines in the image located at imagePath
*/
bool ShapeRec_FeatureDetector : : ComputeLines ( ) {
MESSAGE ( " ShapeRec_FeatureDetector::ComputeLines() " )
// Initialising images
2013-10-22 11:33:32 +00:00
cv : : Mat src , src_gray , detected_edges , dst ;
2012-08-09 07:58:02 +00:00
2013-10-22 11:33:32 +00:00
src = cv : : imread ( imagePath . c_str ( ) , 0 ) ;
2012-08-09 07:58:02 +00:00
Canny ( src , dst , 50 , 200 , 3 ) ;
HoughLinesP ( dst , lines , 1 , CV_PI / 180 , 80 , 30 , 10 ) ;
return true ;
}
/*!
Stores a region of interest given by user in rect
\ param theRect - Region Of Interest of the image located at imagePath
*/
void ShapeRec_FeatureDetector : : SetROI ( const QRect & theRect )
{
if ( ! theRect . isEmpty ( ) ) {
rect = cvRect ( theRect . x ( ) , theRect . y ( ) , theRect . width ( ) , theRect . height ( ) ) ;
}
}
/*!
Crops the image located at imagePath to the region of interest given by the user via SetROI
and stores the result in / tmp
*/
std : : string ShapeRec_FeatureDetector : : CroppImage ( )
{
IplImage * src = cvLoadImage ( imagePath . c_str ( ) , CV_LOAD_IMAGE_COLOR ) ;
cvSetImageROI ( src , rect ) ;
IplImage * cropped_image = cvCreateImage ( cvGetSize ( src ) ,
src - > depth ,
src - > nChannels ) ;
cvCopy ( src , cropped_image , NULL ) ;
cvResetImageROI ( src ) ;
cvSaveImage ( " /tmp/cropped_image.bmp " , cropped_image ) ;
2013-12-18 14:23:59 +00:00
cvReleaseImage ( & src ) ;
cvReleaseImage ( & cropped_image ) ;
2012-08-09 07:58:02 +00:00
return " /tmp/cropped_image.bmp " ;
}
2013-10-22 11:33:32 +00:00
/*!
\ class ShapeRec_CornersParameters
\ brief Parameters for the corners detection
*/
ShapeRec_CornersParameters : : ShapeRec_CornersParameters ( )
{
qualityLevel = 0.2 ;
minDistance = 1 ;
typeCriteria = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS ;
maxIter = 20 ;
epsilon = 0.03 ;
}
ShapeRec_CornersParameters : : ~ ShapeRec_CornersParameters ( )
{
}
2012-08-09 07:58:02 +00:00
/*!
2013-10-22 11:33:32 +00:00
\ class ShapeRec_Parameters
\ brief Parameters for the contour / corners detection
2012-08-09 07:58:02 +00:00
*/
2013-10-22 11:33:32 +00:00
ShapeRec_Parameters : : ShapeRec_Parameters ( )
{
kernelSize = 3 ;
findContoursMethod = CV_CHAIN_APPROX_NONE ;
}
ShapeRec_Parameters : : ~ ShapeRec_Parameters ( )
2012-08-09 07:58:02 +00:00
{
}
/*!
2013-10-22 11:33:32 +00:00
\ class ShapeRec_CannyParameters
\ brief Parameters for the contour detection
2012-08-09 07:58:02 +00:00
*/
2013-10-22 11:33:32 +00:00
ShapeRec_CannyParameters : : ShapeRec_CannyParameters ( )
{
lowThreshold = 100 ; // is used for edge linking.
ratio = 3 ; // lowThreshold*ratio is used to find initial segments of strong edges
L2gradient = true ; // norm L2 or L1
}
2012-08-09 07:58:02 +00:00
2013-10-22 11:33:32 +00:00
ShapeRec_CannyParameters : : ~ ShapeRec_CannyParameters ( )
{
}
2012-08-09 07:58:02 +00:00
2013-10-22 11:33:32 +00:00
/*!
\ class ShapeRec_ColorFilterParameters
\ brief Parameters for the contour detection
*/
ShapeRec_ColorFilterParameters : : ShapeRec_ColorFilterParameters ( )
{
smoothSize = 3 ; // The parameter of the smoothing operation, the aperture width. Must be a positive odd number
histSize = new int [ 2 ] ; // array of the histogram dimension sizes
histSize [ 0 ] = 30 ; // hbins
histSize [ 1 ] = 32 ; // sbins
histType = CV_HIST_ARRAY ; // histogram representation format
threshold = 128 ; // threshold value
maxThreshold = 255 ; // maximum value to use with the THRESH_BINARY thresholding types
}
ShapeRec_ColorFilterParameters : : ~ ShapeRec_ColorFilterParameters ( )
{
2012-08-09 07:58:02 +00:00
}