I'm writing a scientific program that has some intermediate results (plots and images) that I'd like to log (additional to the usual text messages).
I like python's logging interface a lot, so I'm wondering if there is a possibility to use it to create log files that include images.
The first idea that came to my mind was creating a log file as a SVG, so the log text is machine readable and the images can be included easily.
Is there a better approach to make this possible?
You could use SVG, but I'm not sure how compact the SVG would be since it would probably (in general) store the bitmap rather than vector information. An alternative would be to base64-encode the image and store it using a structured format, as documented here - the linked example uses JSON, which might be handy to e.g. store metadata about the image, but you could use a simpler scheme if all you're storing is the image and the format is always the same.
Related
I'm an experienced Python programmer with plenty of image manipulation and computer vision experience. I'm very familiar with all of the standard tools like PIL, Pillow, opencv, numpy, and scikit-image.
How would I go about reading an image into a Python data format like a nested list, bytearray, or similar, if I only had the standard library to work with?
I realize that different image formats have different specifications. My question is how I would even begin to build a function that reads any given format.
NOTE Python 2.6 had a jpeg module in the standard library that has since been deprecated. Let's not discuss that since it is unsupported.
If you're asking how to implement these formats "from scratch" (since the standard libraries don't do this), then a good starting point would be the format specification.
For PNG, this is https://www.w3.org/TR/2003/REC-PNG-20031110/. It defines the makeup of a PNG stream, consisting of the signature (eight bytes, 8950 4e47 0d0a 1a0a, which identifies the file as a PNG image) and a number of data chunks that contain meta data, palette information and the image itself. (It's certainly a substantial project to take on, if you really don't want to use the existing libraries, but not overly so.)
For BMP, it's a bit easier since the file already contains the uncompressed pixel data and you only need to know how to find the size and offset; some of the format definition is on Wikipedia (https://en.wikipedia.org/wiki/BMP_file_format) and here: http://www.digicamsoft.com/bmp/bmp.html
JPG is much trickier. The file doesn't store pixels, but rather "wavelets" which are transformed into the pixel map you see on the screen. To read this format, you'll need to implement this transformation function.
I'm using py-wand to read images in Python. All I really want though is the image meta information, like size, format, color depth, etc. I don't want to load the entire image. Some of my images are extremely large and loading them this way is causing memory problems.
How can I get just the meta information?
The Magickwand method for this is MagickPingImageFile. I quickly skimmed the pywand documentation and didn't see a binding to this method, but it might be provided under another name than 'ping'. It may require a feature request.
I'm writing an app that converts different images to JPG. It operates over a complex directory structure. There, a directory may include other directories, image files (JPG, GIF, PNG, TIFF), PDF files, RAR/ZIP archives, which in turn may include anything of the above. The app finds everything that can be converted to an image and places the resulting JPGs into a separate folder.
How do i write integration tests to test the conversion of images? Specifically, how should i fake the complex directory structure with all the files?
Currently i just store a sample directory structure, which i manually assembled out of various image, PDF and archive files, in a tests/ directory. In a setUp method i put this sample directory in place of the actual data and run the code. I had an idea to generate all these sample files myself (generate JPGs via Imagemagick, for example), but it proved hard.
How integration testing on images is usually done?
Do you write your own library to convert images of you just use existing library? In the latter case you simply do not test it. Author has already tested it somehow. You just need to create an abstraction layer between your code and the image library you use. Then you can simply check if your code calls the library with desired parameters.
If you really insist on testing pictures then you need to make the transformation deterministic (and compare actual result with expected result) or you need to make comparison a bit less strict (from ignoring date fields to OCR recognizing the image).
Testing files is way easier (you do not need probability based OCR).Check if your program placed all files in expected location.
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?
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.