How to get Numpy array of Canvas data? - python-3.x

I am building an application with Tkinter, where one is able to draw e.g. lines in a Canvas. This works well. However, I'm unable to find a method for getting the current Canvas data. Preferably I would like to get a numpy array out of the current Canvas data, since my post-processing steps are mostly using numpy.
Is there any way to build numpy arrays out of the Canvas data? In some color format like RGB, by preference?
I know that I can get the information e.g. of lines (like coordinates) out of the Canvas, but I do not need this information. I need a rasterized image data of the whole Canvas scene. Like a numpy array or a (rasterized) image (jpg, png, tiff, bitmap, ...).

Like #Bryan Oakley said: there is no way to get a rasterized version of a Tkinter Canvas drawing.
However, I figured out this workaround:
import skimage.io as ski_io
(...)
# draw your canvas
(...)
# save canvas to .eps (postscript) file
canvas.postscript(file="tmp_canvas.eps",
colormode="color",
width=CANVAS_WIDTH,
height=CANVAS_HEIGHT,
pagewidth=CANVAS_WIDTH-1,
pageheight=CANVAS_HEIGHT-1)
# read the postscript data
data = ski_io.imread("tmp_canvas.eps")
# write a rasterized png file
ski_io.imsave("canvas_image.png", data)
I do not really like workarounds, but skimage seems to be the fastest solution for reading postscript files and writing pngs.
Scikit-image is developed as a toolkit for SciPy, therefore it is working with scipy.ndimage internally, which is exactly what I want and can be used to create np.ndarray very easily.
Additionally scikit-learn is a powerful and fast image processing software itself, which can manipulate, read, and save various image formats.
Now you have the full choice: get a NumPy np.ndarray out of Canvas data for further computations, manipulate the scipy.ndimage with SciPy/scikit-image or save the data, e.g. as a rasterized png, to disk.

Related

Why is a generated SVG image less rich than the corresponding PNG image

To set this up, I used svgwrite library to create a sample SVG image (20 squares of length 100 at random locations on a display size of length 400)
import svgwrite
import random
random.seed(42)
dwg = svgwrite.Drawing('x.svg', size=(400,400))
dwg.add(dwg.rect(insert=(0,0), size=('100%', '100%'), fill='white')) # White background
for i in range(20):
coordinates = (random.randint(0,399), random.randint(0,399))
color = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
dwg.add(dwg.rect(coordinates, (100, 100),
stroke='black',
fill=svgwrite.rgb(*color),
stroke_width=1)
)
dwg.save()
I then wrote a sample pygame program to generate a PNG image of the same sample. (A seed has been used to generate the same sequence of squares.)
import pygame
import random
random.seed(42)
display = pygame.display.set_mode((400,400))
display.fill((255,255,255)) # White background
for i in range(20):
coordinates = (random.randint(0,399), random.randint(0,399))
color = (random.randint(0,255), random.randint(0,255), random.randint(0,255))
pygame.draw.rect(display, color, coordinates+(100,100), 0)
pygame.draw.rect(display, (0,0,0), coordinates+(100,100), 1) #For black border
pygame.image.save(display, "x.png")
These are the images that I got (SVG's can't be uploaded to SO, so I have provided a screenshot. Nevertheless, the programs above can be run to output the same).
My question is, why is the PNG (on the left) richer and sharper than the corresponding SVG image? The SVG looks blurred and bland, comparatively.
EDIT: One can notice the fine white line between the first two squares at the top-left corner. It's not very clear in the SVG.
Two things I think may impact:
You are using an image viewer, which could distort the vectorial SVG image. I think all of the vector images viewers get the actual screen size, then export the vectorial image into a matrix image sized in function of the size of the screen you have. Then they display the matrix image. If they render the image with softened sharpness, or if they have a problem by getting the size of your screen, the image may be blurred.
To make the PNG image, you use pygame. But you are using another module to make the SVG image. This module may function differently, and also exports the image with another quality than if you were exporting it with pygame.
For me personally the SVG image appears blurred with Gimp, for example, but not with another SVG viewer.
So I think the problem comes from your image viewer.

Does the backend matter for savefig

I have a script which plots some pandas data, and then either shows the plot interactively with plt.show(), or saves it to a file with plt.savefig(args.out).
import matplotlib.pyplot as plt
# set up the dataframe here
ax = df.plot.line(x=0, title=args.title, figsize=(12,8), grid=True, **kwargs)
if (args.out):
vprint("Saving figure to ", args.out, "...")
plt.savefig(args.out)
else:
vprint("Showing interactive plot...")
plt.show()
The question is, does the default matplotlib backend matter for the scenario where I save to a file with savefig? It definitely matters in the other case since it's used to display the interactive plot, but if I call savefig is another backend used entirely?
When showing a figure, the backend obviously matters, because it provides two things:
The renderer to draw the image
The GUI within which the image is shown.
When saving a figure, only the former matters. However, matplotlib provides a multitude of export formats. At the end, the chosen backend will determine what to do when a figure is saved, and in most cases, will use one of the existing non-interactive backends to produce the output file.
Some examples:
TkAgg will use the tkinter GUI to show a figure. For saving a png figure, it will fall back to the basic Agg backend to produce the png file. For saving an svg file, it will fall back to the svg backend, for saving a pdf it will fallback to the pdf backend, etc.
TkCairo, will use the tkinter GUI to show a figure. For saving a png figure, it will fall back to the basic Cairo backend to produce the png file. For the rest, same as above.
Qt5Agg will use the PyQt GUI to show a figure. For png will fall back to Agg. For others same as above.
similar for other backends.

Imagemagick's import is frustratingly slow

I am writing an small python script to take screenshots of a game window (which will be in the background/minimized) and performing some simple template matching and ocr using cv2.
I am currently calling im's import as follows:
import -window windowID png:-
to take a screenshot of an inactive window.
However this takes almost 4s and is easily the slowest part of my script by a factor of 100x.
Is there any alternative to import or perhaps another way of approaching this that will be faster?
I have already tried graphicsmagick (ended up being slower than imagemagick) and xwd (did not capture the unfocused window even though the windowID was specified)
Link to full python script (Line 44 is where the screenshot taking happens)
You are doing all the PNG encoding and zlib compression in ImageMagick and then decompressing it all again in OpenCV. I guess you would do better if you found a format that is more closely shared between the two.
Specifically, ImageMagick could give you RGB pixels directly, which you could then convert to BGR very easily in OpenCV with cvtColor().
import -window windowID rgb:
You would have to query the window dimensions to get width and height.
Alternatively, you could use PPM format which OpenCV can also read without any libraries and which includes dimensions:
import -window windowID ppm:

Python / PIL - Raw RGB565 data to PNG?

I have raw RGB565 data as a bytes-like object and I want to save it as a PNG.
Although it is possible with libraries such as PyQt5, as you can here:
QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16)
I would like to use only PIL, but I cannot find a way to do this with only PIL.
More generally, a method that does not involve Qt would be fine.
Thanks.
It so happens that the pypng repository has a tool to convert from Kobo's 15-bit to PNG.
It's here: https://github.com/drj11/pypng/blob/master/code/kobo565topng
One word of warning however, it outputs an 8-bit RGB PNG.
You don't save any space by saving it as an R5G6B5 PNG, so that might not matter much.

Using reportlab to build PDF with vector-based graphs generated by matplotlib

I'm trying to build PDF-documents on the server-side in a Django-Installation using reportlab. These documents should contain several graphs which are to be created with matplotlib.
I already figured out how to make reportlab use matplotlib's images without dumping them to the filesystem temporarily by passing PIL-Image objects directly to the Image()-flowable. This works surprisingly well for rasterized images formats like PNG.
Now, the icing on the cake would be able to embed vector based graphics (like SVG).
I used svglib to convert SVGs generated by matplotlib to reportlab graphic objects but unfortunately svglib does omit the tickmarks and axis labels. On some graphs it fails in general.
Do you have any ideas?
This page has a solution that I haven't had a chance to test myself yet: https://web.archive.org/web/20120725125858/http://lateral.netmanagers.com.ar/weblog/posts/BB753.html
You can generate matplotlib graphics as pdf and use pdfrw to embed it in reportlab canvas as described in this answer

Resources