Commit 6fdd16e9 authored by Cédric Traizet's avatar Cédric Traizet

Merge branch 'refactor_compare_image' into 'develop'

Refactor compare image

Closes #2014

See merge request !683
parents 61e8f514 ce7f4527
Pipeline #3926 passed with stages
in 84 minutes and 55 seconds
......@@ -29,6 +29,8 @@
#include "otbDifferenceImageFilter.h"
#include "itkStreamingImageFilter.h"
#include "otbPersistentFilterStreamingDecorator.h"
#include "otbImageFileWriter.h"
int otbGridResampleImageFilter(int itkNotUsed(argc), char* itkNotUsed(argv)[])
......@@ -114,7 +116,7 @@ int otbGridResampleImageFilter(int itkNotUsed(argc), char* itkNotUsed(argv)[])
refFilter->SetOutputSpacing(uspacing);
refFilter->SetOutputDirection(direction);
typedef otb::DifferenceImageFilter<ImageType, ImageType> ComparisonFilterType;
typedef otb::PersistentFilterStreamingDecorator< otb::DifferenceImageFilter<ImageType, ImageType> > ComparisonFilterType;
typedef itk::StreamingImageFilter<ImageType, ImageType> StreamingFilterType;
StreamingFilterType::Pointer streamingRef = StreamingFilterType::New();
......@@ -126,12 +128,12 @@ int otbGridResampleImageFilter(int itkNotUsed(argc), char* itkNotUsed(argv)[])
streaming->SetNumberOfStreamDivisions(10);
ComparisonFilterType::Pointer comparisonFilter = ComparisonFilterType::New();
comparisonFilter->SetValidInput(streamingRef->GetOutput());
comparisonFilter->SetTestInput(streaming->GetOutput());
comparisonFilter->SetDifferenceThreshold(1e-9);
comparisonFilter->GetFilter()->SetValidInput(streamingRef->GetOutput());
comparisonFilter->GetFilter()->SetTestInput(streaming->GetOutput());
comparisonFilter->GetFilter()->SetDifferenceThreshold(1e-9);
comparisonFilter->Update();
unsigned int nbPixelsWithDiff = comparisonFilter->GetNumberOfPixelsWithDifferences();
unsigned int nbPixelsWithDiff = comparisonFilter->GetFilter()->GetNumberOfPixelsWithDifferences();
std::cout << "Number of pixels with differences: " << nbPixelsWithDiff << std::endl;
......@@ -141,7 +143,7 @@ int otbGridResampleImageFilter(int itkNotUsed(argc), char* itkNotUsed(argv)[])
typedef otb::ImageFileWriter<ImageType> WriterType;
WriterType::Pointer writer = WriterType::New();
writer->SetInput(comparisonFilter->GetOutput());
writer->SetInput(comparisonFilter->GetFilter()->GetOutput());
writer->SetFileName("otbGridResampleImageFilterTestOutput.tif");
writer->Update();
......
......@@ -22,6 +22,8 @@
#include "otbMeanShiftSmoothingImageFilter.h"
#include "otbPersistentFilterStreamingDecorator.h"
#include "otbDifferenceImageFilter.h"
#include "otbMultiChannelExtractROI.h"
......@@ -61,8 +63,10 @@ int otbMeanShiftSmoothingImageFilterSpatialStability(int argc, char* argv[])
typedef otb::MultiChannelExtractROI<PixelType, PixelType> ExtractROIFilterType;
typedef otb::MultiChannelExtractROI<SpatialPixelType, SpatialPixelType> SpatialExtractROIFilterType;
typedef otb::DifferenceImageFilter<ImageType, ImageType> SubtractFilterType;
typedef otb::DifferenceImageFilter<SpatialImageType, SpatialImageType> SpatialSubtractFilterType;
typedef otb::PersistentFilterStreamingDecorator<otb::DifferenceImageFilter<ImageType, ImageType> >
SubtractFilterType;
typedef otb::PersistentFilterStreamingDecorator<otb::DifferenceImageFilter<SpatialImageType, SpatialImageType> >
SpatialSubtractFilterType;
// Instantiating object
......@@ -133,11 +137,11 @@ int otbMeanShiftSmoothingImageFilterSpatialStability(int argc, char* argv[])
filterROISpatial2->SetSizeY(sizeYROI);
SpatialSubtractFilterType::Pointer filterSubSpatial = SpatialSubtractFilterType::New();
filterSubSpatial->SetValidInput(filterROISpatial1->GetOutput());
filterSubSpatial->SetTestInput(filterROISpatial2->GetOutput());
filterSubSpatial->GetFilter()->SetValidInput(filterROISpatial1->GetOutput());
filterSubSpatial->GetFilter()->SetTestInput(filterROISpatial2->GetOutput());
filterSubSpatial->Update();
SpatialImageType::PixelType spatialOutputDiff = filterSubSpatial->GetTotalDifference();
SpatialImageType::PixelType spatialOutputDiff = filterSubSpatial->GetFilter()->GetTotalDifference();
ExtractROIFilterType::Pointer filterROISpectral1 = ExtractROIFilterType::New();
filterROISpectral1->SetInput(MSfilter->GetRangeOutput());
......@@ -155,11 +159,12 @@ int otbMeanShiftSmoothingImageFilterSpatialStability(int argc, char* argv[])
filterROISpectral2->SetSizeY(sizeYROI);
SubtractFilterType::Pointer filterSubSpectral = SubtractFilterType::New();
filterSubSpectral->SetValidInput(filterROISpectral1->GetOutput());
filterSubSpectral->SetTestInput(filterROISpectral2->GetOutput());
filterSubSpectral->GetFilter()->SetValidInput(filterROISpectral1->GetOutput());
filterSubSpectral->GetFilter()->SetTestInput(filterROISpectral2->GetOutput());
filterSubSpectral->Update();
ImageType::PixelType spectralOutputDiff = filterSubSpectral->GetTotalDifference();
ImageType::PixelType spectralOutputDiff = filterSubSpectral->GetFilter()->GetTotalDifference();
bool spatialUnstable = false;
bool spectralUnstable = false;
......
......@@ -21,7 +21,7 @@
#ifndef otbDifferenceImageFilter_h
#define otbDifferenceImageFilter_h
#include "itkImageToImageFilter.h"
#include "otbPersistentImageFilter.h"
#include "itkNumericTraits.h"
#include "itkArray.h"
......@@ -42,7 +42,7 @@ namespace otb
* \ingroup OTBTestKernel
*/
template <class TInputImage, class TOutputImage>
class ITK_EXPORT DifferenceImageFilter : public itk::ImageToImageFilter<TInputImage, TOutputImage>
class ITK_EXPORT DifferenceImageFilter : public otb::PersistentImageFilter <TInputImage, TOutputImage>
{
public:
/** Standard class typedefs. */
......@@ -87,11 +87,12 @@ public:
itkGetMacro(TotalDifference, AccumulateType);
itkGetMacro(NumberOfPixelsWithDifferences, unsigned long);
void Synthetize(void) override;
void Reset(void) override;
protected:
DifferenceImageFilter();
~DifferenceImageFilter() override
{
}
~DifferenceImageFilter() = default;
void PrintSelf(std::ostream& os, itk::Indent indent) const override;
......@@ -108,10 +109,8 @@ protected:
* ImageToImageFilter::GenerateData() */
void ThreadedGenerateData(const OutputImageRegionType& threadRegion, itk::ThreadIdType threadId) override;
void BeforeThreadedGenerateData() override;
void AfterThreadedGenerateData() override;
void GenerateOutputInformation() override;
ScalarRealType m_DifferenceThreshold;
RealType m_MeanDifference;
AccumulateType m_TotalDifference;
......
......@@ -51,6 +51,7 @@ DifferenceImageFilter<TInputImage, TOutputImage>::DifferenceImageFilter()
m_MeanDifference = itk::NumericTraits<RealType>::ZeroValue(m_MeanDifference);
m_TotalDifference = itk::NumericTraits<AccumulateType>::ZeroValue(m_TotalDifference);
m_NumberOfPixelsWithDifferences = 0;
}
//----------------------------------------------------------------------------
......@@ -80,6 +81,7 @@ void DifferenceImageFilter<TInputImage, TOutputImage>::SetTestInput(const InputI
// The test image should be input 1.
this->SetInput(1, testImage);
}
template <class TInputImage, class TOutputImage>
void DifferenceImageFilter<TInputImage, TOutputImage>::GenerateOutputInformation()
{
......@@ -91,10 +93,12 @@ void DifferenceImageFilter<TInputImage, TOutputImage>::GenerateOutputInformation
}
this->GetOutput()->SetNumberOfComponentsPerPixel(this->GetInput(0)->GetNumberOfComponentsPerPixel());
}
//----------------------------------------------------------------------------
template <class TInputImage, class TOutputImage>
void DifferenceImageFilter<TInputImage, TOutputImage>::BeforeThreadedGenerateData()
void DifferenceImageFilter<TInputImage, TOutputImage>::Reset()
{
this->UpdateOutputInformation();
int numberOfThreads = this->GetNumberOfThreads();
itk::NumericTraits<RealType>::SetLength(m_MeanDifference, this->GetInput(0)->GetNumberOfComponentsPerPixel());
......@@ -251,12 +255,12 @@ void DifferenceImageFilter<TInputImage, TOutputImage>::ThreadedGenerateData(cons
}
// Update global difference image statistics.
m_ThreadDifferenceSum[threadId] = threadDifferenceSum;
m_ThreadNumberOfPixels[threadId] = threadNumberOfPixels;
m_ThreadDifferenceSum[threadId] += threadDifferenceSum;
m_ThreadNumberOfPixels[threadId] += threadNumberOfPixels;
}
//----------------------------------------------------------------------------
template <class TInputImage, class TOutputImage>
void DifferenceImageFilter<TInputImage, TOutputImage>::AfterThreadedGenerateData()
void DifferenceImageFilter<TInputImage, TOutputImage>::Synthetize()
{
// Set statistics about difference image.
int numberOfThreads = this->GetNumberOfThreads();
......@@ -277,6 +281,8 @@ void DifferenceImageFilter<TInputImage, TOutputImage>::AfterThreadedGenerateData
m_MeanDifference = m_TotalDifference / numberOfPixels;
}
} // end namespace otb
#endif
......@@ -1203,17 +1203,16 @@ int TestHelper::RegressionTestBinaryFile(const char* testBinaryFileName, const c
int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, const char* baselineImageFilename, const double toleranceDiffPixelImage) const
{
// Use the factory mechanism to read the test and baseline files and convert them to double
typedef otb::VectorImage<double, 2> ImageType;
typedef otb::ImageFileReader<ImageType> ReaderType;
// Read the baseline file
ReaderType::Pointer baselineReader = ReaderType::New();
using ImageType = otb::VectorImage<double, 2>;
using ReaderType = otb::ImageFileReader<ImageType>;
// Read the baseline image informations
auto baselineReader = ReaderType::New();
baselineReader->SetFileName(baselineImageFilename);
try
{
baselineReader->UpdateLargestPossibleRegion();
baselineReader->UpdateOutputInformation();
}
catch (itk::ExceptionObject& e)
{
......@@ -1221,12 +1220,12 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
return 1000;
}
// Read the file generated by the test
ReaderType::Pointer testReader = ReaderType::New();
// Read the generated image information
auto testReader = ReaderType::New();
testReader->SetFileName(testImageFilename);
try
{
testReader->UpdateLargestPossibleRegion();
testReader->UpdateOutputInformation();
}
catch (itk::ExceptionObject& e)
{
......@@ -1235,10 +1234,8 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
}
// The sizes of the baseline and test image must match
ImageType::SizeType baselineSize;
baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
ImageType::SizeType testSize;
testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();
auto baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
auto testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();
if (baselineSize != testSize)
{
......@@ -1248,16 +1245,17 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
return 1;
}
// Now compare the two images
typedef otb::DifferenceImageFilter<ImageType, ImageType> DiffType;
DiffType::Pointer diff = DiffType::New();
diff->SetValidInput(baselineReader->GetOutput());
diff->SetTestInput(testReader->GetOutput());
diff->SetDifferenceThreshold(toleranceDiffPixelImage);
diff->UpdateLargestPossibleRegion();
// Use a virtual writer over the DifferenceImageFilter to compute the number of pixel with differences.
using DiffType = otb::PersistentFilterStreamingDecorator<otb::DifferenceImageFilter<ImageType, ImageType> >;
auto diffWriter = DiffType::New();
auto diffFilter = diffWriter->GetFilter();
diffFilter->SetValidInput(baselineReader->GetOutput());
diffFilter->SetTestInput(testReader->GetOutput());
diffFilter->SetDifferenceThreshold(toleranceDiffPixelImage);
diffWriter->Update();
ImageType::PixelType status = diff->GetTotalDifference();
unsigned long numberOfPixelsWithDifferences = diff->GetNumberOfPixelsWithDifferences();
ImageType::PixelType status = diffFilter->GetTotalDifference();
unsigned long numberOfPixelsWithDifferences = diffFilter->GetNumberOfPixelsWithDifferences();
int ret = 0;
if ((status.GetSquaredNorm() > 0) && ((double)numberOfPixelsWithDifferences > m_ToleranceRatio * baselineSize[0] * baselineSize[1]))
{
......@@ -1270,7 +1268,8 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
otbGenericMsgDebugMacro(<< "RegressionTestImage DifferenceThreshold: " << toleranceDiffPixelImage);
otbGenericMsgDebugMacro(<< "Status diff->GetTotalDifference: " << status << " for " << numberOfPixelsWithDifferences << " pixel(s).");
}
// if there are discrepencies, create an diff image
if (ret && m_ReportErrors)
{
typedef otb::PrintableImageFilter<ImageType> RescaleType;
......@@ -1292,8 +1291,8 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
std::cout << toleranceDiffPixelImage;
std::cout << "</DartMeasurement>" << std::endl;
diff->UpdateOutputInformation();
ImageType::SizeType size = diff->GetOutput()->GetLargestPossibleRegion().GetSize();
diffFilter->UpdateOutputInformation();
ImageType::SizeType size = diffFilter->GetOutput()->GetLargestPossibleRegion().GetSize();
if (size[0] * size[1] <= m_MaxArea)
{
......@@ -1301,9 +1300,9 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
diffName << testImageFilename << ".diff.png";
try
{
rescale->SetInput(diff->GetOutput());
rescale->SetInput(diffFilter->GetOutput());
for (unsigned int i = 1; i <= std::min(diff->GetOutput()->GetNumberOfComponentsPerPixel(), 3U); ++i)
for (unsigned int i = 1; i <= std::min(diffFilter->GetOutput()->GetNumberOfComponentsPerPixel(), 3U); ++i)
{
rescale->SetChannel(i);
}
......@@ -1415,6 +1414,7 @@ int TestHelper::RegressionTestImage(int cpt, const char* testImageFilename, cons
std::cout << "</DartMeasurement>" << std::endl;
}
}
return ret;
}
......
......@@ -27,8 +27,9 @@ set(OTBTestKernelTests
otbCompareAsciiTests6.cxx
otbCompareAsciiTestScientificNotation.cxx
otbCompareAsciiTests.cxx
otbCopyTest.cxx
otbCompareAsciiTestsEpsilon3_WhiteSpace.cxx
otbTestKernelTestDriver.cxx )
otbTestKernelTestDriver.cxx )
add_executable(otbTestKernelTestDriver ${OTBTestKernelTests})
target_link_libraries(otbTestKernelTestDriver ${OTBTestKernel-Test_LIBRARIES})
......@@ -175,3 +176,32 @@ otb_add_test(NAME tsTvCompareAscii6 COMMAND otbTestKernelTestDriver
${TEMP}/tsTvCompareAscii6_ref.txt
${TEMP}/tsTvCompareAscii6_test.txt
)
otb_add_test(NAME tsTvCompareImages_SameImages COMMAND otbTestKernelTestDriver
--compare-image 0
${INPUTDATA}/Spot5-Gloucester-before.tif
${TEMP}/tsTvCompareImages_SameImages.tif
otbCopyTest
${INPUTDATA}/Spot5-Gloucester-before.tif
${TEMP}/tsTvCompareImages_SameImages.tif
)
otb_add_test(NAME tsTvCompareImages_DifferentImages COMMAND otbTestKernelTestDriver
--compare-image 0
${INPUTDATA}/Spot5-Gloucester-after.tif
${TEMP}/tsTvCompareImages_DifferentImages.tif
otbCopyTest
${INPUTDATA}/Spot5-Gloucester-before.tif
${TEMP}/tsTvCompareImages_DifferentImages.tif
)
set_property(TEST tsTvCompareImages_DifferentImages PROPERTY WILL_FAIL true)
otb_add_test(NAME tsTvCompareImages_DifferentSizes COMMAND otbTestKernelTestDriver
--compare-image 0
${INPUTDATA}/ROI_QB_MUL_1.tif
${TEMP}/tsTvCompareImages_DifferentSizes.tif
otbCopyTest
${INPUTDATA}/Spot5-Gloucester-before.tif
${TEMP}/tsTvCompareImages_DifferentSizes.tif
)
set_property(TEST tsTvCompareImages_DifferentSizes PROPERTY WILL_FAIL true)
/*
* Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
*
* This file is part of Orfeo Toolbox
*
* https://www.orfeo-toolbox.org/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "otbVectorImage.h"
// Copy the input image in the output image. Used to test --compare-image.
// We don't call --compare-image directly on the input data because the output (.diff, .base, .test)
// are written at the same location as the input, and we don't want to pollute OTB/Data
int otbCopyTest(int argc, char* argv[])
{
if (argc != 3)
{
std::cerr << "Usage: " << argv[0];
std::cerr << " inputFileName outputFileName" << std::endl;
return EXIT_FAILURE;
}
using ImageType = otb::VectorImage<double, 2>;
using ReaderType = otb::ImageFileReader<ImageType>;
using WriterType = otb::ImageFileWriter<ImageType>;
auto reader = ReaderType::New();
reader->SetFileName(argv[1]);
auto writer = WriterType::New();
writer->SetFileName(argv[2]);
writer->SetInput(reader->GetOutput());
writer->Update();
return EXIT_SUCCESS;
}
......@@ -30,4 +30,5 @@ void RegisterTests()
REGISTER_TEST(otbCompareAsciiTestScientificNotation);
REGISTER_TEST(otbCompareAsciiTests);
REGISTER_TEST(otbCompareAsciiTestsEpsilon3_WhiteSpace);
REGISTER_TEST(otbCopyTest);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment