I have a 3-d numpy array and save it using Pillow as JPEG image. When I reloaded the image using Pillow, the resulting numpy array is different. I write a demo code for this:
The answer is very simple...
JPEG is "lossy". It discards the least obvious details to save space - see Wikipedia entry for JPEG and scroll down looking for "Quantisation". It also doesn't even get started with 16-bit per sample/channel data.
PNG, BMP and TIFF (other than JPEG-encoded TIFF) are lossless - that means you get back exactly what you saved.
GIF is a bit different as it has a limited palette, so you may get back something different from what you saved depending on how many colours your original image had.
If your data is 16-bit per sample/channel, you should probably use PNG, NetPBM or TIFF because BMP can not store 16-bit per sample data - what they call 24-bit means 3 channels of 8-bits each.