|
|
|
@ -54,6 +54,8 @@ |
|
|
|
|
#include <cerrno> |
|
|
|
|
#include <opencv2/core/utils/logger.hpp> |
|
|
|
|
#include <opencv2/core/utils/configuration.private.hpp> |
|
|
|
|
#include <opencv2/imgcodecs.hpp> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************************\
|
|
|
|
@ -658,57 +660,14 @@ bool imreadmulti(const String& filename, std::vector<Mat>& mats, int start, int |
|
|
|
|
static |
|
|
|
|
size_t imcount_(const String& filename, int flags) |
|
|
|
|
{ |
|
|
|
|
/// Search for the relevant decoder to handle the imagery
|
|
|
|
|
ImageDecoder decoder; |
|
|
|
|
|
|
|
|
|
#ifdef HAVE_GDAL |
|
|
|
|
if (flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL) { |
|
|
|
|
decoder = GdalDecoder().newDecoder(); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
#else |
|
|
|
|
CV_UNUSED(flags); |
|
|
|
|
#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
|
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
// read the header to make sure it succeeds
|
|
|
|
|
if (!decoder->readHeader()) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
catch (const cv::Exception& e) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "imcount_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
catch (...) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "imcount_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush; |
|
|
|
|
try{ |
|
|
|
|
ImageCollection collection(filename, flags); |
|
|
|
|
return collection.size(); |
|
|
|
|
} catch(cv::Exception const& e) { |
|
|
|
|
// Reading header or finding decoder for the filename is failed
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size_t result = 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (decoder->nextPage()) |
|
|
|
|
{ |
|
|
|
|
++result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size_t imcount(const String& filename, int flags) |
|
|
|
@ -1032,6 +991,247 @@ bool haveImageWriter( const String& filename ) |
|
|
|
|
return !encoder.empty(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class ImageCollection::Impl { |
|
|
|
|
public: |
|
|
|
|
Impl() = default; |
|
|
|
|
Impl(const std::string& filename, int flags); |
|
|
|
|
void init(String const& filename, int flags); |
|
|
|
|
size_t size() const; |
|
|
|
|
Mat& at(int index); |
|
|
|
|
Mat& operator[](int index); |
|
|
|
|
void releaseCache(int index); |
|
|
|
|
ImageCollection::iterator begin(ImageCollection* ptr); |
|
|
|
|
ImageCollection::iterator end(ImageCollection* ptr); |
|
|
|
|
Mat read(); |
|
|
|
|
int width() const; |
|
|
|
|
int height() const; |
|
|
|
|
bool readHeader(); |
|
|
|
|
Mat readData(); |
|
|
|
|
bool advance(); |
|
|
|
|
int currentIndex() const; |
|
|
|
|
void reset(); |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
String m_filename; |
|
|
|
|
int m_flags{}; |
|
|
|
|
std::size_t m_size{}; |
|
|
|
|
int m_width{}; |
|
|
|
|
int m_height{}; |
|
|
|
|
int m_current{}; |
|
|
|
|
std::vector<cv::Mat> m_pages; |
|
|
|
|
ImageDecoder m_decoder; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
ImageCollection::Impl::Impl(std::string const& filename, int flags) { |
|
|
|
|
this->init(filename, flags); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ImageCollection::Impl::init(String const& filename, int flags) { |
|
|
|
|
m_filename = filename; |
|
|
|
|
m_flags = flags; |
|
|
|
|
|
|
|
|
|
#ifdef HAVE_GDAL |
|
|
|
|
if (m_flags != IMREAD_UNCHANGED && (m_flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL) { |
|
|
|
|
m_decoder = GdalDecoder().newDecoder(); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
#endif |
|
|
|
|
m_decoder = findDecoder(filename); |
|
|
|
|
#ifdef HAVE_GDAL |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CV_Assert(m_decoder); |
|
|
|
|
m_decoder->setSource(filename); |
|
|
|
|
CV_Assert(m_decoder->readHeader()); |
|
|
|
|
|
|
|
|
|
// count the pages of the image collection
|
|
|
|
|
size_t count = 1; |
|
|
|
|
while(m_decoder->nextPage()) count++; |
|
|
|
|
|
|
|
|
|
m_size = count; |
|
|
|
|
m_pages.resize(m_size); |
|
|
|
|
// Reinitialize the decoder because we advanced to the last page while counting the pages of the image
|
|
|
|
|
#ifdef HAVE_GDAL |
|
|
|
|
if (m_flags != IMREAD_UNCHANGED && (m_flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL) { |
|
|
|
|
m_decoder = GdalDecoder().newDecoder(); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
#endif |
|
|
|
|
m_decoder = findDecoder(m_filename); |
|
|
|
|
#ifdef HAVE_GDAL |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
m_decoder->setSource(m_filename); |
|
|
|
|
m_decoder->readHeader(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size_t ImageCollection::Impl::size() const { return m_size; } |
|
|
|
|
|
|
|
|
|
Mat ImageCollection::Impl::read() { |
|
|
|
|
auto result = this->readHeader(); |
|
|
|
|
if(!result) { |
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|
return this->readData(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int ImageCollection::Impl::width() const { |
|
|
|
|
return m_width; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int ImageCollection::Impl::height() const { |
|
|
|
|
return m_height; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool ImageCollection::Impl::readHeader() { |
|
|
|
|
bool status = m_decoder->readHeader(); |
|
|
|
|
m_width = m_decoder->width(); |
|
|
|
|
m_height = m_decoder->height(); |
|
|
|
|
return status; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// readHeader must be called before calling this method
|
|
|
|
|
Mat ImageCollection::Impl::readData() { |
|
|
|
|
int type = m_decoder->type(); |
|
|
|
|
if ((m_flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && m_flags != IMREAD_UNCHANGED) { |
|
|
|
|
if ((m_flags & IMREAD_ANYDEPTH) == 0) |
|
|
|
|
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type)); |
|
|
|
|
|
|
|
|
|
if ((m_flags & IMREAD_COLOR) != 0 || |
|
|
|
|
((m_flags & IMREAD_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
|
|
|
|
|
Size size = validateInputImageSize(Size(m_width, m_height)); |
|
|
|
|
|
|
|
|
|
Mat mat(size.height, size.width, type); |
|
|
|
|
bool success = false; |
|
|
|
|
try { |
|
|
|
|
if (m_decoder->readData(mat)) |
|
|
|
|
success = true; |
|
|
|
|
} |
|
|
|
|
catch (const cv::Exception &e) { |
|
|
|
|
std::cerr << "ImageCollection class: can't read data: " << e.what() << std::endl << std::flush; |
|
|
|
|
} |
|
|
|
|
catch (...) { |
|
|
|
|
std::cerr << "ImageCollection class:: can't read data: unknown exception" << std::endl << std::flush; |
|
|
|
|
} |
|
|
|
|
if (!success) |
|
|
|
|
return cv::Mat(); |
|
|
|
|
|
|
|
|
|
if ((m_flags & IMREAD_IGNORE_ORIENTATION) == 0 && m_flags != IMREAD_UNCHANGED) { |
|
|
|
|
ApplyExifOrientation(m_decoder->getExifTag(ORIENTATION), mat); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return mat; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool ImageCollection::Impl::advance() { ++m_current; return m_decoder->nextPage(); } |
|
|
|
|
|
|
|
|
|
int ImageCollection::Impl::currentIndex() const { return m_current; } |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator ImageCollection::Impl::begin(ImageCollection* ptr) { return ImageCollection::iterator(ptr); } |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator ImageCollection::Impl::end(ImageCollection* ptr) { return ImageCollection::iterator(ptr, this->size()); } |
|
|
|
|
|
|
|
|
|
void ImageCollection::Impl::reset() { |
|
|
|
|
m_current = 0; |
|
|
|
|
#ifdef HAVE_GDAL |
|
|
|
|
if (m_flags != IMREAD_UNCHANGED && (m_flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL) { |
|
|
|
|
m_decoder = GdalDecoder().newDecoder(); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
#endif |
|
|
|
|
m_decoder = findDecoder(m_filename); |
|
|
|
|
#ifdef HAVE_GDAL |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
m_decoder->setSource(m_filename); |
|
|
|
|
m_decoder->readHeader(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Mat& ImageCollection::Impl::at(int index) { |
|
|
|
|
CV_Assert(index >= 0 && size_t(index) < m_size); |
|
|
|
|
return operator[](index); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Mat& ImageCollection::Impl::operator[](int index) { |
|
|
|
|
if(m_pages.at(index).empty()) { |
|
|
|
|
// We can't go backward in multi images. If the page is not in vector yet,
|
|
|
|
|
// go back to first page and advance until the desired page and read it into memory
|
|
|
|
|
if(m_current != index) { |
|
|
|
|
reset(); |
|
|
|
|
for(int i = 0; i != index && advance(); ++i) {} |
|
|
|
|
} |
|
|
|
|
m_pages[index] = read(); |
|
|
|
|
} |
|
|
|
|
return m_pages[index]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ImageCollection::Impl::releaseCache(int index) { |
|
|
|
|
CV_Assert(index >= 0 && size_t(index) < m_size); |
|
|
|
|
m_pages[index].release(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ImageCollection API*/ |
|
|
|
|
|
|
|
|
|
ImageCollection::ImageCollection() : pImpl(new Impl()) {} |
|
|
|
|
|
|
|
|
|
ImageCollection::ImageCollection(const std::string& filename, int flags) : pImpl(new Impl(filename, flags)) {} |
|
|
|
|
|
|
|
|
|
void ImageCollection::init(const String& img, int flags) { pImpl->init(img, flags); } |
|
|
|
|
|
|
|
|
|
size_t ImageCollection::size() const { return pImpl->size(); } |
|
|
|
|
|
|
|
|
|
const Mat& ImageCollection::at(int index) { return pImpl->at(index); } |
|
|
|
|
|
|
|
|
|
const Mat& ImageCollection::operator[](int index) { return pImpl->operator[](index); } |
|
|
|
|
|
|
|
|
|
void ImageCollection::releaseCache(int index) { pImpl->releaseCache(index); } |
|
|
|
|
|
|
|
|
|
Ptr<ImageCollection::Impl> ImageCollection::getImpl() { return pImpl; } |
|
|
|
|
|
|
|
|
|
/* Iterator API */ |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator ImageCollection::begin() { return pImpl->begin(this); } |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator ImageCollection::end() { return pImpl->end(this); } |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator::iterator(ImageCollection* col) : m_pCollection(col), m_curr(0) {} |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator::iterator(ImageCollection* col, int end) : m_pCollection(col), m_curr(end) {} |
|
|
|
|
|
|
|
|
|
Mat& ImageCollection::iterator::operator*() { |
|
|
|
|
CV_Assert(m_pCollection); |
|
|
|
|
return m_pCollection->getImpl()->operator[](m_curr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Mat* ImageCollection::iterator::operator->() { |
|
|
|
|
CV_Assert(m_pCollection); |
|
|
|
|
return &m_pCollection->getImpl()->operator[](m_curr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator& ImageCollection::iterator::operator++() { |
|
|
|
|
if(m_pCollection->pImpl->currentIndex() == m_curr) { |
|
|
|
|
m_pCollection->pImpl->advance(); |
|
|
|
|
} |
|
|
|
|
m_curr++; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ImageCollection::iterator ImageCollection::iterator::operator++(int) { |
|
|
|
|
iterator tmp = *this; |
|
|
|
|
++(*this); |
|
|
|
|
return tmp; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* End of file. */ |
|
|
|
|