JPEG images have different pixel values across multiple devices
The JPEG standard does not require that decoder implementations produce bit-for-bit identical output images. Unfortunately the standards document specifying decoder requirements, ISO 10918-2, is apparently not freely available online but Wikipedia says:
...the JPEG standard (and the similar MPEG standards) includes some precision requirements for the decoding, including all parts of the decoding process (variable length decoding, inverse DCT, dequantization, renormalization of outputs); the output from the reference algorithm must not exceed:
- a maximum 1 bit of difference for each pixel component
- low mean square error over each 8×8-pixel block
- [etc.]
Differences between different decoder outputs using the same input are generally due to differing levels of internal precision, particularly in performing the IDCT. Another possible source of differences is smoothing, which attempts to reduce "blockiness" artifacts.
Like you, I would expect that setting inPreferQualityOverSpeed
would produce the same output but nothing actually guarantees that. I can think of at least a couple ways that you could get small variations on two different phones:
- The phones may run different versions of Android where the implementation of
BitmapFactory
changed (e.g. perhapsinPreferQualityOverSpeed
was broken and then fixed, or vice versa), or - The phones may provide different hardware features (e.g. vector instruction set, DSP co-processor, etc.) that
BitmapFactory
leverages. Even differences in scalar floating-point units can cause discrepancies, especially with JIT compilation producing the actual machine instructions.
Given the wiggle room in the standard plus your experimental observations, it appears the only way to guarantee bit-for-bit agreement is to perform decoding within your own application. Perhaps you can find some alternative Android-compatible library.
JPEG images have different pixel values across multiple devices
The JPEG standard does not require that decoder implementations produce bit-for-bit identical output images. Unfortunately the standards document specifying decoder requirements, ISO 10918-2, is apparently not freely available online but Wikipedia says:
...the JPEG standard (and the similar MPEG standards) includes some precision requirements for the decoding, including all parts of the decoding process (variable length decoding, inverse DCT, dequantization, renormalization of outputs); the output from the reference algorithm must not exceed:
- a maximum 1 bit of difference for each pixel component
- low mean square error over each 8×8-pixel block
- [etc.]
Differences between different decoder outputs using the same input are generally due to differing levels of internal precision, particularly in performing the IDCT. Another possible source of differences is smoothing, which attempts to reduce "blockiness" artifacts.
Like you, I would expect that setting inPreferQualityOverSpeed
would produce the same output but nothing actually guarantees that. I can think of at least a couple ways that you could get small variations on two different phones:
- The phones may run different versions of Android where the implementation of
BitmapFactory
changed (e.g. perhapsinPreferQualityOverSpeed
was broken and then fixed, or vice versa), or - The phones may provide different hardware features (e.g. vector instruction set, DSP co-processor, etc.) that
BitmapFactory
leverages. Even differences in scalar floating-point units can cause discrepancies, especially with JIT compilation producing the actual machine instructions.
Given the wiggle room in the standard plus your experimental observations, it appears the only way to guarantee bit-for-bit agreement is to perform decoding within your own application. Perhaps you can find some alternative Android-compatible library.
Is it possible read pixels from a jpeg file determenistically across all platforms?
In practice, no. Pixels may differ between different versions of the same library, or even the same version of the same library between platforms.
In theory, you will get the same pixels values if you use the exact same algorithm/software on all platforms you need to support. But I think this means you'll either have to write the decoder yourself, or at least read a lot of source code and configure and compile a known library yourself.
Why does tensorflow decode jpeg images differently from scipy imread?
The discrepancy arises because of inaccurate, but fast, default Discrete Cosine Tranform used by Tensorflow
According to the Source code
// The TensorFlow-chosen default for jpeg decoding is IFAST, sacrificing
// image quality for speed.
flags_.dct_method = JDCT_IFAST;
In order to get accurate decoding one can set the attribute dct_method = 'INTEGER_ACCURATE'
as show in example below
def minimal_example():
#image_source = 'https://upload.wikimedia.org/wikipedia/commons/8/88/Astronaut-EVA.jpg'
image_path = 'astronaut.jpg'
image_file = open(image_path,'rb')
image_raw = image_file.read()
image_scipy = scipy.misc.imread(image_path)
image_tf = tf.image.decode_jpeg(image_raw).eval(session=tf.Session())
image_tf_accurate = tf.image.decode_jpeg(image_raw,dct_method="INTEGER_ACCURATE").eval(session=tf.Session())
print('Error For Default: ', np.sum(np.abs(image_tf - image_scipy)))
print('Error For Accurate: ', np.sum(np.abs(image_tf_accurate - image_scipy)))
#Error For Default: 3420883624
#Error For Accurate: 0
Images opened in Pillow and OpenCV are not equivelant
The original image is a JPEG.
JPEG decoding can produce different results depending on the libjpeg version, compiler optimization, platform, etc.
Check which version of libjpeg Pillow
and OpenCV
are using.
See this answer for more information: JPEG images have different pixel values across multiple devices or here.
BTW, (im-imP)
produces uint8
overflow (there is no way to have such a high amount of large pixel differences without seeing it in your frequency chart). Try to cast to int
type before doing your frequency computation.
the pixel values changed while using imwrite to jpg files in c++
If you want non-lossy compression, you can't use jpg's and have to use a .png (there's .bmp as well but its uncompressed)
jpg = cv.imread("../resources/fisheye/1_1.jpg")
cv.imwrite("1_1.png", jpg)
png = cv.imread("1_1.png")
np.sum(np.where(jpg != png, 1, 0)) # number of differing pixels between images
Output: 0
Fast accessing pixel values of jpeg images
Use CBitmap::GetBits() to get a raw pointer to the pixel data. You can now directly party on the pixels without going through the expensive GetPixel() method. There are a number of things you need to be careful with when you do this:
- You have to use CBitmap::GetPitch() to calculate the offset to the start of a line. The pitch is not the same as the width.
- Lines in the bitmap are stored upside-down
- You have to deal with the pixel format yourself. A 24bpp image stores 3 bytes per pixel. An indexed format like 8bpp requires looking up the color in the color table. 32bpp is the easy one, 4 bytes per pixel and the pitch is always the same as the width.
Copied image saved with different pixels to original with PIL
*.jpg
is a compressed image format. By saving the jpg
again you use a different default quality for the jpg writer
so the resulting pixel-values differ.
See image file format params for jpg for the quality
parameter that you can pass to image.save()
quality
The image quality, on a scale from 1 (worst) to 95 (best). The default is 75. Values above 95 should be avoided; 100 disables portions of the JPEG compression algorithm, and results in large files with hardly any gain in image quality.
Either
- move to a non-compressive format (
png
f.e.) or - copy the file using file operations: see f.e. How do I copy a file in Python?
Related:
- Why is the quality of JPEG images produced by PIL so poor?
Related Topics
How to Check the Multiple Permission at Single Request in Android M
How to to Check If a User Has Rated Your App on the Google Play
How to Write a Custom Filter for Listview with Arrayadapter
How to Change Style of a Default Edittext
Android Datepicker Min Max Date Before API Level 11
Android Studio 3.0 Manifest Error: Unknown Element <Action> Found
Mediarecorder Start Failed: -38
Why "This App Has Been Built with an Incorrect Configuration" Error Occured in Some Phones
Error: Failed to Resolve: Com.Android.Support:Appcompat-V7:29.0.1'
Android Phone Orientation Overview Including Compass
Start Activity with an Animation
Menuitem Tinting on Appcompat Toolbar
How to Add External Fonts to Android Application
Send Touch Events to a Device via Adb
Why Does It Take So Long for Android's Mediaplayer to Prepare Some Live Streams for Playback
Simple Httpurlconnection Post File Multipart/Form-Data from Android to Google Blobstore