I'm trying to understand the JPEG compression process and performed the following steps to verify a few things.
I take an input image img1.jpg and compress it by using IrfanView, say quality=50 (img1_compress.jpg).
Then I crop a small block from the input image img1.jpg (block.jpg of size 8x8 at X,Y=16,16) and compress it by using the same value of quality parameter (50). Let's call it block_compress.jpg.
Now when I compare this block's pixel values with the one in fully compressed image, they don't match.
To clarify, the pixel value at position 0,0 in block_compress.jpg should match with the pixel value at position 16,16 in img1_compress.jpg.
I'm confused why pixel values don't match? Any ideas?
I just did this experiment with my JPEG codec and the pixel values match. Irfanview may be applying some kind of noise filter or other modifications when it compresses JPEG images. Without seeing the source code to the codec you can't know what it's doing. Your experiment is valid, but by using other people's code to test your theory you can't know what's really going on inside their code.
JPEG is lossy compression algorithm. Compressing one image with identical compression settings in different tools can produce differ result. You need use one of lossless algorithms if you want pixel-to-pixel result. I.e. you can use PNG
"the DC component of each 8x8 block is predicted from the previous block.” : by Oli Charlesworth
Related
Imagemagick can invert the colors of a JPEG like so:
mogrify -negate image.jpg
However, that's not lossless. My intuition says that color inversion should be doable in a lossless fashion, at least for grayscale images, but I know hardly anything about JPEG. Hence my questions:
Is lossless JPEG grayscale inversion possible in theory?
If so, is libjpeg or any other software out there able to do it?
It's not lossless because there is not a 1:1 match between the gamuts of the RGB and YCbCr colorspaces used in JPEG. If you start with an RGB value that is within YCbCR and flip it, you may get a value outside the YCbCr colorspace range that will end up getting clamped.
JPEG encodes images as a series of entropy coded deltas across MCUs (minimum coded units - 8x8 blocks of DCT values) and entropy coded quantized DCT coefficients within each MCU. To do something like inverting the pixel values (even if grayscale) would involve decoding the entropy coded bits, modifying the values and re-encoding them since you can't "invert" entropy coded DCT values. There isn't a one to one matching of entropy coded lengths for each value because the bits are encoded based on the statistical probability and the magnitude/sign of quantized values. The other problem is that the coded DCT values exist in the frequency domain. I'm not a mathematician, so I can't say for sure if there is a simple way to invert the spatial domain values in the frequency domain, but I think at best it's really complicated and likely the quantization of the values will interfere with a simple solution. The kind of things you can do losslessly in JPEG files is rotate, crop and less well known operations such as extracting a grayscale image from a color image. Individual pixel values can't be modified without having to decode and recode the MCUs which incurs the "loss" in JPEG quality.
I just tried to convert few JPEGs to a GIF image using some online services. For a collection of 1.8 MB of randomly selected JPEGs, the resultant GIF was about 3.8 MB in size (without any extra compression enabled).
I understand GIF is lossless compression. And that's why I expected the resultant output to be around 1.8 MB (input size). Can someone please help me understand what's happening with this extra space ?
Additionally, is there a better way to bundle a set of images which are similar to each other (for transmission) ?
JPEG is a lossy compressed file, but still it is compressed. When it uncompresses into raw pixel data and then recompressed into GIF, it is logical to get that bigger a size
GIF is worse as a compression method for photographs, it is suited for flat colored drawings mostly. It uses RLE [run-length encoding] if I remember well, that is you get entries in the compressed file that mean "repeat this value N times", so you need to have lots of same colored pixels in horizontal sequence to get good compression.
If you have images that are similar to each other, maybe you should consider packing them as consequtive frames (the more similar should be closer) of a video stream and use some lossless compressor (or even risk it with a lossy one) for video, but maybe this is an overkill.
If you have a color image, multiply the width x height x 3. That is the normal size of the uncompressed image data.
GIF and JPEG are two difference methods for compressing that data. GIF uses the LZW method of compression. In that method the encoder creates a dictionary of previously encountered data sequences. The encoder write codes representing sequences rather than the actual data. This can actual result in an file larger than the actual image data if the encode cannot find such sequences.
These GIF sequences are more likely to occur in drawing where the same colors are used, rather than in photographic images where the color varies subtly through out.
JPEG uses a series of compression steps. These have the drawback that you might not get out exactly what you put in. The first of these is conversion from RGB to YCbCr. There is not a 1-to-1 mapping between these colorspaces so modification can occur there.
Next is subsampling.The reason for going to YCbCr is that you can sample the Cb and Cr components at a lower rate than the Y component and still get good representation of the original image. If you do 1 Y to 4 Cb and 4 Cr you reduce the amount of data to compress by half.
Next is the discrete cosine transform. This is a real number calculation performed on integers. That can produce rounding errors.
Next is quantization. In this step less significant values from the DCT are discarded (less data to compress). It also introduces errors from integer division.
I'm very interested in understanding how graphic file format (PNG, JPG, GIF) work. Are there any code examples that demonstrate how these files are made and also how they are interpreted (viewed in browser)?
Regardless of which graphic file format you are working with, you need to understand the basic nature that all graphic files have in common.
File Header
File Type, Version, (Time & Date Stamp - if included)
Possible data structure/s info or chunks
Flags for which color type to be expected, if compression is available and which type, byte order (endian), has transparency, and other various flags.
Image Data Info
Width normally in pixels sometimes in pels, bits or bytes
Height normally in pixels sometimes in pels, bits or bytes
Bits Per Pixel or Pixel Depth
Image Size in Bytes: numPixelsWidth * numPixelsHeight * ((bits or bytes) for each pixel)
Color Type: - Each Pixel has color data which can vary
Gray Scale
Palette
Color RGB
Color RGBA
Possible Others
If Compression Is Present Which Coding and Encoding Is Used
The actual image data
Once you understand this basic structure then parsing image files becomes easier once you know the specification to the file structure you are working with. When you know how many bytes to read in to your file pointer that includes all headers and chunks, then you can advance your file pointer to the data structure that will read in or write out all the pixel (color) data. In many cases the pixel data is usually 24bits per pixel such that each channel RGBA - Red, Green, Blue, and Alpha are 8bits each or one byte same as an unsigned char. This is represented in either a structure or a two dimensional array. Either way once you know the file's structure and know how to read in the actual image or color data you can easily store it into a single array. Then what you do with it from there depends on your application's needs.
The most detailed information can be obtained by reading the file format specification and implementing a parser in the language you know best.
A good way would be to read the format and transform it into an array of four byte tupples (RGBA, the red, green, blue and alpha parts of a color) This will allow you to use this format as an in between format between formats for easy conversion. At the same time most APIs support the displaying of this raw format.
A good format to get started with is BMP. As old as it is, if this is your first encounter with writing a parser this is a safe an 'easy' format. A good second format is PNG. Start with the uncompressed variations and later add the compression.
Next step is TGA to learn reading chunks or JPG to learn more about compression.
Extra tip: Some implementations of writers contain(ed) errors causing images to be in violation of the format. Others added extra features that never made it to the official specs. When writing a parser this can be a real pain. When you are running into problems always second guess the image you are trying to read. A good binary/hex file reader/editor can be a very helpful tool. I used AXE, if I remember correctly it allows you to overlay the hex codes with a format so you can quickly recognize the header and chunks.
I have read that for reading a compressed image into memory it must be decompressed first and the original size will be allocated. So, since it is decompressed and it's size before compression is allocated in memory, why is the resolution of a compressed image when viewed with a certain software not the same of the original one?
Compression is not about reducing the resolution, or size in pixels, of an image. Compression is about reducing the amount of bytes required to represent a specific image.
You can see an image as an array of 4-byte structures, one for each pixel, where each byte represents one of the components of the color of each pixel, namely red, green, blue and alpha. The size required to represent an image with this scheme is
width * height * 4
So a 100x100 pixel image would have 10000 pixels, and therefore consume 40000 bytes. This is in fact, roughly the way in which the BMP format stores images.
However, this is not the only way you can represent those 10000 pixels. If, for example, the first 5000 pixels are blue, and the bottom pixels are brown, you could represent the image by saying something like "blue: 5000, brown 5000", and that would take much fewer bytes to represent. This scheme is roughly how RLE (Run Length Encoding) works, and is widely used in many formats such as GIF.
However, there is only so much you can do to reduce the amount of bytes required to represent the bytes in your image. The data is not always easy to represent with fewer bytes, so what some compression algorithms, like the one used in JPEG files do, is to modify the pixels just a bit, so the data is much easier to compress, yet the changes are not very noticeable. If such changes are acceptable, it is possible to achieve impressive results when compressing the image. This is what is called "lossy compression".
The entire point of compressing images is to make it easier to move images from one place to another, be it by storing them on a disc or sending them over the internet. However, when you are going to display an image, your computer has to tell the monitor what color each pixel has to get, so once you are going to display the image, you need to decompress it.
Technically, decompressing a compressed image does maintain the quality of the compressed image. However compressing an image may reduce quality (ie. the compressed image is slightly degraded from the original image).
The specific changes to the image depend on what sort of compression you apply; that said, I'm not familiar with any sort of compression that would change the resolution or size of the image. Are you sure you got that right?
In my jpeg file there are few FFDA markers. From which marker my data starts, and how do I know from which marker I decode the file?
The JPEG standard has many options that are not used very often. A typical color image will have 3 color components (Y, Cr, Cb) interleaved in a single scan (one FFDA marker). They can also be stored in any combination in separate scans. A progressive JPEG image encodes multiple scans with more and more detail (AC coefficients) in each successive scan, but the standard allows any combination of color components and coefficients to be mixed in different scans. I have only seen one case of a non-progressive JPEG with separate scans for each color component; it came from an IP camera.
Your JPEG is probably progressive which means you have to decode the data after at least the first FFDA marker, which will bring you an intermediate result.
If this is your first attempt at making a JPEG decoder you should choose another image and try to implement a baseline decoder instead. Progressive images adds a lot of complexity to the problem.