mirror of
https://github.com/opencv/opencv.git
synced 2025-06-08 01:53:19 +08:00
Merge pull request #22064 from Kumataro:3.4-fix22052
* imgcodecs: jpeg: add IMWRITE_JPEG_SAMPLING_FACTOR parameter * fix compile error * imgcodecs: jpeg: add CV_LOG_WARNING() and fix how to initilize Mat * imgcodecs: jpeg: fix for C++98 mode. * samples: imgcodec_jpeg: Remove license
This commit is contained in:
parent
9d06e58c3c
commit
dd7b9000ad
@ -89,6 +89,7 @@ enum ImwriteFlags {
|
|||||||
IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart.
|
IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart.
|
||||||
IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is -1 - don't use.
|
IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is -1 - don't use.
|
||||||
IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is -1 - don't use.
|
IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is -1 - don't use.
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR = 7, //!< For JPEG, set sampling factor. See cv::ImwriteJPEGSamplingFactorParams.
|
||||||
IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting).
|
IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting).
|
||||||
IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
|
IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
|
||||||
IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0.
|
IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0.
|
||||||
@ -102,12 +103,22 @@ enum ImwriteFlags {
|
|||||||
IMWRITE_TIFF_COMPRESSION = 259 //!< For TIFF, use to specify the image compression scheme. See libtiff for integer constants corresponding to compression formats. Note, for images whose depth is CV_32F, only libtiff's SGILOG compression scheme is used. For other supported depths, the compression scheme can be specified by this flag; LZW compression is the default.
|
IMWRITE_TIFF_COMPRESSION = 259 //!< For TIFF, use to specify the image compression scheme. See libtiff for integer constants corresponding to compression formats. Note, for images whose depth is CV_32F, only libtiff's SGILOG compression scheme is used. For other supported depths, the compression scheme can be specified by this flag; LZW compression is the default.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ImwriteJPEGSamplingFactorParams {
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_411 = 0x411111, //!< 4x1,1x1,1x1
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_420 = 0x221111, //!< 2x2,1x1,1x1(Default)
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_422 = 0x211111, //!< 2x1,1x1,1x1
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_440 = 0x121111, //!< 1x2,1x1,1x1
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_444 = 0x111111 //!< 1x1,1x1,1x1(No subsampling)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
enum ImwriteEXRTypeFlags {
|
enum ImwriteEXRTypeFlags {
|
||||||
/*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */
|
/*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */
|
||||||
IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16)
|
IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16)
|
||||||
IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default)
|
IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//! Imwrite PNG specific flags used to tune the compression algorithm.
|
//! Imwrite PNG specific flags used to tune the compression algorithm.
|
||||||
/** These flags will be modify the way of PNG image compression and will be passed to the underlying zlib processing stage.
|
/** These flags will be modify the way of PNG image compression and will be passed to the underlying zlib processing stage.
|
||||||
|
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
#ifdef HAVE_JPEG
|
#ifdef HAVE_JPEG
|
||||||
|
|
||||||
|
#include <opencv2/core/utils/logger.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
//interaction between '_setjmp' and C++ object destruction is non-portable
|
//interaction between '_setjmp' and C++ object destruction is non-portable
|
||||||
#pragma warning(disable: 4611)
|
#pragma warning(disable: 4611)
|
||||||
@ -640,6 +642,7 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
|
|||||||
int rst_interval = 0;
|
int rst_interval = 0;
|
||||||
int luma_quality = -1;
|
int luma_quality = -1;
|
||||||
int chroma_quality = -1;
|
int chroma_quality = -1;
|
||||||
|
uint32_t sampling_factor = 0; // same as 0x221111
|
||||||
|
|
||||||
for( size_t i = 0; i < params.size(); i += 2 )
|
for( size_t i = 0; i < params.size(); i += 2 )
|
||||||
{
|
{
|
||||||
@ -687,6 +690,27 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
|
|||||||
rst_interval = params[i+1];
|
rst_interval = params[i+1];
|
||||||
rst_interval = MIN(MAX(rst_interval, 0), 65535L);
|
rst_interval = MIN(MAX(rst_interval, 0), 65535L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( params[i] == IMWRITE_JPEG_SAMPLING_FACTOR )
|
||||||
|
{
|
||||||
|
sampling_factor = static_cast<uint32_t>(params[i+1]);
|
||||||
|
|
||||||
|
switch ( sampling_factor )
|
||||||
|
{
|
||||||
|
case IMWRITE_JPEG_SAMPLING_FACTOR_411:
|
||||||
|
case IMWRITE_JPEG_SAMPLING_FACTOR_420:
|
||||||
|
case IMWRITE_JPEG_SAMPLING_FACTOR_422:
|
||||||
|
case IMWRITE_JPEG_SAMPLING_FACTOR_440:
|
||||||
|
case IMWRITE_JPEG_SAMPLING_FACTOR_444:
|
||||||
|
// OK.
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CV_LOG_WARNING(NULL, cv::format("Unknown value for IMWRITE_JPEG_SAMPLING_FACTOR: 0x%06x", sampling_factor ) );
|
||||||
|
sampling_factor = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_set_defaults( &cinfo );
|
jpeg_set_defaults( &cinfo );
|
||||||
@ -699,6 +723,14 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
|
|||||||
if( optimize )
|
if( optimize )
|
||||||
cinfo.optimize_coding = TRUE;
|
cinfo.optimize_coding = TRUE;
|
||||||
|
|
||||||
|
if( (channels > 1) && ( sampling_factor != 0 ) )
|
||||||
|
{
|
||||||
|
cinfo.comp_info[0].v_samp_factor = (sampling_factor >> 16 ) & 0xF;
|
||||||
|
cinfo.comp_info[0].h_samp_factor = (sampling_factor >> 20 ) & 0xF;
|
||||||
|
cinfo.comp_info[1].v_samp_factor = 1;
|
||||||
|
cinfo.comp_info[1].h_samp_factor = 1;
|
||||||
|
}
|
||||||
|
|
||||||
#if JPEG_LIB_VERSION >= 70
|
#if JPEG_LIB_VERSION >= 70
|
||||||
if (luma_quality >= 0 && chroma_quality >= 0)
|
if (luma_quality >= 0 && chroma_quality >= 0)
|
||||||
{
|
{
|
||||||
|
@ -178,6 +178,98 @@ TEST(Imgcodecs_Jpeg, encode_decode_rst_jpeg)
|
|||||||
EXPECT_EQ(0, remove(output_normal.c_str()));
|
EXPECT_EQ(0, remove(output_normal.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
static const uint32_t default_sampling_factor = static_cast<uint32_t>(0x221111);
|
||||||
|
|
||||||
|
static uint32_t test_jpeg_subsampling( const Mat src, const vector<int> param )
|
||||||
|
{
|
||||||
|
vector<uint8_t> jpeg;
|
||||||
|
|
||||||
|
if ( cv::imencode(".jpg", src, jpeg, param ) == false )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( src.channels() != 3 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find SOF Marker(FFC0)
|
||||||
|
int sof_offset = 0; // not found.
|
||||||
|
int jpeg_size = static_cast<int>( jpeg.size() );
|
||||||
|
for ( int i = 0 ; i < jpeg_size - 1; i++ )
|
||||||
|
{
|
||||||
|
if ( (jpeg[i] == 0xff ) && ( jpeg[i+1] == 0xC0 ) )
|
||||||
|
{
|
||||||
|
sof_offset = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( sof_offset == 0 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract Subsampling Factor from SOF.
|
||||||
|
return ( jpeg[sof_offset + 0x0A + 3 * 0 + 1] << 16 ) +
|
||||||
|
( jpeg[sof_offset + 0x0A + 3 * 1 + 1] << 8 ) +
|
||||||
|
( jpeg[sof_offset + 0x0A + 3 * 2 + 1] ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Imgcodecs_Jpeg, encode_subsamplingfactor_default)
|
||||||
|
{
|
||||||
|
vector<int> param;
|
||||||
|
Mat src( 48, 64, CV_8UC3, cv::Scalar::all(0) );
|
||||||
|
EXPECT_EQ( default_sampling_factor, test_jpeg_subsampling(src, param) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Imgcodecs_Jpeg, encode_subsamplingfactor_usersetting_valid)
|
||||||
|
{
|
||||||
|
Mat src( 48, 64, CV_8UC3, cv::Scalar::all(0) );
|
||||||
|
const uint32_t sampling_factor_list[] = {
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_411,
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_420,
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_422,
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_440,
|
||||||
|
IMWRITE_JPEG_SAMPLING_FACTOR_444,
|
||||||
|
};
|
||||||
|
const int sampling_factor_list_num = 5;
|
||||||
|
|
||||||
|
for ( int i = 0 ; i < sampling_factor_list_num; i ++ )
|
||||||
|
{
|
||||||
|
vector<int> param;
|
||||||
|
param.push_back( IMWRITE_JPEG_SAMPLING_FACTOR );
|
||||||
|
param.push_back( sampling_factor_list[i] );
|
||||||
|
EXPECT_EQ( sampling_factor_list[i], test_jpeg_subsampling(src, param) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Imgcodecs_Jpeg, encode_subsamplingfactor_usersetting_invalid)
|
||||||
|
{
|
||||||
|
Mat src( 48, 64, CV_8UC3, cv::Scalar::all(0) );
|
||||||
|
const uint32_t sampling_factor_list[] = { // Invalid list
|
||||||
|
0x111112,
|
||||||
|
0x000000,
|
||||||
|
0x001111,
|
||||||
|
0xFF1111,
|
||||||
|
0x141111, // 1x4,1x1,1x1 - unknown
|
||||||
|
0x241111, // 2x4,1x1,1x1 - unknown
|
||||||
|
0x421111, // 4x2,1x1,1x1 - unknown
|
||||||
|
0x441111, // 4x4,1x1,1x1 - 410(libjpeg cannot handle it)
|
||||||
|
};
|
||||||
|
const int sampling_factor_list_num = 8;
|
||||||
|
|
||||||
|
for ( int i = 0 ; i < sampling_factor_list_num; i ++ )
|
||||||
|
{
|
||||||
|
vector<int> param;
|
||||||
|
param.push_back( IMWRITE_JPEG_SAMPLING_FACTOR );
|
||||||
|
param.push_back( sampling_factor_list[i] );
|
||||||
|
EXPECT_EQ( default_sampling_factor, test_jpeg_subsampling(src, param) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // HAVE_JPEG
|
#endif // HAVE_JPEG
|
||||||
|
|
||||||
}} // namespace
|
}} // namespace
|
||||||
|
82
samples/cpp/imgcodecs_jpeg.cpp
Normal file
82
samples/cpp/imgcodecs_jpeg.cpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#include <opencv2/core.hpp>
|
||||||
|
#include <opencv2/imgproc.hpp>
|
||||||
|
#include <opencv2/imgcodecs.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace cv;
|
||||||
|
|
||||||
|
int main(int /*argc*/, const char** /* argv */ )
|
||||||
|
{
|
||||||
|
Mat framebuffer( 160 * 2, 160 * 5, CV_8UC3, cv::Scalar::all(255) );
|
||||||
|
|
||||||
|
Mat img( 160, 160, CV_8UC3, cv::Scalar::all(255) );
|
||||||
|
|
||||||
|
// Create test image.
|
||||||
|
{
|
||||||
|
const Point center( img.rows / 2 , img.cols /2 );
|
||||||
|
|
||||||
|
for( int radius = 5; radius < img.rows ; radius += 3.5 )
|
||||||
|
{
|
||||||
|
cv::circle( img, center, radius, Scalar(255,0,255) );
|
||||||
|
}
|
||||||
|
cv::rectangle( img, Point(0,0), Point(img.rows-1, img.cols-1), Scalar::all(0), 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw original image(s).
|
||||||
|
int top = 0; // Upper images
|
||||||
|
{
|
||||||
|
for( int left = 0 ; left < img.rows * 5 ; left += img.rows ){
|
||||||
|
Mat roi = framebuffer( Rect( left, top, img.rows, img.cols ) );
|
||||||
|
img.copyTo(roi);
|
||||||
|
|
||||||
|
cv::putText( roi, "original", Point(5,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar::all(0), 2, 4, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw lossy images
|
||||||
|
top += img.cols; // Lower images
|
||||||
|
{
|
||||||
|
struct test_config{
|
||||||
|
string comment;
|
||||||
|
uint32_t sampling_factor;
|
||||||
|
} config [] = {
|
||||||
|
{ "411", IMWRITE_JPEG_SAMPLING_FACTOR_411 },
|
||||||
|
{ "420", IMWRITE_JPEG_SAMPLING_FACTOR_420 },
|
||||||
|
{ "422", IMWRITE_JPEG_SAMPLING_FACTOR_422 },
|
||||||
|
{ "440", IMWRITE_JPEG_SAMPLING_FACTOR_440 },
|
||||||
|
{ "444", IMWRITE_JPEG_SAMPLING_FACTOR_444 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const int config_num = 5;
|
||||||
|
|
||||||
|
int left = 0;
|
||||||
|
|
||||||
|
for ( int i = 0 ; i < config_num; i++ )
|
||||||
|
{
|
||||||
|
// Compress images with sampling factor parameter.
|
||||||
|
vector<int> param;
|
||||||
|
param.push_back( IMWRITE_JPEG_SAMPLING_FACTOR );
|
||||||
|
param.push_back( config[i].sampling_factor );
|
||||||
|
vector<uint8_t> jpeg;
|
||||||
|
(void) imencode(".jpg", img, jpeg, param );
|
||||||
|
|
||||||
|
// Decompress it.
|
||||||
|
Mat jpegMat(jpeg);
|
||||||
|
Mat lossy_img = imdecode(jpegMat, -1);
|
||||||
|
|
||||||
|
// Copy into framebuffer and comment
|
||||||
|
Mat roi = framebuffer( Rect( left, top, lossy_img.rows, lossy_img.cols ) );
|
||||||
|
lossy_img.copyTo(roi);
|
||||||
|
cv::putText( roi, config[i].comment, Point(5,155), FONT_HERSHEY_SIMPLEX, 0.5, Scalar::all(0), 2, 4, false );
|
||||||
|
|
||||||
|
left += lossy_img.rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output framebuffer(as lossless).
|
||||||
|
imwrite( "imgcodecs_jpeg_samplingfactor_result.png", framebuffer );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user