Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- glcontext=None
- if (VideoImageWidget.glcontext==None):
- print("VideoImageWidget: initializeGL: creating context for sharing")
- VideoImageWidget.glcontext=QtGui.QOpenGLContext()
- ok=VideoImageWidget.glcontext.create()
- print("VideoImageWidget: initializeGL: created context for sharing",VideoImageWidget.glcontext,ok)
- context=self.context()
- print("VideoImageWidget: initializeGL: automatically created context:",context)
- context.setShareContext(VideoImageWidget.glcontext)
- ok=context.create() # must call this ..
- print("VideoImageWidget: initializeGL: recreated my context:",ok)
- import sys
- import time
- from PyQt5 import QtWidgets, QtCore, QtGui # Qt5
- from OpenGL.GL import *
- from PIL import Image
- """
- Demonstrating a bug (?) in QOpenGLWidget / Qt OpenGL insfrastructure :
- You need:
- * to have two tiff images ("base.tif" and "2.tif") in the same directory
- * to remove/install some libraries:
- sudo apt-get install python3-pyqt5 pip3
- sudo apt-get remove python3-opengl # we want the most recent version of the opengl bindings
- sudo pip3 install PyOpenGL PyOpenGL_accelerate
- sudo pip3 install imutils
- Usage:
- * look for the tag "TOGGLE HERE" below to switch between nested QWidgets / individual windows
- * run program with
- python3 context_test.py
- What's going on here?
- * Press the button a few times : a new image appears to the first widget
- * The image should appear only to the first widget
- * .. but it appears in both widgets if we set "nested=False", i.e. when the widgets constitute individual windows
- * .. confirm this by clicking / resizing the second window after clicking the button a few times
- Why this happens?
- * Qt creates some sort of "top-level" (?) opengl context that is referring to the same texture ids = bug ?
- This code is licensed under the do-with-it-whatever-you-want license, written by Sampsa Riikonen, 2017
- """
- def getImg(fname):
- im =QtGui.QImage(fname)
- im =im.convertToFormat(QtGui.QImage.Format_RGB888)
- ix =im.width()
- iy =im.height()
- ptr=im.bits()
- ptr.setsize(im.byteCount())
- return ptr.asstring(), ix, iy
- class VideoImageWidget(QtWidgets.QOpenGLWidget): # http://doc.qt.io/qt-5/qopenglwidget.html # Qt5
- def __init__(self,parent=None):
- super().__init__(parent=parent)
- self.parent=parent
- self.baseimage, self.ix, self.iy =getImg("base.tif")
- self.gl_format=GL_RGB
- self.ratio =1
- self.picratio =1
- def changeTexture(self,image,ix,iy):
- glBindTexture(GL_TEXTURE_2D, self.tex) # this is the texture we will manipulate
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
- glTexImage2D(GL_TEXTURE_2D, 0, self.gl_format, ix, iy, 0, self.gl_format, GL_UNSIGNED_BYTE, image) # load bitmap to texture
- self.picratio=self.iy/self.ix
- def resetTexture(self):
- self.changeTexture(self.baseimage,self.ix,self.iy)
- def initializeGL(self):
- # "This function should set up any required OpenGL resources and state"
- glEnable(GL_TEXTURE_2D)
- self.tex = glGenTextures(1) # create a new texture
- # https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenTextures.xml
- # "it is guaranteed that none of the returned names was in use immediately before the call"
- print("VideoImageWidget: glGenTextures returned:",self.tex)
- self.resetTexture()
- def paintGL(self):
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Clear The Screen And The Depth Buffer
- glLoadIdentity() # Reset The View
- glBindTexture(GL_TEXTURE_2D, self.tex) # this is the texture we will manipulate
- glBegin(GL_QUADS)
- dz=0
- r=self.ratio/self.picratio # screen h/w // picture h/w
- if (r<1): # screen wider than image
- dy=1
- dx=r
- elif (r>1): # screen taller than image
- dx=1
- dy=1/r
- else:
- dx=1
- dy=1
- glTexCoord2f(0.0, 0.0); glVertex3f(-dx, dy, dz)
- glTexCoord2f(1.0, 0.0); glVertex3f( dx, dy, dz)
- glTexCoord2f(1.0, 1.0); glVertex3f( dx,-dy, dz)
- glTexCoord2f(0.0, 1.0); glVertex3f(-dx,-dy, dz)
- glEnd()
- def resizeGL(self, width, height):
- """Called upon window resizing: reinitialize the viewport.
- """
- glViewport(0, 0, width, height)
- glLoadIdentity()
- glOrtho(-1, 1, 1, -1, -1, 1)
- self.ratio=height/width
- @QtCore.pyqtSlot(object)
- def frameReceived(self,frame):
- buf =frame[0]
- width =frame[1]
- height=frame[2]
- print("VideoImageWidget updating with frame",width,height)
- self.changeTexture(buf,width,height)
- self.update()
- class MyGui(QtWidgets.QMainWindow):
- f1 = QtCore.pyqtSignal(object)
- f2 = QtCore.pyqtSignal(object)
- def __init__(self,parent=None):
- super().__init__(parent)
- self.cw=QtWidgets.QWidget(self)
- self.setCentralWidget(self.cw)
- self.lay = QtWidgets.QVBoxLayout(self.cw)
- self.b = QtWidgets.QPushButton("Send frame",self.cw)
- # *** TOGGLE HERE ***
- # nested=True # *** widgets sitting in the QMainWindow
- nested=False # *** individual windows
- self.lay.addWidget(self.b)
- if (nested):
- self.v1 = VideoImageWidget(parent=self.cw)
- self.v2 = VideoImageWidget(parent=self.cw)
- self.lay.addWidget(self.v1)
- self.lay.addWidget(self.v2)
- else:
- self.v1 = VideoImageWidget(parent=None)
- self.v2 = VideoImageWidget(parent=None)
- self.v1.show()
- self.v2.show()
- self.b.clicked. connect(self.clicked)
- self.f1. connect(self.v1.frameReceived)
- self.newimage, self.ix, self.iy =getImg("2.tif")
- @QtCore.pyqtSlot()
- def clicked(self):
- print("emitting frame")
- self.f1.emit([self.newimage, self.ix, self.iy]) # update _only_ the first VideoImageWidget
- if (__name__=="__main__"):
- app=QtWidgets.QApplication([])
- # *** Set this to apply context sharing ***
- # app.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
- """
- .. but that does not work for textures
- See the last comment on this post:
- http://stackoverflow.com/questions/29838356/is-it-possible-to-use-the-same-opengl-context-between-top-level-windows-in-qt
- "I've realised that this does not solve the problem in the question, as it does not actually share the context, but enables sharing of a subset of resources .."
- That is said also in the qt docs, but in an extremely implicit way..
- http://doc.qt.io/qt-5/qopenglwidget.html
- "Creating extra QOpenGLContext instances that share resources like textures .. "
- """
- print("OpenGL context sharing status:",app.testAttribute(QtCore.Qt.AA_ShareOpenGLContexts))
- mg=MyGui()
- mg.show()
- app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement