When I use pylab and python under Linux to draw and show an image, like in the following example:
img = pylab.imread(filename)
pylab.imshow(img)
pylab.show()
pylab.draw()
When I do so, a new window pops up with the image.
My question: How can I influence the position and the size?
The whole point of pylab's Image stuff is that you get a np.array of pixel data.
So, you can just do this:
img = pylab.imread(filename)
img = img * myTransformationMatrix
pylab.imshow(img)
If that immediately tells you what you need to know, great. If you don't understand what matrix multiplication has to do with rotating, translating, and scaling images, pylab is probably not the image library you want to use. Just use PIL.
If you're trying to manipulate the windows, rather than the images, pylab is really not meant for that.
You probably want to use TkInter, the windowing library that comes built-in with Python. It's can be ugly, clunky, and slow, and some advanced uses are either impossible or require you to write Tcl code instead of Python… but for simple stuff, it's not going to be a step down from pylab. In fact, it's what pylab uses under the covers.
If you start to hit the limits of TkInter, it's time to look at an external windowing library. You can go with a full GUI framework like Gtk+, Qt, or wx. The Python bindings to the three aren't that different; the important difference is that in the slightly different models of how GUIs work, so read about them and pick the model you like best. Alternatively, you can use something like pygame, which does very bare-bones windowing (the kind of thing games would need, rather than, say, word processors).
Related
Note: You really only need to read the checklist and understand that I want to do this in Tkinter, the rest of the information is for clarification
The complete code is here: https://gist.github.com/SnugBug/1cc5ea67d11487d69aae8549107372ef
I need to be able to manipulate pixels. The goal is to be able to:
Control which pixels are drawn first
Change the color and position of each pixel
Update everything as a whole, so that if a pixel changes the change shows up
Clear everything as a whole
The question is, what's the fastest way to check off this list in tkinter? I tried creating an image with PIL, then loading it into tkinter, but I cannot update the image or clear it. The other thing I tried is using tkinter's PhotoImage class, as shown below:
#The function definitions are in the GIST.
#This snippet should be enough information to understand the problem, however.
for i in range(0,3600):
rot = [0,i,0]
Tx,Ty,Tz,Zm = [0,0,200,200]
x,y,z = [10,10,10]
for m,n in itertools.product(range(-50,50,2),range(-50,50,2)):
x,y,z = rotate([m,n,0],rot)
img.put("#ffffff", (int(WIDTH/2 + ((x+Tx)*Zm/(z+Tz))), int(HEIGHT/2 - ((y+Ty)*Zm/(z+Tz)))))
canvas.update()
img.blank()
#the confusing math in the `img.put` call is just 3D math
This way is extremely slow. The next way I tried is even slower. It's drawing a line like this:
canvas.create_line(x,y,x+1,y+1, ...)
Which creates a line of length 1, showing a single pixel. This is excruciatingly slow.
If the separate image method is the fastest, could you include a working snippet in your answer? I cannot figure out the separate image method. I have PIL installed, that's what I was using to attempt it. I lost the python file so I cannot include the code I used to attempt the separate image method.
What I mean by the separate image method: create an image using PIL, drawing on it using PIL, then making that show up on a tkinter screen. This doesn't meet everything on the checklist, however (from what I understand).
If the separate image method is not the fastest, please tell me a way I can check off everything in the checklist some other way. I have a few questions I looked at for help and some sites. They're below
Why is Photoimage put slow?
Any of these answers don't work for me because it only creates squares. I need to be able to make any shape.
python tkinter: how to work with pixels?
This answer doesn't work because it's too slow.
How to load .bmp file into BitmapImage class Tkinter python This could be helpful
http://zetcode.com/gui/tkinter/drawing/ None of these methods work because I cannot manipulate the order each pixel is drawn, and the color of each individual pixel. If you are familiar with 3D terminology, I need this for a Z-Buffer
If there are any confusions or you need something clarified, please tell me below in the comment section. I am open minded, so if you have a deep understanding of my question and have another idea on how to solve it, I would love to hear it.
If you are using Windows, then the fastest way to put an image on a frame is by ImageWin. The tkinter process of first transforming from PIL image to a tkphotoimage is very slow.
from PIL import Image, ImageWin
from win32gui import GetDC
from tkinter import Tk
root = Tk()
im = Image.open(<file path>)
ImageWin.Dib(im).draw(
GetDC(ImageWin.HWND(root.winfo_id())),
(0,0,100,100)
)
I have a python funtion that draws a Fractal to a PIL.Image, but i want to vary the parameters of the function in realtime and to plot it to the screen. How can i plot the image and keep updating the ploted image each time the parametes of the function vary
Use matplotlib, wxPython, PyQt, PyGame, Tk/TCL or some other lib to display the image.
Draw as many images as you need, whenever you need, using any lib you need, and then display it on a screen using one of above mentioned or some other GUI libs.
If you are working with plots and math functions, matplotlib will help you most. You might even totally use it, forgoing PIL completely.
If you want to stick to PIL only, you will have to write your own show() function, that will use some external imaging software which will seemlessly change to show another image when you send it. Perhaps Irfan View would do.
Is there a way to use OpenGL to draw offscreen? What I want to do is this: I want to be able to use functions like glVertex, and get the result in a 2D pixel array.
I am using Python. I tried using PyGame, but it's not working very well. The problem with PyGame is that uses a window event though i don't need it. In addition, I had to draw to scene + flip the screen twice in order to access screen pixels using glReadPixels.
An other problem is that I can't have more that one window at once.
Is there any proper way to accomplish what I am trying to do?
What you are asking for seems to be two things in one... you want an off-screen buffer (FBO) and you want to get the contents of the framebuffer in client memory.
Can you indicate which version of GL you are targeting?
If you are targeting OpenGL 3.0+, then you can use FBOs (Framebuffer Objects) and PBOs (Pixel Buffer Objects) to do this efficiently. However, since you are using glVertex, I do not think you need to bother with efficiency. I would focus on learning to use Framebuffer Objects for the time being.
If you are not using GL3 you might have access to the old EXT FBO extension, but if you do not have that even you might need a PBuffer.
Note that PBuffers and Pixel Buffer Objects are two different things even though they sound the same. Before GL3/FBOs, WGL, GLX, etc. had special platform-specific functionality called Pixel Buffers for drawing off-screen.
I am new to Python, and trying to use PIL to perform a parsing task I need for an Arduino project. This question pertains to the Image.convert() method and the options for color palettes, dithering etc.
I've got some hardware capable of displaying images with only 16 colors at a time (but they can be specified RGB triplets). So, I'd like to automate the task of taking an arbitrary true-color PNG image, choosing an "optimum" 16-color palette to represent it, and converting the image to a palettized one containing ONLY 16 colors.
I want to use dithering. The problem is, the image.convert() method seems to be acting a bit funky. Its arguments aren't completely documented (PIL documentation for Image.convert()) so I don't know if it's my fault or if the method is buggy.
A simple version of my code follows:
import Image
MyImageTrueColor = Image.new('RGB',100,100) # or whatever dimension...
# I paste some images from several other PNG files in using MyImageTrueColor.paste()
MyImageDithered = MyImageTrueColor.convert(mode='P',
colors=16,
dither=1
)
Based on some searches I did (e.g.: How to reduce color palette with PIL) I would think this method should do what I want, but no luck. It dithers the image, but yields an image with more than 16 colors.
Just to make sure, I removed the "dither" argument. Same output.
I re-added the "dither=1" argument and threw in the Image.ADAPTIVE argument (as shown in the link above) just to see what happened. This resulted in an image that contained 16 colors, but NO dithering.
Am I missing something here? Is PIL buggy? The solution I came up with was to perform 2 steps, but that seems sloppy and unnecessary. I want to figure out how to do this right :-) For completeness, here's the version of my code that yields the correct result - but it does it in a sloppy way. (The first step results in a dithered image with >16 colors, and the second results in an image containing only 16 colors.)
MyImage_intermediate = MyImageTrueColor.convert(mode='P',
colors=16
)
MyImageDithered = MyImage_intermediate.convert(mode='P',
colors=16,
dither=1,
palette=Image.ADAPTIVE
)
Thanks!
Well, you're not calling things properly, so it shouldn't be working… but even if we were calling things right, I'm not sure it would work.
First, the "official" free version of the PIL Handbook is both incomplete and out of date; the draft version at http://effbot.org/imagingbook/image.htm is less incomplete and out of date.
im.convert(“P”, **options) ⇒ image
Same, but provides better control when converting an “RGB” image to an
8-bit palette image. Available options are:
dither=. Controls dithering. The default is FLOYDSTEINBERG, which
distributes errors to neighboring pixels. To disable dithering, use
NONE.
palette=. Controls palette generation. The default is WEB, which is
the standard 216-color “web palette”. To use an optimized palette, use
ADAPTIVE.
colors=. Controls the number of colors used for the palette when
palette is ADAPTIVE. Defaults to the maximum value, 256 colors.
So, first, you can't use colors without ADAPTIVE—for obvious reason: the only other choice is WEB, which only handles a fixed 216-color palette.
And second, you can't pass 1 to dither. That might work if it happened to be the value of FLOYDSTEINBERG, but that's 3. So, you're passing an undocumented value; who knows what that will do? Especially since, looking through all of the constants that sound like possible names for dithering algorithms, none of them have the value 1.
So, you could try changing it to dither=Image.FLOYDSTEINBERG (along with palette=Image.ADAPTIVE) and see if that makes a difference.
But, looking at the code, it looks like this isn't going to do any good:
if mode == "P" and palette == ADAPTIVE:
im = self.im.quantize(colors)
return self._new(im)
This happens before we get to the dithering code. So it's exactly the same as calling the (now deprecated/private) method quantize.
Multiple threads suggest that the high-level convert function was only intended to expose "dither to web palette" or "map to nearest N colors". That seems to have changed slightly with 1.1.6 and beyond, but the documentation and implementation are both still incomplete. At http://comments.gmane.org/gmane.comp.python.image/2947 one of the devs recommends reading the PIL/Image.py source.
So, it looks like that's what you need to do. Whatever Image.convert does in Image.WEB mode, you want to do that—but with the palette that would be generated by Image.quantize(colors), not the web palette.
Of course most of the guts of that happens in the C code (under self.im.quantize, self.im.convert, etc.), but you may be able to do something like this pseudocode:
dummy = img.convert(mode='P', paletter='ADAPTIVE', colors=16)
intermediate = img.copy()
intermediate.setpalette(dummy.palette)
dithered = intermediate._new(intermediate.im.convert('P', Image.FLOYDSTEINBERG))
Then again, you may not. You may need to look at the C headers or even source to find out. Or maybe ask on the PIL mailing list.
PS, if you're not familiar with PIL's guts, img.im is the C imaging object underneath the PIL Image object img. From my past experience, this isn't clear the first 3 times you skim through PIL code, and then suddenly everything makes a lot more sense.
I want to do convert array of integers into some sort of 'picture' using PyQt (I've decided to do my app in Qt). I have array like this:
Array = [
[0,0,1,0,0],
[0,1,0,1,0],
[1,0,0,0,1],
[0,1,0,1,0],
[0,0,1,0,0]]
Now I want to rewrite it into picture, by replacing each integer by for example square 10x10 pixels. I have definition for each value in array in RGB. What's more This is some kind of game of life, so it must refresh on each step and shouldn't be slow. Maybe somethinf similar to OpenCV?
Thanks in advance!
Cheers,
Mateusz
You could easily do the above with QGraphicsScene and QGraphicsView. In order to get good performance, you'll want to call setViewport(QGLWidget()) on your QGraphicsView instance. Create a subclass of QGraphicsItem to represent an element in your array. You'll then even be able to animate the changes if you want.
If you do want animations or are demonstrating some progression such as in Conway's Game of Life you might also want to take a look at QTimeLine.
You can look up the equivalent python-based documentation on either the PyQt* or PySide websites. Both PyQt and PySide use a nearly identical API so for most everything you can use them interchangeably.
*Note: The PyQt website is inaccessible at the time of this writing
You should probably use QT’s graphics libraries for performance. Another, maybe simpler way could be to use PIL (Python Imaging Library) or some Python bindings to the ImageMagick or MagickWand library (I haven't found a good and current one) and use NumPy’s arrays for calculations and manipulation, and draw on a surface or canvas using PyGame, QT or some other GUI toolkit.
In PIL there is PIL.Image.fromarray(np_array, 'RGBA'), that reads suitable NumPy arrays – the datatype must usually be dtype=int8 and the shape is (height, width, n_channels).
For a very simple graphics format that uses ascii byte values, see NetPBM.