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
f61076a5
Commit
f61076a5
authored
Feb 20, 2018
by
Vadim Pisarevsky
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10367 from savuor:multiwrite_tiff_renew
parents
5f5fcef9
27b1f8f4
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
191 additions
and
114 deletions
+191
-114
grfmt_base.cpp
modules/imgcodecs/src/grfmt_base.cpp
+5
-0
grfmt_base.hpp
modules/imgcodecs/src/grfmt_base.hpp
+1
-0
grfmt_tiff.cpp
modules/imgcodecs/src/grfmt_tiff.cpp
+112
-95
grfmt_tiff.hpp
modules/imgcodecs/src/grfmt_tiff.hpp
+4
-1
loadsave.cpp
modules/imgcodecs/src/loadsave.cpp
+35
-18
test_tiff.cpp
modules/imgcodecs/test/test_tiff.cpp
+34
-0
No files found.
modules/imgcodecs/src/grfmt_base.cpp
View file @
f61076a5
...
...
@@ -127,6 +127,11 @@ bool BaseImageEncoder::setDestination( std::vector<uchar>& buf )
return
true
;
}
bool
BaseImageEncoder
::
writemulti
(
const
std
::
vector
<
Mat
>&
,
const
std
::
vector
<
int
>&
)
{
return
false
;
}
ImageEncoder
BaseImageEncoder
::
newEncoder
()
const
{
return
ImageEncoder
();
...
...
modules/imgcodecs/src/grfmt_base.hpp
View file @
f61076a5
...
...
@@ -101,6 +101,7 @@ public:
virtual
bool
setDestination
(
const
String
&
filename
);
virtual
bool
setDestination
(
std
::
vector
<
uchar
>&
buf
);
virtual
bool
write
(
const
Mat
&
img
,
const
std
::
vector
<
int
>&
params
)
=
0
;
virtual
bool
writemulti
(
const
std
::
vector
<
Mat
>&
img_vec
,
const
std
::
vector
<
int
>&
params
);
virtual
String
getDescription
()
const
;
virtual
ImageEncoder
newEncoder
()
const
;
...
...
modules/imgcodecs/src/grfmt_tiff.cpp
View file @
f61076a5
...
...
@@ -539,7 +539,6 @@ bool TiffDecoder::readData( Mat& img )
bool
TiffDecoder
::
readData_32FC3
(
Mat
&
img
)
{
int
rows_per_strip
=
0
,
photometric
=
0
;
if
(
!
m_tif
)
{
...
...
@@ -724,44 +723,8 @@ static void readParam(const std::vector<int>& params, int key, int& value)
}
}
bool
TiffEncoder
::
writeLibTiff
(
const
Mat
&
img
,
const
std
::
vector
<
int
>&
params
)
bool
TiffEncoder
::
writeLibTiff
(
const
std
::
vector
<
Mat
>&
img_vec
,
const
std
::
vector
<
int
>&
params
)
{
int
channels
=
img
.
channels
();
int
width
=
img
.
cols
,
height
=
img
.
rows
;
int
depth
=
img
.
depth
();
int
bitsPerChannel
=
-
1
;
switch
(
depth
)
{
case
CV_8U
:
{
bitsPerChannel
=
8
;
break
;
}
case
CV_16U
:
{
bitsPerChannel
=
16
;
break
;
}
default
:
{
return
false
;
}
}
const
int
bitsPerByte
=
8
;
size_t
fileStep
=
(
width
*
channels
*
bitsPerChannel
)
/
bitsPerByte
;
int
rowsPerStrip
=
(
int
)((
1
<<
13
)
/
fileStep
);
readParam
(
params
,
TIFFTAG_ROWSPERSTRIP
,
rowsPerStrip
);
if
(
rowsPerStrip
<
1
)
rowsPerStrip
=
1
;
if
(
rowsPerStrip
>
height
)
rowsPerStrip
=
height
;
// 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
;
...
...
@@ -780,86 +743,133 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
return
false
;
}
//Settings that matter to all images
// defaults for now, maybe base them on params in the future
int
compression
=
COMPRESSION_LZW
;
int
predictor
=
PREDICTOR_HORIZONTAL
;
int
compression
=
COMPRESSION_LZW
;
int
predictor
=
PREDICTOR_HORIZONTAL
;
readParam
(
params
,
TIFFTAG_COMPRESSION
,
compression
);
readParam
(
params
,
TIFFTAG_PREDICTOR
,
predictor
);
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
)
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
if
(
compression
!=
COMPRESSION_NONE
&&
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_PREDICTOR
,
predictor
)
)
//Iterate through each image in the vector and write them out as Tiff directories
for
(
size_t
page
=
0
;
page
<
img_vec
.
size
();
page
++
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
// row buffer, because TIFFWriteScanline modifies the original data!
size_t
scanlineSize
=
TIFFScanlineSize
(
pTiffHandle
);
AutoBuffer
<
uchar
>
_buffer
(
scanlineSize
+
32
);
uchar
*
buffer
=
_buffer
;
if
(
!
buffer
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
const
Mat
&
img
=
img_vec
[
page
];
int
channels
=
img
.
channels
();
int
width
=
img
.
cols
,
height
=
img
.
rows
;
int
depth
=
img
.
depth
();
for
(
int
y
=
0
;
y
<
height
;
++
y
)
{
switch
(
channels
)
int
bitsPerChannel
=
-
1
;
switch
(
depth
)
{
case
1
:
{
memcpy
(
buffer
,
img
.
ptr
(
y
),
scanlineSize
);
break
;
}
case
3
:
case
CV_8U
:
{
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
)
);
bitsPerChannel
=
8
;
break
;
}
case
4
:
case
CV_16U
:
{
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
)
);
bitsPerChannel
=
16
;
break
;
}
default
:
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
}
int
writeResult
=
TIFFWriteScanline
(
pTiffHandle
,
buffer
,
y
,
0
);
if
(
writeResult
!=
1
)
const
int
bitsPerByte
=
8
;
size_t
fileStep
=
(
width
*
channels
*
bitsPerChannel
)
/
bitsPerByte
;
int
rowsPerStrip
=
(
int
)((
1
<<
13
)
/
fileStep
);
readParam
(
params
,
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
()
)))
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
if
(
compression
!=
COMPRESSION_NONE
&&
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_PREDICTOR
,
predictor
))
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
// row buffer, because TIFFWriteScanline modifies the original data!
size_t
scanlineSize
=
TIFFScanlineSize
(
pTiffHandle
);
AutoBuffer
<
uchar
>
_buffer
(
scanlineSize
+
32
);
uchar
*
buffer
=
_buffer
;
if
(
!
buffer
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
for
(
int
y
=
0
;
y
<
height
;
++
y
)
{
switch
(
channels
)
{
case
1
:
{
memcpy
(
buffer
,
img
.
ptr
(
y
),
scanlineSize
);
break
;
}
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
));
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
));
break
;
}
default
:
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
}
int
writeResult
=
TIFFWriteScanline
(
pTiffHandle
,
buffer
,
y
,
0
);
if
(
writeResult
!=
1
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
}
}
TIFFWriteDirectory
(
pTiffHandle
);
}
TIFFClose
(
pTiffHandle
);
...
...
@@ -946,6 +956,11 @@ bool TiffEncoder::write_32FC1(const Mat& _img)
return
true
;
}
bool
TiffEncoder
::
writemulti
(
const
std
::
vector
<
Mat
>&
img_vec
,
const
std
::
vector
<
int
>&
params
)
{
return
writeLibTiff
(
img_vec
,
params
);
}
bool
TiffEncoder
::
write
(
const
Mat
&
img
,
const
std
::
vector
<
int
>&
params
)
{
int
depth
=
img
.
depth
();
...
...
@@ -961,7 +976,9 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
CV_Assert
(
depth
==
CV_8U
||
depth
==
CV_16U
);
return
writeLibTiff
(
img
,
params
);
std
::
vector
<
Mat
>
img_vec
;
img_vec
.
push_back
(
img
);
return
writeLibTiff
(
img_vec
,
params
);
}
}
// namespace
...
...
modules/imgcodecs/src/grfmt_tiff.hpp
View file @
f61076a5
...
...
@@ -128,6 +128,9 @@ public:
bool
isFormatSupported
(
int
depth
)
const
;
bool
write
(
const
Mat
&
img
,
const
std
::
vector
<
int
>&
params
);
bool
writemulti
(
const
std
::
vector
<
Mat
>&
img_vec
,
const
std
::
vector
<
int
>&
params
);
ImageEncoder
newEncoder
()
const
;
protected
:
...
...
@@ -135,7 +138,7 @@ protected:
TiffFieldType
fieldType
,
int
count
,
int
value
);
bool
writeLibTiff
(
const
Mat
&
img
,
const
std
::
vector
<
int
>&
params
);
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
);
...
...
modules/imgcodecs/src/loadsave.cpp
View file @
f61076a5
...
...
@@ -667,33 +667,45 @@ bool imreadmulti(const String& filename, std::vector<Mat>& mats, int flags)
return
imreadmulti_
(
filename
,
flags
,
mats
);
}
static
bool
imwrite_
(
const
String
&
filename
,
const
Mat
&
image
,
static
bool
imwrite_
(
const
String
&
filename
,
const
std
::
vector
<
Mat
>&
img_vec
,
const
std
::
vector
<
int
>&
params
,
bool
flipv
)
{
Mat
temp
;
const
Mat
*
pimage
=
&
image
;
CV_Assert
(
image
.
channels
()
==
1
||
image
.
channels
()
==
3
||
image
.
channels
()
==
4
);
bool
isMultiImg
=
img_vec
.
size
()
>
1
;
std
::
vector
<
Mat
>
write_vec
;
ImageEncoder
encoder
=
findEncoder
(
filename
);
if
(
!
encoder
)
CV_Error
(
CV_StsError
,
"could not find a writer for the specified extension"
);
if
(
!
encoder
->
isFormatSupported
(
image
.
depth
())
)
{
CV_Assert
(
encoder
->
isFormatSupported
(
CV_8U
)
);
image
.
convertTo
(
temp
,
CV_8U
);
pimage
=
&
temp
;
}
if
(
flipv
)
for
(
size_t
page
=
0
;
page
<
img_vec
.
size
();
page
++
)
{
flip
(
*
pimage
,
temp
,
0
);
pimage
=
&
temp
;
Mat
image
=
img_vec
[
page
];
CV_Assert
(
image
.
channels
()
==
1
||
image
.
channels
()
==
3
||
image
.
channels
()
==
4
);
Mat
temp
;
if
(
!
encoder
->
isFormatSupported
(
image
.
depth
())
)
{
CV_Assert
(
encoder
->
isFormatSupported
(
CV_8U
)
);
image
.
convertTo
(
temp
,
CV_8U
);
image
=
temp
;
}
if
(
flipv
)
{
flip
(
image
,
temp
,
0
);
image
=
temp
;
}
write_vec
.
push_back
(
image
);
}
encoder
->
setDestination
(
filename
);
CV_Assert
(
params
.
size
()
<=
CV_IO_MAX_IMAGE_PARAMS
*
2
);
bool
code
=
encoder
->
write
(
*
pimage
,
params
);
bool
code
;
if
(
!
isMultiImg
)
code
=
encoder
->
write
(
write_vec
[
0
],
params
);
else
code
=
encoder
->
writemulti
(
write_vec
,
params
);
//to be implemented
// CV_Assert( code );
return
code
;
...
...
@@ -703,9 +715,14 @@ bool imwrite( const String& filename, InputArray _img,
const
std
::
vector
<
int
>&
params
)
{
CV_TRACE_FUNCTION
();
Mat
img
=
_img
.
getMat
();
return
imwrite_
(
filename
,
img
,
params
,
false
);
std
::
vector
<
Mat
>
img_vec
;
//Did we get a Mat or a vector of Mats?
if
(
_img
.
isMat
())
img_vec
.
push_back
(
_img
.
getMat
());
else
if
(
_img
.
isMatVector
())
_img
.
getMatVector
(
img_vec
);
return
imwrite_
(
filename
,
img_vec
,
params
,
false
);
}
static
void
*
...
...
modules/imgcodecs/test/test_tiff.cpp
View file @
f61076a5
...
...
@@ -206,6 +206,40 @@ INSTANTIATE_TEST_CASE_P(AllModes, Imgcodecs_Tiff_Modes, testing::ValuesIn(all_mo
//==================================================================================================
TEST
(
Imgcodecs_Tiff_Modes
,
write_multipage
)
{
const
string
root
=
cvtest
::
TS
::
ptr
()
->
get_data_path
();
const
string
filename
=
root
+
"readwrite/multipage.tif"
;
const
string
page_files
[]
=
{
"readwrite/multipage_p1.tif"
,
"readwrite/multipage_p2.tif"
,
"readwrite/multipage_p3.tif"
,
"readwrite/multipage_p4.tif"
,
"readwrite/multipage_p5.tif"
,
"readwrite/multipage_p6.tif"
};
const
size_t
page_count
=
sizeof
(
page_files
)
/
sizeof
(
page_files
[
0
]);
vector
<
Mat
>
pages
;
for
(
size_t
i
=
0
;
i
<
page_count
;
i
++
)
{
const
Mat
page
=
imread
(
root
+
page_files
[
i
]);
pages
.
push_back
(
page
);
}
string
tmp_filename
=
cv
::
tempfile
(
".tiff"
);
bool
res
=
imwrite
(
tmp_filename
,
pages
);
ASSERT_TRUE
(
res
);
vector
<
Mat
>
read_pages
;
imreadmulti
(
tmp_filename
,
read_pages
);
for
(
size_t
i
=
0
;
i
<
page_count
;
i
++
)
{
EXPECT_PRED_FORMAT2
(
cvtest
::
MatComparator
(
0
,
0
),
read_pages
[
i
],
pages
[
i
]);
}
}
//==================================================================================================
TEST
(
Imgcodecs_Tiff
,
imdecode_no_exception_temporary_file_removed
)
{
const
string
root
=
cvtest
::
TS
::
ptr
()
->
get_data_path
();
...
...
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