Skip to content

Commit b13b5d8

Browse files
authored
Merge pull request opencv#19109 from tailsu:sd/imdecode-jp2k-codestream
* OpenJPEG: decoder for J2K codestreams * code review fixes * exclude .j2c from GDAL tests
1 parent 1526591 commit b13b5d8

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -495,20 +495,16 @@ detail::StreamPtr opjCreateBufferInputStream(detail::OpjMemoryBuffer* buf)
495495

496496
/////////////////////// Jpeg2KOpjDecoder ///////////////////
497497

498-
Jpeg2KOpjDecoder::Jpeg2KOpjDecoder()
498+
namespace detail {
499+
500+
Jpeg2KOpjDecoderBase::Jpeg2KOpjDecoderBase(OPJ_CODEC_FORMAT format)
501+
: format_(format)
499502
{
500-
static const unsigned char signature[] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10 };
501-
m_signature = String((const char*)(signature), sizeof(signature));
502503
m_buf_supported = true;
503504
}
504505

505506

506-
ImageDecoder Jpeg2KOpjDecoder::newDecoder() const
507-
{
508-
return makePtr<Jpeg2KOpjDecoder>();
509-
}
510-
511-
bool Jpeg2KOpjDecoder::readHeader()
507+
bool Jpeg2KOpjDecoderBase::readHeader()
512508
{
513509
if (!m_buf.empty()) {
514510
opjBuf_ = detail::OpjMemoryBuffer(m_buf);
@@ -521,7 +517,7 @@ bool Jpeg2KOpjDecoder::readHeader()
521517
if (!stream_)
522518
return false;
523519

524-
codec_.reset(opj_create_decompress(OPJ_CODEC_JP2));
520+
codec_.reset(opj_create_decompress(format_));
525521
if (!codec_)
526522
return false;
527523

@@ -587,7 +583,7 @@ bool Jpeg2KOpjDecoder::readHeader()
587583
return true;
588584
}
589585

590-
bool Jpeg2KOpjDecoder::readData( Mat& img )
586+
bool Jpeg2KOpjDecoderBase::readData( Mat& img )
591587
{
592588
using DecodeFunc = bool(*)(const opj_image_t&, cv::Mat&, uint8_t shift);
593589

@@ -606,7 +602,9 @@ bool Jpeg2KOpjDecoder::readData( Mat& img )
606602
switch (image_->color_space)
607603
{
608604
case OPJ_CLRSPC_UNKNOWN:
609-
CV_LOG_WARNING(NULL, "OpenJPEG2000: Image has unknown color space, SRGB is assumed");
605+
/* FALLTHRU */
606+
case OPJ_CLRSPC_UNSPECIFIED:
607+
CV_LOG_WARNING(NULL, "OpenJPEG2000: Image has unknown or unspecified color space, SRGB is assumed");
610608
/* FALLTHRU */
611609
case OPJ_CLRSPC_SRGB:
612610
decode = decodeSRGBData;
@@ -617,8 +615,6 @@ bool Jpeg2KOpjDecoder::readData( Mat& img )
617615
case OPJ_CLRSPC_SYCC:
618616
decode = decodeSYCCData;
619617
break;
620-
case OPJ_CLRSPC_UNSPECIFIED:
621-
CV_Error(Error::StsNotImplemented, "OpenJPEG2000: Image has unspecified color space");
622618
default:
623619
CV_Error(Error::StsNotImplemented,
624620
cv::format("OpenJPEG2000: Unsupported color space conversion: %s -> %s",
@@ -654,6 +650,31 @@ bool Jpeg2KOpjDecoder::readData( Mat& img )
654650
return decode(*image_, img, shift);
655651
}
656652

653+
} // namespace detail
654+
655+
Jpeg2KJP2OpjDecoder::Jpeg2KJP2OpjDecoder()
656+
: Jpeg2KOpjDecoderBase(OPJ_CODEC_JP2)
657+
{
658+
static const unsigned char JP2Signature[] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10 };
659+
m_signature = String((const char*) JP2Signature, sizeof(JP2Signature));
660+
}
661+
662+
ImageDecoder Jpeg2KJP2OpjDecoder::newDecoder() const
663+
{
664+
return makePtr<Jpeg2KJP2OpjDecoder>();
665+
}
666+
667+
Jpeg2KJ2KOpjDecoder::Jpeg2KJ2KOpjDecoder()
668+
: Jpeg2KOpjDecoderBase(OPJ_CODEC_J2K)
669+
{
670+
static const unsigned char J2KSignature[] = { 0xff, 0x4f, 0xff, 0x51 };
671+
m_signature = String((const char*) J2KSignature, sizeof(J2KSignature));
672+
}
673+
674+
ImageDecoder Jpeg2KJ2KOpjDecoder::newDecoder() const
675+
{
676+
return makePtr<Jpeg2KJ2KOpjDecoder>();
677+
}
657678

658679
/////////////////////// Jpeg2KOpjEncoder ///////////////////
659680

modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.hpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,11 @@ using StreamPtr = std::unique_ptr<opj_stream_t, detail::OpjStreamDeleter>;
5959
using CodecPtr = std::unique_ptr<opj_codec_t, detail::OpjCodecDeleter>;
6060
using ImagePtr = std::unique_ptr<opj_image_t, detail::OpjImageDeleter>;
6161

62-
} // namespace detail
63-
64-
class Jpeg2KOpjDecoder CV_FINAL : public BaseImageDecoder
62+
class Jpeg2KOpjDecoderBase : public BaseImageDecoder
6563
{
6664
public:
67-
Jpeg2KOpjDecoder();
68-
~Jpeg2KOpjDecoder() CV_OVERRIDE = default;
65+
Jpeg2KOpjDecoderBase(OPJ_CODEC_FORMAT format);
6966

70-
ImageDecoder newDecoder() const CV_OVERRIDE;
7167
bool readData( Mat& img ) CV_OVERRIDE;
7268
bool readHeader() CV_OVERRIDE;
7369

@@ -79,6 +75,23 @@ class Jpeg2KOpjDecoder CV_FINAL : public BaseImageDecoder
7975
detail::OpjMemoryBuffer opjBuf_;
8076

8177
OPJ_UINT32 m_maxPrec = 0;
78+
OPJ_CODEC_FORMAT format_;
79+
};
80+
81+
} // namespace detail
82+
83+
class Jpeg2KJP2OpjDecoder CV_FINAL : public detail::Jpeg2KOpjDecoderBase {
84+
public:
85+
Jpeg2KJP2OpjDecoder();
86+
87+
ImageDecoder newDecoder() const CV_OVERRIDE;
88+
};
89+
90+
class Jpeg2KJ2KOpjDecoder CV_FINAL : public detail::Jpeg2KOpjDecoderBase {
91+
public:
92+
Jpeg2KJ2KOpjDecoder();
93+
94+
ImageDecoder newDecoder() const CV_OVERRIDE;
8295
};
8396

8497
class Jpeg2KOpjEncoder CV_FINAL : public BaseImageEncoder

modules/imgcodecs/src/loadsave.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ struct ImageCodecInitializer
179179
encoders.push_back( makePtr<Jpeg2KEncoder>() );
180180
#endif
181181
#ifdef HAVE_OPENJPEG
182-
decoders.push_back( makePtr<Jpeg2KOpjDecoder>() );
182+
decoders.push_back( makePtr<Jpeg2KJP2OpjDecoder>() );
183+
decoders.push_back( makePtr<Jpeg2KJ2KOpjDecoder>() );
183184
encoders.push_back( makePtr<Jpeg2KOpjEncoder>() );
184185
#endif
185186
#ifdef HAVE_OPENEXR

modules/imgcodecs/test/test_grfmt.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ const string all_images[] =
7878
"readwrite/Bretagne2.jp2",
7979
"readwrite/Grey.jp2",
8080
"readwrite/Grey.jp2",
81+
"readwrite/balloon.j2c",
8182
#endif
83+
8284
#ifdef HAVE_GDCM
8385
"readwrite/int16-mono1.dcm",
8486
"readwrite/uint8-mono2.dcm",
@@ -109,11 +111,11 @@ INSTANTIATE_TEST_CASE_P(All, Imgcodecs_FileMode,
109111
testing::ValuesIn(all_images),
110112
testing::ValuesIn(basic_modes)));
111113

112-
// GDAL does not support "hdr", "dcm" and have problems with "jp2"
114+
// GDAL does not support "hdr", "dcm" and has problems with JPEG2000 files (jp2, j2c)
113115
struct notForGDAL {
114116
bool operator()(const string &name) const {
115117
const string &ext = name.substr(name.size() - 3, 3);
116-
return ext == "hdr" || ext == "dcm" || ext == "jp2" ||
118+
return ext == "hdr" || ext == "dcm" || ext == "jp2" || ext == "j2c" ||
117119
name.find("rle8.bmp") != std::string::npos;
118120
}
119121
};

0 commit comments

Comments
 (0)