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
7 years ago
by
Vadim Pisarevsky
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10367 from savuor:multiwrite_tiff_renew
parents
5f5fcef9
27b1f8f4
No related merge requests found
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
130 additions
and
53 deletions
+130
-53
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
+57
-40
grfmt_tiff.hpp
modules/imgcodecs/src/grfmt_tiff.hpp
+4
-1
loadsave.cpp
modules/imgcodecs/src/loadsave.cpp
+29
-12
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
();
...
...
This diff is collapsed.
Click to expand it.
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
;
...
...
This diff is collapsed.
Click to expand it.
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,8 +723,38 @@ 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
)
{
// 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
;
TiffEncoderBufHelper
buf_helper
(
m_buf
);
if
(
m_buf
)
{
pTiffHandle
=
buf_helper
.
open
();
}
else
{
pTiffHandle
=
TIFFOpen
(
m_filename
.
c_str
(),
"w"
);
}
if
(
!
pTiffHandle
)
{
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
;
readParam
(
params
,
TIFFTAG_COMPRESSION
,
compression
);
readParam
(
params
,
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
++
)
{
const
Mat
&
img
=
img_vec
[
page
];
int
channels
=
img
.
channels
();
int
width
=
img
.
cols
,
height
=
img
.
rows
;
int
depth
=
img
.
depth
();
...
...
@@ -752,44 +781,18 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
const
int
bitsPerByte
=
8
;
size_t
fileStep
=
(
width
*
channels
*
bitsPerChannel
)
/
bitsPerByte
;
int
rowsPerStrip
=
(
int
)((
1
<<
13
)
/
fileStep
);
int
rowsPerStrip
=
(
int
)((
1
<<
13
)
/
fileStep
);
readParam
(
params
,
TIFFTAG_ROWSPERSTRIP
,
rowsPerStrip
);
if
(
rowsPerStrip
<
1
)
if
(
rowsPerStrip
<
1
)
rowsPerStrip
=
1
;
if
(
rowsPerStrip
>
height
)
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
;
TiffEncoderBufHelper
buf_helper
(
m_buf
);
if
(
m_buf
)
{
pTiffHandle
=
buf_helper
.
open
();
}
else
{
pTiffHandle
=
TIFFOpen
(
m_filename
.
c_str
(),
"w"
);
}
if
(
!
pTiffHandle
)
{
return
false
;
}
// defaults for now, maybe base them on params in the future
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
)
if
(
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_IMAGEWIDTH
,
width
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_IMAGELENGTH
,
height
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_BITSPERSAMPLE
,
bitsPerChannel
)
||
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_COMPRESSION
,
compression
)
...
...
@@ -797,13 +800,16 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
||
!
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
)
)
if
(
compression
!=
COMPRESSION_NONE
&&
!
TIFFSetField
(
pTiffHandle
,
TIFFTAG_PREDICTOR
,
predictor
)
)
{
TIFFClose
(
pTiffHandle
);
return
false
;
...
...
@@ -811,7 +817,7 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
// row buffer, because TIFFWriteScanline modifies the original data!
size_t
scanlineSize
=
TIFFScanlineSize
(
pTiffHandle
);
AutoBuffer
<
uchar
>
_buffer
(
scanlineSize
+
32
);
AutoBuffer
<
uchar
>
_buffer
(
scanlineSize
+
32
);
uchar
*
buffer
=
_buffer
;
if
(
!
buffer
)
{
...
...
@@ -821,7 +827,7 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
for
(
int
y
=
0
;
y
<
height
;
++
y
)
{
switch
(
channels
)
switch
(
channels
)
{
case
1
:
{
...
...
@@ -832,18 +838,18 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
case
3
:
{
if
(
depth
==
CV_8U
)
icvCvt_BGR2RGB_8u_C3R
(
img
.
ptr
(
y
),
0
,
buffer
,
0
,
cvSize
(
width
,
1
)
);
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
)
);
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
)
);
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
)
);
icvCvt_BGRA2RGBA_16u_C4R
(
img
.
ptr
<
ushort
>
(
y
),
0
,
(
ushort
*
)
buffer
,
0
,
cvSize
(
width
,
1
)
);
break
;
}
...
...
@@ -862,6 +868,10 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
}
}
TIFFWriteDirectory
(
pTiffHandle
);
}
TIFFClose
(
pTiffHandle
);
return
true
;
}
...
...
@@ -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
...
...
This diff is collapsed.
Click to expand it.
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
);
...
...
This diff is collapsed.
Click to expand it.
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"
);
for
(
size_t
page
=
0
;
page
<
img_vec
.
size
();
page
++
)
{
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
);
pimage
=
&
temp
;
image
=
temp
;
}
if
(
flipv
)
{
flip
(
*
pimage
,
temp
,
0
);
pimage
=
&
temp
;
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
*
...
...
This diff is collapsed.
Click to expand it.
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
();
...
...
This diff is collapsed.
Click to expand it.
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