From ce34a6077ea6d67e7c1e06296267c298dac176d9 Mon Sep 17 00:00:00 2001 From: Antoine Regimbeau <antoine.regimbeau@c-s.fr> Date: Mon, 17 Jul 2017 10:47:25 +0200 Subject: [PATCH] Get rid of itk histogram to gain in precision of what we are doing --- .../Filtering/Contrast/test/CMakeLists.txt | 1 - .../test/otbContrastEnhancementFilter.cxx | 214 ++++++++++-------- 2 files changed, 118 insertions(+), 97 deletions(-) diff --git a/Modules/Filtering/Contrast/test/CMakeLists.txt b/Modules/Filtering/Contrast/test/CMakeLists.txt index e6d3bf6920..850e18ff4e 100644 --- a/Modules/Filtering/Contrast/test/CMakeLists.txt +++ b/Modules/Filtering/Contrast/test/CMakeLists.txt @@ -17,7 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - otb_module_test() set(OTBContrastTests diff --git a/Modules/Filtering/Contrast/test/otbContrastEnhancementFilter.cxx b/Modules/Filtering/Contrast/test/otbContrastEnhancementFilter.cxx index 2ac67c20b9..bf9f205285 100644 --- a/Modules/Filtering/Contrast/test/otbContrastEnhancementFilter.cxx +++ b/Modules/Filtering/Contrast/test/otbContrastEnhancementFilter.cxx @@ -5,31 +5,66 @@ #include "otbVectorImage.h" #include "otbImageFileReader.h" #include "otbImageFileWriter.h" -#include "itkImageLinearIteratorWithIndex.h" +#include "itkImageRegionConstIterator.h" #include "itkImageToHistogramFilter.h" #include "itkVectorIndexSelectionCastImageFilter.h" #include "itkMultiplyImageFilter.h" +#include "itkComposeImageFilter.h" - +int const sizeh = 256; typedef int PixelType; typedef itk::Image< PixelType , 2 > ImageType; typedef itk::VectorImage< PixelType , 2 > VectorImageType; +typedef itk::Statistics::ImageToHistogramFilter< ImageType > HistogramFilterType; +typedef HistogramFilterType::HistogramType HistogramType; void -computeLuminance( ImageType::Pointer luminance , - VectorImageType::Pointer input ) +equalized( std::array< int , sizeh > const inputHisto, + std::array< int , sizeh > const targethisto, + std::array< int , sizeh > & lut) + { - itk::ImageRegionIterator< VectorImageType > itinp( input , input->GetRequestedRegion() ); - itk::ImageRegionIterator< ImageType > itlum( luminance , luminance->GetRequestedRegion() ); - itinp.GoToBegin(); - itlum.GoToBegin(); - while ( !itinp.IsAtEnd() ) - { - // 0.3R 0.6G 0.1B - itlum.Set( round(0.3 * itinp.Get()[0] + 0.6 * itinp.Get()[1] + 0.1 * itinp.Get()[2]) ); - ++itinp; - ++itlum; - } + int countMapValue = 0 ; + int countValue = 0; + int countInput = inputHisto[ countValue ]; + int countTarget = targethisto[ countMapValue ]; + while ( countMapValue<256 ) + { + if (countInput > countTarget) + { + ++countMapValue; + countTarget += targethisto[countMapValue]; + } + else + { + lut[countValue] = countMapValue ; + ++countValue; + countInput += inputHisto[ countValue ]; + } + } +} + +void +computehisto( ImageType::Pointer const input, + std::array<int , sizeh> & inputHisto) +{ + itk::ImageRegionConstIterator< ImageType > it ( input , input->GetRequestedRegion() ); + it.GoToBegin(); + while ( !it.IsAtEnd() ) + { + ++inputHisto[ it.Get() ]; + ++it; + } +} + +void +createTarget( std::array< int , sizeh > & targetHisto, + ImageType::Pointer const input ) +{ + ImageType::SizeType size = input->GetLargestPossibleRegion().GetSize(); + int nbPixel = size[0] * size[1]; + int height = nbPixel/256 ; + targetHisto.fill( height ); } int @@ -38,104 +73,91 @@ main( int argc, { // const char * inputfilename = argv[ 1 ]; // const char * outputfilename = argv[ 2 ]; - + if (argc<3) + { + std::cout<<"error"<<std::endl; + return 1; + } typedef otb::ImageFileReader< VectorImageType > ReaderType; - typedef itk::Statistics::ImageToHistogramFilter< ImageType > HistogramFilterType; - typedef HistogramFilterType::HistogramType HistogramType; typedef itk::VectorIndexSelectionCastImageFilter< VectorImageType , ImageType > VectorToImageFilterType; - + typedef itk::Image< float , 2 > ImageGainType; + typedef itk::VectorImage< float , 2 > VectorGainType; + typedef itk::ComposeImageFilter< ImageGainType > ImageGainToVectorImageGainFilterType; + typedef itk::ComposeImageFilter< ImageType > ImageToVectorImageFilterType; + typedef itk::MultiplyImageFilter< ImageType, ImageGainType, ImageType > MultiplyImageFilterType; ReaderType::Pointer reader( ReaderType::New() ); reader->SetFileName( argv[ 1 ] ); reader->Update(); VectorImageType::Pointer input = reader->GetOutput(); - ImageType::Pointer lum ( ImageType::New() ); - lum->SetRegions( input->GetRequestedRegion() ); - lum->Allocate(); - lum->SetOrigin( input->GetOrigin() ); - VectorToImageFilterType::Pointer vectorToImageFilter ( VectorToImageFilterType::New() ); - if ( input->GetVectorLength() == 3 ) - { - computeLuminance(lum, input); - } - else - { - // default is a black and white image, if length>3 and is not equal to one - // other case : how to apply the equalization : - // - channel per channel? - // - with a general luminance? - vectorToImageFilter->SetInput( input ); - vectorToImageFilter->SetIndex( 0 ); - vectorToImageFilter->Update(); - lum = vectorToImageFilter->GetOutput(); - } - + ImageGainToVectorImageGainFilterType::Pointer imageGainToVectorImageGainFilterOut( ImageGainToVectorImageGainFilterType::New() ); + ImageToVectorImageFilterType::Pointer imageToVectorImageFilterOut( ImageToVectorImageFilterType::New() ); + VectorToImageFilterType::Pointer vectorToImageFilter ( VectorToImageFilterType::New() ); + vectorToImageFilter->SetInput( input ); + vectorToImageFilter->SetIndex( 0 ); + // Hack to get quick result HistogramFilterType::Pointer histofilter( HistogramFilterType::New() ); - histofilter->SetInput( lum ); + histofilter->SetInput( vectorToImageFilter->GetOutput() ); histofilter->Update(); - // Compute the histogram of the bw image - HistogramType * histo = histofilter->GetOutput(); + + std::array< int , sizeh > hTarget; + createTarget( hTarget , vectorToImageFilter->GetOutput() ); + int m = input->GetVectorLength (); + for (int chanel = 0 ; chanel<m ; chanel++ ) + { + MultiplyImageFilterType::Pointer gainMultiplyer ( MultiplyImageFilterType::New() ); + vectorToImageFilter->SetIndex( chanel ); + vectorToImageFilter->Update(); + ImageGainType::Pointer gainImage ( ImageGainType::New() ); + gainImage->SetRegions( vectorToImageFilter->GetOutput()->GetRequestedRegion() ); + gainImage->Allocate(); + gainImage->SetOrigin( vectorToImageFilter->GetOutput()->GetOrigin() ); + itk::ImageRegionIterator< ImageGainType > itgain( gainImage , gainImage->GetRequestedRegion() ); + std::array< int , sizeh > hInput; + hInput.fill(0); + computehisto( vectorToImageFilter->GetOutput() , hInput ); - // Define propertise of the target histogram : nomber of bin, height per bin - ImageType::SizeType lumSize = lum->GetLargestPossibleRegion().GetSize(); - int npx = lumSize[0] * lumSize[1]; - int nbin = histo->GetSize()[0]; - float height = npx / nbin; + // histofilter->SetInput( vectorToImageFilter->GetOutput() ); + // histofilter->Update(); + // HistogramType::Pointer hInput = histofilter->GetOutput(); + + std::array< int , sizeh > lut; + equalized( hInput , hTarget , lut ); + itk::ImageRegionIterator< ImageType > itin( vectorToImageFilter->GetOutput() , vectorToImageFilter->GetOutput()->GetRequestedRegion() ); + itin.GoToBegin(); + itgain.GoToBegin(); + while( !itin.IsAtEnd() ) + { + itgain.Set( static_cast<float>(lut[itin.Get()]) / static_cast<float>( itin.Get() ) ) ; + // itin.Set(lut[itin.Get()]); + ++itin; + ++itgain; + } + // gainImage->SetOrigin( vectorToImageFilter->GetOutput() ); + // gainImage->SetSpacing( vectorToImageFilter->GetOutput() ); - // The transfer function will be a look up table - std::vector< int > lut; - float nbOri, nbNew ; - int countnew, countold; - countnew = 0; - countold = 0; - nbNew = height; - HistogramType::Iterator it = histo->Begin(); - nbOri = it.GetFrequency(); - while ( it != histo->End() ) - { - if (nbOri> nbNew) - { - nbNew += height; - // index[0] += 1; - ++countnew; + gainMultiplyer->SetInput1( vectorToImageFilter->GetOutput() ); + gainMultiplyer->SetInput2( gainImage ); + gainMultiplyer->Update(); + imageGainToVectorImageGainFilterOut->SetInput( chanel , gainImage ); + imageToVectorImageFilterOut->SetInput( chanel , gainMultiplyer->GetOutput() ); + // imageToVectorImageFilterOut->SetInput( chanel , vectorToImageFilter->GetOutput() ); } - else - { - ++it; - nbOri += it.GetFrequency(); - ++countold; - lut.push_back(countnew); - } - } // Here we compute a gain image corresponding to the associated gain of the equalization - typedef itk::Image< float , 2 > ImageGainType; - ImageGainType::Pointer gainImage ( ImageGainType::New() ); - gainImage->SetRegions( lum->GetRequestedRegion() ); - gainImage->Allocate(); - gainImage->SetOrigin( lum->GetOrigin() ); - itk::ImageRegionIterator< ImageType > itlum( lum , lum->GetRequestedRegion() ); - itk::ImageRegionIterator< ImageGainType > itgain( gainImage , gainImage->GetRequestedRegion() ); - itlum.GoToBegin(); - itgain.GoToBegin(); - while( !itlum.IsAtEnd() ) - { - itgain.Set( static_cast<float>(lut[itlum.Get()]) / static_cast<float>( itlum.Get() ) ) ; - ++itlum; - ++itgain; - } - - typedef itk::MultiplyImageFilter< VectorImageType, ImageGainType, VectorImageType > MultiplyImageFilterType; - MultiplyImageFilterType::Pointer gainMultiplyer ( MultiplyImageFilterType::New() ); - gainMultiplyer->SetInput1( input ); - gainMultiplyer->SetInput2( gainImage ); - gainMultiplyer->Update(); - typedef otb::ImageFileWriter<VectorImageType> writertype; - writertype::Pointer writer( writertype::New()); + VectorGainType::Pointer gainVector = imageGainToVectorImageGainFilterOut->GetOutput(); + typedef otb::ImageFileWriter<VectorImageType> WriterType; + WriterType::Pointer writer( WriterType::New()); writer->SetFileName( argv[2] ); - writer->SetInput( gainMultiplyer->GetOutput() ); + writer->SetInput( imageToVectorImageFilterOut->GetOutput() ); writer->Update(); + + typedef otb::ImageFileWriter<VectorGainType> WriterGainType; + WriterGainType::Pointer writergain( WriterGainType::New() ); + writergain->SetFileName( argv[3] ); + writergain->SetInput( gainVector ); + writergain->Update(); return 0; } -- GitLab