diff --git a/Documentation/Cookbook/Art/contrast1.png b/Documentation/Cookbook/Art/contrast1.png new file mode 100644 index 0000000000000000000000000000000000000000..614c9f00c9e6c905ccbe6995464a4e6531863b8c Binary files /dev/null and b/Documentation/Cookbook/Art/contrast1.png differ diff --git a/Documentation/Cookbook/Art/contrast2.png b/Documentation/Cookbook/Art/contrast2.png new file mode 100644 index 0000000000000000000000000000000000000000..39deef978d7fb2f1faa2452c2d9c5e1077a999a6 Binary files /dev/null and b/Documentation/Cookbook/Art/contrast2.png differ diff --git a/Documentation/Cookbook/Art/contrast4.png b/Documentation/Cookbook/Art/contrast4.png new file mode 100644 index 0000000000000000000000000000000000000000..93eb1b67af7b2e1e040343d72e4cd8dd17961a17 Binary files /dev/null and b/Documentation/Cookbook/Art/contrast4.png differ diff --git a/Documentation/Cookbook/Art/contrast_orig.jpg b/Documentation/Cookbook/Art/contrast_orig.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5fd20d82a36edc8a715ff2d8ca3ad5c2486c9a20 Binary files /dev/null and b/Documentation/Cookbook/Art/contrast_orig.jpg differ diff --git a/Documentation/Cookbook/Art/contrast_result.jpg b/Documentation/Cookbook/Art/contrast_result.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f22ab522064b7942551949aa85993a3a21fd9f69 Binary files /dev/null and b/Documentation/Cookbook/Art/contrast_result.jpg differ diff --git a/Documentation/Cookbook/rst/Recipes.rst b/Documentation/Cookbook/rst/Recipes.rst index fa9478d5abf7698b4abbdcf806d625a0ab220cba..18cab29de9d970df06441d440b7972d980b9e37e 100644 --- a/Documentation/Cookbook/rst/Recipes.rst +++ b/Documentation/Cookbook/rst/Recipes.rst @@ -13,7 +13,9 @@ and demonstrate how the can be applied. recipes/sarprocessing.rst recipes/residual_registration.rst recipes/improc.rst + recipes/bandmathx.rst + recipes/contrast_enhancement.rst recipes/pbclassif.rst recipes/featextract.rst recipes/stereo.rst - recipes/bandmathx.rst + diff --git a/Documentation/Cookbook/rst/recipes/contrast_enhancement.rst b/Documentation/Cookbook/rst/recipes/contrast_enhancement.rst new file mode 100644 index 0000000000000000000000000000000000000000..79273a1b8dad1225cf2e6628664cae3250c5bcd2 --- /dev/null +++ b/Documentation/Cookbook/rst/recipes/contrast_enhancement.rst @@ -0,0 +1,101 @@ +Enhance local contrast +====================== + +Principles +~~~~~~~~~~ + +Sensor images have often a wide dynamic range. Whereas it is helpful to have +high precision to do complex processing, it is pretty hard to display high +dynamic images, even on modern screen as the dynamic range for basic screen is +of 8 bits while images can be encoded on 12 or 16 bits (or even more!). + +.. _Figure1: + +|image5| |image6| + +The *ContrastEnhancement* application aims to reduce the image dynamic by +reorganizing it in a smarter way than just linear compression and improve the +local contrast and enhance the definitions of edges. + +.. _Figure2: + +|image1| |image2| + +The equalization of histogram creates a look up table in order to maximize the +dynamic. The target histogram is perfectly flat. The gain applied on each pixel +comes from the computation of the transfer function :math:`T` such that : + +.. math:: \forall i \quad \int_{min}^{i*T(i)}h_{istogram}(j)dj = + \int_{min}^{i}h_{target}(j)dj + +where :math:`h_{target}` is the corresponding flat histogram with the constraint +that white and black are still white and black after equalization : + +.. math:: T(min) = T(max) = 1 + +You can apply this transformation with the *ContrastEnhancement* application: + +:: + + otbcli_ContrastEnhancement -in input_image.tif + -out output_image.tif + -spatial global + +It allows to compress the dynamic without loosing details and contrast. + +Advanced parameters +~~~~~~~~~~~~~~~~~~~ + +The *ContrastEnhancement* provides different options to configure the contrast +enhancement method. Let us see what there are for. + +First what you want to equalize. Two modes are available: + +* **luminance:** on 3 bands image, the equalization will be done on a single + band which will be a composition of the original bands. The computed gain will + then be applied on the different bands. The classical use of this method is to + conserve ratio between the different color, conserve the hue. +* **channel:** each bands are equalized independently. + +The other option is the local equalization. You can choose a window size that +will be use to split the image in tiles and histograms will be computed over +those tiles. Gain will be interpolated between the adjacent tiles in order to +give a smooth result. + +:: + + otbcli_ContrastEnhancement -in input_image.tif + -out output_image.tif spatial.local.h 500 + -spatial.local.w 500 + -mode lum + +The *ContrastEnhancement* application also offers a way to limit contrast by +adjusting original histogram with the **hfact** parameter. The limitation factor +represents the limit height that can have any bucket of the histogram; the +application computes the height of the flat histogram and the maximal height is +the limitation factor time this "flat height". + +.. _Figure3: + +|image4| + +Finally, you can ignore a particular value with the **nodata** parameter, and +also set manually your minimum and maximum value. Any value out of bound will be +ignored. + + +.. |image1| image:: ../Art/contrast1.png + :scale: 30% + +.. |image2| image:: ../Art/contrast2.png + :scale: 30% + +.. |image4| image:: ../Art/contrast4.png + +.. |image5| image:: ../Art/contrast_orig.jpg + :scale: 30% + :alt: original + +.. |image6| image:: ../Art/contrast_result.jpg + :scale: 30% + :alt: result diff --git a/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx b/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx index 977d4e75a469f86c3d611ab3f7343487df7f6054..16e518a278b56373e958ed974aab6dd2508103c1 100644 --- a/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx +++ b/Modules/Applications/AppFiltering/app/otbContrastEnhancement.cxx @@ -68,7 +68,7 @@ public: } // end operator () - void SetRgb( std::vector<int> rgb) + void SetRgb( std::vector<unsigned int> rgb) { m_Rgb = rgb; } @@ -82,7 +82,7 @@ public: return m_LumCoef; } private: - std::vector<int> m_Rgb; + std::vector<unsigned int> m_Rgb; std::vector<float> m_LumCoef; }; // end of functor class MultiplyOperator @@ -383,10 +383,17 @@ private: } else if ( m_EqMode == "lum") { - std::vector<int> rgb( 3 , 0 ); + std::vector< unsigned int > rgb( 3 , 0 ); rgb[0] = GetParameterInt("mode.lum.red.ch"); rgb[1] = GetParameterInt("mode.lum.green.ch"); rgb[2] = GetParameterInt("mode.lum.blue.ch"); + if ( !( nbChannel > std::max( rgb[0] , std::max( rgb[1] , rgb[2] ) ) ) ) + { + std::ostringstream oss; + oss<<"One of the selected channel needed for luminance computation " + "exceed the number of component of the image."; + otbAppLogFATAL( << oss.str() ) + } ComputeLuminance( inImage , rgb ); LuminanceEqualization( inputImageList , rgb , outputImageList ); } @@ -695,7 +702,7 @@ private: // Compute the luminance with user parameters void ComputeLuminance( const FloatVectorImageType::Pointer inImage , - std::vector < int > rgb ) + std::vector < unsigned int > rgb ) { // Retreive coeffs for each channel std::vector < float > lumCoef( 3 , 0.0 ); @@ -719,7 +726,7 @@ private: // Equalize the luminance and apply the corresponding gain on each channel // used to compute this luminance void LuminanceEqualization( const ImageListType::Pointer inputImageList , - const std::vector < int > rgb , + const std::vector < unsigned int > rgb , ImageListType::Pointer outputImageList ) { m_GainLutFilter.resize( 1 , GainLutFilterType::New() );