Unverified Commit 8d784000 authored by StefanBruens's avatar StefanBruens Committed by GitHub

Merge pull request #16494 from StefanBruens:jpeg2000_openjpeg_port

Jpeg2000 OpenJPEG port

* OpenJPEG based JPEG2000 decoder implementation

Currently, the following input color spaces and depth conversions are
supported:

- 8 bit -> 8 bit
- 16 bit -> 16 bit (IMREAD_UNCHANGED, IMREAD_ANYDEPTH)

- RGB(a) -> BGR
- RGBA -> BGRA (IMREAD_UNCHANGED)
- Y(a) -> Y(a) (IMREAD_ANYCOLOR, IMREAD_GRAY, IMREAD_UNCHANGED))
- YCC -> Y (IMREAD_GRAY)

* Check for OpenJPEG availability

This enables OpenJPEG based JPEG2000 imread support by default, which
can be disabled by -DWITH_OPENJPEG=OFF. In case OpenJPEG is enabled
and found, any checks for Jasper are skipped.

* Implement precision downscaling for precision > 8 without IMREAD_UNCHANGED

With IMREAD_UNCHANGED, values are kept from the input image, without it
components are downscaled to CV_8U range.

* Enable Jpeg2K tests when OpenJPEG is available

* Add support for some more color conversions

Support IMREAD_GRAY when input color space is RGB or unspecified.
Support YUV input color space for BGR output.

* fix: problems with unmanaged memory

* fix: CMake warning - HAVE_OPENJPEG is undefined

Removed trailing whitespaces

* fix: CMake find_package OpenJPEG add minimal version

* Basic JPEG2K encoder

Images with depth CV_8U and CV_16U are supported, with 1 to 4 channels.

* feature: Improved code for OpenJPEG2000 encoder/decoder

 - Removed code duplication
 - Added error handlers
 - Extracted functions

* feature: Update conversion openjpeg array from/to Mat

* feature: Extend ChannelsIterator to fulfill RandomAccessIterator named requirements

 - Removed channels split in copyFromMatImpl. With ChannelsIterator no allocations are performed.
 - Split whole loop into 2 parts in copyToMat -> where std::copy and std::transforms are called.

* fix: Applied review comments.

 - Changed `nullptr` in CV_LOG* functions to `NULL`
 - Added `falls through` comment in decoder color space `switch`
 - Added warning about unsupported parameters for the encoder

* feature: Added decode from in-memory buffers.
Co-authored-by: 's avatarVadim Levin <vadim.levin@xperience.ai>
parent c303aaa9
......@@ -285,9 +285,12 @@ OCV_OPTION(WITH_INF_ENGINE "Include Intel Inference Engine support" OFF
OCV_OPTION(WITH_NGRAPH "Include nGraph support" WITH_INF_ENGINE
VISIBLE_IF TRUE
VERIFY TARGET ngraph::ngraph)
OCV_OPTION(WITH_JASPER "Include JPEG2K support" ON
OCV_OPTION(WITH_JASPER "Include JPEG2K support (Jasper)" ON
VISIBLE_IF NOT IOS
VERIFY HAVE_JASPER)
OCV_OPTION(WITH_OPENJPEG "Include JPEG2K support (OpenJPEG)" ON
VISIBLE_IF NOT IOS
VERIFY HAVE_OPENJPEG)
OCV_OPTION(WITH_JPEG "Include JPEG support" ON
VISIBLE_IF TRUE
VERIFY HAVE_JPEG)
......@@ -1249,8 +1252,12 @@ if(WITH_TIFF OR HAVE_TIFF)
status(" TIFF:" TIFF_FOUND THEN "${TIFF_LIBRARY} (ver ${TIFF_VERSION} / ${TIFF_VERSION_STRING})" ELSE "build (ver ${TIFF_VERSION} - ${TIFF_VERSION_STRING})")
endif()
if(WITH_JASPER OR HAVE_JASPER)
status(" JPEG 2000:" JASPER_FOUND THEN "${JASPER_LIBRARY} (ver ${JASPER_VERSION_STRING})" ELSE "build (ver ${JASPER_VERSION_STRING})")
if(HAVE_OPENJPEG)
status(" JPEG 2000:" "OpenJPEG (ver ${OPENJPEG_MAJOR_VERSION}.${OPENJPEG_MINOR_VERSION}.${OPENJPEG_BUILD_VERSION})")
elseif(HAVE_JASPER)
status(" JPEG 2000:" JASPER_FOUND THEN "${JASPER_LIBRARY} (ver ${JASPER_VERSION_STRING})" ELSE "build Jasper (ver ${JASPER_VERSION_STRING})")
elseif(WITH_OPENJPEG OR WITH_JASPER)
status(" JPEG 2000:" "NO")
endif()
if(WITH_OPENEXR OR HAVE_OPENEXR)
......
......@@ -153,8 +153,23 @@ if(NOT WEBP_VERSION AND WEBP_INCLUDE_DIR)
endif()
endif()
# --- libopenjp2 (optional, check before libjasper) ---
if(WITH_OPENJPEG)
find_package(OpenJPEG QUIET)
if(NOT OpenJPEG_FOUND OR OPENJPEG_MAJOR_VERSION LESS 2)
set(HAVE_OPENJPEG NO)
ocv_clear_vars(OPENJPEG_MAJOR_VERSION OPENJPEG_MINOR_VERSION OPENJPEG_BUILD_VERSION OPENJPEG_LIBRARIES OPENJPEG_INCLUDE_DIRS)
message(STATUS "Could NOT find OpenJPEG (minimal suitable version: 2.0, recommended version >= 2.3.1)")
else()
set(HAVE_OPENJPEG YES)
message(STATUS "Found OpenJPEG: ${OPENJPEG_LIBRARIES} "
"(found version \"${OPENJPEG_MAJOR_VERSION}.${OPENJPEG_MINOR_VERSION}.${OPENJPEG_BUILD_VERSION}\")")
endif()
endif()
# --- libjasper (optional, should be searched after libjpeg) ---
if(WITH_JASPER)
if(WITH_JASPER AND NOT HAVE_OPENJPEG)
if(BUILD_JASPER)
ocv_clear_vars(JASPER_FOUND)
else()
......@@ -273,4 +288,4 @@ if(WITH_IMGCODEC_PFM)
set(HAVE_IMGCODEC_PFM ON)
elseif(DEFINED WITH_IMGCODEC_PFM)
set(HAVE_IMGCODEC_PFM OFF)
endif()
\ No newline at end of file
endif()
......@@ -81,6 +81,7 @@
#cmakedefine HAVE_IPP_IW_LL
/* JPEG-2000 codec */
#cmakedefine HAVE_OPENJPEG
#cmakedefine HAVE_JASPER
/* IJG JPEG codec */
......
......@@ -45,6 +45,11 @@ if(HAVE_TIFF)
list(APPEND GRFMT_LIBS ${TIFF_LIBRARIES})
endif()
if(HAVE_OPENJPEG)
ocv_include_directories(${OPENJPEG_INCLUDE_DIRS})
list(APPEND GRFMT_LIBS ${OPENJPEG_LIBRARIES})
endif()
if(HAVE_JASPER)
ocv_include_directories(${JASPER_INCLUDE_DIR})
list(APPEND GRFMT_LIBS ${JASPER_LIBRARIES})
......
This diff is collapsed.
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2020, Stefan Brüns <stefan.bruens@rwth-aachen.de>
#ifndef _GRFMT_OPENJPEG_H_
#define _GRFMT_OPENJPEG_H_
#ifdef HAVE_OPENJPEG
#include "grfmt_base.hpp"
#include <openjpeg.h>
namespace cv {
namespace detail {
struct OpjStreamDeleter
{
void operator()(opj_stream_t* stream) const
{
opj_stream_destroy(stream);
}
};
struct OpjCodecDeleter
{
void operator()(opj_codec_t* codec) const
{
opj_destroy_codec(codec);
}
};
struct OpjImageDeleter
{
void operator()(opj_image_t* image) const
{
opj_image_destroy(image);
}
};
struct OpjMemoryBuffer {
OPJ_BYTE* pos{nullptr};
OPJ_BYTE* begin{nullptr};
OPJ_SIZE_T length{0};
OpjMemoryBuffer() = default;
explicit OpjMemoryBuffer(cv::Mat& mat)
: pos{ mat.ptr() }, begin{ mat.ptr() }, length{ mat.rows * mat.cols * mat.elemSize() }
{
}
OPJ_SIZE_T availableBytes() const CV_NOEXCEPT {
return begin + length - pos;
}
};
using StreamPtr = std::unique_ptr<opj_stream_t, detail::OpjStreamDeleter>;
using CodecPtr = std::unique_ptr<opj_codec_t, detail::OpjCodecDeleter>;
using ImagePtr = std::unique_ptr<opj_image_t, detail::OpjImageDeleter>;
} // namespace detail
class Jpeg2KOpjDecoder CV_FINAL : public BaseImageDecoder
{
public:
Jpeg2KOpjDecoder();
~Jpeg2KOpjDecoder() CV_OVERRIDE = default;
ImageDecoder newDecoder() const CV_OVERRIDE;
bool readData( Mat& img ) CV_OVERRIDE;
bool readHeader() CV_OVERRIDE;
private:
detail::StreamPtr stream_{nullptr};
detail::CodecPtr codec_{nullptr};
detail::ImagePtr image_{nullptr};
detail::OpjMemoryBuffer opjBuf_;
OPJ_UINT32 m_maxPrec = 0;
};
class Jpeg2KOpjEncoder CV_FINAL : public BaseImageEncoder
{
public:
Jpeg2KOpjEncoder();
~Jpeg2KOpjEncoder() CV_OVERRIDE = default;
bool isFormatSupported( int depth ) const CV_OVERRIDE;
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE;
ImageEncoder newEncoder() const CV_OVERRIDE;
};
} //namespace cv
#endif
#endif/*_GRFMT_OPENJPEG_H_*/
......@@ -51,6 +51,7 @@
#include "grfmt_tiff.hpp"
#include "grfmt_png.hpp"
#include "grfmt_jpeg2000.hpp"
#include "grfmt_jpeg2000_openjpeg.hpp"
#include "grfmt_exr.hpp"
#include "grfmt_webp.hpp"
#include "grfmt_hdr.hpp"
......
......@@ -178,6 +178,10 @@ struct ImageCodecInitializer
decoders.push_back( makePtr<Jpeg2KDecoder>() );
encoders.push_back( makePtr<Jpeg2KEncoder>() );
#endif
#ifdef HAVE_OPENJPEG
decoders.push_back( makePtr<Jpeg2KOpjDecoder>() );
encoders.push_back( makePtr<Jpeg2KOpjEncoder>() );
#endif
#ifdef HAVE_OPENEXR
decoders.push_back( makePtr<ExrDecoder>() );
encoders.push_back( makePtr<ExrEncoder>() );
......
......@@ -71,7 +71,8 @@ TEST_P(Imgcodecs_FileMode, regression)
const string all_images[] =
{
#if defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)
#if (defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)) \
|| defined(HAVE_OPENJPEG)
"readwrite/Rome.jp2",
"readwrite/Bretagne2.jp2",
"readwrite/Bretagne2.jp2",
......
......@@ -194,7 +194,8 @@ const string exts[] = {
#ifdef HAVE_JPEG
"jpg",
#endif
#if defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)
#if (defined(HAVE_JASPER) && defined(OPENCV_IMGCODECS_ENABLE_JASPER_TESTS)) \
|| defined(HAVE_OPENJPEG)
"jp2",
#endif
#if 0 /*defined HAVE_OPENEXR && !defined __APPLE__*/
......
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