mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Merge pull request #26508 from Kumataro:fix26507
Support CV_32U, CV_64U and CV_64S for TIFF #26508 Close https://github.com/opencv/opencv/issues/26507 Note: Predictor 2 for 64-bit is only supported after libtiff 4.4.0. But Linux x64 Debug uses libtiff 4.1.0 (releases at 2019/11/3). I append fallback fix to NONE. I hope It works well. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -332,7 +332,10 @@ can be saved using this function, with these exceptions:
|
||||
8-bit (or 16-bit) 4-channel image BGRA, where the alpha channel goes last. Fully transparent pixels
|
||||
should have alpha set to 0, fully opaque pixels should have alpha set to 255/65535 (see the code sample below).
|
||||
- With PGM/PPM encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- With TIFF encoder, 8-bit unsigned (CV_8U), 16-bit unsigned (CV_16U),
|
||||
- With TIFF encoder, 8-bit unsigned (CV_8U), 8-bit signed (CV_8S),
|
||||
16-bit unsigned (CV_16U), 16-bit signed (CV_16S),
|
||||
32-bit unsigned (CV_32U), 32-bit signed (CV_32S),
|
||||
64-bit unsigned (CV_64U), 64-bit signed (CV_64S),
|
||||
32-bit float (CV_32F) and 64-bit float (CV_64F) images can be saved.
|
||||
- Multiple images (vector of Mat) can be saved in TIFF format (see the code sample below).
|
||||
- 32-bit float 3-channel (CV_32FC3) TIFF images will be saved
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
|
||||
#include "tiff.h"
|
||||
#include "tiffio.h"
|
||||
#include "tiffvers.h" // For TIFFLIB_VERSION
|
||||
|
||||
namespace cv
|
||||
{
|
||||
@@ -344,17 +345,20 @@ bool TiffDecoder::readHeader()
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
CV_Check((int)sample_format, sample_format == SAMPLEFORMAT_IEEEFP || sample_format == SAMPLEFORMAT_INT, "");
|
||||
int depth = sample_format == SAMPLEFORMAT_IEEEFP ? CV_32F : CV_32S;
|
||||
CV_Check((int)sample_format, sample_format == SAMPLEFORMAT_IEEEFP || sample_format == SAMPLEFORMAT_UINT || sample_format == SAMPLEFORMAT_INT, "");
|
||||
int depth = sample_format == SAMPLEFORMAT_IEEEFP ? CV_32F : sample_format == SAMPLEFORMAT_INT ? CV_32S : CV_32U;
|
||||
m_type = CV_MAKETYPE(depth, wanted_channels);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
case 64:
|
||||
CV_CheckEQ((int)sample_format, SAMPLEFORMAT_IEEEFP, "");
|
||||
m_type = CV_MAKETYPE(CV_64F, wanted_channels);
|
||||
{
|
||||
CV_Check((int)sample_format, sample_format == SAMPLEFORMAT_IEEEFP || sample_format == SAMPLEFORMAT_UINT || sample_format == SAMPLEFORMAT_INT, "");
|
||||
int depth = sample_format == SAMPLEFORMAT_IEEEFP ? CV_64F : sample_format == SAMPLEFORMAT_INT ? CV_64S : CV_64U;
|
||||
m_type = CV_MAKETYPE(depth, wanted_channels);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CV_Error(cv::Error::StsError, "Invalid bitsperpixel value read from TIFF header! Must be 1, 8, 10, 12, 14, 16, 32 or 64.");
|
||||
}
|
||||
@@ -589,21 +593,24 @@ bool TiffDecoder::readData( Mat& img )
|
||||
int type = img.type();
|
||||
int depth = CV_MAT_DEPTH(type);
|
||||
|
||||
CV_CheckDepth(type, ( depth == CV_8U || depth == CV_8S ||
|
||||
depth == CV_16U || depth == CV_16S ||
|
||||
depth == CV_32U || depth == CV_32S ||
|
||||
depth == CV_64U || depth == CV_64S ||
|
||||
depth == CV_32F || depth == CV_64F), "Unsupported depth of image");
|
||||
|
||||
CV_Assert(!m_tif.empty());
|
||||
TIFF* tif = (TIFF*)m_tif.get();
|
||||
|
||||
uint16_t photometric = (uint16_t)-1;
|
||||
CV_TIFF_CHECK_CALL(TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric));
|
||||
|
||||
if (m_hdr && depth >= CV_32F)
|
||||
if (m_hdr && ((depth == CV_32F) || (depth == CV_64F)) )
|
||||
{
|
||||
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT));
|
||||
}
|
||||
|
||||
bool color = img.channels() > 1;
|
||||
|
||||
CV_CheckType(type, depth == CV_8U || depth == CV_8S || depth == CV_16U || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F, "");
|
||||
|
||||
if (m_width && m_height)
|
||||
{
|
||||
int is_tiled = TIFFIsTiled(tif) != 0;
|
||||
@@ -755,7 +762,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dst_bpp == 32 || dst_bpp == 64)
|
||||
else if (depth == CV_32F || depth == CV_64F)
|
||||
{
|
||||
CV_Assert(ncn == img.channels());
|
||||
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP));
|
||||
@@ -1038,7 +1045,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
CV_TIFF_CHECK_CALL((int)TIFFReadEncodedTile(tif, tileidx, src_buffer, src_buffer_size) >= 0);
|
||||
}
|
||||
|
||||
Mat m_tile(Size(tile_width0, tile_height0), CV_MAKETYPE((dst_bpp == 32) ? (depth == CV_32S ? CV_32S : CV_32F) : CV_64F, ncn), src_buffer);
|
||||
Mat m_tile(Size(tile_width0, tile_height0), CV_MAKETYPE(depth, ncn), src_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 && !m_use_rgb)
|
||||
@@ -1066,7 +1073,7 @@ bool TiffDecoder::readData( Mat& img )
|
||||
( ( dst_bpp != 8 ) && ( !doReadScanline ) ) );
|
||||
}
|
||||
|
||||
if (m_hdr && depth >= CV_32F)
|
||||
if (m_hdr && ((depth == CV_32F) || (depth == CV_64F)) )
|
||||
{
|
||||
CV_Assert(photometric == PHOTOMETRIC_LOGLUV);
|
||||
if (m_use_rgb)
|
||||
@@ -1097,7 +1104,11 @@ ImageEncoder TiffEncoder::newEncoder() const
|
||||
|
||||
bool TiffEncoder::isFormatSupported( int depth ) const
|
||||
{
|
||||
return depth == CV_8U || depth == CV_8S || depth == CV_16U || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F;
|
||||
return depth == CV_8U || depth == CV_8S ||
|
||||
depth == CV_16U || depth == CV_16S ||
|
||||
depth == CV_32U || depth == CV_32S ||
|
||||
depth == CV_64U || depth == CV_64S ||
|
||||
depth == CV_32F || depth == CV_64F;
|
||||
}
|
||||
|
||||
class TiffEncoderBufHelper
|
||||
@@ -1237,7 +1248,7 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
|
||||
int width = img.cols, height = img.rows;
|
||||
int type = img.type();
|
||||
int depth = CV_MAT_DEPTH(type);
|
||||
CV_CheckType(type, depth == CV_8U || depth == CV_8S || depth == CV_16U || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F, "");
|
||||
CV_CheckDepth(type, isFormatSupported(depth), "Unsupported depth of input image");
|
||||
CV_CheckType(type, channels >= 1 && channels <= 4, "");
|
||||
|
||||
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width));
|
||||
@@ -1281,12 +1292,34 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
|
||||
break;
|
||||
}
|
||||
|
||||
case CV_32U:
|
||||
{
|
||||
bitsPerChannel = 32;
|
||||
sample_format = SAMPLEFORMAT_UINT;
|
||||
break;
|
||||
}
|
||||
|
||||
case CV_32S:
|
||||
{
|
||||
bitsPerChannel = 32;
|
||||
sample_format = SAMPLEFORMAT_INT;
|
||||
break;
|
||||
}
|
||||
|
||||
case CV_64U:
|
||||
{
|
||||
bitsPerChannel = 64;
|
||||
sample_format = SAMPLEFORMAT_UINT;
|
||||
break;
|
||||
}
|
||||
|
||||
case CV_64S:
|
||||
{
|
||||
bitsPerChannel = 64;
|
||||
sample_format = SAMPLEFORMAT_INT;
|
||||
break;
|
||||
}
|
||||
|
||||
case CV_32F:
|
||||
{
|
||||
bitsPerChannel = 32;
|
||||
@@ -1307,6 +1340,16 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
|
||||
}
|
||||
}
|
||||
|
||||
// Predictor 2 for 64-bit is supported at v4.4.0 or later.
|
||||
// See https://libtiff.gitlab.io/libtiff/releases/v4.4.0.html
|
||||
#if TIFFLIB_VERSION < 20220520 /* Magic number of libtiff v4.4.0 */
|
||||
if ( (bitsPerChannel == 64) && (predictor == PREDICTOR_HORIZONTAL /* 2 */) )
|
||||
{
|
||||
CV_LOG_ONCE_WARNING(NULL, "Predictor 2(HORIZONTAL) for 64-bit is supported at v4.4.0 or later, so it is fallbacked to 0(NONE)");
|
||||
predictor = PREDICTOR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
const int bitsPerByte = 8;
|
||||
size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
|
||||
CV_Assert(fileStep > 0);
|
||||
@@ -1423,7 +1466,7 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
|
||||
int type = img.type();
|
||||
int depth = CV_MAT_DEPTH(type);
|
||||
|
||||
CV_CheckType(type, depth == CV_8U || depth == CV_8S || depth == CV_16U || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F, "");
|
||||
CV_CheckDepth(type, isFormatSupported(depth), "Unsupported depth of input image");
|
||||
|
||||
std::vector<Mat> img_vec;
|
||||
img_vec.push_back(img);
|
||||
@@ -1434,24 +1477,16 @@ static void extend_cvtColor( InputArray _src, OutputArray _dst, int code )
|
||||
{
|
||||
CV_Assert( !_src.empty() );
|
||||
CV_Assert( _src.dims() == 2 );
|
||||
CV_Assert( (code == COLOR_BGR2RGB) || (code == COLOR_BGRA2RGBA) );
|
||||
|
||||
// This function extend_cvtColor reorders the src channels with only thg limited condition.
|
||||
// Otherwise, it calls cvtColor.
|
||||
|
||||
const int stype = _src.type();
|
||||
if(!
|
||||
(
|
||||
(
|
||||
( stype == CV_8SC3 ) || ( stype == CV_8SC4 ) ||
|
||||
( stype == CV_16SC3 ) || ( stype == CV_16SC4 ) ||
|
||||
( stype == CV_32SC3 ) || ( stype == CV_32SC4 ) ||
|
||||
( stype == CV_64FC3 ) || ( stype == CV_64FC4 )
|
||||
)
|
||||
&&
|
||||
(
|
||||
( code == COLOR_BGR2RGB ) || ( code == COLOR_BGRA2RGBA )
|
||||
)
|
||||
)
|
||||
if(
|
||||
( stype == CV_8UC3 ) || ( stype == CV_8UC4 ) ||
|
||||
( stype == CV_16UC3 ) || ( stype == CV_16UC4 ) ||
|
||||
( stype == CV_32FC3 ) || ( stype == CV_32FC4 )
|
||||
)
|
||||
{
|
||||
cvtColor( _src, _dst, code );
|
||||
|
||||
@@ -951,7 +951,10 @@ Imgcodes_Tiff_TypeAndComp all_types[] = {
|
||||
{ CV_8SC1, true }, { CV_8SC3, true }, { CV_8SC4, true },
|
||||
{ CV_16UC1, true }, { CV_16UC3, true }, { CV_16UC4, true },
|
||||
{ CV_16SC1, true }, { CV_16SC3, true }, { CV_16SC4, true },
|
||||
{ CV_32UC1, true }, { CV_32UC3, true }, { CV_32UC4, true },
|
||||
{ CV_32SC1, true }, { CV_32SC3, true }, { CV_32SC4, true },
|
||||
{ CV_64UC1, true }, { CV_64UC3, true }, { CV_64UC4, true },
|
||||
{ CV_64SC1, true }, { CV_64SC3, true }, { CV_64SC4, true },
|
||||
{ CV_32FC1, false }, { CV_32FC3, false }, { CV_32FC4, false }, // No compression
|
||||
{ CV_64FC1, false }, { CV_64FC3, false }, { CV_64FC4, false } // No compression
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user