What class to use for showing images in PyQt5 - python

I've been trying to figure this out for awhile now, but cannot seem to figure it out. I am developing a program with a UI that I made in Qt Designer, where I will be analyzing images using cv2. Part of this analysis involves having the user click on the image to store different coordinates from the image to be used later. When I made the UI in Qt Designer, the image object is of the class QtWidgets.QGraphicsView, but I cannot figure out how to show an image from cv2, which is a numpy array on an object of type QtWidgets.QGraphicsView. I am thinking I should be using a QtGui.QPixmap, but I'm still not sure. It seems there is not great documentation, so I'm having troubles figuring out how to choose how to represent these images that I plan to have interactions with and analysis of.

I did end up using QGraphicsPixmapItem as suggested by ekhumoro in the comments. I also used QImage to do this though. An example of how I'm doing this is
image_window = QtWidgets.QGraphicsView(centralwidget)
raw_image = cv2.imread('image.jpg')
height, width, channel = image.shape
bytes_per_line = width * 3
image = QtGui.QImage(raw_image.data, width, height, bytes_per_line, QtGui.QImage.Format_RGB888)
scene = QtWidgets.QGraphicsScene()
scene.addPixmap(QtGui.QPixmap.fromImage(image)
image_window.setScene(scene)
And this worked great for me. There may still be some optimizations I can do, but it gives me the freedom to keep everything separated so I can easily do manipulations to the raw_image pixel matrix. I also have everything abstracted by having a class for the scene and raw_image.

Related

Tkinter screwing with PIL image transparency?

I made a custom image viewing program in python since I couldn't find one that worked how I wanted it to, and I know it at least USED to work with transparent gifs but now it doesn't. The effects seem to vary from gif to gif to gif but it always is an issue with the transparency. Doing some testing with .save I found that the PIL image is completely fine and I can export it as a png with absolutely no issues and perfect transparency. With that said, despite making the program I never really learned Tkinter since I just didn't need to use it beyond simple canvas clearing and updating, so I have no clue how to test beyond PIL. I believe the issue should be in these lines :
image = ImageTk.PhotoImage(GifFrameSized) #GifFrameSized is the resized GIF
imagesprite = canvas.create_image(show.w/2,show.h/2,image=image) #w and h are the width and height of the monitor
root.update_idletasks()
root.update()
canvas.pack()
I genuinely have no idea how the issue could be coming from any of these but I was able to use PIL to save a png of the frame in the line immediately above "image = ImageTk.PhotoImage(GifFrameSized)" and it looked fine so I have to imagine its somewhere in those lines.

Fastest way to draw a pixel on tkinter

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)
)

PyQt4: Graphics View and Pixmap Size

I'm developing a GUI using QTDesigner for some image processing tasks. I have two graphic views beneath each other in a grid layout. Both should display an image and later on I will add overlays.
I create my Pixmap img_pixmap and add it to my Scene. This scene is then added to my graphics view. Since my image is much larger than my screen size I apply fitInView(). In code:
self.img_pixmap_p = self.img_scene.addPixmap(img_pixmap)
self.img_view.setScene(self.img_scene)
self.img_scene.setSceneRect(QtCore.QRectF())
self.img_view.fitInView(self.img_scene.sceneRect(), QtCore.Qt.KeepAspectRatio)
So far, so good but how do i get rid of the white space around my image view? Ideally, I want my pixmap use the full width of the graphics view and to keep the aspect ratio, the graphics view should adjust its height accordingly. Any ideas on how to achieve that in a straight forward fashion?
Here an image to get a better idea of what I get:
As you can see, there are white borders, which I want to avoid.
Okay, I did as suggested by Pavel:
img_aspect_ratio = float(pixmap.size().width()) / pixmap.size().height()
width = img_view.size().width()
img_view.setFixedHeight( width / img_aspect_ratio )
img_view.fitInView(img_scene.sceneRect(), QtCore.Qt.KeepAspectRatio)
It works fine when you call this in each resizeEvent().

Loading greyscale images in wxPython

I'm writing a little desktop app using wxPython that does a bit of image manipulation, but I'm finding it's running rather slowly.
One of the biggest problems at the moment is that I am using three channels of data (RGB) where I only really need one - greyscale images are fine for my purposes.
At the moment I'm manipulating the images by loading them into a numpy array. Once the processing is done, they're converted into a wx Image object (via the ImageFromBuffer() function, which is then loaded into a StaticBitmap for the user interface. This seems like a lot of steps...
So I have two questions - the first is how would you load a numpy array directly into a greyscale wx Image? Is this even possible?
The second is more general - what is the fastest way of dealing with images in wxPython? I don't have much choice but to loop over the numpy arrays (I need the mathematical functionality), but any way of speeding things up before and after this process would be welcome!
you could do a pingpong with PIL like this :)
def convertToGrayscale(img):
import Image, ImageOps
orig = Image.new("RGB", img.GetSize())
orig.fromstring(img.GetData())
pil = ImageOps.grayscale(pil)
ret = wx.EmptyImage(pil.size[0], pil.size[1])
ret.SetData(pil.convert('RGB').tostring())
return ret
refer this link link

streaming video from camera using pyqt4

I am using a thirdparty library that utilizes a circular buffer for image data and video. It has a method for getting the last image or popping it. I was wondering what would be the best way to implement video functionality in pyqt for this. Is there some video widget with a callback function that I could use? Or do I have to somehow implement parallel processing on my own? Parallel to this, suggestions on how this would be implemented in qt if you dont know how to implement it in pyqt would also be very much appreciated.
Thanks in advance!
I would pop the last image (from the circular buffer) and load it into a QPixmap. This allows you to put the image into a form that a pyqt4 gui would be able to load.
Depending on your libraries image format (straight forward bmp? jpg? png? raw pixels?), you can load the data into the QPixmap in one of two ways.
First: do it pixel by pixel (set the width and height of the image and copy each pixels value over one by one). This method is slow and I'd only resort to it if necessary.
Second: if the image is being stored in a common format (ones that are 'supported' are listed here), this becomes trivial.
Then after the image is loaded in the QPixmap, I would use QLabel.setPixmap() to display the image.
Do this with a QTimer slot at a certain rate and you'll be able to display your images in a pyqt4 gui.

Categories

Resources