Saving An Image In OpenCV increase Image Size - opencv

I've already asked this question I did not get satisfactory answers, So I did more research and I'm putting this question forward in a better way. I read an image through OpenCV``imread method. And I saved it using imwrite method. It increases the output file size by more than double.
Below are the details of the images which I obtained from imagemagick (I did not write all the details down, I'm attaching the images for all the details are needed):
Input Image:
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 1836x3264+0+0
Resolution: 72x72
Print size: 25.5x45.3333
Units: PixelsPerInch
Type: TrueColor
Endianess: Undefined
Colorspace: sRGB
Depth: 8-bit
Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit
Channel statistics:
    Pixels: 5992704
Compression: JPEG
Quality: 75
Filesize: 267KB
Number pixels: 5.993M
Output Image:
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 1836x3264+0+0
Units: Undefined
Type: TrueColor
Endianess: Undefined
Colorspace: sRGB
Depth: 8-bit
Channel depth:
red: 8-bit
green: 8-bit
blue: 8-bit
Channel statistics:
Pixels: 5992704
Compression: JPEG
Quality: 95
Filesize: 611KB
Number pixels: 5.993M
As you can see, the input image size is 267KB but the output image size turned out to be 611KB. Now I know that its size depends on the encoder, Compression value, bit-rate etc.
I want to know is there anyway I can save the image in the exact same size of the input image.
I also tried using the compression in openCV like this
cv2.imwrite('result.jpg', image, [int(cv2.IMWRITE_JPEG_QUALITY), 45]).
Here the image quality would be 45, but the image size would still be greater than the input image (around 300KB).
I don't want to go less than 45 because it would affect the image details and loss of data.
I tried using external libraries like scipy, matplotlib. But they all bump the image size regardless.
Any clue on why the output image increase and how we can fix it is very much appreciated.
Here is some code for reference
import cv2 #opencv library for image processing implementations
def main():
im = cv2.imread('sample.jpg')
cv2.imwrite('result.jpg', im)
if __name__=='__main__':
main()
And here is the image for reference.

Your original image has quality 75. If you don't define the quality of saving with OpenCV it defaults to 95, so you should expect the file to be larger.
If you want to set it to some maximum size, you can use ImageMagick like this to set it to, say 300kB:
convert sample.jpg -define jpeg:extent=300k a.jpg
And that gets you a 299,810 byte file with quality 83.
If you are prepared to permit 400kB, you can use:
convert sample.jpg -define jpeg:extent=400k a.jpg
and that gets you a 358,000 byte file with quality 93.
I wrote something similar in Python that lets you save at a specified size using a binary search here.

The solution for this will be, saving an image using imageio.imwrite, this worked for me, when I was doing image compression. while saving a compressed image file using CV2 it increased the compressed image size more than the original image size. imageio.imwrite solved this issue for me
example: imageio.imwrite("image_name.jpg", cv2_image)
The increase in file size while saving with jpg is that it decompresses the image file

Related

how to convert scanned jpg files to pbm format losslessly?

Using ImageMagick's convert utility to convert some scanned jpg files to pbm files.
However, even if the option -quality 100 is used, the pbm's resolution still looks worse than the original scanned jpg file.
Worse, the scanned jpg file is a colored one, while the converted pbm is black and white.
Info of original jpg:
image size: 2256 × 1568 pixels
dpi: 300 pixels/inch
color model: RGB
info of the converted pbm:
image size: 2256 × 1568 pixels
dpi: 72 pixels/inch
color model: Gray
Currently, here is what I did to convert the format:
qiang#bonjour:~/scan$ convert scan000.jpg scan000.pbm
Am I missing any option to use with convert? As I mentioned earlier, -quality 100 had been tried, but to no avail.
Using ImageMagick, I think you want to output to PPM not PBM. Try
convert image.jpg image.ppm
or try the ascii version by using
convert image.jpg -compress none image.ppm
PBM is binary (black/white) and PGM is grayscale. If you want to keep color, then you need to use PPM.
Unfortunately, I believe that ImageMagick can only read DJVU format images. So you cannot write to it directly from ImageMagick.

Lossless YCbCr Tiff?

My goal is to create a Tiff image that natively holds uncompressed (or with lossless compression) YCbCr data inside (since the original image is YUV420 and IMO it would be a poor choice to upsample and convert to RGB).
I’m able to create (using imagemagick for instance) a valid YCbCr Tiff with a JPEG compressed data. When I try uncompressed / deflate / lzw I get a broken image (neither windows image viewer nor photoshop can open it). On page 94 of the TIFF 6.0 spec (under “Minimum Requirements for YCbCr Images”):
Compression = none (1), LZW (5) or JPEG (6). SHORT.
What’s wrong? Is there a Tiff extension which says that YCbCr color space is supported only when using jpeg compression?
Thanks,
Mark.
Command that works:
convert infileRGB.tif -colorspace ycbcr -compress jpeg outfileYCbCr.tif
Commands that don't work (broken tiff):
convert infileRGB.tif -colorspace ycbcr -compress none outfileYCbCr.tif
convert infileRGB.tif -colorspace ycbcr -compress lzw outfileYCbCr.tif

Imagemagick convert tif to rgba16 png

So here is my source tif image:
$ identify -verbose source.tif
Image:
Format: TIFF (Tagged Image File Format)
Class: DirectClass
Geometry: 512x512+0+0
Resolution: 72x72
Print size: 7.11111x7.11111
Units: PixelsPerInch
Type: Palette
Base type: TrueColor
Endianess: MSB
Colorspace: RGB
Depth: 8-bit
Channel depth:
red: 8-bit
green: 8-bit
blue: 1-bit
And I've tried:
convert source.tif output.png
And here are the results:
$ identify -verbose output.png
Format: PNG (Portable Network Graphics)
Class: DirectClass
Geometry: 512x512+0+0
Resolution: 28.34x28.34
Print size: 18.0663x18.0663
Units: PixelsPerCentimeter
Type: Palette
Endianess: Undefined
Colorspace: RGB
Depth: 8-bit
Channel depth:
red: 8-bit
green: 8-bit
blue: 1-bit
But I'm not seeing how to make the PNG be RGBA16. Which as I understand means it needs a 16 bit depth, and an alpha channel.
In general, ImageMagick will use the most economical output format that is compatible with your specifications. So, if your input image doesn't have an alpha channel (i.e. transparency), your output image won't have transparency. If a 256-colour palette is adequate for the colours in your image, it will create a palettised output image. If an 8-bit output depth is adequate for your image, it will not bother creating a 16-bit output. And so on...
If you want to force ImageMagick to do something different, you have a number of options.
If you want to force true-colour, or a palettised (indexed) output file, you can do this:
convert input.png -type palette output.png # Force palettised (indexed) output
convert input.png -type truecolor output.png # Force true colour output
If you want to force 8-bit or 16-bit, you can do this:
convert input.png -depth 8 output.png # Force 8-bit output
convert input.png -depth 16 output.png # Force 16-bit (per channel) output
If you want to force an alpha/transparency channel, you can do:
convert input.tif -type TrueColorAlpha output.png # Force a true color output with transparency
And you can combine these too. If you want to see the type options, use this command:
identify -list type
Bilevel
ColorSeparation
ColorSeparationAlpha
ColorSeparationMatte
Grayscale
GrayscaleAlpha
GrayscaleMatte
Optimize
Palette
PaletteBilevelAlpha
PaletteBilevelMatte
PaletteAlpha
PaletteMatte
TrueColorAlpha
TrueColorMatte
TrueColor
Furthermore, specifically in the case of PNG files, you can also force the output by specifying the PNG type in capitals, followed by a colon in front of the output filename, thus:
convert input.tif PNG64:output.png # Force 64-bit RGBA (3 channels # 16-bits each, plus alpha)
convert input.tif PNG32:output.png # Force 32-bit RGBA (3 channels # 8-bits each, plus alpha)
convert input.tif PNG48:output.png # Force 48-bit output (3 channels # 16-bits each, no alpha)
convert input.tif PNG24:output.png # Force 24-bit output (3 channels # 8-bits each, no alpha)
So the short answer is
convert input.tif PNG64:output.png
or
convert input.tif -depth 16 -type TrueColorAlpha output.png
Beware though, ImageMagick will override the second version if no alpha channel is present in your input image, whereas it will not do that if you use PNG64:.

ImageMagick convert adds several extra "border" colors from tiff to jpeg?

I created an 8-bit .tiff image ("test.tiff") containing a grid of 30 different color patches in the RGB color space using ImageMagick -convert.
When I convert this image into a jpeg (which is what I need) using:
convert -quality 100 -colorspace RGB -depth 8 test.tiff test.jpg
The identify -verbose command reveals that the resulting jpeg has several additional colors in the color table, each only taking up a few (1-4) pixels and residing very near the desired colors in RGB space. My assumption is that some kind of border bleeding is happening; maybe due to compression?
I don't understand why this border bleeding has occurred, especially given that it does not occur when I convert the tiff image to either a bmp or pcx image.
Thank you
By definition, JPEG is a lossy compression. The effects your experiencing are expected with the JPEG format. Setting the -quality of 100 will not have a 1-to-1 image result as tiff.
See additional answers:
Should I use JPG or TIFF for high-quality prints?
[...] because every time [JPEG] would save it it would generate some changes.
Is Jpeg lossless when quality is set to 100?
At [quality] 100, you just get the LEAST loss possible.
I don't know how you created your 30 colour swatch, or how your histogram looks, but you might try adding -dither None and -colors 30 options to your convert commands:
convert test.tiff -dither None -colors 30 ...

ImageMagick: convert keeps changing the colorspace to Gray. How to preserve sRGB colorspace?

I have a batch script that converts my PNG-24 (with Transparency) images to 50% and 25% size (for mobile development). Usually these images have colors in them but now I am trying to convert an image that has no colors and ImageMagick keeps changing the colorspace profile to "Gray", which messes up my image in the 3d engine I'm using (Unity).
I have tried forcing it to use type TrueColor, colorspace sRGB, and the sRGB.icc profile (the one included with OSX) but it doesn't seem to care. It still changes it to Gray.
> convert old.png -profile srgb.icc -colorspace sRGB -type TrueColor new.png
> identify *.png
old.png PNG 140x140 140x140+0+0 8-bit sRGB 3.68KB 0.000u 0:00.000
new.png PNG 140x140 140x140+0+0 8-bit sRGB 256c 2.33KB 0.000u 0:00.000
ImageMagick still identifies it as an 8-bit sRGB image but it puts "256c" after it which I'm assuming means it has reduced it down to 256 colors, which I don't want either. When I look at the image in OSX Preview.app, it says it is using the Gray color profile. The image also visually looks a lot different.
Here is the image I'm using: https://dl.dropbox.com/u/59304/old.png
There is a duplicate question here, ImageMagick Reduces Colorspace to Gray, but the answer does not work for me and I don't have enough reputation to comment on his answer, unfortunately. I imagine my case is different because I'm using PNG and not JPG.
Version: ImageMagick 6.8.0-7 2013-01-02 Q16 http://www.imagemagick.org
Features: OpenCL
edit- After reading the ImageMagick forums as specified in one of the answers, it looks like just prepending PNG32: or PNG24: to the output file solves the problem.
The proper way to keep a grayscale PNG as RGB is to use PNG24:result.png
Input:
convert lena.png -colorspace gray PNG24:lenag_rgb.png
identify -verbose lenag_rgb.png
Image: lenag_rgb.png
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: DirectClass
Geometry: 256x256+0+0
Units: Undefined
Colorspace: sRGB
Type: Grayscale
So as you see above, Colorspace is RGB while the type is Grayscale.
For other image formats such as JPG and TIFF, use -define colorspace:auto-grayscale=false along with -type truecolor.
You may pass -set colorspace:auto-grayscale off to convert to disable automatic conversion of RGB channels to a single grayscale channel.
This solution was not yet available at the time of your question, but was introduced in 2015 with version 6.9.2:
2015-07-25 6.9.2-0 Dirk Lemstra <dirk#lem.....org>
Added -set colorspace:auto-grayscale=false that will prevent automatic conversion to grayscale inside coders that support grayscale.

Resources