Opencv Cvsaveimage Jpeg Compression Factor

OpenCV cvSaveImage Jpeg Compression Factor

Currently cvSaveImage() is declared to take only two parameters:

int cvSaveImage( const char* filename, const CvArr* image );

However, the "latest tested snapshot" has:

  #define CV_IMWRITE_JPEG_QUALITY 1
#define CV_IMWRITE_PNG_COMPRESSION 16
#define CV_IMWRITE_PXM_BINARY 32

/* save image to file */
CVAPI(int) cvSaveImage( const char* filename, const CvArr* image,
const int* params CV_DEFAULT(0) );

I've been unable to find any documentation, but my impression from poking through this code is that you would build an array of int values to pass in the third parameter:

int p[3];
p[0] = CV_IMWRITE_JPEG_QUALITY;
p[1] = desired_quality_value;
p[2] = 0;

I don't know how the quality value is encoded, and I've never tried this, so caveat emptor.

Edit:

Being a bit curious about this, I downloaded and built the latest trunk version of OpenCV, and was able to confirm the above via this bit of throwaway code:

#include "cv.h"
#include "highgui.h"
int main(int argc, char **argv)
{
int p[3];
IplImage *img = cvLoadImage("test.jpg");

p[0] = CV_IMWRITE_JPEG_QUALITY;
p[1] = 10;
p[2] = 0;

cvSaveImage("out1.jpg", img, p);

p[0] = CV_IMWRITE_JPEG_QUALITY;
p[1] = 100;
p[2] = 0;

cvSaveImage("out2.jpg", img, p);

exit(0);
}

My "test.jpg" was 2,054 KB, the created "out1.jpg" was 182 KB and "out2.jpg" was 4,009 KB.

Looks like you should be in good shape assuming you can use the latest code available from the Subversion repository.

BTW, the range for the quality parameter is 0-100, default is 95.

openCV cvSaveImage() increases the size of image

There are different methods of compression and coding combined in JPEG.
Most likely your original image used a different compression/coding than standard openCV parametrization for cvSaveImage.

Try this:

IplImage* src = cvLoadImage("test.jpg", 0);
cvSaveImage("reTest.jpg", src);
IplImage* reSrc = cvLoadImage("reTest.jpg",0);
cvSaveImage("reTest2.jpg", reSrc);

if reTest.jpg and reTest2.jpg have the same size, openCV does not increase the filesize but just uses a different compression level or sth.
You would have to find out the compression level and coding of your original file and save it with these same parameters, maybe with a different library than openCV.

Open and save image in OpenCV makes image a lot larger (ruby-opencv)

Here it is as an answer:

It is probably because CV_IMWRITE_JPEG_QUALITY is set to 95. You might want to try out cv::imwrite and set the quality to something that you want. For further details, you can refer to the cv::imwrite documentation..

Supplementary reading as added by @mydoghasworms : OpenCV cvSaveImage Jpeg Compression Factor

Example solution in Ruby setting JPEG quality to 20:

require 'opencv'

include OpenCV

image = CvMat.load("samples/CIMG0388.JPG")
image.save("samples/CIMG0388_2.JPG", {CV_IMWRITE_JPEG_QUALITY => 20})

Compressing images on opencv (imwrite). How to explicitly set the compression factor?

As suggested, activating C++0x allows me to pass a vector explicitly defined inline to the function. This solved the issue.

Automatically choose optimal JPEG compression in OpenCV?

Unfortunately, to "optimize" JPEG compression, one would have to learn and apply many technical details about the JPEG compression. Because of this, many libraries do not offer the full suite of adjustment parameters. The 0-100 JPEG quality parameter is already a good compromise.


ImageMagick may have such functionality.


You are looking for a way to "automatically choose a reasonable JPEG compression level in OpenCV".

However, "reasonable" is subjective, and depends on the the image owner's perception of what features are important in the given image. This means the perception can be different for every combination of (different owners) x (different images).

  • The short answer
    • No, OpenCV does not currently offer this functionality.
  • The "sysadmin" answer
    • Look at OpenCV ImageMagick integration.
    • http://www.imagemagick.org/discourse-server/viewtopic.php?f=22&t=20333&start=45
  • The quick and dirty answer
    • Use method of bisection (0, 100, 50, 75, 87, ...) to search for a JPEG quality level that will approach a specified output file size.
    • Secant method may also be applicable.
      • Edited: Newton's method is probably not useful, because one cannot obtain the first derivative of the quality-file size curve without an analytical model.
    • Obviously this is too inefficient for practical every-day use, so it is not provided by the library.
    • If you want to use it, you have to implement it yourself with your own choice of techniques.
    • To avoid disk I/O, use cv::imencode which writes to memory instead of to disk.
  • The slightly longer answer
    • Although it doesn't implement this functionality, it is obvious that it is a nice feature to have.
    • If someone is willing to implement it with code quality good for use in OpenCV, OpenCV may consider accept it.
  • The yet longer answer
    • OpenCV uses jpeglib, or optionally libjpeg-turbo, and both libraries allow one to configure the technical details of JPEG compression.
    • Below I will focus on these technical details.

Read first: JPEG compression on Wikipedia


Of the JPEG compression pipeline, three of the compression steps can be configured by users of jpeglib or libjpeg-turbo:

  • Chroma subsampling
    • After the conversion from RGB to YCbCr, the chroma (color-carrying) channels: Chroma-blue and Chroma-red, are optionally stored in a lower resolution relative to the Luminance (Y) channel, also known as the Intensity or Grayscale channel, the latter is always stored at full resolution.
    • Most JPEG decoders can support these downsampling factors:
      • (1, 1) - no subsampling
      • (1, 2), (2, 1), (2, 2) - moderate subsampling, where one or both dimensions may be subsampled by 2.
      • (1, 4), (2, 4), (4, 2), (4, 1) - heavy subsampling. Note that the original JPEG specification forbids some of these combinations, but most JPEG decoders are able to decode them nevertheless.
  • Quantization table
    • Each JPEG image can define a quantization table for the "AC coefficients" of the DCT transformed coefficients
    • Each JPEG image can define a quantization table for the "DC coefficient" (i.e. the average value of the 8x8 block) computed from the DCT transform.
    • Quantization is the "lossy step" of JPEG compression. So, a technical user will have to decide how much loss (quantization) is acceptable, and then configure the quantization table accordingly.
  • Huffman table
    • Huffman coding is a lossless compression technique. In other words, if one could really spend time optimizing the Huffman coding table based on the statistics of the quantized DCT coefficients of the whole image, one can often construct a good Huffman table to optimize compression without having to trade off quality.
    • Unfortunately, the reality is more complicated, and such optimization is often not enabled.
      • It requires keeping all DCT coefficients in memory, for the whole image. This bloats memory usage.
      • Writing to the file cannot start until everything is in memory. In contrast, if a library chooses the quantization table and Huffman table up-front, without looking at the statistics of the DCT coefficients, then the library would be able to write to the file incrementally as rows and rows of pixels are being processed. Because libjpeg is designed to be usable in the lowest-denominator devices (including smart watches, and maybe your refrigerator too?), being able to operate with minimum memory is an important feature.

How to build opencv that only support decode jpeg?

You'd better use other frameworks other than OpenCV. OpenCV is extremely heavy for this kind of job. It's mainly focused on image processing.

Maybe you can use OpenImageIO, freeimage or other libs.

You can refer to these posts:

Reading an image file in C/C++

https://products.fileformat.com/image/cpp/openimageio

OpenCV imwrite gives washed-out result for jpeg images

You can try to increase the compression quality parameter as shown in OpenCV Documentation of cv::imwrite :

cv::Mat img = cv::imread("dir/frogImage.jpg",-1);

std::vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(100);

cv::imwrite("dir/result.jpg",img, compression_params);

Without specifying the compression quality manually, quality of 95% will be applied.

but 1. you don't know what jpeg compression quality your original image had (so maybe you might increase the image size) and 2. it will (afaik) still introduce additional minor artifacts, because after all it is a lossy compression method.

UPDATE your problem seems to be not because of compression artifacts but because of an image with Adobe RGB 1998 color format. OpenCV interprets the color values as they are, but instead it should scale the color values to fit the "real" RGB color space. Browser and some image viewers do apply the color format correctly, while others don't (e.g. irfanView). I used GIMP to verify. Using GIMP you can decide on startup how to interpret the color values by format, either getting your desired or your "washed out" image.
OpenCV definitely doesn't care about such things, since it's not a photo editing library, so neither on reading nor on writing, color format will be handled.

Compressing a raw image buffer

I believe Embedded JPEG may be what you are looking for.



Related Topics



Leave a reply



Submit