Difference between revisions of "JPEG2000 with GDAL OpenJpeg plugin"

From OTBWiki
Jump to: navigation, search
(Created page with "Since GDAL version 1.10.0, an OpenJpeg driver has been included in GDAL. However this driver is not compiled by default. This driver is intended to be used with OpenJpeg 2.0 ...")
 
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
Since GDAL version 1.10.0, an OpenJpeg driver has been included in GDAL. However this driver is not compiled by default.  
 
Since GDAL version 1.10.0, an OpenJpeg driver has been included in GDAL. However this driver is not compiled by default.  
This driver is intended to be used with OpenJpeg 2.0 official release. This driver allows to open Jpeg2000 datasets in OTB without using the home-made otb::JPEG2000ImageIO. The common otb::GDALImageIO is used instead.
+
This driver is intended to be used with OpenJpeg 2.0 official release. It allows to open Jpeg2000 datasets in OTB without using the home-made <code>otb::JPEG2000ImageIO</code>. The common <code>otb::GDALImageIO</code> is used instead.
 +
 
 +
'''WARNING''' : the behaviour is not exactly the same between <code>otb::JPEG2000ImageIO</code> and GDAL driver :
 +
* GDAL can compute any overview level but they are not all retrieved from the input file. If the overview level has both dimensions lower than 256, GDAL uses its default nearest neighbour approach to compute the overview, instead of using the wavelet coefficients.
 +
* The size of the overviews is computed as a simple integer division by 2^n, whereas in <code>otb::JPEG2000ImageIO</code> this overview size is increased by 1 when the original image size is not a multiple of 2^n.
 +
 
 +
As a matter of fact, the GDAL Openjpeg driver doesn't pass the conformance test in the OTB (ioTvMultiChannelROI_p1_06_JPEG2000_2_TIF_res4). This problem has been submited to GDAL.
 +
 
 +
There are 2 ways of using this driver :
 +
* Use a GDAL library with a built-in OpenJpeg driver
 +
* Use a standard GDAL library and configure an external OpenJpeg driver
 +
 
 +
Each case is detailed in the following sections.
 +
 
 +
Note : more general information about OTB dependencies can be found in the [https://www.orfeo-toolbox.org/SoftwareGuide/SoftwareGuidech2.html#x14-190002 SoftwareGuide]
 +
 
 +
== Building OpenJpeg ==
 +
 
 +
Let's assume that OpenJpeg is not installed on your system. You can build it from sources using CMake.
 +
 
 +
The default CMake configuration is simple to perform, it will build the main codec. You can choose your own <tt>CMAKE_INSTALL_PREFIX</tt> depending on where you want to deploy the library.
 +
 
 +
Once you have finished the configure step of CMake, run :
 +
<pre>
 +
> make
 +
> make install
 +
</pre>
 +
 
 +
== Built-in driver ==
 +
 
 +
When building GDAL from sources, the different drivers to use can be chosen at the configure step. When calling the configure script, activate the option to compile OpenJpeg driver :
 +
<pre>
 +
> ./configure  --prefix=$GDAL_INSTALL_PREFIX
 +
              [... all your other options ...]
 +
              --with-openjpeg=$OPENJPEG_INSTALL
 +
</pre>
 +
where <tt>OPENJPEG_INSTALL</tt> is the directory where OpenJpeg is installed. Examples of scripts to build GDAL are present in the repository [http://hg.orfeo-toolbox.org/OTB-DevUtils/file/d4c97f047e0b/Scripts/build_gdal_trunk.sh OTB-DevUtils].
 +
 
 +
Note : if the GDAL library (<tt>libgdal.so</tt>) is not installed in the same directory as OpenJpeg, you will need to add the OpenJpeg library folder to your LD configuration (either with the variable <tt>LD_LIBRARY_PATH</tt>, or with the <tt>/etc/ld.conf.d/</tt> configuration).
 +
 
 +
== External driver ==
 +
 
 +
If you don't want to re-compile your GDAL library, you can build separately an external driver that will be loaded at run-time. For this you will need :
 +
* An OpenJpeg library installed (version 2.0)
 +
* the headers of your GDAL library
 +
* the source file of the OpenJpeg driver, available through GDAL sources in <tt>frmts/openjpeg/openjpegdataset.cpp</tt>. Make sure you take a source file from the same version as your current GDAL library.
 +
 
 +
Then the OpenJpeg plugin can be compiled with this command line :
 +
<pre>
 +
g++ -fPIC -g -Wall openjpegdataset.cpp -shared -o gdal_JP2OpenJPEG.so
 +
    -I$GDAL_INCLUDE_DIR -I$OPENJPEG_INSTALL_DIR/include
 +
    -L. -lgdal -L$OPENJPEG_INSTALL_DIR/lib -lopenjp2
 +
</pre>
 +
The name of the output shared library can't be changed, because 'JP2OpenJPEG' is the official name of the OpenJpeg driver in GDAL. In order for this plugin to be detected at run-time, you have to use the <tt>GDAL_DRIVER_PATH</tt> environment variable. Set it to the folder containing your plugin.
 +
 
 +
It seems that GDAL also has a standard location for plugins. Let say your GDAL library is installed in <tt>/usr/lib</tt>, you may already have a folder <tt>/usr/lib/gdalplugins</tt>. At run-time, GDAL will check this folder for external plugins (without having to define the <tt>GDAL_DRIVER_PATH</tt>).
 +
 
 +
Note : same remark as before about the location of the OpenJpeg library and your LD configuration.
 +
 
 +
== Symbols conflict ==
 +
 
 +
It is important to know that the OpenJpeg library doesn't support name mangling since version 2.0. As a consequence, if other libraries linked by your project already contain OpenJpeg, there may be a symbol conflict at run-time. For instance, this was observed with OTB build on a recent ITK version (ver. 4). The ITK library already had a version of OpenJpeg in <tt>libitkopenjpeg-*.so</tt>, which contained the OpenJpeg symbols un-wrapped. These symbols were also loaded by the GDAL driver but only the first ones were used, which caused a crash.
 +
 
 +
=== Mangling ===
 +
The first solution to this problem is to use symbol mangling to rename the symbols in one of the conflicting OpenJpeg library.
 +
 
 +
If you choose to mangle your system OpenJpeg v2.0, you have to hack the OpenJpeg sources in order to re-activate the mangling (only for the main codec). A patch has been made (see last section).
 +
 
 +
If you choose to mangle the OpenJpeg v1.x embedded in an external ITK, you have to hack in the Third Party sources in <tt>Modules/ThirdParty/OpenJPEG</tt>. A patch has been made (see last section).
 +
 
 +
=== External GDCM ===
 +
The second solution is to make shure that ITK doesn't try to use an internal OpenJpeg library, but rather link to an external library. In fact, using an external OpenJpeg with an internal GDCM is not going to work since this GDCM version only support an OpenJpeg v1. This would imply handling 2 OpenJpeg libs in the system (v1 and v2), and still cause a symbol conflict at runtime.
 +
The use of an external GDCM is done with the following steps :
 +
* compile GDCM (v 2.4.2) with the options <tt>USE_SYSTEM_OPENJPEG=ON</tt> and <tt>OPENJPEG_V2</tt>. Since this GDCM version is higher than the internal one in ITK, you may use your system OpenJpeg v2 library.
 +
* compile ITK with the option <tt>USE_SYSTEM_GDCM=ON</tt>
 +
* compile OTB with this external ITK.
 +
 
 +
== OpenJpeg 2.1 ==
 +
 
 +
There are a few changes between version 2.0 and 2.1.
 +
 
 +
In GDAL versions from 1.10.0 up to 1.11.1, only OpenJPEG 2.0 is supported. Starting from 1.11.2, both versions of OpenJPEG are supported (2.0 and 2.1).
 +
 
 +
Then, there is one API modification in the library that impacts the driver compilation :
 +
 
 +
<code>opj_stream_set_user_data(pStream, pData)</code> becomes <code>opj_stream_set_user_data(pStream, pData , pFunction)</code>
 +
where <code>pFunction</code> is a function to free the data pointer.
 +
 
 +
== On-going actions ==
 +
 
 +
Several actions have been made towards ITK, OpenJpeg and GDAL projects in order to enhance the integration of OpenJpeg in OTB :
 +
* Report to OpenJpeg the need of a mangling system, a patch has been submitted (https://code.google.com/p/openjpeg/issues/detail?id=346). In version 2.1.0, no mangling is supported.
 +
* Report to ITK the need to mangled their internal OpenJpeg v1.x third-party library. A patch has been submitted on Gerrit (http://review.source.kitware.com/#/q/status:open+project:ITK+branch:master+topic:thirdparty_openjpeg_mangle,n,z). The patch has been integrated in version 4.6.0
 +
* Report to GDAL that their driver doesn't pass the conformance tests. A topic has been posted on gdal-dev mailing list. For now, it looks like they won't take any actions.

Latest revision as of 17:06, 15 July 2015

Since GDAL version 1.10.0, an OpenJpeg driver has been included in GDAL. However this driver is not compiled by default. This driver is intended to be used with OpenJpeg 2.0 official release. It allows to open Jpeg2000 datasets in OTB without using the home-made otb::JPEG2000ImageIO. The common otb::GDALImageIO is used instead.

WARNING : the behaviour is not exactly the same between otb::JPEG2000ImageIO and GDAL driver :

  • GDAL can compute any overview level but they are not all retrieved from the input file. If the overview level has both dimensions lower than 256, GDAL uses its default nearest neighbour approach to compute the overview, instead of using the wavelet coefficients.
  • The size of the overviews is computed as a simple integer division by 2^n, whereas in otb::JPEG2000ImageIO this overview size is increased by 1 when the original image size is not a multiple of 2^n.

As a matter of fact, the GDAL Openjpeg driver doesn't pass the conformance test in the OTB (ioTvMultiChannelROI_p1_06_JPEG2000_2_TIF_res4). This problem has been submited to GDAL.

There are 2 ways of using this driver :

  • Use a GDAL library with a built-in OpenJpeg driver
  • Use a standard GDAL library and configure an external OpenJpeg driver

Each case is detailed in the following sections.

Note : more general information about OTB dependencies can be found in the SoftwareGuide

Building OpenJpeg

Let's assume that OpenJpeg is not installed on your system. You can build it from sources using CMake.

The default CMake configuration is simple to perform, it will build the main codec. You can choose your own CMAKE_INSTALL_PREFIX depending on where you want to deploy the library.

Once you have finished the configure step of CMake, run :

> make
> make install

Built-in driver

When building GDAL from sources, the different drivers to use can be chosen at the configure step. When calling the configure script, activate the option to compile OpenJpeg driver :

> ./configure  --prefix=$GDAL_INSTALL_PREFIX
               [... all your other options ...]
               --with-openjpeg=$OPENJPEG_INSTALL

where OPENJPEG_INSTALL is the directory where OpenJpeg is installed. Examples of scripts to build GDAL are present in the repository OTB-DevUtils.

Note : if the GDAL library (libgdal.so) is not installed in the same directory as OpenJpeg, you will need to add the OpenJpeg library folder to your LD configuration (either with the variable LD_LIBRARY_PATH, or with the /etc/ld.conf.d/ configuration).

External driver

If you don't want to re-compile your GDAL library, you can build separately an external driver that will be loaded at run-time. For this you will need :

  • An OpenJpeg library installed (version 2.0)
  • the headers of your GDAL library
  • the source file of the OpenJpeg driver, available through GDAL sources in frmts/openjpeg/openjpegdataset.cpp. Make sure you take a source file from the same version as your current GDAL library.

Then the OpenJpeg plugin can be compiled with this command line :

g++ -fPIC -g -Wall openjpegdataset.cpp -shared -o gdal_JP2OpenJPEG.so 
    -I$GDAL_INCLUDE_DIR -I$OPENJPEG_INSTALL_DIR/include 
    -L. -lgdal -L$OPENJPEG_INSTALL_DIR/lib -lopenjp2

The name of the output shared library can't be changed, because 'JP2OpenJPEG' is the official name of the OpenJpeg driver in GDAL. In order for this plugin to be detected at run-time, you have to use the GDAL_DRIVER_PATH environment variable. Set it to the folder containing your plugin.

It seems that GDAL also has a standard location for plugins. Let say your GDAL library is installed in /usr/lib, you may already have a folder /usr/lib/gdalplugins. At run-time, GDAL will check this folder for external plugins (without having to define the GDAL_DRIVER_PATH).

Note : same remark as before about the location of the OpenJpeg library and your LD configuration.

Symbols conflict

It is important to know that the OpenJpeg library doesn't support name mangling since version 2.0. As a consequence, if other libraries linked by your project already contain OpenJpeg, there may be a symbol conflict at run-time. For instance, this was observed with OTB build on a recent ITK version (ver. 4). The ITK library already had a version of OpenJpeg in libitkopenjpeg-*.so, which contained the OpenJpeg symbols un-wrapped. These symbols were also loaded by the GDAL driver but only the first ones were used, which caused a crash.

Mangling

The first solution to this problem is to use symbol mangling to rename the symbols in one of the conflicting OpenJpeg library.

If you choose to mangle your system OpenJpeg v2.0, you have to hack the OpenJpeg sources in order to re-activate the mangling (only for the main codec). A patch has been made (see last section).

If you choose to mangle the OpenJpeg v1.x embedded in an external ITK, you have to hack in the Third Party sources in Modules/ThirdParty/OpenJPEG. A patch has been made (see last section).

External GDCM

The second solution is to make shure that ITK doesn't try to use an internal OpenJpeg library, but rather link to an external library. In fact, using an external OpenJpeg with an internal GDCM is not going to work since this GDCM version only support an OpenJpeg v1. This would imply handling 2 OpenJpeg libs in the system (v1 and v2), and still cause a symbol conflict at runtime. The use of an external GDCM is done with the following steps :

  • compile GDCM (v 2.4.2) with the options USE_SYSTEM_OPENJPEG=ON and OPENJPEG_V2. Since this GDCM version is higher than the internal one in ITK, you may use your system OpenJpeg v2 library.
  • compile ITK with the option USE_SYSTEM_GDCM=ON
  • compile OTB with this external ITK.

OpenJpeg 2.1

There are a few changes between version 2.0 and 2.1.

In GDAL versions from 1.10.0 up to 1.11.1, only OpenJPEG 2.0 is supported. Starting from 1.11.2, both versions of OpenJPEG are supported (2.0 and 2.1).

Then, there is one API modification in the library that impacts the driver compilation :

opj_stream_set_user_data(pStream, pData) becomes opj_stream_set_user_data(pStream, pData , pFunction) where pFunction is a function to free the data pointer.

On-going actions

Several actions have been made towards ITK, OpenJpeg and GDAL projects in order to enhance the integration of OpenJpeg in OTB :