Merge pull request #3575 from Ashod:multipage_imread
This commit is contained in:
commit
390f17d1e0
@ -134,6 +134,16 @@ returns an empty matrix ( Mat::data==NULL ). Currently, the following file forma
|
||||
*/
|
||||
CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR );
|
||||
|
||||
/** @brief Loads a multi-page image from a file. (see imread for details.)
|
||||
|
||||
@param filename Name of file to be loaded.
|
||||
@param flags Flags specifying the color type of a loaded image (see imread).
|
||||
Defaults to IMREAD_ANYCOLOR, as each page may be different.
|
||||
@param mats A vector of Mat objects holding each page, if more than one.
|
||||
|
||||
*/
|
||||
CV_EXPORTS_W bool imreadmulti(const String& filename, std::vector<Mat>& mats, int flags = IMREAD_ANYCOLOR);
|
||||
|
||||
/** @brief Saves an image to a specified file.
|
||||
|
||||
@param filename Name of the file.
|
||||
|
@ -70,6 +70,9 @@ public:
|
||||
virtual bool readHeader() = 0;
|
||||
virtual bool readData( Mat& img ) = 0;
|
||||
|
||||
/// Called after readData to advance to the next page, if any.
|
||||
virtual bool nextPage() { return false; }
|
||||
|
||||
virtual size_t signatureLength() const;
|
||||
virtual bool checkSignature( const String& signature ) const;
|
||||
virtual ImageDecoder newDecoder() const;
|
||||
|
@ -118,10 +118,13 @@ bool TiffDecoder::readHeader()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
close();
|
||||
// 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
|
||||
TIFF* tif = TIFFOpen( m_filename.c_str(), "r" );
|
||||
TIFF* tif = static_cast<TIFF*>(m_tif);
|
||||
if (!m_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
|
||||
tif = TIFFOpen(m_filename.c_str(), "r");
|
||||
}
|
||||
|
||||
if( tif )
|
||||
{
|
||||
@ -182,6 +185,13 @@ bool TiffDecoder::readHeader()
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TiffDecoder::nextPage()
|
||||
{
|
||||
// Prepare the next page, if any.
|
||||
return m_tif &&
|
||||
TIFFReadDirectory(static_cast<TIFF*>(m_tif)) &&
|
||||
readHeader();
|
||||
}
|
||||
|
||||
bool TiffDecoder::readData( Mat& img )
|
||||
{
|
||||
@ -413,7 +423,6 @@ bool TiffDecoder::readData( Mat& img )
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,7 @@ public:
|
||||
bool readHeader();
|
||||
bool readData( Mat& img );
|
||||
void close();
|
||||
bool nextPage();
|
||||
|
||||
size_t signatureLength() const;
|
||||
bool checkSignature( const String& signature ) const;
|
||||
|
@ -320,6 +320,84 @@ imread_( const String& filename, int flags, int hdrtype, Mat* mat=0 )
|
||||
hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read an image into memory and return the information
|
||||
*
|
||||
* @param[in] filename File to load
|
||||
* @param[in] flags Flags
|
||||
* @param[in] mats Reference to C++ vector<Mat> object to hold the images
|
||||
*
|
||||
*/
|
||||
static bool
|
||||
imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
||||
{
|
||||
/// Search for the relevant decoder to handle the imagery
|
||||
ImageDecoder decoder;
|
||||
|
||||
#ifdef HAVE_GDAL
|
||||
if ((flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL){
|
||||
decoder = GdalDecoder().newDecoder();
|
||||
}
|
||||
else{
|
||||
#endif
|
||||
decoder = findDecoder(filename);
|
||||
#ifdef HAVE_GDAL
|
||||
}
|
||||
#endif
|
||||
|
||||
/// if no decoder was found, return nothing.
|
||||
if (!decoder){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// set the filename in the driver
|
||||
decoder->setSource(filename);
|
||||
|
||||
// read the header to make sure it succeeds
|
||||
if (!decoder->readHeader())
|
||||
return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// grab the decoded type
|
||||
int type = decoder->type();
|
||||
if (flags != -1)
|
||||
{
|
||||
if ((flags & CV_LOAD_IMAGE_ANYDEPTH) == 0)
|
||||
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
|
||||
|
||||
if ((flags & CV_LOAD_IMAGE_COLOR) != 0 ||
|
||||
((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1))
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
|
||||
else
|
||||
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
|
||||
}
|
||||
|
||||
// established the required input image size.
|
||||
CvSize size;
|
||||
size.width = decoder->width();
|
||||
size.height = decoder->height();
|
||||
|
||||
Mat mat;
|
||||
mat.create(size.height, size.width, type);
|
||||
|
||||
// read the image data
|
||||
if (!decoder->readData(mat))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
mats.push_back(mat);
|
||||
if (!decoder->nextPage())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !mats.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an image
|
||||
*
|
||||
@ -340,6 +418,21 @@ Mat imread( const String& filename, int flags )
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a multi-page image
|
||||
*
|
||||
* This function merely calls the actual implementation above and returns itself.
|
||||
*
|
||||
* @param[in] filename File to load
|
||||
* @param[in] mats Reference to C++ vector<Mat> object to hold the images
|
||||
* @param[in] flags Flags you wish to set.
|
||||
*
|
||||
*/
|
||||
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,
|
||||
const std::vector<int>& params, bool flipv )
|
||||
{
|
||||
|
@ -45,6 +45,68 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
static
|
||||
bool mats_equal(const Mat& lhs, const Mat& rhs)
|
||||
{
|
||||
if (lhs.channels() != rhs.channels() ||
|
||||
lhs.depth() != rhs.depth() ||
|
||||
lhs.size().height != rhs.size().height ||
|
||||
lhs.size().width != rhs.size().width)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Mat diff = (lhs != rhs);
|
||||
const Scalar s = sum(diff);
|
||||
for (int i = 0; i < s.channels; ++i)
|
||||
{
|
||||
if (s[i] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool imread_compare(const string& filepath, int flags = IMREAD_COLOR)
|
||||
{
|
||||
vector<Mat> pages;
|
||||
if (!imreadmulti(filepath, pages, flags) ||
|
||||
pages.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Mat single = imread(filepath, flags);
|
||||
return mats_equal(single, pages[0]);
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_imread, regression)
|
||||
{
|
||||
const char* const filenames[] =
|
||||
{
|
||||
"color_palette_alpha.png",
|
||||
"multipage.tif",
|
||||
"rle.hdr",
|
||||
"ordinary.bmp",
|
||||
"rle8.bmp",
|
||||
"test_1_c1.jpg"
|
||||
};
|
||||
|
||||
const string folder = string(cvtest::TS::ptr()->get_data_path()) + "/readwrite/";
|
||||
|
||||
for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); ++i)
|
||||
{
|
||||
ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_UNCHANGED));
|
||||
ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_GRAYSCALE));
|
||||
ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_COLOR));
|
||||
ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_ANYDEPTH));
|
||||
ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_ANYCOLOR));
|
||||
ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_LOAD_GDAL));
|
||||
}
|
||||
}
|
||||
|
||||
class CV_GrfmtWriteBigImageTest : public cvtest::BaseTest
|
||||
{
|
||||
@ -591,6 +653,46 @@ TEST(Imgcodecs_Tiff, decode_tile_remainder)
|
||||
CV_GrfmtReadTifTiledWithNotFullTiles test; test.safe_run();
|
||||
}
|
||||
|
||||
class CV_GrfmtReadTifMultiPage : public cvtest::BaseTest
|
||||
{
|
||||
private:
|
||||
void compare(int flags)
|
||||
{
|
||||
const string folder = string(cvtest::TS::ptr()->get_data_path()) + "/readwrite/";
|
||||
const int page_count = 6;
|
||||
|
||||
vector<Mat> pages;
|
||||
bool res = imreadmulti(folder + "multipage.tif", pages, flags);
|
||||
ASSERT_TRUE(res == true);
|
||||
ASSERT_TRUE(pages.size() == page_count);
|
||||
|
||||
for (int i = 0; i < page_count; i++)
|
||||
{
|
||||
char buffer[256];
|
||||
sprintf(buffer, "%smultipage_p%d.tif", folder.c_str(), i + 1);
|
||||
const string filepath(buffer);
|
||||
const Mat page = imread(filepath, flags);
|
||||
ASSERT_TRUE(mats_equal(page, pages[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void run(int)
|
||||
{
|
||||
compare(IMREAD_UNCHANGED);
|
||||
compare(IMREAD_GRAYSCALE);
|
||||
compare(IMREAD_COLOR);
|
||||
compare(IMREAD_ANYDEPTH);
|
||||
compare(IMREAD_ANYCOLOR);
|
||||
compare(IMREAD_LOAD_GDAL);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Imgcodecs_Tiff, decode_multipage)
|
||||
{
|
||||
CV_GrfmtReadTifMultiPage test; test.safe_run();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WEBP
|
||||
|
Loading…
x
Reference in New Issue
Block a user