imwrite for multipage images implemented

pull/10367/head
Rostislav Vasilikhin 7 years ago
parent c6e1e3acdc
commit 27b1f8f446
  1. 5
      modules/imgcodecs/src/grfmt_base.cpp
  2. 1
      modules/imgcodecs/src/grfmt_base.hpp
  3. 75
      modules/imgcodecs/src/grfmt_tiff.cpp
  4. 5
      modules/imgcodecs/src/grfmt_tiff.hpp
  5. 41
      modules/imgcodecs/src/loadsave.cpp
  6. 34
      modules/imgcodecs/test/test_tiff.cpp

@ -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();

@ -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;

@ -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();
@ -761,32 +790,6 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
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)
@ -797,6 +800,9 @@ 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);
@ -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

@ -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 );

@ -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*

@ -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();

Loading…
Cancel
Save