Search code examples
pythonopencvimage-processingcompressionimage-compression

OpenCV: Saving image files - Difference between cv.imwrite and f.write()?


I'm importing images from a security camera for image processing. After importing the image, I want to save the image for archiving (processing will happen on the fly).

I see two available methods for doing so:

  • Python's built in file writer (which I will refer to as the "file method")
  • OpenCV's imwrite (which I will refer to as the "OpenCV method"), which requires me to decode the image using NumPy

During testing using the code below, I found the following results:

  • OpenCV method file (292 KB) is considerably larger than the file method's file (153 KB)
  • Values such as dpi (96), bit depth (24) and pixel resolution (1920x1080) are identical between the files
  • The file method's file contains more metadata, such as creation time, color representation and camera info (see screenshot ), likely due to NumPy/OpenCV not passing this data on.

Thus, my question is: Which method is better? I want to retain as much information as possible. Why is there such a disparity between the images?

import requests
import numpy as np
import cv2 as cv

response = requests.get(cam_url, auth=login)
image = cv.imdecode(np.frombuffer(response.content, dtype=np.uint8), -1)

with open('file_method.jpg', 'wb') as f:
    f.write(response.content)

cv.imwrite('opencv_method.jpg', image)

N.B.:

  • I cannot link the snapshots themselves for privacy reasons. But trust me, there's no discernable difference between the two.
  • I am aware that using PNG files is preferred over JPEG, but that's beside the point here).

System info:

  • Python 3.12.7
  • OpenCV 4.10.0
  • NumPy 2.1.3
  • WSL2 (Ubuntu 22.04.5 LTS (GNU/Linux 5.15.167.4-microsoft-standard-WSL2 x86_64)

EDIT:

Conclusion (summary of the kind comments below):

  • The first method saves the raw file directly, the second encodes it (NumPy) then decodes it (OpenCV) and then saves it.
  • The encoding / decoding process strips the image of its EXIF metadata.
  • The difference in file size is likely due to greater compatibility of the re-encoded version, which in my case is redundant.
  • The first method results in a smaller file with EXIF data included, albeit with the constraint that the output image format needs to be the same as the input. The second method is "safer", allowing the user to choose the output format.

EXIF Info (from ExifTool):

File Method

    ExifTool Version Number         : 12.40
    File Name                       : file_method.jpg
    Directory                       : .
    File Size                       : 153 KiB
    File Modification Date/Time     : 2025:01:20 11:26:40+01:00
    File Access Date/Time           : 2025:01:20 11:44:37+01:00
    File Inode Change Date/Time     : 2025:01:20 11:44:31+01:00
    File Permissions                : -rw-r--r--
    File Type                       : JPEG
    File Type Extension             : jpg
    MIME Type                       : image/jpeg
    JFIF Version                    : 1.02
    Resolution Unit                 : None
    X Resolution                    : 1
    Y Resolution                    : 1
    Exif Byte Order                 : Little-endian (Intel, II)
    Make                            : AXIS
    Camera Model Name               : P1455-LE
    Software                        : 10.4.5
    Modify Date                     : 2025:01:20 11:16:51
    Exposure Time                   : 1/82
    F Number                        : 429496729.5
    ISO                             : 65535
    Sensitivity Type                : Unknown
    Time Zone Offset                : 1
    Exif Version                    : 0231
    Date/Time Original              : 2025:01:20 11:16:51
    Create Date                     : 2025:01:20 11:16:51
    Sub Sec Time Original           : 987
    Sub Sec Time Digitized          : 987
    Flashpix Version                : 0100
    Color Space                     : sRGB
    Exposure Mode                   : Auto
    Serial Number                   : B8A44F0C0631
    Comment                         : ..g�"�bg�"�b.
    Image Width                     : 1920
    Image Height                    : 1080
    Encoding Process                : Baseline DCT, Huffman coding
    Bits Per Sample                 : 8
    Color Components                : 3
    Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
    Aperture                        : 429496729.5
    Image Size                      : 1920x1080
    Megapixels                      : 2.1
    Shutter Speed                   : 1/82
    Create Date                     : 2025:01:20 11:16:51.987
    Date/Time Original              : 2025:01:20 11:16:51.987
    Light Value                     : 54.4

OpenCV Method

    ExifTool Version Number         : 12.40
    File Name                       : opencv_file.jpg
    Directory                       : .
    File Size                       : 292 KiB
    File Modification Date/Time     : 2025:01:20 11:13:20+01:00
    File Access Date/Time           : 2025:01:20 11:26:58+01:00
    File Inode Change Date/Time     : 2025:01:20 11:13:20+01:00
    File Permissions                : -rw-r--r--
    File Type                       : JPEG
    File Type Extension             : jpg
    MIME Type                       : image/jpeg
    JFIF Version                    : 1.01
    Resolution Unit                 : None
    X Resolution                    : 1
    Y Resolution                    : 1
    Image Width                     : 1920
    Image Height                    : 1080
    Encoding Process                : Baseline DCT, Huffman coding
    Bits Per Sample                 : 8
    Color Components                : 3
    Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
    Image Size                      : 1920x1080
    Megapixels                      : 2.1

Solution

  • If, as stated, your goal is to retain as much quality as possible, you should use the write() method because it retains exactly the quality and metadata you got from the original feed.

    Using cv2.imwrite() will definitely lose metadata and any attached colour profiles and also risks either losing quality, or adding unnecessary bloat but it cannot improve the quality.


    The reason the two are different is most likely due to a different JPEG quality setting. You can explore the parameters of the original vs OpenCV-saved image with:

    exiftool YOURIMAGE
    

    Or, in a more targeted way, with:

    exiftool -filesize -JPEGQualityEstimate -n YOURIMAGE
    

    Output will look similar to this:

    File Size                       : 292000
    JPEG Quality Estimate           : 75