21 #ifndef otbLineSegmentDetector_hxx
22 #define otbLineSegmentDetector_hxx
25 #include "itkImageRegionIterator.h"
26 #include "itkMinimumMaximumImageCalculator.h"
27 #include "itkImageConstIterator.h"
28 #include "itkNeighborhoodIterator.h"
30 #include "itkCastImageFilter.h"
36 #include "itkMatrix.h"
37 #include "itkSymmetricEigenAnalysis.h"
40 extern "C" double dlngam_(
double* x);
41 extern "C" double dbetai_(
double* x,
double* a,
double* b);
46 template <
class TInputImage,
class TPrecision>
49 this->SetNumberOfRequiredInputs(1);
50 this->SetNumberOfRequiredOutputs(1);
52 m_DirectionsAllowed = 1. / 8.;
53 m_Prec =
CONST_PI * m_DirectionsAllowed;
57 m_GradientFilter = GradientFilterType::New();
58 m_MagnitudeFilter = MagnitudeFilterType::New();
59 m_OrientationFilter = OrientationFilterType::New();
63 m_UsedPointImage = LabelImageType::New();
66 template <
class TInputImage,
class TPrecision>
69 this->Superclass::SetNthInput(0,
const_cast<InputImageType*
>(input));
72 template <
class TInputImage,
class TPrecision>
75 if (this->GetNumberOfInputs() < 1)
80 return static_cast<const InputImageType*
>(this->Superclass::GetInput(0));
83 template <
class TInputImage,
class TPrecision>
87 Superclass::GenerateInputRequestedRegion();
90 typename InputImageType::Pointer input =
const_cast<InputImageType*
>(this->GetInput());
99 input->SetRequestedRegionToLargestPossibleRegion();
102 template <
class TInputImage,
class TPrecision>
105 if (this->GetInput()->GetRequestedRegion() != this->GetInput()->GetLargestPossibleRegion())
107 itkExceptionMacro(<<
"Not streamed filter. ERROR : requested region is not the largest possible region.");
111 m_UsedPointImage->SetRegions(this->GetInput()->GetLargestPossibleRegion());
112 m_UsedPointImage->Allocate();
113 m_UsedPointImage->FillBuffer(0);
117 typedef itk::CastImageFilter<InputImageType, OutputImageType> castFilerType;
118 typename castFilerType::Pointer castFilter = castFilerType::New();
119 castFilter->SetInput(this->GetInput());
123 m_GradientFilter->SetInput(castFilter->GetOutput());
124 m_GradientFilter->SetSigma(0.6);
125 m_MagnitudeFilter->SetInput(m_GradientFilter->GetOutput());
126 m_OrientationFilter->SetInput(m_GradientFilter->GetOutput());
129 m_MagnitudeFilter->Update();
130 m_OrientationFilter->Update();
133 CoordinateHistogramType CoordinateHistogram;
134 CoordinateHistogram = this->SortImageByModulusValue(m_MagnitudeFilter->GetOutput());
137 this->LineSegmentDetection(CoordinateHistogram);
140 this->ComputeRectangles();
143 template <
class TInputImage,
class TPrecision>
147 RegionType largestRegion = this->GetInput()->GetLargestPossibleRegion();
150 double logNT = 5. * std::log10(
static_cast<double>(largestRegion.GetNumberOfPixels())) / 2.;
151 double log1_p = std::log10(m_DirectionsAllowed);
152 double rapport = logNT / log1_p;
153 m_MinimumRegionSize =
static_cast<unsigned int>(-rapport);
156 typedef itk::MinimumMaximumImageCalculator<OutputImageType> MinMaxCalculatorFilter;
157 typename MinMaxCalculatorFilter::Pointer minmaxCalculator = MinMaxCalculatorFilter::New();
159 minmaxCalculator->SetImage(modulusImage);
160 minmaxCalculator->ComputeMinimum();
161 OutputPixelType min = minmaxCalculator->GetMinimum();
162 minmaxCalculator->ComputeMaximum();
163 OutputPixelType max = minmaxCalculator->GetMaximum();
166 m_Threshold = m_Threshold * ((max - min) / 255.);
169 unsigned int NbBin = 1024;
170 double lengthBin =
static_cast<double>((max - min)) /
static_cast<double>(NbBin - 1);
176 SizeType size = modulusImage->GetRequestedRegion().GetSize();
177 InputIndexType
id = modulusImage->GetRequestedRegion().GetIndex();
181 if (modulusImage->GetRequestedRegion().GetIndex()[0] == 0)
185 if (modulusImage->GetRequestedRegion().GetSize()[0] + modulusImage->GetRequestedRegion().GetIndex()[0] == largestRegion.GetSize(0))
188 else if (modulusImage->GetRequestedRegion().GetSize()[0] + modulusImage->GetRequestedRegion().GetIndex()[0] == largestRegion.GetSize(0))
193 if (modulusImage->GetRequestedRegion().GetIndex()[1] == 0)
197 if (modulusImage->GetRequestedRegion().GetSize()[1] + modulusImage->GetRequestedRegion().GetIndex()[1] == largestRegion.GetSize(1))
200 else if (modulusImage->GetRequestedRegion().GetSize()[1] + modulusImage->GetRequestedRegion().GetIndex()[1] == largestRegion.GetSize(1))
206 region.SetSize(size);
208 itk::ImageRegionIterator<OutputImageType> it(modulusImage, region);
211 while (!it.IsAtEnd())
213 unsigned int bin =
static_cast<unsigned int>(
static_cast<double>(it.Value() - min) / lengthBin);
218 if (it.Value() - m_Threshold > 1e-10)
219 tempHisto[NbBin - bin - 1].push_back(it.GetIndex());
221 SetPixelToUsed(it.GetIndex());
234 template <
class TInputImage,
class TPrecision>
239 CoordinateHistogramIteratorType ItCoordinateList = CoordinateHistogram.begin();
241 while (ItCoordinateList != CoordinateHistogram.end())
243 typename IndexVectorType::iterator ItIndexVector = (*ItCoordinateList).begin();
244 while (ItIndexVector != (*ItCoordinateList).end())
246 InputIndexType index = *(ItIndexVector);
249 if (this->IsNotUsed(index))
251 IndexVectorType region;
252 double regionAngle = 0.;
254 bool fail = GrowRegion(index, region, regionAngle);
259 RectangleType rectangle = Region2Rectangle(region, regionAngle);
262 double nfa = ImproveRectangle(rectangle);
265 (double)region.size() /
266 (std::sqrt((rectangle[2] - rectangle[0]) * (rectangle[2] - rectangle[0]) + (rectangle[3] - rectangle[1]) * (rectangle[3] - rectangle[1])) *
277 m_RectangleList.push_back(rectangle);
281 SetRegionToNotIni(region);
297 template <
class TInputImage,
class TPrecision>
301 this->GetOutput(0)->SetMetaDataDictionary(this->GetInput()->GetMetaDataDictionary());
303 typename DataNodeType::Pointer root = this->GetOutput(0)->GetDataTree()->GetRoot()->Get();
305 typename DataNodeType::Pointer document = DataNodeType::New();
308 this->GetOutput(0)->GetDataTree()->Add(document, root);
310 typename DataNodeType::Pointer folder = DataNodeType::New();
313 this->GetOutput(0)->GetDataTree()->Add(folder, document);
314 this->GetOutput(0)->SetProjectionRef(this->GetInput()->GetProjectionRef());
317 SpacingType spacing = this->GetInput()->GetSignedSpacing();
318 OriginType origin = this->GetInput()->GetOrigin();
321 RectangleListTypeIterator itRec = m_RectangleList.begin();
322 while (itRec != m_RectangleList.end())
324 VertexType start, end;
327 start[0] = origin[0] +
static_cast<TPrecision
>((*itRec)[0]) * spacing[0];
328 start[1] = origin[1] +
static_cast<TPrecision
>((*itRec)[1]) * spacing[1];
330 end[0] = origin[0] +
static_cast<TPrecision
>((*itRec)[2]) * spacing[0];
331 end[1] = origin[1] +
static_cast<TPrecision
>((*itRec)[3]) * spacing[1];
333 typename DataNodeType::Pointer CurrentGeometry = DataNodeType::New();
334 CurrentGeometry->SetNodeId(
"FEATURE_LINE");
336 typename LineType::Pointer line = LineType::New();
337 CurrentGeometry->SetLine(line);
338 this->GetOutput(0)->GetDataTree()->Add(CurrentGeometry, folder);
339 CurrentGeometry->GetLine()->AddVertex(start);
340 CurrentGeometry->GetLine()->AddVertex(end);
353 template <
class TInputImage,
class TPrecision>
356 RectangleIteratorType itSrc = rSrc.begin();
358 while (itSrc != rSrc.end())
360 rDst.push_back(*(itSrc));
371 template <
class TInputImage,
class TPrecision>
377 double delta_2 = delta / 2.0;
380 double nfa_rect = this->ComputeRectNFA(rec);
386 CopyRectangle(r, rec);
387 for (n = 0; n < 5; ++n)
391 nfa_new = this->ComputeRectNFA(r);
392 if (nfa_new > nfa_rect)
395 CopyRectangle(rec, r);
403 CopyRectangle(r, rec);
404 for (n = 0; n < 5; ++n)
407 nfa_new = this->ComputeRectNFA(r);
408 if (nfa_new > nfa_rect)
411 CopyRectangle(rec, r);
418 CopyRectangle(r, rec);
419 for (n = 0; n < 5; ++n)
421 if ((r[4] - delta) >= 0.5)
423 r[0] += -std::sin(r[5]) * delta_2;
424 r[1] += std::cos(r[5]) * delta_2;
425 r[2] += -std::sin(r[5]) * delta_2;
426 r[3] += std::cos(r[5]) * delta_2;
429 nfa_new = this->ComputeRectNFA(r);
430 if (nfa_new > nfa_rect)
433 CopyRectangle(rec, r);
440 CopyRectangle(r, rec);
441 for (n = 0; n < 5; ++n)
443 if ((r[4] - delta) >= 0.5)
445 r[0] -= -std::sin(r[5]) * delta_2;
446 r[1] -= std::cos(r[5]) * delta_2;
447 r[2] -= -std::sin(r[5]) * delta_2;
448 r[3] -= std::cos(r[5]) * delta_2;
451 nfa_new = this->ComputeRectNFA(r);
452 if (nfa_new > nfa_rect)
455 CopyRectangle(rec, r);
463 CopyRectangle(r, rec);
464 for (n = 0; n < 5; ++n)
468 nfa_new = this->ComputeRectNFA(r);
469 if (nfa_new > nfa_rect)
472 CopyRectangle(rec, r);
484 template <
class TInputImage,
class TPrecision>
487 bool isNotUsed =
false;
489 typedef itk::ImageConstIterator<LabelImageType> ImageIteratorType;
490 RegionType region = m_UsedPointImage->GetLargestPossibleRegion();
491 InputIndexType indexRef = region.GetIndex();
492 ImageIteratorType itLabel(m_UsedPointImage, region);
495 if (m_UsedPointImage->GetLargestPossibleRegion().IsInside(index))
497 itLabel.SetIndex(index);
498 if (itLabel.Get() == 0)
503 itkExceptionMacro(<<
"Can't access to index " << index <<
", outside the image largest region (" << indexRef <<
", " << region.GetSize() <<
")");
513 template <
class TInputImage,
class TPrecision>
518 typedef itk::ImageConstIterator<LabelImageType> ImageIteratorType;
519 RegionType region = m_UsedPointImage->GetLargestPossibleRegion();
520 InputIndexType indexRef = region.GetIndex();
521 ImageIteratorType itLabel(m_UsedPointImage, region);
524 if (m_UsedPointImage->GetLargestPossibleRegion().IsInside(index))
526 itLabel.SetIndex(index);
527 if (itLabel.Get() == 255)
532 itkExceptionMacro(<<
"Can't access to index " << index <<
", outside the image largest region (" << indexRef <<
", " << region.GetSize() <<
")");
543 template <
class TInputImage,
class TPrecision>
546 bool isNotIni =
false;
548 typedef itk::ImageConstIterator<LabelImageType> ImageIteratorType;
549 RegionType region = m_UsedPointImage->GetLargestPossibleRegion();
550 InputIndexType indexRef = region.GetIndex();
551 ImageIteratorType itLabel(m_UsedPointImage, region);
554 if (m_UsedPointImage->GetLargestPossibleRegion().IsInside(index))
556 itLabel.SetIndex(index);
557 if (itLabel.Get() == 127)
562 itkExceptionMacro(<<
"Can't access to index " << index <<
", outside the image largest region (" << indexRef <<
", " << region.GetSize() <<
")");
573 template <
class TInputImage,
class TPrecision>
576 typedef itk::NeighborhoodIterator<LabelImageType> NeighborhoodLabelIteratorType;
577 typename NeighborhoodLabelIteratorType::SizeType radiusLabel;
579 NeighborhoodLabelIteratorType itLabel(radiusLabel, m_UsedPointImage, m_UsedPointImage->GetRequestedRegion());
580 itLabel.SetLocation(index);
581 itLabel.SetCenterPixel(255);
590 template <
class TInputImage,
class TPrecision>
593 typedef itk::NeighborhoodIterator<LabelImageType> NeighborhoodLabelIteratorType;
594 typename NeighborhoodLabelIteratorType::SizeType radiusLabel;
596 NeighborhoodLabelIteratorType itLabel(radiusLabel, m_UsedPointImage, m_UsedPointImage->GetRequestedRegion());
597 itLabel.SetLocation(index);
598 itLabel.SetCenterPixel(127);
607 template <
class TInputImage,
class TPrecision>
610 IndexVectorIteratorType it = region.begin();
611 while (it != region.end())
613 this->SetPixelToNotIni(*it);
625 template <
class TInputImage,
class TPrecision>
630 this->SetPixelToUsed(index);
633 typedef itk::ConstNeighborhoodIterator<OutputImageType> NeighborhoodIteratorType;
634 typename NeighborhoodIteratorType::SizeType radius;
636 NeighborhoodIteratorType itNeigh(radius, m_MagnitudeFilter->GetOutput(), m_MagnitudeFilter->GetOutput()->GetRequestedRegion());
637 NeighborhoodIteratorType itNeighDir(radius, m_OrientationFilter->GetOutput(), m_OrientationFilter->GetOutput()->GetRequestedRegion());
641 unsigned int neighSize = itNeigh.GetSize()[0] * itNeigh.GetSize()[1];
644 region.push_back(index);
651 for (
unsigned int cpt = 0; cpt < region.size(); ++cpt)
653 itNeigh.SetLocation(region[cpt]);
654 itNeighDir.SetLocation(region[cpt]);
655 sumX += std::cos(*(itNeighDir.GetCenterValue()));
656 sumY += std::sin(*(itNeighDir.GetCenterValue()));
657 regionAngle = std::atan2(sumY, sumX);
661 while (s < neighSize)
663 InputIndexType NeighIndex = itNeigh.GetIndex(s);
664 double angleComp = itNeighDir.GetPixel(s);
668 if ((this->IsNotUsed(NeighIndex) || this->IsNotIni(NeighIndex)) && this->IsAligned(angleComp, regionAngle, m_Prec))
670 this->SetPixelToUsed(NeighIndex);
671 region.push_back(NeighIndex);
679 unsigned int nbPixels = this->GetInput()->GetLargestPossibleRegion().GetNumberOfPixels();
680 if (region.size() > m_MinimumRegionSize && region.size() < nbPixels / 4)
695 template <
class TInputImage,
class TPrecision>
698 double diff = Angle - regionAngle;
717 template <
class TInputImage,
class TPrecision>
723 double weight = 0., sumWeight = 0.;
724 double x = 0., y = 0.;
725 double l_min = 0., l_max = 0., l = 0., w = 0., w_min = 0., w_max = 0.;
728 typedef itk::ConstNeighborhoodIterator<OutputImageType> NeighborhoodIteratorType;
729 typename NeighborhoodIteratorType::SizeType radius;
731 NeighborhoodIteratorType itNeigh(radius, m_MagnitudeFilter->GetOutput(), m_MagnitudeFilter->GetOutput()->GetRequestedRegion());
735 IndexVectorIteratorType it = region.begin();
736 while (it != region.end())
738 itNeigh.SetLocation(*it);
739 weight = *itNeigh.GetCenterValue();
740 x +=
static_cast<double>((*it)[0]) * weight;
741 y +=
static_cast<double>((*it)[1]) * weight;
745 if (sumWeight < 1e-10)
758 double theta = this->ComputeRegionOrientation(region, x, y, regionAngle);
761 typedef std::vector<MagnitudePixelType> MagnitudeVector;
763 RegionType largestRegion = this->GetInput()->GetLargestPossibleRegion();
764 unsigned int Diagonal =
765 static_cast<unsigned int>(vnl_math_hypot(
static_cast<double>(largestRegion.GetSize(1)),
static_cast<double>(largestRegion.GetSize(0))) + 2);
767 MagnitudeVector sum_l(2 * Diagonal, itk::NumericTraits<MagnitudePixelType>::Zero);
768 MagnitudeVector sum_w(2 * Diagonal, itk::NumericTraits<MagnitudePixelType>::Zero);
770 double dx = std::cos(theta);
771 double dy = std::sin(theta);
774 while (it != region.end())
776 itNeigh.SetLocation(*it);
777 weight = *itNeigh.GetCenterValue();
778 l = (
static_cast<double>((*it)[0]) - x) * dx + (
static_cast<double>((*it)[1]) - y) * dy;
779 w = -(
static_cast<double>((*it)[0]) - x) * dy + (
static_cast<double>((*it)[1]) - y) * dx;
790 sum_l[
static_cast<int>(std::floor(l) + 0.5) + Diagonal] +=
static_cast<MagnitudePixelType
>(weight);
791 sum_w[
static_cast<int>(std::floor(w) + 0.5) + Diagonal] +=
static_cast<MagnitudePixelType
>(weight);
797 double sum_th = 0.01 * sumWeight;
801 for (s = 0.0, i =
static_cast<int>(l_min); s < sum_th && i <= static_cast<int>(l_max); ++i)
802 s += sum_l[Diagonal + i];
804 double lb = (
static_cast<double>(i - 1) - 0.5);
806 for (s = 0.0, i =
static_cast<int>(l_max); s < sum_th && i >=
static_cast<int>(l_min); i--)
807 s += sum_l[Diagonal + i];
808 double lf = (
static_cast<double>(i + 1) + 0.5);
810 for (s = 0.0, i =
static_cast<int>(w_min); s < sum_th && i <= static_cast<int>(w_max); ++i)
811 s += sum_w[Diagonal + i];
813 double wr = (
static_cast<double>(i - 1) - 0.5);
815 for (s = 0.0, i =
static_cast<int>(w_max); s < sum_th && i >=
static_cast<int>(w_min); i--)
816 s += sum_w[Diagonal + i];
818 double wl = (
static_cast<double>(i + 1) + 0.5);
830 RectangleType rec(8, 0.);
833 if (std::abs(wl - wr) -
834 std::sqrt(
static_cast<double>(largestRegion.GetSize(0) * largestRegion.GetSize(0) + largestRegion.GetSize(1) * largestRegion.GetSize(1))) <
837 rec[0] = (x + lb * dx > 0) ? x + lb * dx : 0.;
838 rec[1] = (y + lb * dy > 0) ? y + lb * dy : 0.;
839 rec[2] = (x + lf * dx > 0) ? x + lf * dx : 0.;
840 rec[3] = (y + lf * dy > 0) ? y + lf * dy : 0;
844 rec[7] = m_DirectionsAllowed;
846 if (rec[4] - 1. < 1e-10)
858 template <
class TInputImage,
class TPrecision>
866 double weight = 0., sum = 0.;
869 typedef itk::ConstNeighborhoodIterator<OutputImageType> NeighborhoodIteratorType;
870 typename NeighborhoodIteratorType::SizeType radius;
872 NeighborhoodIteratorType itNeigh(radius, m_MagnitudeFilter->GetOutput(), m_MagnitudeFilter->GetOutput()->GetRequestedRegion());
876 IndexVectorIteratorType it = region.begin();
877 while (it != region.end())
879 itNeigh.SetLocation(*it);
880 weight = *itNeigh.GetCenterValue();
881 double Iyy2 =
static_cast<double>((*it)[0]) - x;
882 double Ixx2 =
static_cast<double>((*it)[1]) - y;
885 Ixx += Ixx2 * Ixx2 * weight;
886 Iyy += Iyy2 * Iyy2 * weight;
887 Ixy -= Ixx2 * Iyy2 * weight;
893 typedef itk::Matrix<double, 2, 2> MatrixType;
894 typedef std::vector<double> MatrixEigenType;
895 MatrixType Inertie, eigenVector;
896 MatrixEigenType eigenMatrix(2, 0.);
902 typedef itk::SymmetricEigenAnalysis<MatrixType, MatrixEigenType> EigenAnalysisType;
903 EigenAnalysisType eigenFilter(2);
904 eigenFilter.ComputeEigenValuesAndVectors(Inertie, eigenMatrix, eigenVector);
905 theta = std::atan2(eigenVector[1][1], -eigenVector[1][0]);
911 if (this->angle_diff(theta, angleRegion) > m_Prec)
922 template <
class TInputImage,
class TPrecision>
941 template <
class TInputImage,
class TPrecision>
954 OTBRectangleType::Pointer rectangle = OTBRectangleType::New();
957 for (
int i = 0; i < 2; ++i)
959 typename OTBRectangleType::VertexType vertex;
960 vertex[0] = rec[2 * i];
961 vertex[1] = rec[2 * i + 1];
962 rectangle->AddVertex(vertex);
964 rectangle->SetWidth(rec[4]);
965 rectangle->SetOrientation(rec[5]);
969 OutputImageDirRegionType region = m_OrientationFilter->GetOutput()->GetLargestPossibleRegion();
970 region.Crop(rectangle->GetBoundingRegion());
974 itk::ImageRegionIterator<OutputImageDirType> it(m_OrientationFilter->GetOutput(), region);
979 while (!it.IsAtEnd())
981 if (rectangle->IsInside(it.GetIndex()) && m_OrientationFilter->GetOutput()->GetBufferedRegion().IsInside(it.GetIndex()))
985 if (this->IsAligned(it.Get(), rec[5] , rec[6] ))
992 RegionType largestRegion =
const_cast<Self*
>(
this)->GetInput()->GetLargestPossibleRegion();
993 double logNT = 5. * std::log10(
static_cast<double>(largestRegion.GetNumberOfPixels())) / 2.;
996 nfa_val = NFA(pts, NbAligned, m_DirectionsAllowed, logNT);
1010 template <
class TInputImage,
class TPrecision>
1014 double n_d =
static_cast<double>(n);
1015 double k_d =
static_cast<double>(k);
1022 double b = n_d - k_d + 1.0;
1023 val = -logNT - log10(
dbetai_(&p, &a, &b));
1025 if (vnl_math_isinf(val))
1027 double x1 = n_d + 1.0;
1028 double x2 = k_d + 1.0;
1029 double x3 = n_d - k_d + 1.0;
1039 template <
class TInputImage,
class TPrecision>
1042 Superclass::PrintSelf(os, indent);