为什么 cv::imencode 为 bgr8 和 mono8 图像提供相似大小的输出缓冲区?
Why cv::imencode gives similar size of output buffer for bgr8 and mono8 images?
我注意到 4.1 MB/s @50fps 1280x720 bgr8.
......和3.7 MB/s @50fps 1280x720 mono8.
我原以为灰度的带宽消耗会减少大约 3 倍。
我完全编辑了我的问题以简化并使其更直接。
下面是我的简单 C++ 程序及其输出,它可以重现我的发现。 lenna.png
#include <iostream>
#include <vector>
#include <opencv2/imgproc/imgproc.hpp> // gray
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
Mat im, imGray;
im = imread( "lenna.png", IMREAD_COLOR ); // Read the file
imGray = imread( "lenna.png", IMREAD_GRAYSCALE ); // Read the file
if( im.empty() ) // Check for invalid input
{
cout << "Could not open or find the image" << std::endl ;
return -1;
}
if(true){
std::vector<int> params;
params.resize(9, 0);
params[0] = cv::IMWRITE_JPEG_QUALITY;
params[1] = 80;
params[2] = cv::IMWRITE_JPEG_PROGRESSIVE;
params[3] = 0;
params[4] = cv::IMWRITE_JPEG_OPTIMIZE;
params[5] = 0;
params[6] = cv::IMWRITE_JPEG_RST_INTERVAL;
params[7] = 0;
std::vector< uchar > buffer, bufferGray;
if (cv::imencode(".jpeg", im, buffer, params))
{
float cRatio = (float)(im.rows * im.cols * im.elemSize())
/ (float)buffer.size();
printf("BGR8 Jpeg image size: %lu KB, Compression Ratio: 1:%.2f\n", buffer.size()/1024, cRatio);
}
else
{
printf("cv::imencode (jpeg) failed on bgr8 image\n");
}
if (cv::imencode(".jpeg", imGray, bufferGray, params))
{
float cRatio = (float)(imGray.rows * imGray.cols * imGray.elemSize())
/ (float)bufferGray.size();
printf("MONO8 Jpeg image size: %lu KB, Compression Ratio: 1:%.2f\n\n", bufferGray.size()/1024, cRatio);
}
else
{
printf("cv::imencode (jpeg) failed on mono8 image\n");
}
}
imshow( "BGR8", im );
imshow( "MONO8", imGray );
waitKey(0);
return 0;
}
g++ -g -O3 main.cpp -o main pkg-config --libs --cflags opencv4
输出:
我担心的是灰度压缩率低。
以下是我的一些系统信息:
jai@jai:~$ opencv_version
4.2.0
jai@jai:~$ opencv_version -v | grep jpeg
JPEG: /usr/lib/x86_64-linux-gnu/libjpeg.so (ver 80)
jai@jai:~$ ldconfig -p | grep jpeg
libmjpegutils-2.1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libmjpegutils-2.1.so.0
libjpegxr.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libjpegxr.so.0
libjpeg.so.8 (libc6,x86-64) => /lib/x86_64-linux-gnu/libjpeg.so.8
libjpeg.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libjpeg.so
libgdcmjpeg16.so.3.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg16.so.3.0
libgdcmjpeg16.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg16.so
libgdcmjpeg12.so.3.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg12.so.3.0
libgdcmjpeg12.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg12.so
libgdcmjpeg8.so.3.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg8.so.3.0
libgdcmjpeg8.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg8.so
jai@jai:~$
我检查了 opencv4、opencv3.4.0 和 opencv3.4.9。
默认编码器设置中的 JPEG 4:2:0 chroma subsampling。因此,彩色图像的带宽是灰度图像带宽的三倍的假设是错误的。相反,它应该是因子 1,5。但另外:
- 两个色度通道是相对于intensity/green通道(YCbCr color model)存储的,这意味着它们可以更有效地压缩。
- 您总是需要存储 headers、量化矩阵等,因此在比较缓冲区大小时您有一个要考虑的基线
最后,我想说 43kb 和 33kb 看起来很合理。
我注意到 4.1 MB/s @50fps 1280x720 bgr8.
......和3.7 MB/s @50fps 1280x720 mono8.
我原以为灰度的带宽消耗会减少大约 3 倍。
我完全编辑了我的问题以简化并使其更直接。 下面是我的简单 C++ 程序及其输出,它可以重现我的发现。 lenna.png
#include <iostream>
#include <vector>
#include <opencv2/imgproc/imgproc.hpp> // gray
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
Mat im, imGray;
im = imread( "lenna.png", IMREAD_COLOR ); // Read the file
imGray = imread( "lenna.png", IMREAD_GRAYSCALE ); // Read the file
if( im.empty() ) // Check for invalid input
{
cout << "Could not open or find the image" << std::endl ;
return -1;
}
if(true){
std::vector<int> params;
params.resize(9, 0);
params[0] = cv::IMWRITE_JPEG_QUALITY;
params[1] = 80;
params[2] = cv::IMWRITE_JPEG_PROGRESSIVE;
params[3] = 0;
params[4] = cv::IMWRITE_JPEG_OPTIMIZE;
params[5] = 0;
params[6] = cv::IMWRITE_JPEG_RST_INTERVAL;
params[7] = 0;
std::vector< uchar > buffer, bufferGray;
if (cv::imencode(".jpeg", im, buffer, params))
{
float cRatio = (float)(im.rows * im.cols * im.elemSize())
/ (float)buffer.size();
printf("BGR8 Jpeg image size: %lu KB, Compression Ratio: 1:%.2f\n", buffer.size()/1024, cRatio);
}
else
{
printf("cv::imencode (jpeg) failed on bgr8 image\n");
}
if (cv::imencode(".jpeg", imGray, bufferGray, params))
{
float cRatio = (float)(imGray.rows * imGray.cols * imGray.elemSize())
/ (float)bufferGray.size();
printf("MONO8 Jpeg image size: %lu KB, Compression Ratio: 1:%.2f\n\n", bufferGray.size()/1024, cRatio);
}
else
{
printf("cv::imencode (jpeg) failed on mono8 image\n");
}
}
imshow( "BGR8", im );
imshow( "MONO8", imGray );
waitKey(0);
return 0;
}
g++ -g -O3 main.cpp -o main pkg-config --libs --cflags opencv4
输出:
以下是我的一些系统信息:
jai@jai:~$ opencv_version
4.2.0
jai@jai:~$ opencv_version -v | grep jpeg
JPEG: /usr/lib/x86_64-linux-gnu/libjpeg.so (ver 80)
jai@jai:~$ ldconfig -p | grep jpeg
libmjpegutils-2.1.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libmjpegutils-2.1.so.0
libjpegxr.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libjpegxr.so.0
libjpeg.so.8 (libc6,x86-64) => /lib/x86_64-linux-gnu/libjpeg.so.8
libjpeg.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libjpeg.so
libgdcmjpeg16.so.3.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg16.so.3.0
libgdcmjpeg16.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg16.so
libgdcmjpeg12.so.3.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg12.so.3.0
libgdcmjpeg12.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg12.so
libgdcmjpeg8.so.3.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg8.so.3.0
libgdcmjpeg8.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libgdcmjpeg8.so
jai@jai:~$
我检查了 opencv4、opencv3.4.0 和 opencv3.4.9。
默认编码器设置中的 JPEG 4:2:0 chroma subsampling。因此,彩色图像的带宽是灰度图像带宽的三倍的假设是错误的。相反,它应该是因子 1,5。但另外:
- 两个色度通道是相对于intensity/green通道(YCbCr color model)存储的,这意味着它们可以更有效地压缩。
- 您总是需要存储 headers、量化矩阵等,因此在比较缓冲区大小时您有一个要考虑的基线
最后,我想说 43kb 和 33kb 看起来很合理。