I'm trying to figure out the reason, why this code snippet returns False:
decodedBase64 = tf.io.decode_base64(imgBase64)
decodedBase64==tf.io.encode_png(tf.io.decode_png(decodedBase64))
A png image can be compressed and decode_png detects it, so I used different 'compression=' values in encode_png. I still got False with all values between -1 to 9.
What can be done to retrieve correct decodedBase64 characteristics to make encode_png <-> decode_png reversible?
I am not very familiar with tensorflow and your code is not runnable to be able to try it, so I may well be wrong and will delete my answer if so. I also think that the base64 encoding and decoding is something of a red herring. I think you are actually asking why you get a different PNG from one you already have when you encode with tensorflow. If so, there are several possible reasons:
the date and time may be encoded in the PNG so if you write a PNG and then write it again with the same compression 1 second later, it will differ if that is the case
the original PNG might have been created with a different library, a different version or different parameters, and although you will get the same pixels back because the encoding is lossless, the encoded data on disk could differ. For example, one library might choose a different filter for some rows - or no filter at all
Of course, if you want a definitive rather than speculative answer, you'd need to share the 2 PNGs - unmodified.
Related
I saved the image to the clipboard, and when I read the image information from the clipboard and saved it locally, the image quality changed. How can I save it to maintain the original high quality?
from PIL import ImageGrab
im = ImageGrab.grabclipboard()
im.save('somefile.png','PNG')
I tried adding the parameter 'quality=95' in im.save(), but it didn't work. The original image quality is 131K, and the saved image is 112K.
The size of the file is not directly related to the quality of the image. It also depends on how efficiently the encoder does its job. As it is PNG, the process is lossless, so you don't need to worry - the quality is retained.
Note that the quality parameter has a different meaning when saving JPEG files versus PNG files:
With JPEG files, if you specify a lower quality you are effectively allowing the encoder to discard more information and give up image quality in return for a smaller file size.
With PNG, your encoding and decoding are lossless. The quality is a hint to the decoder as to how much time to spend compressing the file (always losslessly) and about the types of filtering/encoding that may suit best. It is more akin to the parameter to gzip like --best or --fast.
Further information about PNG format is here on Wikipedia.
Without analysing the content of the two images it is impossible to say why the sizes differ - there could be many reasons:
One encoder may have noticed that the image contains fewer than 256 colours and so has decided to use a palette whereas the other may not have done. That could make the images size differ by a factor of 3 times, yet the quality would be identical.
One encoder may use a larger buffer and spend longer looking for repeating patterns in the image. For a simplistic example, imagine the image was 32,000 pixels wide and each line was the same as the one above. If one encoder uses an 8kB buffer, it can never spot that the image just repeats over and over down the page so it has to encode every single line in full, whereas an encoder with a 64kB buffer might just be able to use 1 byte per line and use the PNG filtering to say "same as line above".
One encoder might decide, on grounds of simplicity of code or for lack of code space, to always encode the data in a 16-bit version even if it could use just 8 bits.
One encoder might decide it is always going to store an alpha layer even if it is opaque because that may make the code/data cleaner simpler.
One encoder may always elect to do no filtering, whilst the other has the code required to do sub, up, average or Paeth filtering.
One encoder may not have enough memory to hold the entire image, so it may have to use a simplistic approach to be assured that it can handle whatever turns up later in the image stream.
I just made these examples up - don't take them was gospel - I am just trying to illustrate some possibilities.
To reproduce an exact copy of file from a clipboard, the only way is if the clipboard contains a byte-for-byte copy of the original. This does not happen when the content comes from the "Copy" function in a program.
In theory a program could be created to do that by setting a blob-type object with a copy of the original file, but that would be highly inefficient and defeat the purpose of the clipboard.
Some points:
- When you copy into the clipboard using the file manager, the clipboard will have a reference to the original file (not the entire file which can potentially be much larger than ram)
- Most programs will set the clipboard contents to some "useful version" of the displayed or selected data. This is very much subject to interpretation by the creator of the program.
- Parsing the clipboard content when reading an image is again subject to the whims of the library used to process the data and pack it back into an image format.
Generally if you want to copy a file exactly you will be better off just copying the original file.
Having said that: Evaluate the purpose of the copy-paste process and decide whether the data you get from the clipboard is "good enough" for the intended purpose. This obviously depends on what you want to use it for.
I am working on an application that requires images submitted to it to be lossless. Currently I am opening the image with PIL and checking if the "format" attribute is a lossless format. This requires me to manually keep a list of formats, and I have no idea if, for instance, a jpeg that was submitted just happens to have the lossless variant applied.
import PIL
import PIL.Image
def validate_image(path):
img = PIL.Image.open(path)
if not img.format.lower() in ['bmp', 'gif', 'png', ...]:
raise Exception("File %s has invalid image format %s" % (path, img.format))
Is there a better way to check if the image file is lossless?
I think I now understand things: You want to open the images via PIL. You want to reject lossy images because you're doing scientific processing of some kind that needs all that lost data because information that's unimportant for human visual processing is important for your algorithms.
PIL does not have any kind of interface at the top level to distinguish different types of compression. You could reach inside the image decoders and assume that anything that uses the "raw" decoder is lossless, but even if you wanted to do that, that's too limited—it'll rule out GIF, LZW-compressed TIFF, etc. along with JPEG, JPEG-compressed TIFF, etc.
Keep in mind that the real problem is here is messaging and documentation—managing user expectations. The check for lossy images is really just a heuristic, a way to catch the more obvious mistakes and remind the user what the requirements are. So, you don't need something perfect, but having something pretty good may be helpful anyway.
So, there are only a few options, none of them very good:
Hack up PIL's decoder source to retain the encoding information and pass it up to the top level. This is, obviously, going to take some non-trivial work, in 30 different importers, possibly involving C as well as Python, and it will result in a patch that you have to maintain against a (slowly-)evolving codebase—although of course you can always submit it upstream and hope that it makes it into future versions of PIL.
Dig into the decoders themselves to get the information at runtime. The only semi-standard thing you can really find is whether they use the raw decoder or the bit decoder, which isn't useful at all (many lossless formats will need the bit decoder), so you'll probably end up reading all 30 importers and writing a dozen or so pieces of code to extract information from them.
Use another library along with (or in place of) PIL. For example, while ImageMagick is definitely not significantly easier than PIL, it does have an API to tell you what type of compression an image file uses. Basically, if it's UndefinedCompression or JPEGCompression it's lossy, anything else, it's lossless. The major downside (besides needing to install two image libraries) is that there will be files that PIL can open but IM can't, and vice-versa, and multi-image files that PIL and IM handle differently, and so on.
Do what you're already doing. Read through the 30 importers to make a list of which are lossy and which are lossless. To handle cases like JPEG and TIFF that are sometimes lossless, you may want to write code that doesn't flat-out reject them, but instead gives a warning saying "These files may be lossy. Are you sure you want to import them?" (Or, alternatively, just offer an "I know what I'm doing" override for all lossy formats, and then just consider JPEG and TIFF lossy.)
For many use cases, I'd be very wary of going with #4, but for yours, it actually seems pretty reasonable. You're not trying to block lossy images because your code will crash, or for security reasons, or anything like that; you're just trying to warn people that they're going to waste a lot of time getting useless information if they submit a JPEG, right?
in a local as3 application i need to capture a video at 25 frames per second and send the bytearray to a local python script.
when i try to encode the bytearray to png inside as3 it is much to slow.
so i decided to just write the raw bytearray i got from :
var bitmapdata:BitmapData = new BitmapData(_videow,_videoh,false,0);
bitmapdata.draw(_video);
var ba:ByteArray=bitmapdata.getPixels(bitmapdata.rect);
this is pretty performant and does not drop frames so far.
however, i need to convert these raw bytes to png on the python side.
any idea how i can achieve that?
thanks!
It's roughly the same as PCX* (some earlier variant of BMP). It is actually very similar to BMP, save that there are no headers, and the pixels are written from left to right, top down ARGB for transparent bitmapdata and RGB for solid.
What PNG encoder did you use? Have you tried this one: http://www.blooddy.by/en/crypto/ ? Of course, Python may be using GD / Imagemagic behind the scenes, so, obviously C code would be faster, but if you wanted it to run on the user's PC, then I'd give this a try.
PS: http://www.senocular.com/flash/actionscript/?file=ActionScript_3.0/com/senocular/images/BMPEncoder.as this may give some insights, as it is converting bitmapdata into BMP.
Sorry, that's not a PCX, I've confused PCX to something else, it's just a variant of BMP, with a different pixel ordering.
Does anyone know a way get the pixel data from a PythonMagick.Image instance without having to write it to disk first?
For instance, I can read in an image using:
import PythonMagick
im = PythonMagick.Image('image.jp2')
I would now like to be able to get the uncompressed image data so that I can use it in something else like NumPy or matplotlib, but I can't seem to find any way to do this. I would just use matplotlib or PIL directly but the image format I'm reading in is JPEG 2000 which is only supported by PythonMagick as far as I know.
Any suggestions?
Disclaimer: I don't have PythonMagick built where I am right now and am no expert, so (1) any or all of the following may be wrong, (2) it will certainly be less specific than you'd like, and (3) if someone else knows better I hope they won't be put off by seeing an answer already here. Anyway:
From a quick look at the code, it looks as if you can read pixel values one by one using the pixelColor method on the Image class. This returns a PythonMagick.Color value, from which you can extract R,G,B components. The underlying C++ library supports reading out lots of pixels at a time using Image::writePixels, which is also present in PythonMagick.Image; but I think the proper use of that method depends on other things that aren't implemented in PythonMagick. That's a pity, because I bet it would have been much much more efficient than reading one pixel at a time.
Alternatively and probably better, it looks as if you can write the contents of the image to a PythonMagick.Blob object in memory, which basically does the same as writing to a file only without the file :-). You can choose what format it should write in, just as you do when writing to a file. There seems to be something called get_blob_data for extracting the contents of a Blob. Something like this:
im = PythonMagick.Image('image.jp2')
blob = PythonMagick.Blob()
im.write(blob, "png")
data = PythonMagick.get_blob_data(blob)
The resulting data is, I think, a Python string whose bytes are the binary representation of the image. (I'm assuming you're using Python 2.x, where the string type is 8-bit. I don't know whether PythonMagick works with 3.x.) I think there are some formats that are basically raw pixel data; try "RGB". You can then extract the contents via lots of struct.unpack or whatever.
I'm working on a Python tool to convert image data into these color formats:
RGB565
RGBA5551
RGBA4444.
What's the simplest way to achieve this?
I've used the Python Imaging Library (PIL) frequently. So I know how to load an image and obtain each pixel value in RGBA8888 format. And I know how to write all the conversion code manually from that point.
Is there an easier way? Perhaps some type of 'formatter' plugin for PIL?
Does PIL already support some of the formats I'm targeting? I can't ever figure out which formats PIL really supports without digging though all of the source code.
Or is there a better library than PIL to accomplish this in Python?
Any tips would be appreciated. Thanks!
Changing something from 8 to 5 bits is trivial. In 8 bits the value is between 0 and 255, in 5 bits it's between 0 and 31, so all you need to do is divide the value with 8. Or 4 in the case for green in RGB565 mode. Or 16 in RGBA4444 mode as it uses 4 bits per channel, etc.
Edit: Reading through your question again, I think there is a confusion (either with me or you). RGB555 and RGBA4444 etc are not really formats, like GIF or JPG, they are color spaces. That conversion is trivial (see above). What file format you want to save it in later is another question. Most file formats have limited support for color spaces. I think for example that JPEG always saves it in YCbCr (but I could be mistaken), GIF uses a palette (which in turn always is RGB888, I think) etc.
There's a module called Python Colormath which provides a lot of different conversions. Highly recommended.
Numpy is powerful indeed, but to get there and back to PIL requires two memory copies. Have you tried something along the following lines?
im = Image.open('yourimage.png')
im.putdata([yourfunction(r,g,b) for (r,g,b) in im.getdata()])
This is quite fast (especially when you can use a lookup table). I am not familiar with the colour spaces you mention, but as I understand you know the conversion so implementation of yourfunction(r,g,b) should be straight forward.
Also im.convert('RGBA', matrix) might be very powerful as it is super fast in applying a colour transformation through the supplied matrix. However I have never gotten that to do what I wanted it to do... :-/
There is also a module named Grapefruit that let you do conversions between quite a lot of color formats.
I ended up doing the conversions manually as Lennart Regebro suggested.
However, pure Python (iterating over each pixel) turned out to be too slow.
My final solution used PIL to load the image and numpy to operate on (convert) an array of pixels.