4
$\begingroup$

For an extreme example, I have the following image that was a JPEG before stackexchange converted it to a PNG:-

square

Before you perform all sorts of funky image processing tricks on it, it's just a black square. This is what happens with my web cam when there is insufficient light. It just gets low pass filtered out and a black square results. The interesting thing is that when I pull up 100 consecutive images from the camera, they're all exactly 6616 bytes long. There must be an internal light level threshold.

My question is, why was this square's original file size fixed at 6616 bytes? That seems like a lot of overhead to store just a single repeated value of "0", and given that extremely low frequency images should compress greatly. Also, given the random (quantum) nature of the various noise sources impacting the sensor, I would expect some natural variation in size.

For reference, the original image is available here, and it came from this:-

webcam

$\endgroup$
1
  • 1
    $\begingroup$ Could you share the original JPEG somehow? I kinda doubt an actual JPEG image could be all black in practice $\endgroup$ May 1, 2018 at 13:41

3 Answers 3

2
$\begingroup$

This all boils down on what you call JPEG. If you are refering to the entire ITU-81 specifiation, then you can achieve much better compression ratio.

Since your image is no longer available online, let's craft one locally:

$ convert -depth 8 -size 640x480 xc:black black.pgm

Because of an issue in my version of cjpeg I will force usage of grayscale option here:

$ cjpeg -outfile black-huf.jpg -grayscale black.pgm
$ cjpeg -optimize -outfile black-opt.jpg -grayscale black.pgm
$ cjpeg -arithmetic -outfile black-arit.jpg -grayscale black.pgm

Lead to:

$ du -sb black*
128     black-arit.jpg
3932    black-huf.jpg
1361    black-opt.jpg
307215  black.pgm

Arithmetic coding works extremely well in this specific case. So JPEG as a container is perfectly suited for this special corner case.


As a side note, an image perfectly black can be encoded exactly without loss in JPEG format:

$ cjpeg -quality 100 -outfile black-noloss.jpg -grayscale black.pgm
$ djpeg -outfile noloss.pgm black-noloss.jpg
$ md5sum noloss.pgm black.pgm
b9bb7211d70263fb92e5e330d2dea877  noloss.pgm
b9bb7211d70263fb92e5e330d2dea877  black.pgm
$\endgroup$
2
$\begingroup$

The picture you've posted most certainly didn't come directly from the image sensor – it was processed by the camera hardware, and software; it's pure dark grey.

Anyway; JPEG (to be more specific: JFIF as the JPEG-carrying file format) is not zero overhead, and you can expect a couple kB for this kind of image to work.

There's a couple bytes of headers (it's really negligible), but then things get a bit more complicated:

  • For a monochrome image, the actual JPEG quality setting won't do anything to the file size; it just sets a quantization mask, and you're always hitting the DC bin with a value of nonzero for anything. No matter how that turns out, Run-Length Encoding for the rest of the bins in each 8x8 pixel block will reduce the rest to the same number of bytes, regardless of quantization.
  • What does matter is the subsampling mask for the channels. Stanley's answer is a tiny bit wrong w.r.t. to the three channels: JPEG does support 4:2:0 subsampling, meaning that you actually omit one channel every row. But that's a story for a different day. Anyways, since your image doesn't change spatially at all, that saves space
  • Entropy encoding (I think it's a Huffmann method) is applied to the rest. Since the picture is built from identical 8x8 blocks, these should be reduced to very little data at all.
  • There's the special JPEG/JFIF feature of interleaving the info in a way that allows the lower frequency parts of the image to be transferred first (e.g. for slow connections; if you grew up in the 90s, you'll remember pictures that got sharper gradually while you hoped for your dialup modem to take less costly time). While these practically make little difference for "typical" photos, for your monochrome picture, they'll make matters worse and increase the file size by some 20 to 25%, maybe.

So, 6 kB is actually pretty OK, and you should probably look into whatever gave you that picture – it's definitely heavily smoothing the image, to a degree that the data you're presented has nothing to do with what the sensor sees. The sensor sees noise.

$\endgroup$
2
$\begingroup$

JPEG standard will not care about how an image was generated; rather it looks for their block based statistical properties reflected in their quantized DCT coefficients. Under the same compression settings and the same image information, the same output will be produced.

As Marcus has stated, the size is pretty ok even for such a whole zero image. Consider the number of 8 x 8 blocks in your 640 x 480 image: there will be 4800 blocks. As far as I remember, every JPEG block must have at least a single code indicating its end of block (EOB) information which is 1010 in binary.

Then assuming that all your 4800 blocks have an at least one EOB symbol code, and further that they have also to indicate their DC coefficient of quantized DCT transforms (AC coefficents all seem to be zero for this particular case), then that amounts to a few kilobytes depending on how that single DC value was encoded by the standard Huffman entropy table(s) (or a custom entropy table which is allowed and located in a JPEG header).

The header may also contain AC and DC quantization tables for monochrome and RGB images and Huffman tables for both channels if a nondefault compression is employed. Quantization tables (masks) are 8 x 8 matrices and would not add much.

After all your image would take about 1 MB if it were stored as an RGB BMP and now in its RGB JPEG mode it takes only about 6 kB which is pretty good isn't it?

Try encoding in grayscale mode if possible... It reduced to 1.4 kB now.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.