Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitea023b7

Browse files
authored
Merge pull request#26788 from Kumataro:fix26767
jpegxl: support cv::IMREAD_UNCHANGED and other ImreadFlags#26788Close#26767### Pull Request Readiness ChecklistSee details athttps://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request- [x] I agree to contribute to the project under Apache 2 License.- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV- [x] The PR is proposed to the proper branch- [x] There is a reference to the original bug report and related work- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name.- [x] The feature is well documented and sample code can be built with the project CMake
1 parentdb962ea commitea023b7

File tree

4 files changed

+340
-66
lines changed

4 files changed

+340
-66
lines changed

‎modules/imgcodecs/src/grfmt_jpegxl.cpp‎

Lines changed: 260 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@
1212

1313
namespacecv
1414
{
15+
// Callback functions for JpegXLDecoder
16+
staticvoidcbRGBtoBGR_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
17+
staticvoidcbRGBAtoBGRA_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
18+
staticvoidcbRGBtoBGR_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
19+
staticvoidcbRGBAtoBGRA_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
20+
staticvoidcbRGBtoBGR_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
21+
staticvoidcbRGBAtoBGRA_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
22+
staticvoidcbRGBtoGRAY_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
23+
staticvoidcbRGBAtoGRAY_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
24+
staticvoidcbRGBtoGRAY_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
25+
staticvoidcbRGBAtoGRAY_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
26+
staticvoidcbRGBtoGRAY_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
27+
staticvoidcbRGBAtoGRAY_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels);
1528

1629
/////////////////////// JpegXLDecoder ///////////////////
1730

@@ -20,7 +33,7 @@ JpegXLDecoder::JpegXLDecoder() : m_f(nullptr, &fclose)
2033
m_signature ="\xFF\x0A";
2134
m_decoder =nullptr;
2235
m_buf_supported =false;
23-
m_type =m_convert =-1;
36+
m_type = -1;
2437
m_status = JXL_DEC_NEED_MORE_INPUT;
2538
}
2639

@@ -37,7 +50,7 @@ void JpegXLDecoder::close()
3750
m_f.reset();
3851
m_read_buffer = {};
3952
m_width = m_height =0;
40-
m_type =m_convert =-1;
53+
m_type = -1;
4154
m_status = JXL_DEC_NEED_MORE_INPUT;
4255
}
4356

@@ -76,7 +89,7 @@ ImageDecoder JpegXLDecoder::newDecoder() const
7689
return makePtr<JpegXLDecoder>();
7790
}
7891

79-
boolJpegXLDecoder::read(Mat* pimg)
92+
boolJpegXLDecoder::readHeader()
8093
{
8194
// Open file
8295
if (!m_f) {
@@ -106,24 +119,87 @@ bool JpegXLDecoder::read(Mat* pimg)
106119
}
107120
}
108121

109-
// Create buffer for reading
110-
constsize_t read_buffer_size =16384;// 16KB chunks
111-
if (m_read_buffer.capacity() < read_buffer_size)
112-
m_read_buffer.resize(read_buffer_size);
122+
returnread();
123+
}
113124

114-
// Create image if needed
115-
if (m_type != -1 && pimg) {
116-
pimg->create(m_height, m_width, m_type);
117-
if (!pimg->isContinuous())
125+
boolJpegXLDecoder::readData(Mat& img)
126+
{
127+
if (!m_decoder || m_width ==0 || m_height ==0 || m_type == -1)
128+
returnfalse;
129+
130+
// Prepare to decode image
131+
constuint32_t scn =CV_MAT_CN(m_type);// from image
132+
constuint32_t dcn = (uint32_t)img.channels();// to OpenCV
133+
constint depth =CV_MAT_DEPTH(img.type());
134+
JxlImageOutCallback cbFunc =nullptr;
135+
136+
CV_CheckChannels(scn, (scn ==1 || scn ==3 || scn ==4),"Unsupported src channels");
137+
CV_CheckChannels(dcn, (dcn ==1 || dcn ==3 || dcn ==4),"Unsupported dst channels");
138+
CV_CheckDepth(depth, (depth == CV_8U || depth == CV_16U || depth == CV_32F),"Unsupported depth");
139+
140+
m_format = {
141+
dcn,
142+
JXL_TYPE_UINT8,// (temporary)
143+
JXL_NATIVE_ENDIAN,// endianness
144+
0// align stride to bytes
145+
};
146+
switch (depth) {
147+
case CV_8U: m_format.data_type = JXL_TYPE_UINT8;break;
148+
case CV_16U: m_format.data_type = JXL_TYPE_UINT16;break;
149+
case CV_32F: m_format.data_type = JXL_TYPE_FLOAT;break;
150+
default:break;
151+
}
152+
// libjxl cannot read to BGR pixel order directly.
153+
// So we have to use callback function to convert from RGB(A) to BGR(A).
154+
if (!m_use_rgb) {
155+
switch (dcn) {
156+
case1:break;
157+
case3: cbFunc = (depth == CV_32F)? cbRGBtoBGR_32F: (depth == CV_16U)? cbRGBtoBGR_16U: cbRGBtoBGR_8U;break;
158+
case4: cbFunc = (depth == CV_32F)? cbRGBAtoBGRA_32F: (depth == CV_16U)? cbRGBAtoBGRA_16U: cbRGBAtoBGRA_8U;break;
159+
default:break;
160+
}
161+
}
162+
// libjxl cannot convert from color image to gray image directly.
163+
// So we have to use callback function to convert from RGB(A) to GRAY.
164+
if( (scn >=3) && (dcn ==1) )
165+
{
166+
m_format.num_channels = scn;
167+
switch (scn) {
168+
case3: cbFunc = (depth == CV_32F)? cbRGBtoGRAY_32F: (depth == CV_16U)? cbRGBtoGRAY_16U: cbRGBtoGRAY_8U;break;
169+
case4: cbFunc = (depth == CV_32F)? cbRGBAtoGRAY_32F: (depth == CV_16U)? cbRGBAtoGRAY_16U: cbRGBAtoGRAY_8U;break;
170+
default:break;
171+
}
172+
}
173+
if(cbFunc !=nullptr)
174+
{
175+
if (JXL_DEC_SUCCESS !=JxlDecoderSetImageOutCallback(m_decoder.get(),
176+
&m_format,
177+
cbFunc,
178+
static_cast<void*>(&img)))
179+
{
118180
returnfalse;
181+
}
182+
}else{
119183
if (JXL_DEC_SUCCESS !=JxlDecoderSetImageOutBuffer(m_decoder.get(),
120184
&m_format,
121-
pimg->ptr<uint8_t>(),
122-
pimg->total() * pimg->elemSize())) {
185+
img.ptr<uint8_t>(),
186+
img.total() * img.elemSize()))
187+
{
123188
returnfalse;
124189
}
125190
}
126191

192+
returnread();
193+
}
194+
195+
// Common reading routine for readHeader() and readBody()
196+
boolJpegXLDecoder::read()
197+
{
198+
// Create buffer for reading
199+
constsize_t read_buffer_size =16384;// 16KB chunks
200+
if (m_read_buffer.capacity() < read_buffer_size)
201+
m_read_buffer.resize(read_buffer_size);
202+
127203
// Start decoding loop
128204
do {
129205
// Check if we need more input
@@ -163,6 +239,7 @@ bool JpegXLDecoder::read(Mat* pimg)
163239
case JXL_DEC_BASIC_INFO: {
164240
if (m_type != -1)
165241
returnfalse;
242+
166243
JxlBasicInfo info;
167244
if (JXL_DEC_SUCCESS !=JxlDecoderGetBasicInfo(m_decoder.get(), &info))
168245
returnfalse;
@@ -172,49 +249,18 @@ bool JpegXLDecoder::read(Mat* pimg)
172249

173250
m_width = info.xsize;
174251
m_height = info.ysize;
175-
m_format = {
176-
ncn,
177-
JXL_TYPE_UINT8,// (temporary)
178-
JXL_LITTLE_ENDIAN,// endianness
179-
0// align stride to bytes
180-
};
181-
if (!m_use_rgb) {
182-
switch (ncn) {
183-
case3:
184-
m_convert = cv::COLOR_RGB2BGR;
185-
break;
186-
case4:
187-
m_convert = cv::COLOR_RGBA2BGRA;
188-
break;
189-
default:
190-
m_convert = -1;
191-
}
192-
}
193-
if (info.exponent_bits_per_sample >0) {
194-
m_format.data_type = JXL_TYPE_FLOAT;
195-
m_type =CV_MAKETYPE( CV_32F, ncn );
196-
}else {
197-
switch (info.bits_per_sample) {
198-
case8:
199-
m_format.data_type = JXL_TYPE_UINT8;
200-
m_type =CV_MAKETYPE( CV_8U, ncn );
201-
break;
202-
case16:
203-
m_format.data_type = JXL_TYPE_UINT16;
204-
m_type =CV_MAKETYPE( CV_16U, ncn );
205-
break;
206-
default:
207-
returnfalse;
208-
}
252+
int depth = (info.exponent_bits_per_sample >0)?CV_32F:
253+
(info.bits_per_sample ==16)?CV_16U:
254+
(info.bits_per_sample ==8)?CV_8U: -1;
255+
if(depth == -1)
256+
{
257+
returnfalse;// Return to readHeader()
209258
}
210-
if (!pimg)
211-
returntrue;
212-
break;
259+
m_type =CV_MAKETYPE( depth, ncn );
260+
returntrue;
213261
}
214262
case JXL_DEC_FULL_IMAGE: {
215263
// Image is ready
216-
if (m_convert != -1)
217-
cv::cvtColor(*pimg, *pimg, m_convert);
218264
break;
219265
}
220266
case JXL_DEC_ERROR: {
@@ -229,17 +275,172 @@ bool JpegXLDecoder::read(Mat* pimg)
229275
returntrue;
230276
}
231277

232-
boolJpegXLDecoder::readHeader()
278+
// Callback functopms
279+
staticvoidcbRGBtoBGR_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
233280
{
234-
close();
235-
returnread(nullptr);
281+
constuint8_t* src =static_cast<constuint8_t*>(pixels);
282+
283+
constexprint dstStep =3;
284+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
285+
uint8_t* dstBase =const_cast<uint8_t*>(pDst->ptr(y));
286+
uint8_t* dst = dstBase + x * dstStep;
287+
288+
icvCvt_RGB2BGR_8u_C3R( src,0, dst,0,Size(num_pixels ,1) );
236289
}
290+
staticvoidcbRGBAtoBGRA_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
291+
{
292+
constuint8_t* src =static_cast<constuint8_t*>(pixels);
237293

238-
boolJpegXLDecoder::readData(Mat& img)
294+
constexprint dstStep =4;
295+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
296+
uint8_t* dstBase =const_cast<uint8_t*>(reinterpret_cast<constuint8_t*>(pDst->ptr(y)));
297+
uint8_t* dst = dstBase + x * dstStep;
298+
299+
icvCvt_RGBA2BGRA_8u_C4R( src,0, dst,0,Size(num_pixels,1) );
300+
}
301+
staticvoidcbRGBtoBGR_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
239302
{
240-
if (!m_decoder || m_width ==0 || m_height ==0)
241-
returnfalse;
242-
returnread(&img);
303+
constuint16_t* src =static_cast<constuint16_t*>(pixels);
304+
305+
constexprint dstStep =3;
306+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
307+
uint16_t* dstBase =const_cast<uint16_t*>(reinterpret_cast<constuint16_t*>(pDst->ptr(y)));
308+
uint16_t* dst = dstBase + x * dstStep;
309+
310+
icvCvt_BGR2RGB_16u_C3R( src,0, dst,0,Size(num_pixels,1));
311+
}
312+
staticvoidcbRGBAtoBGRA_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
313+
{
314+
constuint16_t* src =static_cast<constuint16_t*>(pixels);
315+
316+
constexprint dstStep =4;
317+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
318+
uint16_t* dstBase =const_cast<uint16_t*>(reinterpret_cast<constuint16_t*>(pDst->ptr(y)));
319+
uint16_t* dst = dstBase + x * dstStep;
320+
321+
icvCvt_BGRA2RGBA_16u_C4R( src,0, dst,0,Size(num_pixels,1));
322+
}
323+
staticvoidcbRGBtoBGR_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
324+
{
325+
constexprint srcStep =3;
326+
constuint32_t* src =static_cast<constuint32_t*>(pixels);
327+
328+
constexprint dstStep =3;
329+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
330+
uint32_t* dstBase =const_cast<uint32_t*>(reinterpret_cast<constuint32_t*>(pDst->ptr(y)));
331+
uint32_t* dst = dstBase + x * dstStep;
332+
333+
for(size_t i =0 ; i < num_pixels; i++)
334+
{
335+
dst[ i * dstStep +0 ] = src[ i * srcStep +2];
336+
dst[ i * dstStep +1 ] = src[ i * srcStep +1];
337+
dst[ i * dstStep +2 ] = src[ i * srcStep +0];
338+
}
339+
}
340+
staticvoidcbRGBAtoBGRA_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
341+
{
342+
constexprint srcStep =4;
343+
constuint32_t* src =static_cast<constuint32_t*>(pixels);
344+
345+
constexprint dstStep =4;
346+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
347+
uint32_t* dstBase =const_cast<uint32_t*>(reinterpret_cast<constuint32_t*>(pDst->ptr(y)));
348+
uint32_t* dst = dstBase + x * dstStep;
349+
350+
for(size_t i =0 ; i < num_pixels; i++)
351+
{
352+
dst[ i * dstStep +0 ] = src[ i * srcStep +2];
353+
dst[ i * dstStep +1 ] = src[ i * srcStep +1];
354+
dst[ i * dstStep +2 ] = src[ i * srcStep +0];
355+
dst[ i * dstStep +3 ] = src[ i * srcStep +3];
356+
}
357+
}
358+
359+
staticvoidcbRGBtoGRAY_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
360+
{
361+
constuint8_t* src =static_cast<constuint8_t*>(pixels);
362+
363+
constexprint dstStep =1;
364+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
365+
uint8_t* dstBase =const_cast<uint8_t*>(reinterpret_cast<constuint8_t*>(pDst->ptr(y)));
366+
uint8_t* dst = dstBase + x * dstStep;
367+
368+
icvCvt_BGR2Gray_8u_C3C1R(src,0, dst,0,Size(num_pixels,1) );
369+
}
370+
staticvoidcbRGBAtoGRAY_8U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
371+
{
372+
constuint8_t* src =static_cast<constuint8_t*>(pixels);
373+
374+
constexprint dstStep =1;
375+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
376+
uint8_t* dstBase =const_cast<uint8_t*>(reinterpret_cast<constuint8_t*>(pDst->ptr(y)));
377+
uint8_t* dst = dstBase + x * dstStep;
378+
379+
icvCvt_BGRA2Gray_8u_C4C1R(src,0, dst,0,Size(num_pixels,1) );
380+
}
381+
staticvoidcbRGBtoGRAY_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
382+
{
383+
constuint16_t* src =static_cast<constuint16_t*>(pixels);
384+
385+
constexprint dstStep =1;
386+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
387+
uint16_t* dstBase =const_cast<uint16_t*>(reinterpret_cast<constuint16_t*>(pDst->ptr(y)));
388+
uint16_t* dst = dstBase + x * dstStep;
389+
390+
icvCvt_BGRA2Gray_16u_CnC1R(src,0, dst,0,Size(num_pixels,1),/* ncn=*/3 );
391+
}
392+
staticvoidcbRGBAtoGRAY_16U(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
393+
{
394+
constuint16_t* src =static_cast<constuint16_t*>(pixels);
395+
396+
constexprint dstStep =1;
397+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
398+
uint16_t* dstBase =const_cast<uint16_t*>(reinterpret_cast<constuint16_t*>(pDst->ptr(y)));
399+
uint16_t* dst = dstBase + x * dstStep;
400+
401+
icvCvt_BGRA2Gray_16u_CnC1R(src,0, dst,0,Size(num_pixels,1),/* ncn=*/4 );
402+
}
403+
staticvoidcbRGBtoGRAY_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
404+
{
405+
constexprfloat cR =0.299f;
406+
constexprfloat cG =0.587f;
407+
constexprfloat cB =1.000f - cR - cG;
408+
409+
constexprint srcStep =3;
410+
constfloat* src =static_cast<constfloat*>(pixels);
411+
412+
constexprint dstStep =1;
413+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
414+
float* dstBase =const_cast<float*>(reinterpret_cast<constfloat*>(pDst->ptr(y)));
415+
float* dst = dstBase + x * dstStep;
416+
417+
for(size_t i =0 ; i < num_pixels; i++)
418+
{
419+
dst[ i * dstStep ] = src[ i * srcStep +0] * cR +
420+
src[ i * srcStep +1] * cG +
421+
src[ i * srcStep +2] * cB;
422+
}
423+
}
424+
staticvoidcbRGBAtoGRAY_32F(void *opaque,size_t x,size_t y,size_t num_pixels,constvoid *pixels)
425+
{
426+
constexprfloat cR =0.299f;
427+
constexprfloat cG =0.587f;
428+
constexprfloat cB =1.000f - cR - cG;
429+
430+
constexprint srcStep =4;
431+
constfloat* src =static_cast<constfloat*>(pixels);
432+
433+
constexprint dstStep =1;
434+
const cv::Mat *pDst =static_cast<cv::Mat*>(opaque);
435+
float* dstBase =const_cast<float*>(reinterpret_cast<constfloat*>(pDst->ptr(y)));
436+
float* dst = dstBase + x * dstStep;
437+
438+
for(size_t i =0 ; i < num_pixels; i++)
439+
{
440+
dst[ i * dstStep ] = src[ i * srcStep +0] * cR +
441+
src[ i * srcStep +1] * cG +
442+
src[ i * srcStep +2] * cB;
443+
}
243444
}
244445

245446
/////////////////////// JpegXLEncoder ///////////////////

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp