From ba19ad7f5e32a6f9c0a5c4c44f8a3724d640248b Mon Sep 17 00:00:00 2001
From: Otmane Lahlou <otmane.lahlou@c-s.fr>
Date: Mon, 9 Feb 2009 14:11:39 +0100
Subject: [PATCH] ADD: Fast LineSegmentDetection & Tests (still some problems
 on the orientation of the segments)

---
 .../otbLineSegmentDetector.h                  |  10 +-
 .../otbLineSegmentDetector.txx                | 147 ++++++++----------
 Testing/Code/FeatureExtraction/CMakeLists.txt |  17 ++
 .../otbFeatureExtractionTests11.cxx           |   4 +-
 .../otbLineSegmentDetector.cxx                |   1 +
 5 files changed, 89 insertions(+), 90 deletions(-)

diff --git a/Code/FeatureExtraction/otbLineSegmentDetector.h b/Code/FeatureExtraction/otbLineSegmentDetector.h
index 4f3b0a72bc..c63c48422b 100644
--- a/Code/FeatureExtraction/otbLineSegmentDetector.h
+++ b/Code/FeatureExtraction/otbLineSegmentDetector.h
@@ -42,7 +42,7 @@ namespace Functor
 	
 	inline TOutputPixel operator()(const TInputPixel& input)
 	  {
-	    return vcl_sqrt(input[0]*input[0]+input[1]*input[1] );
+	    return vcl_sqrt((input[0]+input[1])*(input[0]+input[1])  +(input[0]*input[1])*(input[0]*input[1]) );
 	  }
       };
     
@@ -58,10 +58,10 @@ namespace Functor
 	inline TOutputPixel operator()(const TInputPixel& input)
 	  {
 	    TOutputPixel resp = vcl_atan2(input[1],-input[0]);
-	    if (resp<0)
-	      {
-		resp+=2*M_PI;
-	      }
+/* 	    if (resp<0) */
+/* 	      { */
+/* 		resp+=2*M_PI; */
+/* 	      } */
 	    
 	    return resp;
 	  }
diff --git a/Code/FeatureExtraction/otbLineSegmentDetector.txx b/Code/FeatureExtraction/otbLineSegmentDetector.txx
index abece5eedf..9e2fc7ee75 100644
--- a/Code/FeatureExtraction/otbLineSegmentDetector.txx
+++ b/Code/FeatureExtraction/otbLineSegmentDetector.txx
@@ -27,6 +27,9 @@
 
 #include "otbMath.h"
 
+#include "itkMatrix.h"
+#include "itkSymmetricEigenAnalysis.h"
+
 #define MAXIT 100
 #define EPS 3.0e-7
 #define FPMIN 1.0e-30
@@ -118,7 +121,8 @@ LineSegmentDetector<TInputImage,TPrecision >
   float logNT = 5.*(vcl_log10(static_cast<float>(SizeInput[0])) + vcl_log10(static_cast<float>(SizeInput[1])))/2.;
   float log1_p = vcl_log10(0.125);
   float rapport = logNT/log1_p;
-  m_MinimumRegionSize = -1*static_cast<unsigned int>(rapport);
+  m_MinimumRegionSize = -1*static_cast<unsigned  int>(rapport);
+
   
   /** Definition of the min & the max of an image*/
   OutputPixelType   min = itk::NumericTraits<MagnitudePixelType >::Zero;
@@ -147,7 +151,7 @@ LineSegmentDetector<TInputImage,TPrecision >
   itk::ImageRegionIterator<OutputImageType> it(modulusImage, 
 					       modulusImage->GetRequestedRegion());
     
-  std::cout << "min "<< min<<  " max " << max  << " lengthBin " << lengthBin <<  " et thresh" << m_Threshold << std::endl;
+  //std::cout << "min "<< min<<  " max " << max  << " lengthBin " << lengthBin <<  " et thresh" << m_Threshold << std::endl;
   it.GoToBegin();
   while(!it.IsAtEnd())
     {
@@ -216,9 +220,11 @@ LineSegmentDetector<TInputImage, TPrecision>
   /** Compute the rectangle*/
   CoordinateHistogramIteratorType     ItRegion = m_RegionList.begin();
   DirectionVectorIteratorType         ItDir    =  m_DirectionVector.begin();
-
+  std::cout << " NB DE REGIONS : "<< m_RegionList.size()<< std::endl;
+  
   while(ItRegion != m_RegionList.end() && ItDir !=m_DirectionVector.end() )
     {
+
       this->Region2Rect(*ItRegion, *ItDir );
       ++ItRegion;
       ++ItDir;
@@ -235,7 +241,7 @@ LineSegmentDetector<TInputImage, TPrecision>
        */
       if(NFA > 0./** eps */)
 	{
-	  std::cout << (*itRec)[0] << " " << (*itRec)[1] << " " << (*itRec)[2] << " " << (*itRec)[3]<<std::endl;
+	  //std::cout << (*itRec)[0] << " " << (*itRec)[1] << " " << (*itRec)[2] << " " << (*itRec)[3]<<std::endl;
 	  PointListType pointList;
 	  PointType     point;
 	  
@@ -490,11 +496,11 @@ LineSegmentDetector<TInputImage, TPrecision>
     }/** End Searching loop*/
     
   /** Store the region*/
-  if(reg.size()> m_MinimumRegionSize && reg.size() <static_cast<unsigned int>(m_NumberOfImagePixels/4))
-    {
+  if(reg.size()> m_MinimumRegionSize && reg.size() < static_cast<unsigned int>(m_NumberOfImagePixels/2))
+  {
       m_RegionList.push_back(reg);
       m_DirectionVector.push_back(regionAngle);
-    }
+  }
 }
 
 /**************************************************************************************************************/
@@ -506,17 +512,29 @@ bool
 LineSegmentDetector<TInputImage, TPrecision>
 ::IsAligned(float Angle, float regionAngle, float prec)
 {
+
+ //  if(Angle < 0.) Angle = - Angle;
+//   if(regionAngle < 0.)  regionAngle = -regionAngle ;
+
+//   while(Angle > M_PI) Angle -= M_PI;
+//   while( regionAngle > M_PI)  regionAngle -= M_PI;
+
+//   if(Angle < 0.) Angle = - Angle;
+//   if(regionAngle < 0.)  regionAngle = -regionAngle ;
+
   float diff = Angle - regionAngle;
-  if(diff > 2*M_PI ) diff -= 2*M_PI;
- 
   
   if( diff < 0.0 ) diff = -diff;
+
   if( diff > 1.5*M_PI )
     {
       diff -= 2*M_PI;
       if( diff < 0.0 ) diff = -diff;
     }
 
+
+
+
   return diff < prec;
 }
 
@@ -541,7 +559,7 @@ LineSegmentDetector<TInputImage, TPrecision>
   NeighborhoodIteratorType                                itNeigh(radius,m_MagnitudeFilter->GetOutput(),
 								  m_MagnitudeFilter->GetOutput()->GetRequestedRegion());
 
-  /** Computing the center iof the rectangle*/
+  /** Computing the center of the rectangle*/
   IndexVectorIteratorType    it = region.begin();
   while(it != region.end())
     {
@@ -570,7 +588,7 @@ LineSegmentDetector<TInputImage, TPrecision>
   typedef std::vector<MagnitudePixelType>                          MagnitudeVector;
   SizeType    sizeInput = this->GetInput()->GetRequestedRegion().GetSize();
 
-  int Diagonal =  2*static_cast<unsigned int>(vcl_sqrt(sizeInput[0]*sizeInput[0] +sizeInput[1]*sizeInput[1])) + 4;
+  int Diagonal =  static_cast<unsigned int>(vcl_sqrt(sizeInput[0]*sizeInput[0] +sizeInput[1]*sizeInput[1])) + 2;
   MagnitudeVector sum_l( 2*Diagonal, itk::NumericTraits<MagnitudePixelType>::Zero);
   MagnitudeVector sum_w( 2*Diagonal, itk::NumericTraits<MagnitudePixelType>::Zero);
   
@@ -582,14 +600,15 @@ LineSegmentDetector<TInputImage, TPrecision>
     {
       itNeigh.SetLocation(*it);
       weight = *itNeigh.GetCenterValue(); 
-      l = ( static_cast<float>((*it)[0]) - x )*dx + ( static_cast<float>((*it)[1]) - y )*dy;
+      l =  ( static_cast<float>((*it)[0]) - x )*dx + ( static_cast<float>((*it)[1]) - y )*dy;
       w = -( static_cast<float>((*it)[0]) - x )*dy + ( static_cast<float>((*it)[1]) - y )*dx;
-      
-      sum_l[static_cast< int>(l+0.5)+ Diagonal ] +=  weight;
-      sum_w[static_cast< int>(w+0.5)+ Diagonal ] +=  weight;
-	
+      	
       if(l<l_min) l_min = l;   if(l>l_max)  l_max = l;
       if(w<w_min) w_min = w;   if(w>w_max)  w_max = w;
+
+      sum_l[static_cast< int>(vcl_floor(l)+0.5)+ Diagonal ] +=  weight;
+      sum_w[static_cast< int>(vcl_floor(w)+0.5)+ Diagonal ] +=  weight;
+      
       ++it;
     }
   
@@ -618,6 +637,7 @@ LineSegmentDetector<TInputImage, TPrecision>
   
   float wl = (static_cast<float>(i-1) - 0.5 ) ;  
 
+
   /** Finally store the rectangle in vector this way : 
    *  vec[0] = x1 
    *  vec[1] = y1
@@ -630,47 +650,20 @@ LineSegmentDetector<TInputImage, TPrecision>
    */
   
   RectangleType          rec(8 ,0.);     // Definition of a rectangle : 8 components
-  rec[0] = x + lb*dx;
-  rec[1] = y + lb*dy;
-  rec[2] = x + lf*dx;
-  rec[3] = y + lf*dy;
+  rec[0] = (x + lb*dx >0)?x + lb*dx:0.;
+  rec[1] = (y + lb*dy>0 )?y + lb*dy:0.;
+  rec[2] = (x + lf*dx >0)?x + lf*dx:0.;
+  rec[3] = (y + lf*dy >0)? y + lf*dy:0;
   rec[4] = vcl_abs(wl - wr);
   rec[5] = theta;
   rec[6] = M_PI/8;
-  rec[7] = 0.125;
+  rec[7] = 1./8.;
   
   if(rec[4] - 1. <1e-10) rec[4] = 1.;
   m_RectangleList.push_back(rec);
 }
 
 /**************************************************************************************************************/
-/*
-  Region inertia matrix A:
-  Ixx Ixy
-  Ixy Iyy
-  where
-  Ixx = \sum_i y_i^2
-  Iyy = \sum_i x_i^2
-  Ixy = -\sum_i x_i y_i
-
-  lambda1 and lambda2 are the eigenvalues, with lambda1 >= lambda2.
-  They are found by solving the characteristic polynomial
-  det(\lambda I - A) = 0.
-
-  To get the line segment direction we want to get the eigenvector of
-  the smaller eigenvalue. We have to solve a,b in:
-  a.Ixx + b.Ixy = a.lambda2
-  a.Ixy + b.Iyy = b.lambda2
-  We want the angle theta = atan(b/a). I can be computed with
-  any of the two equations:
-  theta = atan( (lambda2-Ixx) / Ixy )
-  or
-  theta = atan( Ixy / (lambda2-Iyy) )
-
-  When |Ixx| > |Iyy| we use the first, otherwise the second
-  (just to get better numeric precision).
-*/
-
 template <class TInputImage, class TPrecision  >
 float
 LineSegmentDetector<TInputImage, TPrecision>
@@ -680,7 +673,6 @@ LineSegmentDetector<TInputImage, TPrecision>
   float Ixx = 0.0;
   float Iyy = 0.0;
   float Ixy = 0.0;
-  float lambda1 = 0.,lambda2 = 0.,tmp = 0.;
   float theta = 0.;
   float weight = 0.,sum = 0.;
   
@@ -697,47 +689,38 @@ LineSegmentDetector<TInputImage, TPrecision>
     {
       itNeigh.SetLocation(*it);
       weight = *itNeigh.GetCenterValue(); 
-      float Ixx2 = static_cast<float>((*it)[0]) - x;
-      float Iyy2 = static_cast<float>((*it)[1]) - y;
+      float Iyy2 = static_cast<float>((*it)[0]) - x;
+      float Ixx2 = static_cast<float>((*it)[1]) - y;
       
-      Ixx += vcl_pow(Ixx2 ,2)*weight;
-      Iyy += vcl_pow(Iyy2 ,2)*weight;
+      Ixx += Ixx2*Ixx2*weight;
+      Iyy += Iyy2*Iyy2*weight;
       Ixy -= Ixx2*Iyy2*weight;
       sum +=  weight;
       ++it;
     }
-  
-  if( sum <= 1e-10 )
-    {  Ixx=0.; Iyy =0.;  Ixy =0.; } 
-  else
-    {
-      Ixx /= sum;
-      Iyy /= sum;
-      Ixy /= sum;
-      lambda1 = ( Ixx+Iyy + vcl_sqrt( (Ixx-Iyy)*(Ixx-Iyy) + 4 * Ixy * Ixy ) ) / 2.0;
-      lambda2 = ( Ixx+Iyy - vcl_sqrt( (Ixx-Iyy)*(Ixx-Iyy) + 4 * Ixy * Ixy ) ) / 2.0;
-    }
-
-  if( vcl_abs(lambda1) < vcl_abs(lambda2) )
-    {
-      tmp = lambda1;
-      lambda1 = lambda2;
-      lambda2 = tmp;
-    }
-
-  if( vcl_fabs(Ixx) > vcl_fabs(Iyy) )
-    theta = vcl_atan2( lambda2 - Ixx , Ixy );
-  else
-    theta = vcl_atan2( Ixy, lambda2 - Iyy );
 
+  /** using te itk Eigen analysis*/
+  typedef itk::Matrix<float , 2, 2>    MatrixType;
+  typedef std::vector<float >    MatrixEigenType;
+  MatrixType Inertie, eigenVector;
+  MatrixEigenType  eigenMatrix(2,0.);
+  Inertie[0][0] =Ixx;
+  Inertie[1][1] =Iyy;
+  Inertie[0][1] =Ixy;
+  Inertie[1][0] =Ixy;
+  
+  typedef itk::SymmetricEigenAnalysis<MatrixType,MatrixEigenType>   EigenAnalysisType;
+  EigenAnalysisType eigenFilter(2) ;
+  eigenFilter.ComputeEigenValuesAndVectors(Inertie,eigenMatrix,eigenVector  );
+  theta = vcl_atan2(eigenVector[1][1], -eigenVector[1][0]);
+  
   /* the previous procedure don't cares orientations,
      so it could be wrong by 180 degrees.
      here is corrected if necessary */
-  float prec = 0.125;
-  //std::cout << "AngleImage" <<theta  << "Angle Region" << angleRegion <<std::endl;
+
+  float prec = M_PI/8;
   if( this->angle_diff(theta,angleRegion) > prec ) theta += M_PI;
 
-  
   return theta;
 }
 
@@ -751,8 +734,8 @@ LineSegmentDetector<TInputImage, TPrecision>
 ::angle_diff(float a, float b)
 {
   a -= b;
-  while( a <= -M_PI ) a += 2.0*M_PI;
-  while( a >   M_PI ) a -= 2.0*M_PI;
+  while( a <= -M_PI ) a += 2*M_PI;
+  while( a >   M_PI ) a -= 2*M_PI;
   if( a < 0.0 ) a = -a;
   return a;
 }
@@ -837,8 +820,6 @@ LineSegmentDetector<TInputImage, TPrecision>
   float logNT = 5.*(vcl_log10(static_cast<float>(SizeInput[0])) + vcl_log10(static_cast<float>(SizeInput[1])))/2.;
   
   nfa_val = NFA(pts,NbAligned ,0.125,logNT);
-  //std::cout <<"Aligned " << NbAligned << " PtsInRegion" << pts << " NFA " << nfa_val <<std::endl;
-
   
   return nfa_val;
 }
diff --git a/Testing/Code/FeatureExtraction/CMakeLists.txt b/Testing/Code/FeatureExtraction/CMakeLists.txt
index b63b5201d0..4ffdc3c835 100644
--- a/Testing/Code/FeatureExtraction/CMakeLists.txt
+++ b/Testing/Code/FeatureExtraction/CMakeLists.txt
@@ -1043,6 +1043,21 @@ ADD_TEST(feTpSimplifyManyPathListFilter ${FEATUREEXTRACTION_TESTS11}
         )
 
 
+# -------            otb::LineSegmenbtDetector   -------------
+ADD_TEST(feTuLineSegmentDetectorNew ${FEATUREEXTRACTION_TESTS11} 
+    otbLineSegmentDetectorNew)
+
+ADD_TEST(feTvLineSegmentDetector ${FEATUREEXTRACTION_TESTS11} 
+--compare-image ${EPS}
+     ${BASELINE}/feTvLineSegmentdetectorOutputImage.tif
+     ${TEMP}/feTvLineSegmentdetectorOutputImage.tif
+    otbLineSegmentDetector
+     ${INPUTDATA}/prison_toulouse.tif 
+    ${TEMP}/feTvLineSegmentdetectorOutputImage.tif
+)
+
+
+
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ otbFeatureExtractionTests12 ~~~~~~~~~~~~~~~~~~~~~
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1459,6 +1474,8 @@ otbCloudEstimatorFilter.cxx
 otbCloudDetectionFilterNew.cxx
 otbCloudDetectionFilter.cxx
 otbSimplifyManyPathListFilter.cxx
+otbLineSegmentDetectorNew.cxx
+otbLineSegmentDetector.cxx
 )
 SET(BasicFeatureExtraction_SRCS12
 otbTextureFunctorBase.cxx
diff --git a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx
index ea2a616409..97062cb345 100644
--- a/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx
+++ b/Testing/Code/FeatureExtraction/otbFeatureExtractionTests11.cxx
@@ -33,6 +33,6 @@ REGISTER_TEST(otbCloudEstimatorFilter);
 REGISTER_TEST(otbCloudDetectionFilterNew);
 REGISTER_TEST(otbCloudDetectionFilter);
 REGISTER_TEST(otbSimplifyManyPathListFilter);
-  REGISTER_TEST(otbLineSegmentDetectorNew);
-  REGISTER_TEST(otbLineSegmentDetector);
+REGISTER_TEST(otbLineSegmentDetectorNew);
+REGISTER_TEST(otbLineSegmentDetector);
 }
diff --git a/Testing/Code/FeatureExtraction/otbLineSegmentDetector.cxx b/Testing/Code/FeatureExtraction/otbLineSegmentDetector.cxx
index 8ab16cd512..502400140f 100644
--- a/Testing/Code/FeatureExtraction/otbLineSegmentDetector.cxx
+++ b/Testing/Code/FeatureExtraction/otbLineSegmentDetector.cxx
@@ -84,6 +84,7 @@ int otbLineSegmentDetector( int argc, char * argv[] )
       IndexEnd[0]= x1 ; IndexEnd[1] = y1;
 
       LineIteratorFilter   itLine(reader->GetOutput(),IndexBegin,  IndexEnd);
+      itLine.GoToBegin();
       while(!itLine.IsAtEnd())
 	{
 	  itLine.Set(255.);
-- 
GitLab