Can PIL be used to get dimensions of an svg file? - python

I have svg files which I would like to compare based on their dimensions.
I read about PIL as the best image tool in python. Does PIL handle svg files? I can't seem to find this anywhere.
When googling I saw people interpreting svg files as text which seems counterintuitive.
What if not PIL is be the best way to get the x & y dimensions of a .svg file?
Thanks

PIL handles many image types, but not (yet?) SVG. Partly, this is because SVG is a set of instructions to produce an image, not a container for raw image data.
Fortunately, SVG can be read as XML, using the tool of your choice; for example, xml.etree.ElementTree in the Python standard library.
Unfortunately, by its nature, SVG doesn't have a single native size. Instead, it has two size concepts: the view box, and the height and width attributes.
If your svg file has width and height attributes, you can safely use those as the x and y dimensions, respectively. Otherwise, if it has a viewBox attribute, it is meant to scale to any size you need it to; however, you can use its third and fourth numbers as width and height, if you need to.
Worse, SVG files could lack either one. In that case, one could potentially compute a height and width based on the elements in the file, but that's trickier than anyone really wants to do, given the full capabilities of the format.

Related

Converting svg to png without changing the pixel values

I have been stuck in this problem for some time now. Essentially, I have a bunch of svg images. Each 'child' in the svg file has been labelled with some pixel value. Currently the number of this values is very small and everything is labelled as rgb(0.0, 0.0, 0.0), rgb(1.0, 1.0, 1.0) ... rgb(9.0, 9.0, 9.0), so essentially I have 10 different types of pixels.
Now, I want to convert these images into png format, and more importantly I need the mapping of pixel values to be 1-to-1. Essentially, all pixels that have values rgb(0.0, 0.0, 0.0) in svg files, need to have values rgb(x,x,x) in png files (or even better L(x)); rgb(1.0, 1.0, 1.0) on svg files need to be converted to rgb(y,y,y) on png files (or even better L(y)) and so on. This one to one mapping is a dealbreaker for my application, because this is essentially the ground truth for my work.
By simply writing in the console:
convert test.svg test.png
doesn't give me what I want. Checking the historgram of values, it seems that I have 248 unique values instead of 10, and that isn't good for me (despite that the vast majority of them have just a few pixels).
Does anyone know:
if this can be done.
how this can be done.
I've tried so far using other libraries like Python's cairosvg but that seems to work even worse. Yes, I know that svg and png are totally different formats.
For clarification, adding an svg and a png file:
svg: https://drive.google.com/open?id=0B_vhcDz1zxeYeGVDSnhfeWplOWs
png: https://drive.google.com/open?id=0B_vhcDz1zxeYUnYzZUtIUmVqVWM
Opening the file in Python, seems that there are 248 unique pixel values, while there should be only 4 (background + three symbols).
Thanks!
Your request isn't making a lot of sense. As far as I can see, your sample SVG file only has two colours: black and white (rgb(255.0, 255.0, 255.0)). So where does this 10 colours idea come from?
Also the SVG standard does not specify exactly how vector shapes should be converted to pixels. There will be subtle differences between SVG renderers.
Remember that vector shape edges that pass through the middle of a pixel will produce a grey pixel. This is called anti-aliasing. It is designed to give a smoother look to the edge. And I imagine that is why you are seeing many more pixel values than you expect.
Perhaps what you are saying is that you want a way to disable anti-aliasing? Some conversion programs may have options to do this. Alternatively you can try adding the shape-rendering attribute to the root <svg> tag of your file:
<ns0:svg ...(snip)... shape-rendering="crispEdges">
However some SVG conversion programs may not support this attribute. But you can see it working if you try it in most browsers.
The output generated by turning antialiasing off will not look as good. But perhaps for your purposes you don't care about that.
Alternatively, perhaps you are wanting to know how to convert the SVG to a bitmap, whilst limiting the antialiasing to 10 specific levels of grey? Imagemagick lets you do that. I am not an Imagemagick user, but apparently you can tell imagemagick to use a specific colour paletter by passing a palette image using the -map parameter.
3 Years but no great solution gg:
I found 2 good ones:
in the ImageMagick command line you can use:
"convert in.svg +antialias out.png"
but be careful my source said that "+" deactivates AA and "-" activates it. But the source is pretty old and this seems strange so. I couldn't try this
Inkscape brought a great solution in an update (I tried this in Version 1.0.1):
in the Advanced Settings for "export png" you can choose Antialiasing directly "CAIRO_ANTIALIAS_NONE" works perfectly for me

Extract tiles from tiled TIFF and store in numpy array

My overall goal is to crop several regions from an input mirax (.mrxs) slide image to JPEG output files.
Here is what one of these images looks like:
Note that the darker grey area is part of the image, and the regions I ultimately wish to extract in JPEG format are the 3 black square regions.
Now, for the specifics:
I'm able to extract the color channels from the mirax image into 3 separate TIFF files using vips on the command line:
vips extract_band INPUT.mrxs OUTPUT.tiff[tile,compression=jpeg] C --n 1
Where C corresponds to the channel number (0-2), and each output file is about 250 MB in size.
The next job is to somehow recognize and extract the regions of interest from the images, so I turned to several python imaging libraries, and this is where I encountered difficulties.
When I try to load any of the TIFFs using OpenCV using:
i = cv2.imread('/home/user/input_img.tiff',cv2.IMREAD_ANYDEPTH)
I get an error error: (-211) The total matrix size does not fit to "size_t" type in function setSize
I managed to get a little more traction with Pillow, by doing:
from PIL import Image
tiff = Image.open('/home/user/input_img.tiff')
print len(tiff.tile)
print tiff.tile[0]
print tiff.info
which outputs:
636633
('jpeg', (0, 0, 128, 128), 8, ('L', ''))
{'compression': 'jpeg', 'dpi': (25.4, 25.4)}
However, beyond loading the image, I can't seem to perform any useful operations; for example doing tiff.tostring() results in a MemoryError (I do this in an attempt to convert the PIL object to a numpy array) I'm not sure this operation is even valid given the existence of tiles.
From my limited understanding, these TIFFs store the image data in 'tiles' (of which the above image contains 636633) in a JPEG-compressed format.
It's not clear to me, however, how would one would extract these tiles for use as regular JPEG images, or even whether the sequence of steps in the above process I outlined is a potentially useful way of accomplishing the overall goal of extracting the ROIs from the mirax image.
If I'm on the right track, then some guidance would be appreciated, or, if there's another way to accomplish my goal using vips/openslide without python I would be interested in hearing ideas. Additionally, more information about how I could deal with or understand the TIFF files I described would also be helpful.
The ideal situations would include:
1) Some kind of autocropping feature in vips/openslide which can generate JPEGs from either the TIFFs or original mirax image, along the lines of what the following command does, but without generated tens of thousands of images:
vips dzsave CMU-1.mrxs[autocrop] pyramid
2) Being able to extract tiles from the TIFFs and store the data corresponding to the image region as a numpy array in order to detect the 3 ROIs using OpenCV or another methd.
I would use the vips Python binding, it's very like PIL but can handle these huge images. Try something like:
from gi.repository import Vips
slide = Vips.Image.new_from_file(sys.argv[1])
tile = slide.extract_area(left, top, width, height)
tile.write_to_file(sys.argv[2])
You can also extract areas on the command-line, of course:
$ vips extract_area INPUT.mrxs OUTPUT.tiff left top width height
Though that will be a little slower than a loop in Python. You can use crop as a synonym for extract_area.
openslide attaches a lot of metadata to the image describing the layout and position of the various subimages. Try:
$ vipsheader -a myslide.mrxs
And have a look through the output. You might be able to calculate the position of your subimages from that. I would also ask on the openslide mailing list, they are very expert and very helpful.
One more thing you could try: get a low-res overview, corner-detect on that, then extract the tiles from the high-res image. To get a low-res version of your slide, try:
$ vips copy myslide.mrxs[level=7] overview.tif
Level 7 is downsampled by 2 ** 7, so 128x.

Making a 3 Colour FITS file using aplpy

I am trying to make a three colour FITS image using the $aplpy.make_rgb_image$ function. I use three separate FITS images in RGB to do so and am able to save a colour image in png, jpeg.... formats, but I would prefer to save its as a FITS file.
When I try that I get the following error.
IOError: FITS save handler not installed
I've tried to find a solution in the web for a few days but was unable to get any good results.
Would anyone know how to get such a handler installed, or perhaps any other approach I could use to get this done?
I don't think there is enough information for me to answer your question completely; for example, I don't know what call you are making to perform the "image" "save", but I can guess:
FITS does not store RGB data like you wish it to. FITS can store multi-band data as individual monochromatic data layers in a multi-extension data "cube". Software, including ds9 and aplpy, can read that FITS data cube and author RGB images in RGB formats (png, jpg...). The error you see comes from PIL, which has no backend to author FITS files (I think, but the validity of that point doesn't matter).
So I think that you should use aplpy.make_rgb_cube to save a 3 HDU FITS cube based your 3 input FITS files, then import that FITS cube back into aplpy and use aplpy.make_rgb_image to output RGB compatible formats. This way you have the saved FITS cube in near native astronomy formats, and a means to create RGB formats from a variety of tools that can import that cube.

Python: replace a rgb colour with a colour with alpha pixels. batch convert 400 images

How can I replace a colour across multiple images with another in python? I have a folder with 400 sprite animations. I would like to change the block coloured shadow (111,79,51) with one which has alpha transparencies. I could easily do the batch converting using:
img = glob.glob(filepath\*.bmp)
however I dont know how I could change the pixel colours. If it makes any difference, the images are all 96x96 and i dont care how long the process is. I am using python 3.2.2 so I cant really use PIL (I think)
BMP is a windows file format, so you will need PIL or something like it; or you can roll your own reader/writer. The basic modules won't help as far as I'm aware. You can read PPM and GIF using Tk (PhotoImage()) which is part of the standard distribution and use get() and put() on that image to change pixel values. See references online, because it's not straight-forward - the pixels come from get() as 3-tuple integers, but need to go back to put() as space-separated hex text!
Are your images in indexed mode (8 bit per pixel with a palette),or "truecolor" 32bpp images? If they are in indexed modes, it would not be hard to simply mark the palette entry for that color to be transparent across all files.
Otherwise, you will really have to process all pixel data. It also could be done by writting a Python script for GIMP - but that would require Python-2 nonetheless.

Is there a way to extract text information from a postscript file? (.ps .eps)

I want to extract the text information contained in a postscript image file (the captions to my axis labels).
These images were generated with pgplot. I have tried ps2ascii and ps2txt on Ubuntu but they didn't produce any useful results. Does anyone know of another method?
Thanks
It's likely that pgplot drew the fonts in the text directly with lines rather than using text. Especially since pgplot is designed to output to a huge range of devices including plotters where you would have to do this.
Edit:
If you have enough plots to be worth
the effort than it's a very simple
image processing task. Convert each
page to something like tiff, in mono
chrome Threshold the image to binary,
the text will be max pixel value.
Use a template matching technique.
If you have a limited set of
possible labels then just match the
entire label, you can even start
with a template of the correct size
and rotation. Then just flag each
plot as containing label[1-n], no
need to read the actual text.
If you
don't know the label then you can
still do OCR fairly easily, just
extract the region around the axis,
rotate it for the vertical - and use
Google's free OCR lib
If you have pgplot you can even
build the training set for OCR or
the template images directly rather
than having to harvest them from the
image list

Categories