|
|
|
@ -48,6 +48,8 @@ |
|
|
|
|
#include "precomp.hpp" |
|
|
|
|
|
|
|
|
|
#ifdef HAVE_TIFF |
|
|
|
|
#include <opencv2/core/utils/logger.hpp> |
|
|
|
|
|
|
|
|
|
#include "grfmt_tiff.hpp" |
|
|
|
|
#include <limits> |
|
|
|
|
|
|
|
|
@ -61,23 +63,58 @@ using namespace tiff_dummy_namespace; |
|
|
|
|
namespace cv |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
#define CV_TIFF_CHECK_CALL(call) \ |
|
|
|
|
if (0 == (call)) { \
|
|
|
|
|
CV_LOG_WARNING(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed " #call); \
|
|
|
|
|
CV_Error(Error::StsError, "OpenCV TIFF: failed " #call); \
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define CV_TIFF_CHECK_CALL_INFO(call) \ |
|
|
|
|
if (0 == (call)) { \
|
|
|
|
|
CV_LOG_INFO(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed optional call: " #call ", ignoring"); \
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define CV_TIFF_CHECK_CALL_DEBUG(call) \ |
|
|
|
|
if (0 == (call)) { \
|
|
|
|
|
CV_LOG_DEBUG(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed optional call: " #call ", ignoring"); \
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void cv_tiffCloseHandle(void* handle) |
|
|
|
|
{ |
|
|
|
|
TIFFClose((TIFF*)handle); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void cv_tiffErrorHandler(const char* module, const char* fmt, va_list ap) |
|
|
|
|
{ |
|
|
|
|
if (cv::utils::logging::getLogLevel() < cv::utils::logging::LOG_LEVEL_DEBUG) |
|
|
|
|
return; |
|
|
|
|
// TODO cv::vformat() with va_list parameter
|
|
|
|
|
fprintf(stderr, "OpenCV TIFF: "); |
|
|
|
|
if (module != NULL) |
|
|
|
|
fprintf(stderr, "%s: ", module); |
|
|
|
|
fprintf(stderr, "Warning, "); |
|
|
|
|
vfprintf(stderr, fmt, ap); |
|
|
|
|
fprintf(stderr, ".\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool cv_tiffSetErrorHandler_() |
|
|
|
|
{ |
|
|
|
|
TIFFSetErrorHandler(cv_tiffErrorHandler); |
|
|
|
|
TIFFSetWarningHandler(cv_tiffErrorHandler); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool cv_tiffSetErrorHandler() |
|
|
|
|
{ |
|
|
|
|
static bool v = cv_tiffSetErrorHandler_(); |
|
|
|
|
return v; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const char fmtSignTiffII[] = "II\x2a\x00"; |
|
|
|
|
static const char fmtSignTiffMM[] = "MM\x00\x2a"; |
|
|
|
|
|
|
|
|
|
static int grfmt_tiff_err_handler_init = 0; |
|
|
|
|
static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {} |
|
|
|
|
|
|
|
|
|
TiffDecoder::TiffDecoder() |
|
|
|
|
{ |
|
|
|
|
m_tif = 0; |
|
|
|
|
if( !grfmt_tiff_err_handler_init ) |
|
|
|
|
{ |
|
|
|
|
grfmt_tiff_err_handler_init = 1; |
|
|
|
|
|
|
|
|
|
TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler ); |
|
|
|
|
TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler ); |
|
|
|
|
} |
|
|
|
|
m_hdr = false; |
|
|
|
|
m_buf_supported = true; |
|
|
|
|
m_buf_pos = 0; |
|
|
|
@ -86,12 +123,7 @@ TiffDecoder::TiffDecoder() |
|
|
|
|
|
|
|
|
|
void TiffDecoder::close() |
|
|
|
|
{ |
|
|
|
|
if( m_tif ) |
|
|
|
|
{ |
|
|
|
|
TIFF* tif = (TIFF*)m_tif; |
|
|
|
|
TIFFClose( tif ); |
|
|
|
|
m_tif = 0; |
|
|
|
|
} |
|
|
|
|
m_tif.release(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TiffDecoder::~TiffDecoder() |
|
|
|
@ -113,11 +145,13 @@ bool TiffDecoder::checkSignature( const String& signature ) const |
|
|
|
|
|
|
|
|
|
int TiffDecoder::normalizeChannelsNumber(int channels) const |
|
|
|
|
{ |
|
|
|
|
CV_Assert(channels <= 4); |
|
|
|
|
return channels > 4 ? 4 : channels; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ImageDecoder TiffDecoder::newDecoder() const |
|
|
|
|
{ |
|
|
|
|
cv_tiffSetErrorHandler(); |
|
|
|
|
return makePtr<TiffDecoder>(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -201,8 +235,8 @@ bool TiffDecoder::readHeader() |
|
|
|
|
{ |
|
|
|
|
bool result = false; |
|
|
|
|
|
|
|
|
|
TIFF* tif = static_cast<TIFF*>(m_tif); |
|
|
|
|
if (!m_tif) |
|
|
|
|
TIFF* tif = static_cast<TIFF*>(m_tif.get()); |
|
|
|
|
if (!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
|
|
|
|
@ -221,25 +255,30 @@ bool TiffDecoder::readHeader() |
|
|
|
|
{ |
|
|
|
|
tif = TIFFOpen(m_filename.c_str(), "r"); |
|
|
|
|
} |
|
|
|
|
if (tif) |
|
|
|
|
m_tif.reset(tif, cv_tiffCloseHandle); |
|
|
|
|
else |
|
|
|
|
m_tif.release(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if( tif ) |
|
|
|
|
if (tif) |
|
|
|
|
{ |
|
|
|
|
uint32 wdth = 0, hght = 0; |
|
|
|
|
uint16 photometric = 0; |
|
|
|
|
m_tif = tif; |
|
|
|
|
|
|
|
|
|
if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) && |
|
|
|
|
TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) && |
|
|
|
|
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric )) |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wdth)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hght)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)); |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
uint16 bpp=8, ncn = photometric > 1 ? 3 : 1; |
|
|
|
|
TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); |
|
|
|
|
TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); |
|
|
|
|
bool isGrayScale = photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK; |
|
|
|
|
uint16 bpp = 8, ncn = isGrayScale ? 1 : 3; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp)); |
|
|
|
|
CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn)); |
|
|
|
|
|
|
|
|
|
m_width = wdth; |
|
|
|
|
m_height = hght; |
|
|
|
|
if((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV) |
|
|
|
|
if (ncn == 3 && photometric == PHOTOMETRIC_LOGLUV) |
|
|
|
|
{ |
|
|
|
|
m_type = CV_32FC3; |
|
|
|
|
m_hdr = true; |
|
|
|
@ -256,23 +295,23 @@ bool TiffDecoder::readHeader() |
|
|
|
|
switch(bpp) |
|
|
|
|
{ |
|
|
|
|
case 1: |
|
|
|
|
m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1); |
|
|
|
|
m_type = CV_MAKETYPE(CV_8U, !isGrayScale ? wanted_channels : 1); |
|
|
|
|
result = true; |
|
|
|
|
break; |
|
|
|
|
case 8: |
|
|
|
|
m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1); |
|
|
|
|
m_type = CV_MAKETYPE(CV_8U, !isGrayScale ? wanted_channels : 1); |
|
|
|
|
result = true; |
|
|
|
|
break; |
|
|
|
|
case 16: |
|
|
|
|
m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? wanted_channels : 1); |
|
|
|
|
m_type = CV_MAKETYPE(CV_16U, !isGrayScale ? wanted_channels : 1); |
|
|
|
|
result = true; |
|
|
|
|
break; |
|
|
|
|
case 32: |
|
|
|
|
m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1); |
|
|
|
|
m_type = CV_MAKETYPE(CV_32F, wanted_channels); |
|
|
|
|
result = true; |
|
|
|
|
break; |
|
|
|
|
case 64: |
|
|
|
|
m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1); |
|
|
|
|
m_type = CV_MAKETYPE(CV_64F, wanted_channels); |
|
|
|
|
result = true; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
@ -290,206 +329,210 @@ bool TiffDecoder::readHeader() |
|
|
|
|
bool TiffDecoder::nextPage() |
|
|
|
|
{ |
|
|
|
|
// Prepare the next page, if any.
|
|
|
|
|
return m_tif && |
|
|
|
|
TIFFReadDirectory(static_cast<TIFF*>(m_tif)) && |
|
|
|
|
return !m_tif.empty() && |
|
|
|
|
TIFFReadDirectory(static_cast<TIFF*>(m_tif.get())) && |
|
|
|
|
readHeader(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool TiffDecoder::readData( Mat& img ) |
|
|
|
|
{ |
|
|
|
|
if(m_hdr && img.type() == CV_32FC3) |
|
|
|
|
{ |
|
|
|
|
return readData_32FC3(img); |
|
|
|
|
} |
|
|
|
|
if(img.type() == CV_32FC1) |
|
|
|
|
int type_ = img.type(); |
|
|
|
|
int depth = CV_MAT_DEPTH(type_); |
|
|
|
|
|
|
|
|
|
CV_Assert(!m_tif.empty()); |
|
|
|
|
TIFF* tif = (TIFF*)m_tif.get(); |
|
|
|
|
|
|
|
|
|
uint16 photometric = (uint16)-1; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)); |
|
|
|
|
|
|
|
|
|
if (m_hdr && depth >= CV_32F) |
|
|
|
|
{ |
|
|
|
|
return readData_32FC1(img); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT)); |
|
|
|
|
} |
|
|
|
|
bool result = false; |
|
|
|
|
|
|
|
|
|
bool color = img.channels() > 1; |
|
|
|
|
|
|
|
|
|
if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F ) |
|
|
|
|
return false; |
|
|
|
|
CV_CheckType(type_, depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F, ""); |
|
|
|
|
|
|
|
|
|
if( m_tif && m_width && m_height ) |
|
|
|
|
if (m_width && m_height) |
|
|
|
|
{ |
|
|
|
|
TIFF* tif = (TIFF*)m_tif; |
|
|
|
|
uint32 tile_width0 = m_width, tile_height0 = 0; |
|
|
|
|
int x, y, i; |
|
|
|
|
int is_tiled = TIFFIsTiled(tif); |
|
|
|
|
uint16 photometric; |
|
|
|
|
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ); |
|
|
|
|
uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1; |
|
|
|
|
TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); |
|
|
|
|
TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); |
|
|
|
|
int is_tiled = TIFFIsTiled(tif) != 0; |
|
|
|
|
bool isGrayScale = photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK; |
|
|
|
|
uint16 bpp = 8, ncn = isGrayScale ? 1 : 3; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp)); |
|
|
|
|
CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &ncn)); |
|
|
|
|
uint16 img_orientation = ORIENTATION_TOPLEFT; |
|
|
|
|
TIFFGetField( tif, TIFFTAG_ORIENTATION, &img_orientation); |
|
|
|
|
CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_ORIENTATION, &img_orientation)); |
|
|
|
|
bool vert_flip = (img_orientation == ORIENTATION_BOTRIGHT) || (img_orientation == ORIENTATION_RIGHTBOT) || |
|
|
|
|
(img_orientation == ORIENTATION_BOTLEFT) || (img_orientation == ORIENTATION_LEFTBOT); |
|
|
|
|
const int bitsPerByte = 8; |
|
|
|
|
int dst_bpp = (int)(img.elemSize1() * bitsPerByte); |
|
|
|
|
int wanted_channels = normalizeChannelsNumber(img.channels()); |
|
|
|
|
|
|
|
|
|
if(dst_bpp == 8) |
|
|
|
|
if (dst_bpp == 8) |
|
|
|
|
{ |
|
|
|
|
char errmsg[1024]; |
|
|
|
|
if(!TIFFRGBAImageOK( tif, errmsg )) |
|
|
|
|
if (!TIFFRGBAImageOK(tif, errmsg)) |
|
|
|
|
{ |
|
|
|
|
CV_LOG_WARNING(NULL, "OpenCV TIFF: TIFFRGBAImageOK: " << errmsg); |
|
|
|
|
close(); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if( (!is_tiled) || |
|
|
|
|
(is_tiled && |
|
|
|
|
TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) && |
|
|
|
|
TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 ))) |
|
|
|
|
uint32 tile_width0 = m_width, tile_height0 = 0; |
|
|
|
|
|
|
|
|
|
if (is_tiled) |
|
|
|
|
{ |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width0)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height0)); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if(!is_tiled) |
|
|
|
|
TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 ); |
|
|
|
|
// optional
|
|
|
|
|
CV_TIFF_CHECK_CALL_DEBUG(TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &tile_height0)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if( tile_width0 <= 0 ) |
|
|
|
|
{ |
|
|
|
|
if (tile_width0 == 0) |
|
|
|
|
tile_width0 = m_width; |
|
|
|
|
|
|
|
|
|
if( tile_height0 <= 0 || |
|
|
|
|
(!is_tiled && tile_height0 == std::numeric_limits<uint32>::max()) ) |
|
|
|
|
if (tile_height0 == 0 || |
|
|
|
|
(!is_tiled && tile_height0 == std::numeric_limits<uint32>::max()) ) |
|
|
|
|
tile_height0 = m_height; |
|
|
|
|
|
|
|
|
|
if(dst_bpp == 8) { |
|
|
|
|
if (dst_bpp == 8) |
|
|
|
|
{ |
|
|
|
|
// we will use TIFFReadRGBA* functions, so allocate temporary buffer for 32bit RGBA
|
|
|
|
|
bpp = 8; |
|
|
|
|
ncn = 4; |
|
|
|
|
} |
|
|
|
|
const size_t buffer_size = (bpp/bitsPerByte) * ncn * tile_height0 * tile_width0; |
|
|
|
|
AutoBuffer<uchar> _buffer( buffer_size ); |
|
|
|
|
else if (dst_bpp == 32 || dst_bpp == 64) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(ncn == img.channels()); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP)); |
|
|
|
|
} |
|
|
|
|
const size_t buffer_size = (bpp / bitsPerByte) * ncn * tile_height0 * tile_width0; |
|
|
|
|
AutoBuffer<uchar> _buffer(buffer_size); |
|
|
|
|
uchar* buffer = _buffer.data(); |
|
|
|
|
ushort* buffer16 = (ushort*)buffer; |
|
|
|
|
float* buffer32 = (float*)buffer; |
|
|
|
|
double* buffer64 = (double*)buffer; |
|
|
|
|
int tileidx = 0; |
|
|
|
|
|
|
|
|
|
for( y = 0; y < m_height; y += tile_height0 ) |
|
|
|
|
for (int y = 0; y < m_height; y += (int)tile_height0) |
|
|
|
|
{ |
|
|
|
|
int tile_height = tile_height0; |
|
|
|
|
|
|
|
|
|
if( y + tile_height > m_height ) |
|
|
|
|
tile_height = m_height - y; |
|
|
|
|
int tile_height = std::min((int)tile_height0, m_height - y); |
|
|
|
|
|
|
|
|
|
uchar* data = img.ptr(vert_flip ? m_height - y - tile_height : y); |
|
|
|
|
const int img_y = vert_flip ? m_height - y - tile_height : y; |
|
|
|
|
|
|
|
|
|
for( x = 0; x < m_width; x += tile_width0, tileidx++ ) |
|
|
|
|
for(int x = 0; x < m_width; x += (int)tile_width0, tileidx++) |
|
|
|
|
{ |
|
|
|
|
int tile_width = tile_width0, ok; |
|
|
|
|
int tile_width = std::min((int)tile_width0, m_width - x); |
|
|
|
|
|
|
|
|
|
if( x + tile_width > m_width ) |
|
|
|
|
tile_width = m_width - x; |
|
|
|
|
|
|
|
|
|
switch(dst_bpp) |
|
|
|
|
switch (dst_bpp) |
|
|
|
|
{ |
|
|
|
|
case 8: |
|
|
|
|
{ |
|
|
|
|
uchar * bstart = buffer; |
|
|
|
|
if( !is_tiled ) |
|
|
|
|
ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer ); |
|
|
|
|
else |
|
|
|
|
uchar* bstart = buffer; |
|
|
|
|
if (!is_tiled) |
|
|
|
|
{ |
|
|
|
|
ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer ); |
|
|
|
|
//Tiles fill the buffer from the bottom up
|
|
|
|
|
bstart += (tile_height0 - tile_height) * tile_width0 * 4; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFReadRGBAStrip(tif, y, (uint32*)buffer)); |
|
|
|
|
} |
|
|
|
|
if( !ok ) |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
|
return false; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFReadRGBATile(tif, x, y, (uint32*)buffer)); |
|
|
|
|
// Tiles fill the buffer from the bottom up
|
|
|
|
|
bstart += (tile_height0 - tile_height) * tile_width0 * 4; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for( i = 0; i < tile_height; i++ ) |
|
|
|
|
if( color ) |
|
|
|
|
for (int i = 0; i < tile_height; i++) |
|
|
|
|
{ |
|
|
|
|
if (color) |
|
|
|
|
{ |
|
|
|
|
if (wanted_channels == 4) |
|
|
|
|
{ |
|
|
|
|
icvCvt_BGRA2RGBA_8u_C4R( bstart + i*tile_width0*4, 0, |
|
|
|
|
data + x*4 + img.step*(tile_height - i - 1), 0, |
|
|
|
|
cvSize(tile_width,1) ); |
|
|
|
|
icvCvt_BGRA2RGBA_8u_C4R(bstart + i*tile_width0*4, 0, |
|
|
|
|
img.ptr(img_y + tile_height - i - 1, x), 0, |
|
|
|
|
Size(tile_width, 1) ); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0, |
|
|
|
|
data + x*3 + img.step*(tile_height - i - 1), 0, |
|
|
|
|
cvSize(tile_width,1), 2 ); |
|
|
|
|
icvCvt_BGRA2BGR_8u_C4C3R(bstart + i*tile_width0*4, 0, |
|
|
|
|
img.ptr(img_y + tile_height - i - 1, x), 0, |
|
|
|
|
Size(tile_width, 1), 2); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0, |
|
|
|
|
data + x + img.step*(tile_height - i - 1), 0, |
|
|
|
|
cvSize(tile_width,1), 2 ); |
|
|
|
|
img.ptr(img_y + tile_height - i - 1, x), 0, |
|
|
|
|
Size(tile_width, 1), 2); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case 16: |
|
|
|
|
{ |
|
|
|
|
if( !is_tiled ) |
|
|
|
|
ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0; |
|
|
|
|
if (!is_tiled) |
|
|
|
|
{ |
|
|
|
|
CV_TIFF_CHECK_CALL((int)TIFFReadEncodedStrip(tif, tileidx, (uint32*)buffer, buffer_size) >= 0); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0; |
|
|
|
|
|
|
|
|
|
if( !ok ) |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
|
return false; |
|
|
|
|
CV_TIFF_CHECK_CALL((int)TIFFReadEncodedTile(tif, tileidx, (uint32*)buffer, buffer_size) >= 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for( i = 0; i < tile_height; i++ ) |
|
|
|
|
for (int i = 0; i < tile_height; i++) |
|
|
|
|
{ |
|
|
|
|
if( color ) |
|
|
|
|
if (color) |
|
|
|
|
{ |
|
|
|
|
if( ncn == 1 ) |
|
|
|
|
if (ncn == 1) |
|
|
|
|
{ |
|
|
|
|
icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0, |
|
|
|
|
(ushort*)(data + img.step*i) + x*3, 0, |
|
|
|
|
cvSize(tile_width,1) ); |
|
|
|
|
img.ptr<ushort>(img_y + i, x), 0, |
|
|
|
|
Size(tile_width, 1)); |
|
|
|
|
} |
|
|
|
|
else if( ncn == 3 ) |
|
|
|
|
else if (ncn == 3) |
|
|
|
|
{ |
|
|
|
|
icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0, |
|
|
|
|
(ushort*)(data + img.step*i) + x*3, 0, |
|
|
|
|
cvSize(tile_width,1) ); |
|
|
|
|
img.ptr<ushort>(img_y + i, x), 0, |
|
|
|
|
Size(tile_width, 1)); |
|
|
|
|
} |
|
|
|
|
else if (ncn == 4) |
|
|
|
|
{ |
|
|
|
|
if (wanted_channels == 4) |
|
|
|
|
{ |
|
|
|
|
icvCvt_BGRA2RGBA_16u_C4R(buffer16 + i*tile_width0*ncn, 0, |
|
|
|
|
(ushort*)(data + img.step*i) + x * 4, 0, |
|
|
|
|
cvSize(tile_width, 1)); |
|
|
|
|
img.ptr<ushort>(img_y + i, x), 0, |
|
|
|
|
Size(tile_width, 1)); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0, |
|
|
|
|
(ushort*)(data + img.step*i) + x * 3, 0, |
|
|
|
|
cvSize(tile_width, 1), 2); |
|
|
|
|
img.ptr<ushort>(img_y + i, x), 0, |
|
|
|
|
Size(tile_width, 1), 2); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0, |
|
|
|
|
(ushort*)(data + img.step*i) + x*3, 0, |
|
|
|
|
cvSize(tile_width,1), 2 ); |
|
|
|
|
img.ptr<ushort>(img_y + i, x), 0, |
|
|
|
|
Size(tile_width, 1), 2); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if( ncn == 1 ) |
|
|
|
|
{ |
|
|
|
|
memcpy((ushort*)(data + img.step*i)+x, |
|
|
|
|
memcpy(img.ptr<ushort>(img_y + i, x), |
|
|
|
|
buffer16 + i*tile_width0*ncn, |
|
|
|
|
tile_width*sizeof(buffer16[0])); |
|
|
|
|
tile_width*sizeof(ushort)); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0, |
|
|
|
|
(ushort*)(data + img.step*i) + x, 0, |
|
|
|
|
cvSize(tile_width,1), ncn, 2 ); |
|
|
|
|
img.ptr<ushort>(img_y + i, x), 0, |
|
|
|
|
Size(tile_width, 1), ncn, 2); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -500,120 +543,43 @@ bool TiffDecoder::readData( Mat& img ) |
|
|
|
|
case 64: |
|
|
|
|
{ |
|
|
|
|
if( !is_tiled ) |
|
|
|
|
ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, buffer_size ) >= 0; |
|
|
|
|
else |
|
|
|
|
ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, buffer_size ) >= 0; |
|
|
|
|
|
|
|
|
|
if( !ok || ncn != 1 ) |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
|
return false; |
|
|
|
|
CV_TIFF_CHECK_CALL((int)TIFFReadEncodedStrip(tif, tileidx, buffer, buffer_size) >= 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for( i = 0; i < tile_height; i++ ) |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if(dst_bpp == 32) |
|
|
|
|
{ |
|
|
|
|
memcpy((float*)(data + img.step*i)+x, |
|
|
|
|
buffer32 + i*tile_width0*ncn, |
|
|
|
|
tile_width*sizeof(buffer32[0])); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
memcpy((double*)(data + img.step*i)+x, |
|
|
|
|
buffer64 + i*tile_width0*ncn, |
|
|
|
|
tile_width*sizeof(buffer64[0])); |
|
|
|
|
} |
|
|
|
|
CV_TIFF_CHECK_CALL((int)TIFFReadEncodedTile(tif, tileidx, buffer, buffer_size) >= 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Mat m_tile(Size(tile_width0, tile_height0), CV_MAKETYPE((dst_bpp == 32) ? CV_32F : CV_64F, ncn), buffer); |
|
|
|
|
Rect roi_tile(0, 0, tile_width, tile_height); |
|
|
|
|
Rect roi_img(x, img_y, tile_width, tile_height); |
|
|
|
|
if (!m_hdr && ncn == 3) |
|
|
|
|
cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGB2BGR); |
|
|
|
|
else if (!m_hdr && ncn == 4) |
|
|
|
|
cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGBA2BGRA); |
|
|
|
|
else |
|
|
|
|
m_tile(roi_tile).copyTo(img(roi_img)); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
|
return false; |
|
|
|
|
CV_Assert(0 && "OpenCV TIFF: unsupported depth"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
result = true; |
|
|
|
|
} // switch (dst_bpp)
|
|
|
|
|
} // for x
|
|
|
|
|
} // for y
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool TiffDecoder::readData_32FC3(Mat& img) |
|
|
|
|
{ |
|
|
|
|
int rows_per_strip = 0, photometric = 0; |
|
|
|
|
if(!m_tif) |
|
|
|
|
{ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
TIFF *tif = static_cast<TIFF*>(m_tif); |
|
|
|
|
TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); |
|
|
|
|
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT); |
|
|
|
|
int size = 3 * m_width * m_height * sizeof (float); |
|
|
|
|
tstrip_t strip_size = 3 * m_width * rows_per_strip; |
|
|
|
|
float *ptr = img.ptr<float>(); |
|
|
|
|
for (tstrip_t i = 0; i < TIFFNumberOfStrips(tif); i++, ptr += strip_size) |
|
|
|
|
{ |
|
|
|
|
TIFFReadEncodedStrip(tif, i, ptr, size); |
|
|
|
|
size -= strip_size * sizeof(float); |
|
|
|
|
} |
|
|
|
|
close(); |
|
|
|
|
if(photometric == PHOTOMETRIC_LOGLUV) |
|
|
|
|
if (m_hdr && depth >= CV_32F) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(photometric == PHOTOMETRIC_LOGLUV); |
|
|
|
|
cvtColor(img, img, COLOR_XYZ2BGR); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
cvtColor(img, img, COLOR_RGB2BGR); |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool TiffDecoder::readData_32FC1(Mat& img) |
|
|
|
|
{ |
|
|
|
|
if(!m_tif) |
|
|
|
|
{ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
TIFF *tif = static_cast<TIFF*>(m_tif); |
|
|
|
|
|
|
|
|
|
uint32 img_width, img_height; |
|
|
|
|
TIFFGetField(tif,TIFFTAG_IMAGEWIDTH, &img_width); |
|
|
|
|
TIFFGetField(tif,TIFFTAG_IMAGELENGTH, &img_height); |
|
|
|
|
if(img.size() != Size(img_width,img_height)) |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
tsize_t scanlength = TIFFScanlineSize(tif); |
|
|
|
|
tdata_t buf = _TIFFmalloc(scanlength); |
|
|
|
|
float* data; |
|
|
|
|
bool result = true; |
|
|
|
|
for (uint32 row = 0; row < img_height; row++) |
|
|
|
|
{ |
|
|
|
|
if (TIFFReadScanline(tif, buf, row) != 1) |
|
|
|
|
{ |
|
|
|
|
result = false; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
data=(float*)buf; |
|
|
|
|
for (uint32 i=0; i<img_width; i++) |
|
|
|
|
{ |
|
|
|
|
img.at<float>(row,i) = data[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_TIFFfree(buf); |
|
|
|
|
close(); |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
TiffEncoder::TiffEncoder() |
|
|
|
@ -633,7 +599,7 @@ ImageEncoder TiffEncoder::newEncoder() const |
|
|
|
|
|
|
|
|
|
bool TiffEncoder::isFormatSupported( int depth ) const |
|
|
|
|
{ |
|
|
|
|
return depth == CV_8U || depth == CV_16U || depth == CV_32F; |
|
|
|
|
return depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag, |
|
|
|
@ -656,6 +622,8 @@ public: |
|
|
|
|
|
|
|
|
|
TIFF* open () |
|
|
|
|
{ |
|
|
|
|
// 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
|
|
|
|
|
return TIFFClientOpen( "", "w", reinterpret_cast<thandle_t>(this), &TiffEncoderBufHelper::read, |
|
|
|
|
&TiffEncoderBufHelper::write, &TiffEncoderBufHelper::seek, |
|
|
|
|
&TiffEncoderBufHelper::close, &TiffEncoderBufHelper::size, |
|
|
|
@ -721,35 +689,39 @@ private: |
|
|
|
|
toff_t m_buf_pos; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void readParam(const std::vector<int>& params, int key, int& value) |
|
|
|
|
static bool readParam(const std::vector<int>& params, int key, int& value) |
|
|
|
|
{ |
|
|
|
|
for(size_t i = 0; i + 1 < params.size(); i += 2) |
|
|
|
|
if(params[i] == key) |
|
|
|
|
for (size_t i = 0; i + 1 < params.size(); i += 2) |
|
|
|
|
{ |
|
|
|
|
if (params[i] == key) |
|
|
|
|
{ |
|
|
|
|
value = params[i+1]; |
|
|
|
|
break; |
|
|
|
|
value = params[i + 1]; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
TIFF* tif = NULL; |
|
|
|
|
|
|
|
|
|
TiffEncoderBufHelper buf_helper(m_buf); |
|
|
|
|
if ( m_buf ) |
|
|
|
|
{ |
|
|
|
|
pTiffHandle = buf_helper.open(); |
|
|
|
|
tif = buf_helper.open(); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
pTiffHandle = TIFFOpen(m_filename.c_str(), "w"); |
|
|
|
|
tif = TIFFOpen(m_filename.c_str(), "w"); |
|
|
|
|
} |
|
|
|
|
if (!pTiffHandle) |
|
|
|
|
if (!tif) |
|
|
|
|
{ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
cv::Ptr<void> tif_cleanup(tif, cv_tiffCloseHandle); |
|
|
|
|
|
|
|
|
|
//Settings that matter to all images
|
|
|
|
|
int compression = COMPRESSION_LZW; |
|
|
|
@ -768,7 +740,29 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect |
|
|
|
|
const Mat& img = img_vec[page]; |
|
|
|
|
int channels = img.channels(); |
|
|
|
|
int width = img.cols, height = img.rows; |
|
|
|
|
int depth = img.depth(); |
|
|
|
|
int type = img.type(); |
|
|
|
|
int depth = CV_MAT_DEPTH(type); |
|
|
|
|
CV_CheckType(type, depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F, ""); |
|
|
|
|
CV_CheckType(type, channels >= 1 && channels <= 4, ""); |
|
|
|
|
|
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height)); |
|
|
|
|
|
|
|
|
|
if (img_vec.size() > 1) |
|
|
|
|
{ |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PAGENUMBER, page, img_vec.size())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int compression_param = -1; // OPENCV_FUTURE
|
|
|
|
|
if (type == CV_32FC3 && (!readParam(params, IMWRITE_TIFF_COMPRESSION, compression_param) || compression_param == COMPRESSION_SGILOG)) |
|
|
|
|
{ |
|
|
|
|
if (!write_32FC3_SGILOG(img, tif)) |
|
|
|
|
return false; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int page_compression = compression; |
|
|
|
|
|
|
|
|
|
int bitsPerChannel = -1; |
|
|
|
|
switch (depth) |
|
|
|
@ -783,9 +777,20 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect |
|
|
|
|
bitsPerChannel = 16; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case CV_32F: |
|
|
|
|
{ |
|
|
|
|
bitsPerChannel = 32; |
|
|
|
|
page_compression = COMPRESSION_NONE; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case CV_64F: |
|
|
|
|
{ |
|
|
|
|
bitsPerChannel = 64; |
|
|
|
|
page_compression = COMPRESSION_NONE; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -795,57 +800,42 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect |
|
|
|
|
|
|
|
|
|
int rowsPerStrip = (int)((1 << 13) / fileStep); |
|
|
|
|
readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip); |
|
|
|
|
rowsPerStrip = std::max(1, std::min(height, rowsPerStrip)); |
|
|
|
|
|
|
|
|
|
int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK; |
|
|
|
|
|
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_COMPRESSION, page_compression)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, colorspace)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, 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() ))) |
|
|
|
|
) |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, depth >= CV_32F ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT)); |
|
|
|
|
|
|
|
|
|
if (page_compression != COMPRESSION_NONE) |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor)) |
|
|
|
|
if (resUnit >= RESUNIT_NONE && resUnit <= RESUNIT_CENTIMETER) |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, resUnit)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (((resUnit >= RESUNIT_NONE && resUnit <= RESUNIT_CENTIMETER) && !TIFFSetField(pTiffHandle, TIFFTAG_RESOLUTIONUNIT, resUnit)) |
|
|
|
|
|| (dpiX >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_XRESOLUTION, (float)dpiX)) |
|
|
|
|
|| (dpiY >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_YRESOLUTION, (float)dpiY)) |
|
|
|
|
) |
|
|
|
|
if (dpiX >= 0) |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)dpiX)); |
|
|
|
|
} |
|
|
|
|
if (dpiY >= 0) |
|
|
|
|
{ |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)dpiY)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// row buffer, because TIFFWriteScanline modifies the original data!
|
|
|
|
|
size_t scanlineSize = TIFFScanlineSize(pTiffHandle); |
|
|
|
|
size_t scanlineSize = TIFFScanlineSize(tif); |
|
|
|
|
AutoBuffer<uchar> _buffer(scanlineSize + 32); |
|
|
|
|
uchar* buffer = _buffer.data(); |
|
|
|
|
if (!buffer) |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
uchar* buffer = _buffer.data(); CV_DbgAssert(buffer); |
|
|
|
|
Mat m_buffer(Size(width, 1), CV_MAKETYPE(depth, channels), buffer, (size_t)scanlineSize); |
|
|
|
|
|
|
|
|
|
for (int y = 0; y < height; ++y) |
|
|
|
|
{ |
|
|
|
@ -859,122 +849,54 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect |
|
|
|
|
|
|
|
|
|
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)); |
|
|
|
|
cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGR2RGB); |
|
|
|
|
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)); |
|
|
|
|
cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGRA2RGBA); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
CV_Assert(0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0); |
|
|
|
|
if (writeResult != 1) |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFWriteScanline(tif, buffer, y, 0) == 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TIFFWriteDirectory(pTiffHandle); |
|
|
|
|
|
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFWriteDirectory(tif)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool TiffEncoder::write_32FC3(const Mat& _img) |
|
|
|
|
bool TiffEncoder::write_32FC3_SGILOG(const Mat& _img, void* tif_) |
|
|
|
|
{ |
|
|
|
|
TIFF* tif = (TIFF*)tif_; |
|
|
|
|
CV_Assert(tif); |
|
|
|
|
|
|
|
|
|
Mat img; |
|
|
|
|
cvtColor(_img, img, COLOR_BGR2XYZ); |
|
|
|
|
|
|
|
|
|
TIFF* tif; |
|
|
|
|
|
|
|
|
|
TiffEncoderBufHelper buf_helper(m_buf); |
|
|
|
|
if ( m_buf ) |
|
|
|
|
{ |
|
|
|
|
tif = buf_helper.open(); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
tif = TIFFOpen(m_filename.c_str(), "w"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!tif) |
|
|
|
|
{ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); |
|
|
|
|
int strip_size = 3 * img.cols; |
|
|
|
|
float *ptr = const_cast<float*>(img.ptr<float>()); |
|
|
|
|
for (int i = 0; i < img.rows; i++, ptr += strip_size) |
|
|
|
|
{ |
|
|
|
|
TIFFWriteEncodedStrip(tif, i, ptr, strip_size * sizeof(float)); |
|
|
|
|
} |
|
|
|
|
TIFFClose(tif); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool TiffEncoder::write_32FC1(const Mat& _img) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
TIFF* tif; |
|
|
|
|
|
|
|
|
|
TiffEncoderBufHelper buf_helper(m_buf); |
|
|
|
|
if ( m_buf ) |
|
|
|
|
{ |
|
|
|
|
tif = buf_helper.open(); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
tif = TIFFOpen(m_filename.c_str(), "w"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!tif) |
|
|
|
|
{ |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, _img.cols); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, _img.rows); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); |
|
|
|
|
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); |
|
|
|
|
for (uint32 row = 0; row < (uint32)_img.rows; row++) |
|
|
|
|
{ |
|
|
|
|
if (TIFFWriteScanline(tif, (tdata_t)_img.ptr<float>(row), row, 1) != 1) |
|
|
|
|
{ |
|
|
|
|
TIFFClose(tif); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
TIFFWriteDirectory(tif); |
|
|
|
|
TIFFClose(tif); |
|
|
|
|
|
|
|
|
|
//done by caller: CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols));
|
|
|
|
|
//done by caller: CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows));
|
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT)); |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1)); |
|
|
|
|
const int strip_size = 3 * img.cols; |
|
|
|
|
for (int i = 0; i < img.rows; i++) |
|
|
|
|
{ |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFWriteEncodedStrip(tif, i, (tdata_t)img.ptr<float>(i), strip_size * sizeof(float)) != (tsize_t)-1); |
|
|
|
|
} |
|
|
|
|
CV_TIFF_CHECK_CALL(TIFFWriteDirectory(tif)); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -985,18 +907,10 @@ bool TiffEncoder::writemulti(const std::vector<Mat>& img_vec, const std::vector< |
|
|
|
|
|
|
|
|
|
bool TiffEncoder::write( const Mat& img, const std::vector<int>& params) |
|
|
|
|
{ |
|
|
|
|
int depth = img.depth(); |
|
|
|
|
|
|
|
|
|
if(img.type() == CV_32FC3) |
|
|
|
|
{ |
|
|
|
|
return write_32FC3(img); |
|
|
|
|
} |
|
|
|
|
if(img.type() == CV_32FC1) |
|
|
|
|
{ |
|
|
|
|
return write_32FC1(img); |
|
|
|
|
} |
|
|
|
|
int type = img.type(); |
|
|
|
|
int depth = CV_MAT_DEPTH(type); |
|
|
|
|
|
|
|
|
|
CV_Assert(depth == CV_8U || depth == CV_16U); |
|
|
|
|
CV_CheckType(type, depth == CV_8U || depth == CV_16U || depth == CV_32F || depth == CV_64F, ""); |
|
|
|
|
|
|
|
|
|
std::vector<Mat> img_vec; |
|
|
|
|
img_vec.push_back(img); |
|
|
|
|