mirror of
https://github.com/opencv/opencv.git
synced 2025-01-19 06:53:50 +08:00
Merge pull request #23433 from Kumataro:4.x-fix23416
imgcodecs: tiff: Support to encode for CV_32S with compression params Fix https://github.com/opencv/opencv/issues/23416 ### 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. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
88a7e8cdf5
commit
d2dbaa4cd1
@ -63,6 +63,9 @@ using namespace tiff_dummy_namespace;
|
||||
namespace cv
|
||||
{
|
||||
|
||||
// to extend cvtColor() to support CV_8S, CV_16S, CV_32S and CV_64F.
|
||||
static void extend_cvtColor( InputArray _src, OutputArray _dst, int code );
|
||||
|
||||
#define CV_TIFF_CHECK_CALL(call) \
|
||||
if (0 == (call)) { \
|
||||
CV_LOG_WARNING(NULL, "OpenCV TIFF(line " << __LINE__ << "): failed " #call); \
|
||||
@ -1039,9 +1042,9 @@ bool TiffDecoder::readData( Mat& img )
|
||||
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);
|
||||
extend_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);
|
||||
extend_cvtColor(m_tile(roi_tile), img(roi_img), COLOR_RGBA2BGRA);
|
||||
else
|
||||
m_tile(roi_tile).copyTo(img(roi_img));
|
||||
break;
|
||||
@ -1279,13 +1282,17 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
|
||||
break;
|
||||
}
|
||||
|
||||
case CV_32F:
|
||||
sample_format = SAMPLEFORMAT_IEEEFP;
|
||||
/* FALLTHRU */
|
||||
case CV_32S:
|
||||
{
|
||||
bitsPerChannel = 32;
|
||||
sample_format = SAMPLEFORMAT_INT;
|
||||
break;
|
||||
}
|
||||
case CV_32F:
|
||||
{
|
||||
bitsPerChannel = 32;
|
||||
page_compression = COMPRESSION_NONE;
|
||||
sample_format = SAMPLEFORMAT_IEEEFP;
|
||||
break;
|
||||
}
|
||||
case CV_64F:
|
||||
@ -1356,13 +1363,13 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
|
||||
|
||||
case 3:
|
||||
{
|
||||
cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGR2RGB);
|
||||
extend_cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGR2RGB);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGRA2RGBA);
|
||||
extend_cvtColor(img(Rect(0, y, width, 1)), (const Mat&)m_buffer, COLOR_BGRA2RGBA);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1424,6 +1431,57 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
|
||||
return writeLibTiff(img_vec, params);
|
||||
}
|
||||
|
||||
static void extend_cvtColor( InputArray _src, OutputArray _dst, int code )
|
||||
{
|
||||
CV_Assert( !_src.empty() );
|
||||
CV_Assert( _src.dims() == 2 );
|
||||
|
||||
// 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 )
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
cvtColor( _src, _dst, code );
|
||||
return;
|
||||
}
|
||||
|
||||
Mat src = _src.getMat();
|
||||
|
||||
// cv::mixChannels requires the output arrays to be pre-allocated before calling the function.
|
||||
_dst.create( _src.size(), stype );
|
||||
Mat dst = _dst.getMat();
|
||||
|
||||
// BGR to RGB or BGRA to RGBA
|
||||
// src[0] -> dst[2]
|
||||
// src[1] -> dst[1]
|
||||
// src[2] -> dst[0]
|
||||
// src[3] -> dst[3] if src has alpha channel.
|
||||
std::vector<int> fromTo;
|
||||
fromTo.push_back(0); fromTo.push_back(2);
|
||||
fromTo.push_back(1); fromTo.push_back(1);
|
||||
fromTo.push_back(2); fromTo.push_back(0);
|
||||
if ( code == COLOR_BGRA2RGBA )
|
||||
{
|
||||
fromTo.push_back(3); fromTo.push_back(3);
|
||||
}
|
||||
|
||||
cv::mixChannels( src, dst, fromTo );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
@ -14,6 +14,38 @@ namespace opencv_test { namespace {
|
||||
#define int64 int64_hack_
|
||||
#include "tiff.h"
|
||||
|
||||
// Re-define Mat type as enum for showing on Google Test.
|
||||
enum CV_ddtCn{
|
||||
_CV_8UC1 = CV_8UC1, _CV_8UC3 = CV_8UC3, _CV_8UC4 = CV_8UC4,
|
||||
_CV_8SC1 = CV_8SC1, _CV_8SC3 = CV_8SC3, _CV_8SC4 = CV_8SC4,
|
||||
_CV_16UC1 = CV_16UC1, _CV_16UC3 = CV_16UC3, _CV_16UC4 = CV_16UC4,
|
||||
_CV_16SC1 = CV_16SC1, _CV_16SC3 = CV_16SC3, _CV_16SC4 = CV_16SC4,
|
||||
_CV_32SC1 = CV_32SC1, _CV_32SC3 = CV_32SC3, _CV_32SC4 = CV_32SC4,
|
||||
_CV_16FC1 = CV_16FC1, _CV_16FC3 = CV_16FC3, _CV_16FC4 = CV_16FC4,
|
||||
_CV_32FC1 = CV_32FC1, _CV_32FC3 = CV_32FC3, _CV_32FC4 = CV_32FC4,
|
||||
_CV_64FC1 = CV_64FC1, _CV_64FC3 = CV_64FC3, _CV_64FC4 = CV_64FC4,
|
||||
};
|
||||
|
||||
static inline
|
||||
void PrintTo(const CV_ddtCn& val, std::ostream* os)
|
||||
{
|
||||
const int val_type = static_cast<int>(val);
|
||||
|
||||
switch ( CV_MAT_DEPTH(val_type) )
|
||||
{
|
||||
case CV_8U : *os << "CV_8U" ; break;
|
||||
case CV_16U : *os << "CV_16U" ; break;
|
||||
case CV_8S : *os << "CV_8S" ; break;
|
||||
case CV_16S : *os << "CV_16S" ; break;
|
||||
case CV_32S : *os << "CV_32S" ; break;
|
||||
case CV_16F : *os << "CV_16F" ; break;
|
||||
case CV_32F : *os << "CV_32F" ; break;
|
||||
case CV_64F : *os << "CV_64F" ; break;
|
||||
default : *os << "CV_???" ; break;
|
||||
}
|
||||
*os << "C" << CV_MAT_CN(val_type);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Test disabled as it uses a lot of memory.
|
||||
// It is killed with SIGKILL by out of memory killer.
|
||||
@ -840,6 +872,69 @@ TEST(Imgcodecs_Tiff, readWrite_predictor)
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/23416
|
||||
|
||||
typedef std::pair<CV_ddtCn,bool> Imgcodes_Tiff_TypeAndComp;
|
||||
typedef testing::TestWithParam< Imgcodes_Tiff_TypeAndComp > Imgcodecs_Tiff_Types;
|
||||
|
||||
TEST_P(Imgcodecs_Tiff_Types, readWrite_alltypes)
|
||||
{
|
||||
const int mat_types = static_cast<int>(get<0>(GetParam()));
|
||||
const bool isCompAvailable = get<1>(GetParam());
|
||||
|
||||
// Create a test image.
|
||||
const Mat src = cv::Mat::zeros( 120, 160, mat_types );
|
||||
{
|
||||
// Add noise to test compression.
|
||||
cv::Mat roi = cv::Mat(src, cv::Rect(0, 0, src.cols, src.rows/2));
|
||||
cv::randu(roi, cv::Scalar(0), cv::Scalar(256));
|
||||
}
|
||||
|
||||
// Try to encode/decode the test image with LZW compression.
|
||||
std::vector<uchar> bufLZW;
|
||||
{
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_TIFF_COMPRESSION);
|
||||
params.push_back(COMPRESSION_LZW);
|
||||
ASSERT_NO_THROW(cv::imencode(".tiff", src, bufLZW, params));
|
||||
|
||||
Mat dstLZW;
|
||||
ASSERT_NO_THROW(cv::imdecode( bufLZW, IMREAD_UNCHANGED, &dstLZW));
|
||||
ASSERT_EQ(dstLZW.type(), src.type());
|
||||
ASSERT_EQ(dstLZW.size(), src.size());
|
||||
ASSERT_LE(cvtest::norm(dstLZW, src, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
}
|
||||
|
||||
// Try to encode/decode the test image with RAW.
|
||||
std::vector<uchar> bufRAW;
|
||||
{
|
||||
std::vector<int> params;
|
||||
params.push_back(IMWRITE_TIFF_COMPRESSION);
|
||||
params.push_back(COMPRESSION_NONE);
|
||||
ASSERT_NO_THROW(cv::imencode(".tiff", src, bufRAW, params));
|
||||
|
||||
Mat dstRAW;
|
||||
ASSERT_NO_THROW(cv::imdecode( bufRAW, IMREAD_UNCHANGED, &dstRAW));
|
||||
ASSERT_EQ(dstRAW.type(), src.type());
|
||||
ASSERT_EQ(dstRAW.size(), src.size());
|
||||
ASSERT_LE(cvtest::norm(dstRAW, src, NORM_INF | NORM_RELATIVE), 1e-3);
|
||||
}
|
||||
|
||||
// Compare LZW and RAW streams.
|
||||
EXPECT_EQ(bufLZW == bufRAW, !isCompAvailable);
|
||||
}
|
||||
|
||||
Imgcodes_Tiff_TypeAndComp all_types[] = {
|
||||
{ _CV_8UC1, true }, { _CV_8UC3, true }, { _CV_8UC4, true },
|
||||
{ _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_32SC1, true }, { _CV_32SC3, true }, { _CV_32SC4, true },
|
||||
{ _CV_32FC1, false }, { _CV_32FC3, false }, { _CV_32FC4, false }, // No compression
|
||||
{ _CV_64FC1, false }, { _CV_64FC3, false }, { _CV_64FC4, false } // No compression
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AllTypes, Imgcodecs_Tiff_Types, testing::ValuesIn(all_types));
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user