Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
1fb93b62
Commit
1fb93b62
authored
Apr 04, 2019
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14249 from alalek:imgcodecs_tiff_update_3.4
parents
ab21dc6d
ba5ddd64
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
398 additions
and
422 deletions
+398
-422
grfmt_tiff.cpp
modules/imgcodecs/src/grfmt_tiff.cpp
+292
-378
grfmt_tiff.hpp
modules/imgcodecs/src/grfmt_tiff.hpp
+2
-5
utils.cpp
modules/imgcodecs/src/utils.cpp
+24
-19
utils.hpp
modules/imgcodecs/src/utils.hpp
+21
-17
test_tiff.cpp
modules/imgcodecs/test/test_tiff.cpp
+59
-3
No files found.
modules/imgcodecs/src/grfmt_tiff.cpp
View file @
1fb93b62
...
...
@@ -48,6 +48,8 @@
#include "precomp.hpp"
#ifdef HAVE_TIFF
#include <opencv2/core/utils/logger.hpp>
#include "grfmt_tiff.hpp"
#include <limits>
...
...
@@ -61,23 +63,58 @@ using namespace tiff_dummy_namespace;
namespace
cv
{
#define CV_TIFF_CHECK_CALL(call) \
if (0 == (call)) { \
CV_LOG_WARNING(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed " #call); \
CV_Error(Error::StsError, "OpenCV TIFF: failed " #call); \
}
#define CV_TIFF_CHECK_CALL_INFO(call) \
if (0 == (call)) { \
CV_LOG_INFO(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed optional call: " #call ", ignoring"); \
}
#define CV_TIFF_CHECK_CALL_DEBUG(call) \
if (0 == (call)) { \
CV_LOG_DEBUG(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed optional call: " #call ", ignoring"); \
}
static
void
cv_tiffCloseHandle
(
void
*
handle
)
{
TIFFClose
((
TIFF
*
)
handle
);
}
static
void
cv_tiffErrorHandler
(
const
char
*
module
,
const
char
*
fmt
,
va_list
ap
)
{
if
(
cv
::
utils
::
logging
::
getLogLevel
()
<
cv
::
utils
::
logging
::
LOG_LEVEL_DEBUG
)
return
;
// TODO cv::vformat() with va_list parameter
fprintf
(
stderr
,
"OpenCV TIFF: "
);
if
(
module
!=
NULL
)
fprintf
(
stderr
,
"%s: "
,
module
);
fprintf
(
stderr
,
"Warning, "
);
vfprintf
(
stderr
,
fmt
,
ap
);
fprintf
(
stderr
,
".
\n
"
);
}
static
bool
cv_tiffSetErrorHandler_
()
{
TIFFSetErrorHandler
(
cv_tiffErrorHandler
);
TIFFSetWarningHandler
(
cv_tiffErrorHandler
);
return
true
;
}
static
bool
cv_tiffSetErrorHandler
()
{
static
bool
v
=
cv_tiffSetErrorHandler_
();
return
v
;
}
static
const
char
fmtSignTiffII
[]
=
"II
\x2a\x00
"
;
static
const
char
fmtSignTiffMM
[]
=
"MM
\x00\x2a
"
;
static
int
grfmt_tiff_err_handler_init
=
0
;
static
void
GrFmtSilentTIFFErrorHandler
(
const
char
*
,
const
char
*
,
va_list
)
{}
TiffDecoder
::
TiffDecoder
()
{
m_tif
=
0
;
if
(
!
grfmt_tiff_err_handler_init
)
{
grfmt_tiff_err_handler_init
=
1
;
TIFFSetErrorHandler
(
GrFmtSilentTIFFErrorHandler
);
TIFFSetWarningHandler
(
GrFmtSilentTIFFErrorHandler
);
}
m_hdr
=
false
;
m_buf_supported
=
true
;
m_buf_pos
=
0
;
...
...
@@ -86,12 +123,7 @@ TiffDecoder::TiffDecoder()
void
TiffDecoder
::
close
()
{
if
(
m_tif
)
{
TIFF
*
tif
=
(
TIFF
*
)
m_tif
;
TIFFClose
(
tif
);
m_tif
=
0
;
}
m_tif
.
release
();
}
TiffDecoder
::~
TiffDecoder
()
...
...
@@ -113,11 +145,13 @@ bool TiffDecoder::checkSignature( const String& signature ) const
int
TiffDecoder
::
normalizeChannelsNumber
(
int
channels
)
const
{
CV_Assert
(
channels
<=
4
);
return
channels
>
4
?
4
:
channels
;
}
ImageDecoder
TiffDecoder
::
newDecoder
()
const
{
cv_tiffSetErrorHandler
();
return
makePtr
<
TiffDecoder
>
();
}
...
...
@@ -201,8 +235,8 @@ bool TiffDecoder::readHeader()
{
bool
result
=
false
;
TIFF
*
tif
=
static_cast
<
TIFF
*>
(
m_tif
);
if
(
!
m_
tif
)
TIFF
*
tif
=
static_cast
<
TIFF
*>
(
m_tif
.
get
()
);
if
(
!
tif
)
{
// TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading.
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
...
...
@@ -221,25 +255,30 @@ bool TiffDecoder::readHeader()
{
tif
=
TIFFOpen
(
m_filename
.
c_str
(),
"r"
);
}
if
(
tif
)
m_tif
.
reset
(
tif
,
cv_tiffCloseHandle
);
else
m_tif
.
release
();
}
if
(
tif
)
if
(
tif
)
{
uint32
wdth
=
0
,
hght
=
0
;
uint16
photometric
=
0
;
m_tif
=
tif
;
if
(
TIFFGetField
(
tif
,
TIFFTAG_IMAGEWIDTH
,
&
wdth
)
&&
TIFFGetField
(
tif
,
TIFFTAG_IMAGELENGTH
,
&
hght
)
&&
TIFFGetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
&
photometric
))
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_IMAGEWIDTH
,
&
wdth
));
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_IMAGELENGTH
,
&
hght
));
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
&
photometric
));
{
uint16
bpp
=
8
,
ncn
=
photometric
>
1
?
3
:
1
;
TIFFGetField
(
tif
,
TIFFTAG_BITSPERSAMPLE
,
&
bpp
);
TIFFGetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
&
ncn
);
bool
isGrayScale
=
photometric
==
PHOTOMETRIC_MINISWHITE
||
photometric
==
PHOTOMETRIC_MINISBLACK
;
uint16
bpp
=
8
,
ncn
=
isGrayScale
?
1
:
3
;
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_BITSPERSAMPLE
,
&
bpp
));
CV_TIFF_CHECK_CALL_DEBUG
(
TIFFGetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
&
ncn
));
m_width
=
wdth
;
m_height
=
hght
;
if
((
bpp
==
32
&&
ncn
==
3
)
||
photometric
==
PHOTOMETRIC_LOGLUV
)
if
(
ncn
==
3
&&
photometric
==
PHOTOMETRIC_LOGLUV
)
{
m_type
=
CV_32FC3
;
m_hdr
=
true
;
...
...
@@ -256,23 +295,23 @@ bool TiffDecoder::readHeader()
switch
(
bpp
)
{
case
1
:
m_type
=
CV_MAKETYPE
(
CV_8U
,
photometric
>
1
?
wanted_channels
:
1
);
m_type
=
CV_MAKETYPE
(
CV_8U
,
!
isGrayScale
?
wanted_channels
:
1
);
result
=
true
;
break
;
case
8
:
m_type
=
CV_MAKETYPE
(
CV_8U
,
photometric
>
1
?
wanted_channels
:
1
);
m_type
=
CV_MAKETYPE
(
CV_8U
,
!
isGrayScale
?
wanted_channels
:
1
);
result
=
true
;
break
;
case
16
:
m_type
=
CV_MAKETYPE
(
CV_16U
,
photometric
>
1
?
wanted_channels
:
1
);
m_type
=
CV_MAKETYPE
(
CV_16U
,
!
isGrayScale
?
wanted_channels
:
1
);
result
=
true
;
break
;
case
32
:
m_type
=
CV_MAKETYPE
(
CV_32F
,
photometric
>
1
?
3
:
1
);
m_type
=
CV_MAKETYPE
(
CV_32F
,
wanted_channels
);
result
=
true
;
break
;
case
64
:
m_type
=
CV_MAKETYPE
(
CV_64F
,
photometric
>
1
?
3
:
1
);
m_type
=
CV_MAKETYPE
(
CV_64F
,
wanted_channels
);
result
=
true
;
break
;
default
:
...
...
@@ -290,206 +329,210 @@ bool TiffDecoder::readHeader()
bool
TiffDecoder
::
nextPage
()
{
// Prepare the next page, if any.
return
m_tif
&&
TIFFReadDirectory
(
static_cast
<
TIFF
*>
(
m_tif
))
&&
return
!
m_tif
.
empty
()
&&
TIFFReadDirectory
(
static_cast
<
TIFF
*>
(
m_tif
.
get
()
))
&&
readHeader
();
}
bool
TiffDecoder
::
readData
(
Mat
&
img
)
{
if
(
m_hdr
&&
img
.
type
()
==
CV_32FC3
)
{
return
readData_32FC3
(
img
);
}
if
(
img
.
type
()
==
CV_32FC1
)
int
type_
=
img
.
type
();
int
depth
=
CV_MAT_DEPTH
(
type_
);
CV_Assert
(
!
m_tif
.
empty
());
TIFF
*
tif
=
(
TIFF
*
)
m_tif
.
get
();
uint16
photometric
=
(
uint16
)
-
1
;
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
&
photometric
));
if
(
m_hdr
&&
depth
>=
CV_32F
)
{
return
readData_32FC1
(
img
);
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_SGILOGDATAFMT
,
SGILOGDATAFMT_FLOAT
)
);
}
bool
result
=
false
;
bool
color
=
img
.
channels
()
>
1
;
if
(
img
.
depth
()
!=
CV_8U
&&
img
.
depth
()
!=
CV_16U
&&
img
.
depth
()
!=
CV_32F
&&
img
.
depth
()
!=
CV_64F
)
return
false
;
CV_CheckType
(
type_
,
depth
==
CV_8U
||
depth
==
CV_16U
||
depth
==
CV_32F
||
depth
==
CV_64F
,
""
);
if
(
m_tif
&&
m_width
&&
m_height
)
if
(
m_width
&&
m_height
)
{
TIFF
*
tif
=
(
TIFF
*
)
m_tif
;
uint32
tile_width0
=
m_width
,
tile_height0
=
0
;
int
x
,
y
,
i
;
int
is_tiled
=
TIFFIsTiled
(
tif
);
uint16
photometric
;
TIFFGetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
&
photometric
);
uint16
bpp
=
8
,
ncn
=
photometric
>
1
?
3
:
1
;
TIFFGetField
(
tif
,
TIFFTAG_BITSPERSAMPLE
,
&
bpp
);
TIFFGetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
&
ncn
);
int
is_tiled
=
TIFFIsTiled
(
tif
)
!=
0
;
bool
isGrayScale
=
photometric
==
PHOTOMETRIC_MINISWHITE
||
photometric
==
PHOTOMETRIC_MINISBLACK
;
uint16
bpp
=
8
,
ncn
=
isGrayScale
?
1
:
3
;
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_BITSPERSAMPLE
,
&
bpp
));
CV_TIFF_CHECK_CALL_DEBUG
(
TIFFGetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
&
ncn
));
uint16
img_orientation
=
ORIENTATION_TOPLEFT
;
TIFFGetField
(
tif
,
TIFFTAG_ORIENTATION
,
&
img_orientation
);
CV_TIFF_CHECK_CALL_DEBUG
(
TIFFGetField
(
tif
,
TIFFTAG_ORIENTATION
,
&
img_orientation
)
);
bool
vert_flip
=
(
img_orientation
==
ORIENTATION_BOTRIGHT
)
||
(
img_orientation
==
ORIENTATION_RIGHTBOT
)
||
(
img_orientation
==
ORIENTATION_BOTLEFT
)
||
(
img_orientation
==
ORIENTATION_LEFTBOT
);
const
int
bitsPerByte
=
8
;
int
dst_bpp
=
(
int
)(
img
.
elemSize1
()
*
bitsPerByte
);
int
wanted_channels
=
normalizeChannelsNumber
(
img
.
channels
());
if
(
dst_bpp
==
8
)
if
(
dst_bpp
==
8
)
{
char
errmsg
[
1024
];
if
(
!
TIFFRGBAImageOK
(
tif
,
errmsg
))
if
(
!
TIFFRGBAImageOK
(
tif
,
errmsg
))
{
CV_LOG_WARNING
(
NULL
,
"OpenCV TIFF: TIFFRGBAImageOK: "
<<
errmsg
);
close
();
return
false
;
}
}
if
(
(
!
is_tiled
)
||
(
is_tiled
&&
TIFFGetField
(
tif
,
TIFFTAG_TILEWIDTH
,
&
tile_width0
)
&&
TIFFGetField
(
tif
,
TIFFTAG_TILELENGTH
,
&
tile_height0
)))
uint32
tile_width0
=
m_width
,
tile_height0
=
0
;
if
(
is_tiled
)
{
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_TILEWIDTH
,
&
tile_width0
));
CV_TIFF_CHECK_CALL
(
TIFFGetField
(
tif
,
TIFFTAG_TILELENGTH
,
&
tile_height0
));
}
else
{
if
(
!
is_tiled
)
TIFFGetField
(
tif
,
TIFFTAG_ROWSPERSTRIP
,
&
tile_height0
);
// optional
CV_TIFF_CHECK_CALL_DEBUG
(
TIFFGetField
(
tif
,
TIFFTAG_ROWSPERSTRIP
,
&
tile_height0
));
}
if
(
tile_width0
<=
0
)
{
if
(
tile_width0
==
0
)
tile_width0
=
m_width
;
if
(
tile_height0
<
=
0
||
(
!
is_tiled
&&
tile_height0
==
std
::
numeric_limits
<
uint32
>::
max
())
)
if
(
tile_height0
=
=
0
||
(
!
is_tiled
&&
tile_height0
==
std
::
numeric_limits
<
uint32
>::
max
())
)
tile_height0
=
m_height
;
if
(
dst_bpp
==
8
)
{
if
(
dst_bpp
==
8
)
{
// we will use TIFFReadRGBA* functions, so allocate temporary buffer for 32bit RGBA
bpp
=
8
;
ncn
=
4
;
}
const
size_t
buffer_size
=
(
bpp
/
bitsPerByte
)
*
ncn
*
tile_height0
*
tile_width0
;
AutoBuffer
<
uchar
>
_buffer
(
buffer_size
);
else
if
(
dst_bpp
==
32
||
dst_bpp
==
64
)
{
CV_Assert
(
ncn
==
img
.
channels
());
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_SAMPLEFORMAT
,
SAMPLEFORMAT_IEEEFP
));
}
const
size_t
buffer_size
=
(
bpp
/
bitsPerByte
)
*
ncn
*
tile_height0
*
tile_width0
;
AutoBuffer
<
uchar
>
_buffer
(
buffer_size
);
uchar
*
buffer
=
_buffer
.
data
();
ushort
*
buffer16
=
(
ushort
*
)
buffer
;
float
*
buffer32
=
(
float
*
)
buffer
;
double
*
buffer64
=
(
double
*
)
buffer
;
int
tileidx
=
0
;
for
(
y
=
0
;
y
<
m_height
;
y
+=
tile_height0
)
for
(
int
y
=
0
;
y
<
m_height
;
y
+=
(
int
)
tile_height0
)
{
int
tile_height
=
tile_height0
;
if
(
y
+
tile_height
>
m_height
)
tile_height
=
m_height
-
y
;
int
tile_height
=
std
::
min
((
int
)
tile_height0
,
m_height
-
y
);
uchar
*
data
=
img
.
ptr
(
vert_flip
?
m_height
-
y
-
tile_height
:
y
)
;
const
int
img_y
=
vert_flip
?
m_height
-
y
-
tile_height
:
y
;
for
(
x
=
0
;
x
<
m_width
;
x
+=
tile_width0
,
tileidx
++
)
for
(
int
x
=
0
;
x
<
m_width
;
x
+=
(
int
)
tile_width0
,
tileidx
++
)
{
int
tile_width
=
tile_width0
,
ok
;
int
tile_width
=
std
::
min
((
int
)
tile_width0
,
m_width
-
x
)
;
if
(
x
+
tile_width
>
m_width
)
tile_width
=
m_width
-
x
;
switch
(
dst_bpp
)
switch
(
dst_bpp
)
{
case
8
:
{
uchar
*
bstart
=
buffer
;
if
(
!
is_tiled
)
ok
=
TIFFReadRGBAStrip
(
tif
,
y
,
(
uint32
*
)
buffer
);
else
uchar
*
bstart
=
buffer
;
if
(
!
is_tiled
)
{
ok
=
TIFFReadRGBATile
(
tif
,
x
,
y
,
(
uint32
*
)
buffer
);
//Tiles fill the buffer from the bottom up
bstart
+=
(
tile_height0
-
tile_height
)
*
tile_width0
*
4
;
CV_TIFF_CHECK_CALL
(
TIFFReadRGBAStrip
(
tif
,
y
,
(
uint32
*
)
buffer
));
}
if
(
!
ok
)
else
{
close
();
return
false
;
CV_TIFF_CHECK_CALL
(
TIFFReadRGBATile
(
tif
,
x
,
y
,
(
uint32
*
)
buffer
));
// Tiles fill the buffer from the bottom up
bstart
+=
(
tile_height0
-
tile_height
)
*
tile_width0
*
4
;
}
for
(
i
=
0
;
i
<
tile_height
;
i
++
)
if
(
color
)
for
(
int
i
=
0
;
i
<
tile_height
;
i
++
)
{
if
(
color
)
{
if
(
wanted_channels
==
4
)
{
icvCvt_BGRA2RGBA_8u_C4R
(
bstart
+
i
*
tile_width0
*
4
,
0
,
data
+
x
*
4
+
img
.
step
*
(
tile_height
-
i
-
1
),
0
,
cvSize
(
tile_width
,
1
)
);
icvCvt_BGRA2RGBA_8u_C4R
(
bstart
+
i
*
tile_width0
*
4
,
0
,
img
.
ptr
(
img_y
+
tile_height
-
i
-
1
,
x
),
0
,
Size
(
tile_width
,
1
)
);
}
else
{
icvCvt_BGRA2BGR_8u_C4C3R
(
bstart
+
i
*
tile_width0
*
4
,
0
,
data
+
x
*
3
+
img
.
step
*
(
tile_height
-
i
-
1
),
0
,
cvSize
(
tile_width
,
1
),
2
);
icvCvt_BGRA2BGR_8u_C4C3R
(
bstart
+
i
*
tile_width0
*
4
,
0
,
img
.
ptr
(
img_y
+
tile_height
-
i
-
1
,
x
),
0
,
Size
(
tile_width
,
1
),
2
);
}
}
else
{
icvCvt_BGRA2Gray_8u_C4C1R
(
bstart
+
i
*
tile_width0
*
4
,
0
,
data
+
x
+
img
.
step
*
(
tile_height
-
i
-
1
),
0
,
cvSize
(
tile_width
,
1
),
2
);
img
.
ptr
(
img_y
+
tile_height
-
i
-
1
,
x
),
0
,
Size
(
tile_width
,
1
),
2
);
}
}
break
;
}
case
16
:
{
if
(
!
is_tiled
)
ok
=
(
int
)
TIFFReadEncodedStrip
(
tif
,
tileidx
,
(
uint32
*
)
buffer
,
buffer_size
)
>=
0
;
if
(
!
is_tiled
)
{
CV_TIFF_CHECK_CALL
((
int
)
TIFFReadEncodedStrip
(
tif
,
tileidx
,
(
uint32
*
)
buffer
,
buffer_size
)
>=
0
);
}
else
ok
=
(
int
)
TIFFReadEncodedTile
(
tif
,
tileidx
,
(
uint32
*
)
buffer
,
buffer_size
)
>=
0
;
if
(
!
ok
)
{
close
();
return
false
;
CV_TIFF_CHECK_CALL
((
int
)
TIFFReadEncodedTile
(
tif
,
tileidx
,
(
uint32
*
)
buffer
,
buffer_size
)
>=
0
);
}
for
(
i
=
0
;
i
<
tile_height
;
i
++
)
for
(
int
i
=
0
;
i
<
tile_height
;
i
++
)
{
if
(
color
)
if
(
color
)
{
if
(
ncn
==
1
)
if
(
ncn
==
1
)
{
icvCvt_Gray2BGR_16u_C1C3R
(
buffer16
+
i
*
tile_width0
*
ncn
,
0
,
(
ushort
*
)(
data
+
img
.
step
*
i
)
+
x
*
3
,
0
,
cvSize
(
tile_width
,
1
)
);
img
.
ptr
<
ushort
>
(
img_y
+
i
,
x
)
,
0
,
Size
(
tile_width
,
1
)
);
}
else
if
(
ncn
==
3
)
else
if
(
ncn
==
3
)
{
icvCvt_RGB2BGR_16u_C3R
(
buffer16
+
i
*
tile_width0
*
ncn
,
0
,
(
ushort
*
)(
data
+
img
.
step
*
i
)
+
x
*
3
,
0
,
cvSize
(
tile_width
,
1
)
);
img
.
ptr
<
ushort
>
(
img_y
+
i
,
x
)
,
0
,
Size
(
tile_width
,
1
)
);
}
else
if
(
ncn
==
4
)
{
if
(
wanted_channels
==
4
)
{
icvCvt_BGRA2RGBA_16u_C4R
(
buffer16
+
i
*
tile_width0
*
ncn
,
0
,
(
ushort
*
)(
data
+
img
.
step
*
i
)
+
x
*
4
,
0
,
cv
Size
(
tile_width
,
1
));
img
.
ptr
<
ushort
>
(
img_y
+
i
,
x
)
,
0
,
Size
(
tile_width
,
1
));
}
else
{
icvCvt_BGRA2BGR_16u_C4C3R
(
buffer16
+
i
*
tile_width0
*
ncn
,
0
,
(
ushort
*
)(
data
+
img
.
step
*
i
)
+
x
*
3
,
0
,
cv
Size
(
tile_width
,
1
),
2
);
img
.
ptr
<
ushort
>
(
img_y
+
i
,
x
)
,
0
,
Size
(
tile_width
,
1
),
2
);
}
}
else
{
icvCvt_BGRA2BGR_16u_C4C3R
(
buffer16
+
i
*
tile_width0
*
ncn
,
0
,
(
ushort
*
)(
data
+
img
.
step
*
i
)
+
x
*
3
,
0
,
cvSize
(
tile_width
,
1
),
2
);
img
.
ptr
<
ushort
>
(
img_y
+
i
,
x
)
,
0
,
Size
(
tile_width
,
1
),
2
);
}
}
else
{
if
(
ncn
==
1
)
{
memcpy
(
(
ushort
*
)(
data
+
img
.
step
*
i
)
+
x
,
memcpy
(
img
.
ptr
<
ushort
>
(
img_y
+
i
,
x
)
,
buffer16
+
i
*
tile_width0
*
ncn
,
tile_width
*
sizeof
(
buffer16
[
0
]
));
tile_width
*
sizeof
(
ushort
));
}
else
{
icvCvt_BGRA2Gray_16u_CnC1R
(
buffer16
+
i
*
tile_width0
*
ncn
,
0
,
(
ushort
*
)(
data
+
img
.
step
*
i
)
+
x
,
0
,
cvSize
(
tile_width
,
1
),
ncn
,
2
);
img
.
ptr
<
ushort
>
(
img_y
+
i
,
x
)
,
0
,
Size
(
tile_width
,
1
),
ncn
,
2
);
}
}
}
...
...
@@ -500,120 +543,43 @@ bool TiffDecoder::readData( Mat& img )
case
64
:
{
if
(
!
is_tiled
)
ok
=
(
int
)
TIFFReadEncodedStrip
(
tif
,
tileidx
,
buffer
,
buffer_size
)
>=
0
;
else
ok
=
(
int
)
TIFFReadEncodedTile
(
tif
,
tileidx
,
buffer
,
buffer_size
)
>=
0
;
if
(
!
ok
||
ncn
!=
1
)
{
close
();
return
false
;
CV_TIFF_CHECK_CALL
((
int
)
TIFFReadEncodedStrip
(
tif
,
tileidx
,
buffer
,
buffer_size
)
>=
0
);
}
for
(
i
=
0
;
i
<
tile_height
;
i
++
)
else
{
if
(
dst_bpp
==
32
)
{
memcpy
((
float
*
)(
data
+
img
.
step
*
i
)
+
x
,
buffer32
+
i
*
tile_width0
*
ncn
,
tile_width
*
sizeof
(
buffer32
[
0
]));
}
else
{
memcpy
((
double
*
)(
data
+
img
.
step
*
i
)
+
x
,
buffer64
+
i
*
tile_width0
*
ncn
,
tile_width
*
sizeof
(
buffer64
[
0
]));
}
CV_TIFF_CHECK_CALL
((
int
)
TIFFReadEncodedTile
(
tif
,
tileidx
,
buffer
,
buffer_size
)
>=
0
);
}
Mat
m_tile
(
Size
(
tile_width0
,
tile_height0
),
CV_MAKETYPE
((
dst_bpp
==
32
)
?
CV_32F
:
CV_64F
,
ncn
),
buffer
);
Rect
roi_tile
(
0
,
0
,
tile_width
,
tile_height
);
Rect
roi_img
(
x
,
img_y
,
tile_width
,
tile_height
);
if
(
!
m_hdr
&&
ncn
==
3
)
cvtColor
(
m_tile
(
roi_tile
),
img
(
roi_img
),
COLOR_RGB2BGR
);
else
if
(
!
m_hdr
&&
ncn
==
4
)
cvtColor
(
m_tile
(
roi_tile
),
img
(
roi_img
),
COLOR_RGBA2BGRA
);
else
m_tile
(
roi_tile
).
copyTo
(
img
(
roi_img
));
break
;
}
default
:
{
close
();
return
false
;
CV_Assert
(
0
&&
"OpenCV TIFF: unsupported depth"
);
}
}
}
}
result
=
true
;
}
// switch (dst_bpp)
}
// for x
}
// for y
}
}
return
result
;
}
bool
TiffDecoder
::
readData_32FC3
(
Mat
&
img
)
{
int
rows_per_strip
=
0
,
photometric
=
0
;
if
(
!
m_tif
)
{
return
false
;
}
TIFF
*
tif
=
static_cast
<
TIFF
*>
(
m_tif
);
TIFFGetField
(
tif
,
TIFFTAG_ROWSPERSTRIP
,
&
rows_per_strip
);
TIFFGetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
&
photometric
);
TIFFSetField
(
tif
,
TIFFTAG_SGILOGDATAFMT
,
SGILOGDATAFMT_FLOAT
);
int
size
=
3
*
m_width
*
m_height
*
sizeof
(
float
);
tstrip_t
strip_size
=
3
*
m_width
*
rows_per_strip
;
float
*
ptr
=
img
.
ptr
<
float
>
();
for
(
tstrip_t
i
=
0
;
i
<
TIFFNumberOfStrips
(
tif
);
i
++
,
ptr
+=
strip_size
)
{
TIFFReadEncodedStrip
(
tif
,
i
,
ptr
,
size
);
size
-=
strip_size
*
sizeof
(
float
);
}
close
();
if
(
photometric
==
PHOTOMETRIC_LOGLUV
)
if
(
m_hdr
&&
depth
>=
CV_32F
)
{
CV_Assert
(
photometric
==
PHOTOMETRIC_LOGLUV
);
cvtColor
(
img
,
img
,
COLOR_XYZ2BGR
);
}
else
{
cvtColor
(
img
,
img
,
COLOR_RGB2BGR
);
}
return
true
;
}
bool
TiffDecoder
::
readData_32FC1
(
Mat
&
img
)
{
if
(
!
m_tif
)
{
return
false
;
}
TIFF
*
tif
=
static_cast
<
TIFF
*>
(
m_tif
);
uint32
img_width
,
img_height
;
TIFFGetField
(
tif
,
TIFFTAG_IMAGEWIDTH
,
&
img_width
);
TIFFGetField
(
tif
,
TIFFTAG_IMAGELENGTH
,
&
img_height
);
if
(
img
.
size
()
!=
Size
(
img_width
,
img_height
))
{
close
();
return
false
;
}
tsize_t
scanlength
=
TIFFScanlineSize
(
tif
);
tdata_t
buf
=
_TIFFmalloc
(
scanlength
);
float
*
data
;
bool
result
=
true
;
for
(
uint32
row
=
0
;
row
<
img_height
;
row
++
)
{
if
(
TIFFReadScanline
(
tif
,
buf
,
row
)
!=
1
)
{
result
=
false
;
break
;
}
data
=
(
float
*
)
buf
;
for
(
uint32
i
=
0
;
i
<
img_width
;
i
++
)
{
img
.
at
<
float
>
(
row
,
i
)
=
data
[
i
];
}
}
_TIFFfree
(
buf
);
close
();
return
result
;
}
//////////////////////////////////////////////////////////////////////////////////////////
TiffEncoder
::
TiffEncoder
()
...
...
@@ -633,7 +599,7 @@ ImageEncoder TiffEncoder::newEncoder() const
bool
TiffEncoder
::
isFormatSupported
(
int
depth
)
const
{
return
depth
==
CV_8U
||
depth
==
CV_16U
||
depth
==
CV_32F
;
return
depth
==
CV_8U
||
depth
==
CV_16U
||
depth
==
CV_32F
||
depth
==
CV_64F
;
}
void
TiffEncoder
::
writeTag
(
WLByteStream
&
strm
,
TiffTag
tag
,
...
...
@@ -656,6 +622,8 @@ public:
TIFF
*
open
()
{
// do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
return
TIFFClientOpen
(
""
,
"w"
,
reinterpret_cast
<
thandle_t
>
(
this
),
&
TiffEncoderBufHelper
::
read
,
&
TiffEncoderBufHelper
::
write
,
&
TiffEncoderBufHelper
::
seek
,
&
TiffEncoderBufHelper
::
close
,
&
TiffEncoderBufHelper
::
size
,
...
...
@@ -721,35 +689,39 @@ private:
toff_t
m_buf_pos
;
};
static
void
readParam
(
const
std
::
vector
<
int
>&
params
,
int
key
,
int
&
value
)
static
bool
readParam
(
const
std
::
vector
<
int
>&
params
,
int
key
,
int
&
value
)
{
for
(
size_t
i
=
0
;
i
+
1
<
params
.
size
();
i
+=
2
)
if
(
params
[
i
]
==
key
)
for
(
size_t
i
=
0
;
i
+
1
<
params
.
size
();
i
+=
2
)
{
if
(
params
[
i
]
==
key
)
{
value
=
params
[
i
+
1
];
break
;
value
=
params
[
i
+
1
];
return
true
;
}
}
return
false
;
}
bool
TiffEncoder
::
writeLibTiff
(
const
std
::
vector
<
Mat
>&
img_vec
,
const
std
::
vector
<
int
>&
params
)
{
// do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
TIFF
*
pTiffHandle
;
TIFF
*
tif
=
NULL
;
TiffEncoderBufHelper
buf_helper
(
m_buf
);
if
(
m_buf
)
{
pTiffHandle
=
buf_helper
.
open
();
tif
=
buf_helper
.
open
();
}
else
{
pTiffHandle
=
TIFFOpen
(
m_filename
.
c_str
(),
"w"
);
tif
=
TIFFOpen
(
m_filename
.
c_str
(),
"w"
);
}
if
(
!
pTiffHandle
)
if
(
!
tif
)
{
return
false
;
}
cv
::
Ptr
<
void
>
tif_cleanup
(
tif
,
cv_tiffCloseHandle
);
//Settings that matter to all images
int
compression
=
COMPRESSION_LZW
;
...
...
@@ -768,7 +740,29 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
const
Mat
&
img
=
img_vec
[
page
];
int
channels
=
img
.
channels
();
int
width
=
img
.
cols
,
height
=
img
.
rows
;
int
depth
=
img
.
depth
();
int
type
=
img
.
type
();
int
depth
=
CV_MAT_DEPTH
(
type
);
CV_CheckType
(
type
,
depth
==
CV_8U
||
depth
==
CV_16U
||
depth
==
CV_32F
||
depth
==
CV_64F
,
""
);
CV_CheckType
(
type
,
channels
>=
1
&&
channels
<=
4
,
""
);
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_IMAGEWIDTH
,
width
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_IMAGELENGTH
,
height
));
if
(
img_vec
.
size
()
>
1
)
{
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_SUBFILETYPE
,
FILETYPE_PAGE
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_PAGENUMBER
,
page
,
img_vec
.
size
()));
}
int
compression_param
=
-
1
;
// OPENCV_FUTURE
if
(
type
==
CV_32FC3
&&
(
!
readParam
(
params
,
IMWRITE_TIFF_COMPRESSION
,
compression_param
)
||
compression_param
==
COMPRESSION_SGILOG
))
{
if
(
!
write_32FC3_SGILOG
(
img
,
tif
))
return
false
;
continue
;
}
int
page_compression
=
compression
;
int
bitsPerChannel
=
-
1
;
switch
(
depth
)
...
...
@@ -783,9 +777,20 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
bitsPerChannel
=
16
;
break
;
}
case
CV_32F
:
{
bitsPerChannel
=
32
;
page_compression
=
COMPRESSION_NONE
;
break
;
}
case
CV_64F
:
{
bitsPerChannel
=
64
;
page_compression
=
COMPRESSION_NONE
;
break
;
}
default
:
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
}
...
...
@@ -795,57 +800,42 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
int
rowsPerStrip
=
(
int
)((
1
<<
13
)
/
fileStep
);
readParam
(
params
,
TIFFTAG_ROWSPERSTRIP
,
rowsPerStrip
);
rowsPerStrip
=
std
::
max
(
1
,
std
::
min
(
height
,
rowsPerStrip
));
int
colorspace
=
channels
>
1
?
PHOTOMETRIC_RGB
:
PHOTOMETRIC_MINISBLACK
;
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_BITSPERSAMPLE
,
bitsPerChannel
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_COMPRESSION
,
page_compression
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
colorspace
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
channels
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_PLANARCONFIG
,
PLANARCONFIG_CONTIG
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_ROWSPERSTRIP
,
rowsPerStrip
));
if
(
rowsPerStrip
<
1
)
rowsPerStrip
=
1
;
if
(
rowsPerStrip
>
height
)
rowsPerStrip
=
height
;
int
colorspace
=
channels
>
1
?
PHOTOMETRIC_RGB
:
PHOTOMETRIC_MINISBLACK
;
if
(
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_IMAGEWIDTH
,
width
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_IMAGELENGTH
,
height
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_BITSPERSAMPLE
,
bitsPerChannel
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_COMPRESSION
,
compression
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_PHOTOMETRIC
,
colorspace
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_SAMPLESPERPIXEL
,
channels
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_PLANARCONFIG
,
PLANARCONFIG_CONTIG
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_ROWSPERSTRIP
,
rowsPerStrip
)
||
(
img_vec
.
size
()
>
1
&&
(
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_SUBFILETYPE
,
FILETYPE_PAGE
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_PAGENUMBER
,
page
,
img_vec
.
size
()
)))
)
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_SAMPLEFORMAT
,
depth
>=
CV_32F
?
SAMPLEFORMAT_IEEEFP
:
SAMPLEFORMAT_UINT
));
if
(
page_compression
!=
COMPRESSION_NONE
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_PREDICTOR
,
predictor
));
}
if
(
compression
!=
COMPRESSION_NONE
&&
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_PREDICTOR
,
predictor
)
)
if
(
resUnit
>=
RESUNIT_NONE
&&
resUnit
<=
RESUNIT_CENTIMETER
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_RESOLUTIONUNIT
,
resUnit
));
}
if
(((
resUnit
>=
RESUNIT_NONE
&&
resUnit
<=
RESUNIT_CENTIMETER
)
&&
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_RESOLUTIONUNIT
,
resUnit
))
||
(
dpiX
>=
0
&&
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_XRESOLUTION
,
(
float
)
dpiX
))
||
(
dpiY
>=
0
&&
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_YRESOLUTION
,
(
float
)
dpiY
))
)
if
(
dpiX
>=
0
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_XRESOLUTION
,
(
float
)
dpiX
));
}
if
(
dpiY
>=
0
)
{
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_YRESOLUTION
,
(
float
)
dpiY
));
}
// row buffer, because TIFFWriteScanline modifies the original data!
size_t
scanlineSize
=
TIFFScanlineSize
(
pTiffHandle
);
size_t
scanlineSize
=
TIFFScanlineSize
(
tif
);
AutoBuffer
<
uchar
>
_buffer
(
scanlineSize
+
32
);
uchar
*
buffer
=
_buffer
.
data
();
if
(
!
buffer
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
uchar
*
buffer
=
_buffer
.
data
();
CV_DbgAssert
(
buffer
);
Mat
m_buffer
(
Size
(
width
,
1
),
CV_MAKETYPE
(
depth
,
channels
),
buffer
,
(
size_t
)
scanlineSize
);
for
(
int
y
=
0
;
y
<
height
;
++
y
)
{
...
...
@@ -859,122 +849,54 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
case
3
:
{
if
(
depth
==
CV_8U
)
icvCvt_BGR2RGB_8u_C3R
(
img
.
ptr
(
y
),
0
,
buffer
,
0
,
cvSize
(
width
,
1
));
else
icvCvt_BGR2RGB_16u_C3R
(
img
.
ptr
<
ushort
>
(
y
),
0
,
(
ushort
*
)
buffer
,
0
,
cvSize
(
width
,
1
));
cvtColor
(
img
(
Rect
(
0
,
y
,
width
,
1
)),
(
const
Mat
&
)
m_buffer
,
COLOR_BGR2RGB
);
break
;
}
case
4
:
{
if
(
depth
==
CV_8U
)
icvCvt_BGRA2RGBA_8u_C4R
(
img
.
ptr
(
y
),
0
,
buffer
,
0
,
cvSize
(
width
,
1
));
else
icvCvt_BGRA2RGBA_16u_C4R
(
img
.
ptr
<
ushort
>
(
y
),
0
,
(
ushort
*
)
buffer
,
0
,
cvSize
(
width
,
1
));
cvtColor
(
img
(
Rect
(
0
,
y
,
width
,
1
)),
(
const
Mat
&
)
m_buffer
,
COLOR_BGRA2RGBA
);
break
;
}
default
:
{
TIFFClose
(
pTiffHandle
);
return
false
;
CV_Assert
(
0
);
}
}
int
writeResult
=
TIFFWriteScanline
(
pTiffHandle
,
buffer
,
y
,
0
);
if
(
writeResult
!=
1
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
CV_TIFF_CHECK_CALL
(
TIFFWriteScanline
(
tif
,
buffer
,
y
,
0
)
==
1
);
}
TIFFWriteDirectory
(
pTiffHandle
);
CV_TIFF_CHECK_CALL
(
TIFFWriteDirectory
(
tif
));
}
TIFFClose
(
pTiffHandle
);
return
true
;
}
bool
TiffEncoder
::
write_32FC3
(
const
Mat
&
_img
)
bool
TiffEncoder
::
write_32FC3
_SGILOG
(
const
Mat
&
_img
,
void
*
tif_
)
{
TIFF
*
tif
=
(
TIFF
*
)
tif_
;
CV_Assert
(
tif
);
Mat
img
;
cvtColor
(
_img
,
img
,
COLOR_BGR2XYZ
);
TIFF
*
tif
;
TiffEncoderBufHelper
buf_helper
(
m_buf
);
if
(
m_buf
)
{
tif
=
buf_helper
.
open
();
}
else
{
tif
=
TIFFOpen
(
m_filename
.
c_str
(),
"w"
);
}
if
(
!
tif
)
{
return
false
;
}
TIFFSetField
(
tif
,
TIFFTAG_IMAGEWIDTH
,
img
.
cols
);
TIFFSetField
(
tif
,
TIFFTAG_IMAGELENGTH
,
img
.
rows
);
TIFFSetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
3
);
TIFFSetField
(
tif
,
TIFFTAG_COMPRESSION
,
COMPRESSION_SGILOG
);
TIFFSetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
PHOTOMETRIC_LOGLUV
);
TIFFSetField
(
tif
,
TIFFTAG_PLANARCONFIG
,
PLANARCONFIG_CONTIG
);
TIFFSetField
(
tif
,
TIFFTAG_SGILOGDATAFMT
,
SGILOGDATAFMT_FLOAT
);
TIFFSetField
(
tif
,
TIFFTAG_ROWSPERSTRIP
,
1
);
int
strip_size
=
3
*
img
.
cols
;
float
*
ptr
=
const_cast
<
float
*>
(
img
.
ptr
<
float
>
());
for
(
int
i
=
0
;
i
<
img
.
rows
;
i
++
,
ptr
+=
strip_size
)
{
TIFFWriteEncodedStrip
(
tif
,
i
,
ptr
,
strip_size
*
sizeof
(
float
));
}
TIFFClose
(
tif
);
return
true
;
}
bool
TiffEncoder
::
write_32FC1
(
const
Mat
&
_img
)
{
TIFF
*
tif
;
TiffEncoderBufHelper
buf_helper
(
m_buf
);
if
(
m_buf
)
{
tif
=
buf_helper
.
open
();
}
else
{
tif
=
TIFFOpen
(
m_filename
.
c_str
(),
"w"
);
}
if
(
!
tif
)
{
return
false
;
}
TIFFSetField
(
tif
,
TIFFTAG_IMAGEWIDTH
,
_img
.
cols
);
TIFFSetField
(
tif
,
TIFFTAG_IMAGELENGTH
,
_img
.
rows
);
TIFFSetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
1
);
TIFFSetField
(
tif
,
TIFFTAG_BITSPERSAMPLE
,
32
);
TIFFSetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
PHOTOMETRIC_MINISBLACK
);
TIFFSetField
(
tif
,
TIFFTAG_SAMPLEFORMAT
,
SAMPLEFORMAT_IEEEFP
);
TIFFSetField
(
tif
,
TIFFTAG_COMPRESSION
,
COMPRESSION_NONE
);
for
(
uint32
row
=
0
;
row
<
(
uint32
)
_img
.
rows
;
row
++
)
{
if
(
TIFFWriteScanline
(
tif
,
(
tdata_t
)
_img
.
ptr
<
float
>
(
row
),
row
,
1
)
!=
1
)
{
TIFFClose
(
tif
);
return
false
;
}
}
TIFFWriteDirectory
(
tif
);
TIFFClose
(
tif
);
//done by caller: CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols));
//done by caller: CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_SAMPLESPERPIXEL
,
3
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_BITSPERSAMPLE
,
32
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_COMPRESSION
,
COMPRESSION_SGILOG
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_PHOTOMETRIC
,
PHOTOMETRIC_LOGLUV
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_PLANARCONFIG
,
PLANARCONFIG_CONTIG
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_SGILOGDATAFMT
,
SGILOGDATAFMT_FLOAT
));
CV_TIFF_CHECK_CALL
(
TIFFSetField
(
tif
,
TIFFTAG_ROWSPERSTRIP
,
1
));
const
int
strip_size
=
3
*
img
.
cols
;
for
(
int
i
=
0
;
i
<
img
.
rows
;
i
++
)
{
CV_TIFF_CHECK_CALL
(
TIFFWriteEncodedStrip
(
tif
,
i
,
(
tdata_t
)
img
.
ptr
<
float
>
(
i
),
strip_size
*
sizeof
(
float
))
!=
(
tsize_t
)
-
1
);
}
CV_TIFF_CHECK_CALL
(
TIFFWriteDirectory
(
tif
));
return
true
;
}
...
...
@@ -985,18 +907,10 @@ bool TiffEncoder::writemulti(const std::vector<Mat>& img_vec, const std::vector<
bool
TiffEncoder
::
write
(
const
Mat
&
img
,
const
std
::
vector
<
int
>&
params
)
{
int
depth
=
img
.
depth
();
if
(
img
.
type
()
==
CV_32FC3
)
{
return
write_32FC3
(
img
);
}
if
(
img
.
type
()
==
CV_32FC1
)
{
return
write_32FC1
(
img
);
}
int
type
=
img
.
type
();
int
depth
=
CV_MAT_DEPTH
(
type
);
CV_
Assert
(
depth
==
CV_8U
||
depth
==
CV_16U
);
CV_
CheckType
(
type
,
depth
==
CV_8U
||
depth
==
CV_16U
||
depth
==
CV_32F
||
depth
==
CV_64F
,
""
);
std
::
vector
<
Mat
>
img_vec
;
img_vec
.
push_back
(
img
);
...
...
modules/imgcodecs/src/grfmt_tiff.hpp
View file @
1fb93b62
...
...
@@ -106,10 +106,8 @@ public:
ImageDecoder
newDecoder
()
const
CV_OVERRIDE
;
protected
:
void
*
m_tif
;
cv
::
Ptr
<
void
>
m_tif
;
int
normalizeChannelsNumber
(
int
channels
)
const
;
bool
readData_32FC3
(
Mat
&
img
);
bool
readData_32FC1
(
Mat
&
img
);
bool
m_hdr
;
size_t
m_buf_pos
;
...
...
@@ -139,8 +137,7 @@ protected:
int
count
,
int
value
);
bool
writeLibTiff
(
const
std
::
vector
<
Mat
>&
img_vec
,
const
std
::
vector
<
int
>&
params
);
bool
write_32FC3
(
const
Mat
&
img
);
bool
write_32FC1
(
const
Mat
&
img
);
bool
write_32FC3_SGILOG
(
const
Mat
&
img
,
void
*
tif
);
private
:
TiffEncoder
(
const
TiffEncoder
&
);
// copy disabled
...
...
modules/imgcodecs/src/utils.cpp
View file @
1fb93b62
...
...
@@ -42,6 +42,8 @@
#include "precomp.hpp"
#include "utils.hpp"
namespace
cv
{
int
validateToInt
(
size_t
sz
)
{
int
valueInt
=
(
int
)
sz
;
...
...
@@ -56,7 +58,7 @@ int validateToInt(size_t sz)
void
icvCvt_BGR2Gray_8u_C3C1R
(
const
uchar
*
rgb
,
int
rgb_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
,
int
_swap_rb
)
Size
size
,
int
_swap_rb
)
{
int
i
;
int
swap_rb
=
_swap_rb
?
2
:
0
;
...
...
@@ -75,7 +77,7 @@ void icvCvt_BGR2Gray_8u_C3C1R( const uchar* rgb, int rgb_step,
void
icvCvt_BGRA2Gray_16u_CnC1R
(
const
ushort
*
rgb
,
int
rgb_step
,
ushort
*
gray
,
int
gray_step
,
Cv
Size
size
,
int
ncn
,
int
_swap_rb
)
Size
size
,
int
ncn
,
int
_swap_rb
)
{
int
i
;
int
swap_rb
=
_swap_rb
?
2
:
0
;
...
...
@@ -94,7 +96,7 @@ void icvCvt_BGRA2Gray_16u_CnC1R( const ushort* rgb, int rgb_step,
void
icvCvt_BGRA2Gray_8u_C4C1R
(
const
uchar
*
rgba
,
int
rgba_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
,
int
_swap_rb
)
Size
size
,
int
_swap_rb
)
{
int
i
;
int
swap_rb
=
_swap_rb
?
2
:
0
;
...
...
@@ -112,7 +114,7 @@ void icvCvt_BGRA2Gray_8u_C4C1R( const uchar* rgba, int rgba_step,
void
icvCvt_Gray2BGR_8u_C1C3R
(
const
uchar
*
gray
,
int
gray_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
)
uchar
*
bgr
,
int
bgr_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
gray
+=
gray_step
)
...
...
@@ -127,7 +129,7 @@ void icvCvt_Gray2BGR_8u_C1C3R( const uchar* gray, int gray_step,
void
icvCvt_Gray2BGR_16u_C1C3R
(
const
ushort
*
gray
,
int
gray_step
,
ushort
*
bgr
,
int
bgr_step
,
Cv
Size
size
)
ushort
*
bgr
,
int
bgr_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
gray
+=
gray_step
/
sizeof
(
gray
[
0
])
)
...
...
@@ -143,7 +145,7 @@ void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
void
icvCvt_BGRA2BGR_8u_C4C3R
(
const
uchar
*
bgra
,
int
bgra_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
,
int
_swap_rb
)
Size
size
,
int
_swap_rb
)
{
int
i
;
int
swap_rb
=
_swap_rb
?
2
:
0
;
...
...
@@ -163,7 +165,7 @@ void icvCvt_BGRA2BGR_8u_C4C3R( const uchar* bgra, int bgra_step,
void
icvCvt_BGRA2BGR_16u_C4C3R
(
const
ushort
*
bgra
,
int
bgra_step
,
ushort
*
bgr
,
int
bgr_step
,
Cv
Size
size
,
int
_swap_rb
)
Size
size
,
int
_swap_rb
)
{
int
i
;
int
swap_rb
=
_swap_rb
?
2
:
0
;
...
...
@@ -182,7 +184,7 @@ void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
void
icvCvt_BGRA2RGBA_8u_C4R
(
const
uchar
*
bgra
,
int
bgra_step
,
uchar
*
rgba
,
int
rgba_step
,
Cv
Size
size
)
uchar
*
rgba
,
int
rgba_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
)
...
...
@@ -200,7 +202,7 @@ void icvCvt_BGRA2RGBA_8u_C4R( const uchar* bgra, int bgra_step,
}
void
icvCvt_BGRA2RGBA_16u_C4R
(
const
ushort
*
bgra
,
int
bgra_step
,
ushort
*
rgba
,
int
rgba_step
,
Cv
Size
size
)
ushort
*
rgba
,
int
rgba_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
)
...
...
@@ -220,7 +222,7 @@ void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
void
icvCvt_BGR2RGB_8u_C3R
(
const
uchar
*
bgr
,
int
bgr_step
,
uchar
*
rgb
,
int
rgb_step
,
Cv
Size
size
)
uchar
*
rgb
,
int
rgb_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
)
...
...
@@ -237,7 +239,7 @@ void icvCvt_BGR2RGB_8u_C3R( const uchar* bgr, int bgr_step,
void
icvCvt_BGR2RGB_16u_C3R
(
const
ushort
*
bgr
,
int
bgr_step
,
ushort
*
rgb
,
int
rgb_step
,
Cv
Size
size
)
ushort
*
rgb
,
int
rgb_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
)
...
...
@@ -256,7 +258,7 @@ void icvCvt_BGR2RGB_16u_C3R( const ushort* bgr, int bgr_step,
typedef
unsigned
short
ushort
;
void
icvCvt_BGR5552Gray_8u_C2C1R
(
const
uchar
*
bgr555
,
int
bgr555_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
)
uchar
*
gray
,
int
gray_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
gray
+=
gray_step
,
bgr555
+=
bgr555_step
)
...
...
@@ -273,7 +275,7 @@ void icvCvt_BGR5552Gray_8u_C2C1R( const uchar* bgr555, int bgr555_step,
void
icvCvt_BGR5652Gray_8u_C2C1R
(
const
uchar
*
bgr565
,
int
bgr565_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
)
uchar
*
gray
,
int
gray_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
gray
+=
gray_step
,
bgr565
+=
bgr565_step
)
...
...
@@ -290,7 +292,7 @@ void icvCvt_BGR5652Gray_8u_C2C1R( const uchar* bgr565, int bgr565_step,
void
icvCvt_BGR5552BGR_8u_C2C3R
(
const
uchar
*
bgr555
,
int
bgr555_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
)
uchar
*
bgr
,
int
bgr_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
bgr555
+=
bgr555_step
)
...
...
@@ -308,7 +310,7 @@ void icvCvt_BGR5552BGR_8u_C2C3R( const uchar* bgr555, int bgr555_step,
void
icvCvt_BGR5652BGR_8u_C2C3R
(
const
uchar
*
bgr565
,
int
bgr565_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
)
uchar
*
bgr
,
int
bgr_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
bgr565
+=
bgr565_step
)
...
...
@@ -326,7 +328,7 @@ void icvCvt_BGR5652BGR_8u_C2C3R( const uchar* bgr565, int bgr565_step,
void
icvCvt_CMYK2BGR_8u_C4C3R
(
const
uchar
*
cmyk
,
int
cmyk_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
)
uchar
*
bgr
,
int
bgr_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
)
...
...
@@ -346,7 +348,7 @@ void icvCvt_CMYK2BGR_8u_C4C3R( const uchar* cmyk, int cmyk_step,
void
icvCvt_CMYK2Gray_8u_C4C1R
(
const
uchar
*
cmyk
,
int
cmyk_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
)
uchar
*
gray
,
int
gray_step
,
Size
size
)
{
int
i
;
for
(
;
size
.
height
--
;
)
...
...
@@ -371,7 +373,7 @@ void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entr
int
i
;
for
(
i
=
0
;
i
<
entries
;
i
++
)
{
icvCvt_BGR2Gray_8u_C3C1R
(
(
uchar
*
)(
palette
+
i
),
0
,
grayPalette
+
i
,
0
,
cv
Size
(
1
,
1
)
);
icvCvt_BGR2Gray_8u_C3C1R
(
(
uchar
*
)(
palette
+
i
),
0
,
grayPalette
+
i
,
0
,
Size
(
1
,
1
)
);
}
}
...
...
@@ -598,6 +600,9 @@ uchar* FillGrayRow1( uchar* data, uchar* indices, int len, uchar* palette )
return
data
;
}
}
// namespace
using
namespace
cv
;
CV_IMPL
void
cvConvertImage
(
const
CvArr
*
srcarr
,
CvArr
*
dstarr
,
int
flags
)
...
...
@@ -652,7 +657,7 @@ cvConvertImage( const CvArr* srcarr, CvArr* dstarr, int flags )
uchar
*
s
=
src
->
data
.
ptr
,
*
d
=
dst
->
data
.
ptr
;
int
s_step
=
src
->
step
,
d_step
=
dst
->
step
;
int
code
=
src_cn
*
10
+
dst_cn
;
CvSize
size
=
{
src
->
cols
,
src
->
rows
}
;
Size
size
(
src
->
cols
,
src
->
rows
)
;
if
(
CV_IS_MAT_CONT
(
src
->
type
&
dst
->
type
)
)
{
...
...
modules/imgcodecs/src/utils.hpp
View file @
1fb93b62
...
...
@@ -42,6 +42,8 @@
#ifndef _UTILS_H_
#define _UTILS_H_
namespace
cv
{
int
validateToInt
(
size_t
step
);
template
<
typename
_Tp
>
static
inline
...
...
@@ -68,53 +70,53 @@ struct PaletteEntry
void
icvCvt_BGR2Gray_8u_C3C1R
(
const
uchar
*
bgr
,
int
bgr_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
,
int
swap_rb
=
0
);
Size
size
,
int
swap_rb
=
0
);
void
icvCvt_BGRA2Gray_8u_C4C1R
(
const
uchar
*
bgra
,
int
bgra_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
,
int
swap_rb
=
0
);
Size
size
,
int
swap_rb
=
0
);
void
icvCvt_BGRA2Gray_16u_CnC1R
(
const
ushort
*
bgra
,
int
bgra_step
,
ushort
*
gray
,
int
gray_step
,
Cv
Size
size
,
int
ncn
,
int
swap_rb
=
0
);
Size
size
,
int
ncn
,
int
swap_rb
=
0
);
void
icvCvt_Gray2BGR_8u_C1C3R
(
const
uchar
*
gray
,
int
gray_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
);
uchar
*
bgr
,
int
bgr_step
,
Size
size
);
void
icvCvt_Gray2BGR_16u_C1C3R
(
const
ushort
*
gray
,
int
gray_step
,
ushort
*
bgr
,
int
bgr_step
,
Cv
Size
size
);
ushort
*
bgr
,
int
bgr_step
,
Size
size
);
void
icvCvt_BGRA2BGR_8u_C4C3R
(
const
uchar
*
bgra
,
int
bgra_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
,
int
swap_rb
=
0
);
Size
size
,
int
swap_rb
=
0
);
void
icvCvt_BGRA2BGR_16u_C4C3R
(
const
ushort
*
bgra
,
int
bgra_step
,
ushort
*
bgr
,
int
bgr_step
,
Cv
Size
size
,
int
_swap_rb
);
Size
size
,
int
_swap_rb
);
void
icvCvt_BGR2RGB_8u_C3R
(
const
uchar
*
bgr
,
int
bgr_step
,
uchar
*
rgb
,
int
rgb_step
,
Cv
Size
size
);
uchar
*
rgb
,
int
rgb_step
,
Size
size
);
#define icvCvt_RGB2BGR_8u_C3R icvCvt_BGR2RGB_8u_C3R
void
icvCvt_BGR2RGB_16u_C3R
(
const
ushort
*
bgr
,
int
bgr_step
,
ushort
*
rgb
,
int
rgb_step
,
Cv
Size
size
);
ushort
*
rgb
,
int
rgb_step
,
Size
size
);
#define icvCvt_RGB2BGR_16u_C3R icvCvt_BGR2RGB_16u_C3R
void
icvCvt_BGRA2RGBA_8u_C4R
(
const
uchar
*
bgra
,
int
bgra_step
,
uchar
*
rgba
,
int
rgba_step
,
Cv
Size
size
);
uchar
*
rgba
,
int
rgba_step
,
Size
size
);
#define icvCvt_RGBA2BGRA_8u_C4R icvCvt_BGRA2RGBA_8u_C4R
void
icvCvt_BGRA2RGBA_16u_C4R
(
const
ushort
*
bgra
,
int
bgra_step
,
ushort
*
rgba
,
int
rgba_step
,
Cv
Size
size
);
ushort
*
rgba
,
int
rgba_step
,
Size
size
);
#define icvCvt_RGBA2BGRA_16u_C4R icvCvt_BGRA2RGBA_16u_C4R
void
icvCvt_BGR5552Gray_8u_C2C1R
(
const
uchar
*
bgr555
,
int
bgr555_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
);
uchar
*
gray
,
int
gray_step
,
Size
size
);
void
icvCvt_BGR5652Gray_8u_C2C1R
(
const
uchar
*
bgr565
,
int
bgr565_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
);
uchar
*
gray
,
int
gray_step
,
Size
size
);
void
icvCvt_BGR5552BGR_8u_C2C3R
(
const
uchar
*
bgr555
,
int
bgr555_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
);
uchar
*
bgr
,
int
bgr_step
,
Size
size
);
void
icvCvt_BGR5652BGR_8u_C2C3R
(
const
uchar
*
bgr565
,
int
bgr565_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
);
uchar
*
bgr
,
int
bgr_step
,
Size
size
);
void
icvCvt_CMYK2BGR_8u_C4C3R
(
const
uchar
*
cmyk
,
int
cmyk_step
,
uchar
*
bgr
,
int
bgr_step
,
Cv
Size
size
);
uchar
*
bgr
,
int
bgr_step
,
Size
size
);
void
icvCvt_CMYK2Gray_8u_C4C1R
(
const
uchar
*
ycck
,
int
ycck_step
,
uchar
*
gray
,
int
gray_step
,
Cv
Size
size
);
uchar
*
gray
,
int
gray_step
,
Size
size
);
void
FillGrayPalette
(
PaletteEntry
*
palette
,
int
bpp
,
bool
negative
=
false
);
bool
IsColorPalette
(
PaletteEntry
*
palette
,
int
bpp
);
...
...
@@ -136,4 +138,6 @@ CV_INLINE bool isBigEndian( void )
return
(((
const
int
*
)
"
\0
\x1\x2\x3\x4\x5\x6\x7"
)[
0
]
&
255
)
!=
0
;
}
}
// namespace
#endif
/*_UTILS_H_*/
modules/imgcodecs/test/test_tiff.cpp
View file @
1fb93b62
...
...
@@ -158,12 +158,68 @@ TEST(Imgcodecs_Tiff, readWrite_32FC1)
ASSERT_TRUE
(
cv
::
imwrite
(
filenameOutput
,
img
));
const
Mat
img2
=
cv
::
imread
(
filenameOutput
,
IMREAD_UNCHANGED
);
ASSERT_EQ
(
img2
.
type
(),
img
.
type
());
ASSERT_EQ
(
img2
.
size
(),
img
.
size
());
EXPECT_
GE
(
1e-3
,
cvtest
::
norm
(
img
,
img2
,
NORM_INF
|
NORM_RELATIVE
)
);
ASSERT_EQ
(
img2
.
type
(),
img
.
type
());
ASSERT_EQ
(
img2
.
size
(),
img
.
size
());
EXPECT_
LE
(
cvtest
::
norm
(
img
,
img2
,
NORM_INF
|
NORM_RELATIVE
),
1e-3
);
EXPECT_EQ
(
0
,
remove
(
filenameOutput
.
c_str
()));
}
TEST
(
Imgcodecs_Tiff
,
readWrite_64FC1
)
{
const
string
root
=
cvtest
::
TS
::
ptr
()
->
get_data_path
();
const
string
filenameInput
=
root
+
"readwrite/test64FC1.tiff"
;
const
string
filenameOutput
=
cv
::
tempfile
(
".tiff"
);
const
Mat
img
=
cv
::
imread
(
filenameInput
,
IMREAD_UNCHANGED
);
ASSERT_FALSE
(
img
.
empty
());
ASSERT_EQ
(
CV_64FC1
,
img
.
type
());
ASSERT_TRUE
(
cv
::
imwrite
(
filenameOutput
,
img
));
const
Mat
img2
=
cv
::
imread
(
filenameOutput
,
IMREAD_UNCHANGED
);
ASSERT_EQ
(
img2
.
type
(),
img
.
type
());
ASSERT_EQ
(
img2
.
size
(),
img
.
size
());
EXPECT_LE
(
cvtest
::
norm
(
img
,
img2
,
NORM_INF
|
NORM_RELATIVE
),
1e-3
);
EXPECT_EQ
(
0
,
remove
(
filenameOutput
.
c_str
()));
}
TEST
(
Imgcodecs_Tiff
,
readWrite_32FC3_SGILOG
)
{
const
string
root
=
cvtest
::
TS
::
ptr
()
->
get_data_path
();
const
string
filenameInput
=
root
+
"readwrite/test32FC3_sgilog.tiff"
;
const
string
filenameOutput
=
cv
::
tempfile
(
".tiff"
);
const
Mat
img
=
cv
::
imread
(
filenameInput
,
IMREAD_UNCHANGED
);
ASSERT_FALSE
(
img
.
empty
());
ASSERT_EQ
(
CV_32FC3
,
img
.
type
());
ASSERT_TRUE
(
cv
::
imwrite
(
filenameOutput
,
img
));
const
Mat
img2
=
cv
::
imread
(
filenameOutput
,
IMREAD_UNCHANGED
);
ASSERT_EQ
(
img2
.
type
(),
img
.
type
());
ASSERT_EQ
(
img2
.
size
(),
img
.
size
());
EXPECT_LE
(
cvtest
::
norm
(
img
,
img2
,
NORM_INF
|
NORM_RELATIVE
),
0.01
);
EXPECT_EQ
(
0
,
remove
(
filenameOutput
.
c_str
()));
}
TEST
(
Imgcodecs_Tiff
,
readWrite_32FC3_RAW
)
{
const
string
root
=
cvtest
::
TS
::
ptr
()
->
get_data_path
();
const
string
filenameInput
=
root
+
"readwrite/test32FC3_raw.tiff"
;
const
string
filenameOutput
=
cv
::
tempfile
(
".tiff"
);
const
Mat
img
=
cv
::
imread
(
filenameInput
,
IMREAD_UNCHANGED
);
ASSERT_FALSE
(
img
.
empty
());
ASSERT_EQ
(
CV_32FC3
,
img
.
type
());
std
::
vector
<
int
>
params
;
params
.
push_back
(
IMWRITE_TIFF_COMPRESSION
);
params
.
push_back
(
1
/*COMPRESSION_NONE*/
);
ASSERT_TRUE
(
cv
::
imwrite
(
filenameOutput
,
img
,
params
));
const
Mat
img2
=
cv
::
imread
(
filenameOutput
,
IMREAD_UNCHANGED
);
ASSERT_EQ
(
img2
.
type
(),
img
.
type
());
ASSERT_EQ
(
img2
.
size
(),
img
.
size
());
EXPECT_LE
(
cvtest
::
norm
(
img
,
img2
,
NORM_INF
|
NORM_RELATIVE
),
1e-3
);
EXPECT_EQ
(
0
,
remove
(
filenameOutput
.
c_str
()));
}
//==================================================================================================
typedef
testing
::
TestWithParam
<
int
>
Imgcodecs_Tiff_Modes
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment