Merge pull request #19109 from tailsu:sd/imdecode-jp2k-codestream

* OpenJPEG: decoder for J2K codestreams

* code review fixes

* exclude .j2c from GDAL tests
pull/19212/head
Stefan Dragnev 4 years ago committed by GitHub
parent 15265918a7
commit b13b5d86f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp
  2. 25
      modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.hpp
  3. 3
      modules/imgcodecs/src/loadsave.cpp
  4. 6
      modules/imgcodecs/test/test_grfmt.cpp

@ -495,20 +495,16 @@ detail::StreamPtr opjCreateBufferInputStream(detail::OpjMemoryBuffer* buf)
/////////////////////// Jpeg2KOpjDecoder ///////////////////
Jpeg2KOpjDecoder::Jpeg2KOpjDecoder()
namespace detail {
Jpeg2KOpjDecoderBase::Jpeg2KOpjDecoderBase(OPJ_CODEC_FORMAT format)
: format_(format)
{
static const unsigned char signature[] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10 };
m_signature = String((const char*)(signature), sizeof(signature));
m_buf_supported = true;
}
ImageDecoder Jpeg2KOpjDecoder::newDecoder() const
{
return makePtr<Jpeg2KOpjDecoder>();
}
bool Jpeg2KOpjDecoder::readHeader()
bool Jpeg2KOpjDecoderBase::readHeader()
{
if (!m_buf.empty()) {
opjBuf_ = detail::OpjMemoryBuffer(m_buf);
@ -521,7 +517,7 @@ bool Jpeg2KOpjDecoder::readHeader()
if (!stream_)
return false;
codec_.reset(opj_create_decompress(OPJ_CODEC_JP2));
codec_.reset(opj_create_decompress(format_));
if (!codec_)
return false;
@ -587,7 +583,7 @@ bool Jpeg2KOpjDecoder::readHeader()
return true;
}
bool Jpeg2KOpjDecoder::readData( Mat& img )
bool Jpeg2KOpjDecoderBase::readData( Mat& img )
{
using DecodeFunc = bool(*)(const opj_image_t&, cv::Mat&, uint8_t shift);
@ -606,7 +602,9 @@ bool Jpeg2KOpjDecoder::readData( Mat& img )
switch (image_->color_space)
{
case OPJ_CLRSPC_UNKNOWN:
CV_LOG_WARNING(NULL, "OpenJPEG2000: Image has unknown color space, SRGB is assumed");
/* FALLTHRU */
case OPJ_CLRSPC_UNSPECIFIED:
CV_LOG_WARNING(NULL, "OpenJPEG2000: Image has unknown or unspecified color space, SRGB is assumed");
/* FALLTHRU */
case OPJ_CLRSPC_SRGB:
decode = decodeSRGBData;
@ -617,8 +615,6 @@ bool Jpeg2KOpjDecoder::readData( Mat& img )
case OPJ_CLRSPC_SYCC:
decode = decodeSYCCData;
break;
case OPJ_CLRSPC_UNSPECIFIED:
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Image has unspecified color space");
default:
CV_Error(Error::StsNotImplemented,
cv::format("OpenJPEG2000: Unsupported color space conversion: %s -> %s",
@ -654,6 +650,31 @@ bool Jpeg2KOpjDecoder::readData( Mat& img )
return decode(*image_, img, shift);
}
} // namespace detail
Jpeg2KJP2OpjDecoder::Jpeg2KJP2OpjDecoder()
: Jpeg2KOpjDecoderBase(OPJ_CODEC_JP2)
{
static const unsigned char JP2Signature[] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10 };
m_signature = String((const char*) JP2Signature, sizeof(JP2Signature));
}
ImageDecoder Jpeg2KJP2OpjDecoder::newDecoder() const
{
return makePtr<Jpeg2KJP2OpjDecoder>();
}
Jpeg2KJ2KOpjDecoder::Jpeg2KJ2KOpjDecoder()
: Jpeg2KOpjDecoderBase(OPJ_CODEC_J2K)
{
static const unsigned char J2KSignature[] = { 0xff, 0x4f, 0xff, 0x51 };
m_signature = String((const char*) J2KSignature, sizeof(J2KSignature));
}
ImageDecoder Jpeg2KJ2KOpjDecoder::newDecoder() const
{
return makePtr<Jpeg2KJ2KOpjDecoder>();
}
/////////////////////// Jpeg2KOpjEncoder ///////////////////

@ -59,15 +59,11 @@ 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
class Jpeg2KOpjDecoderBase : public BaseImageDecoder
{
public:
Jpeg2KOpjDecoder();
~Jpeg2KOpjDecoder() CV_OVERRIDE = default;
Jpeg2KOpjDecoderBase(OPJ_CODEC_FORMAT format);
ImageDecoder newDecoder() const CV_OVERRIDE;
bool readData( Mat& img ) CV_OVERRIDE;
bool readHeader() CV_OVERRIDE;
@ -79,6 +75,23 @@ private:
detail::OpjMemoryBuffer opjBuf_;
OPJ_UINT32 m_maxPrec = 0;
OPJ_CODEC_FORMAT format_;
};
} // namespace detail
class Jpeg2KJP2OpjDecoder CV_FINAL : public detail::Jpeg2KOpjDecoderBase {
public:
Jpeg2KJP2OpjDecoder();
ImageDecoder newDecoder() const CV_OVERRIDE;
};
class Jpeg2KJ2KOpjDecoder CV_FINAL : public detail::Jpeg2KOpjDecoderBase {
public:
Jpeg2KJ2KOpjDecoder();
ImageDecoder newDecoder() const CV_OVERRIDE;
};
class Jpeg2KOpjEncoder CV_FINAL : public BaseImageEncoder

@ -179,7 +179,8 @@ struct ImageCodecInitializer
encoders.push_back( makePtr<Jpeg2KEncoder>() );
#endif
#ifdef HAVE_OPENJPEG
decoders.push_back( makePtr<Jpeg2KOpjDecoder>() );
decoders.push_back( makePtr<Jpeg2KJP2OpjDecoder>() );
decoders.push_back( makePtr<Jpeg2KJ2KOpjDecoder>() );
encoders.push_back( makePtr<Jpeg2KOpjEncoder>() );
#endif
#ifdef HAVE_OPENEXR

@ -78,7 +78,9 @@ const string all_images[] =
"readwrite/Bretagne2.jp2",
"readwrite/Grey.jp2",
"readwrite/Grey.jp2",
"readwrite/balloon.j2c",
#endif
#ifdef HAVE_GDCM
"readwrite/int16-mono1.dcm",
"readwrite/uint8-mono2.dcm",
@ -109,11 +111,11 @@ INSTANTIATE_TEST_CASE_P(All, Imgcodecs_FileMode,
testing::ValuesIn(all_images),
testing::ValuesIn(basic_modes)));
// GDAL does not support "hdr", "dcm" and have problems with "jp2"
// GDAL does not support "hdr", "dcm" and has problems with JPEG2000 files (jp2, j2c)
struct notForGDAL {
bool operator()(const string &name) const {
const string &ext = name.substr(name.size() - 3, 3);
return ext == "hdr" || ext == "dcm" || ext == "jp2" ||
return ext == "hdr" || ext == "dcm" || ext == "jp2" || ext == "j2c" ||
name.find("rle8.bmp") != std::string::npos;
}
};

Loading…
Cancel
Save