1
0
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:
Kumataro
2024-11-25 17:04:54 +09:00
committed by GitHub
parent 6e229bda2b
commit f7483cd978
3 changed files with 69 additions and 28 deletions
@@ -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
+62 -27
View File
@@ -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 );
+3
View File
@@ -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
};