I am facing a problem running PyQt5 on Raspberry Pi 4.
I use raspberry pi 4, version 10 (buster) kernel version 4.19.75-v71.
The default python is 3.7.3.
I followed the exact same steps of installing sip and PyQt5 as mentioned on this thread here. I also installed python 3.6.0 following the steps introduced on the aforementioned thread.
After finishing the installation without any error, and when I run my code, I face the following error message:
qt5ct: using qt5ct plugin
QEGLPlatformContext: Failed to create context: 3009
QOpenGLWindow::beginPaint: Failed to create context
QOpenGLWindow::beginPaint: Failed to make context current
Traceback (most recent call last):
File "my_code.py", line 68, in initializeGL
self.gl = self.context().versionFunctions()
AttributeError: module 'PyQt5._QOpenGLFunctions_ES2' has no attribute 'QOpenGLFunctions_ES2'
Aborted
Any guidance how to overcome this problem? Much appreciated. Thanks in advance.
PS the code is running smoothly on Win10. Thus, the code itself must have no problem. (the environment on Win10 is: numpy=1.14.3; numpy-stl=2.5.0; pyqt5=5.10.1; sip=4.19.8; six=1.11.0; python=3.6.0; python-utils=2.3.0)
maybe you can try to reinstall pyqt5 to fix this problem. look if there are a thread is occupy pip/pyqt5/qmake.exe.
Or look you GPU, does it is OpenGL2.0 or higher version?
you said that the problems was made by
"self.gl=self.context().versionFunctions()"
And I was writhing an example, you can try it:
import sys
import math
from PyQt5.QtCore import pyqtSignal, QPoint, QSize, Qt
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QOpenGLWidget, QSlider,
QWidget)
import OpenGL.GL as gl
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.glWidget = GLWidget()
self.xSlider = self.createSlider()
self.ySlider = self.createSlider()
self.zSlider = self.createSlider()
self.xSlider.valueChanged.connect(self.glWidget.setXRotation)
self.glWidget.xRotationChanged.connect(self.xSlider.setValue)
self.ySlider.valueChanged.connect(self.glWidget.setYRotation)
self.glWidget.yRotationChanged.connect(self.ySlider.setValue)
self.zSlider.valueChanged.connect(self.glWidget.setZRotation)
self.glWidget.zRotationChanged.connect(self.zSlider.setValue)
mainLayout = QHBoxLayout()
mainLayout.addWidget(self.glWidget)
mainLayout.addWidget(self.xSlider)
mainLayout.addWidget(self.ySlider)
mainLayout.addWidget(self.zSlider)
self.setLayout(mainLayout)
self.xSlider.setValue(15 * 16)
self.ySlider.setValue(345 * 16)
self.zSlider.setValue(0 * 16)
self.setWindowTitle("Hello GL")
def createSlider(self):
slider = QSlider(Qt.Vertical)
slider.setRange(0, 360 * 16)
slider.setSingleStep(16)
slider.setPageStep(15 * 16)
slider.setTickInterval(15 * 16)
slider.setTickPosition(QSlider.TicksRight)
return slider
class GLWidget(QOpenGLWidget):
xRotationChanged = pyqtSignal(int)
yRotationChanged = pyqtSignal(int)
zRotationChanged = pyqtSignal(int)
def __init__(self, parent=None):
super(GLWidget, self).__init__(parent)
self.object = 0
self.xRot = 0
self.yRot = 0
self.zRot = 0
self.lastPos = QPoint()
self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0)
self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0)
def getOpenglInfo(self):
info = """
Vendor: {0}
Renderer: {1}
OpenGL Version: {2}
Shader Version: {3}
""".format(
gl.glGetString(gl.GL_VENDOR),
gl.glGetString(gl.GL_RENDERER),
gl.glGetString(gl.GL_VERSION),
gl.glGetString(gl.GL_SHADING_LANGUAGE_VERSION)
)
return info
def minimumSizeHint(self):
return QSize(50, 50)
def sizeHint(self):
return QSize(400, 400)
def setXRotation(self, angle):
angle = self.normalizeAngle(angle)
if angle != self.xRot:
self.xRot = angle
self.xRotationChanged.emit(angle)
self.update()
def setYRotation(self, angle):
angle = self.normalizeAngle(angle)
if angle != self.yRot:
self.yRot = angle
self.yRotationChanged.emit(angle)
self.update()
def setZRotation(self, angle):
angle = self.normalizeAngle(angle)
if angle != self.zRot:
self.zRot = angle
self.zRotationChanged.emit(angle)
self.update()
def initializeGL(self):
print(self.getOpenglInfo())
self.setClearColor(self.trolltechPurple.darker())
self.object = self.makeObject()
gl.glShadeModel(gl.GL_FLAT)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glEnable(gl.GL_CULL_FACE)
def paintGL(self):
gl.glClear(
gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glLoadIdentity()
gl.glTranslated(0.0, 0.0, -10.0)
gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)
gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
gl.glCallList(self.object)
def resizeGL(self, width, height):
side = min(width, height)
if side 360 * 16:
angle -= 360 * 16
return angle
def setClearColor(self, c):
gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF())
def setColor(self, c):
gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
before try this example, please run this command(install pyOpenGL):
pip install pyOpenGL
Related
I experiencing some issue while trying to understand how animate a qgraphicItem in Pyqt.
I'm trying to animate a qgraphicsItem inside a scene, but when the animation starts all the objects rotate. Is there someone who can help me?
here is my code.
from PyQt6.QtGui import *
from PyQt6.QtCore import *
from PyQt6.QtWidgets import *
class GraphicsView(QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.setRenderHints(QPainter.RenderHint.Antialiasing
| QPainter.RenderHint.TextAntialiasing | QPainter.RenderHint.SmoothPixmapTransform)
self.setViewportUpdateMode(QGraphicsView.ViewportUpdateMode.FullViewportUpdate)
self.scene = QGraphicsScene(QRectF(-250, -250, 1000, 1000), self)
self.setScene(self.scene)
self.graphicItem = QGraphicsRectItem(0, 0, 100, 100)
self.graphicItem.setZValue(10)
self.graphicItem.setPos(100, 100)
self.scene.addItem(self.graphicItem)
self.scene.addRect(self.sceneRect(), brush=QBrush(Qt.GlobalColor.gray))
self.animateRotation()
def rot(self, angle: QVariant) -> None:
self.rotate(self.graphicItem.rotation() - angle)
self.graphicItem.setRotation(angle)
#pyqtSlot()
def animateRotation(self):
self.animation = QVariantAnimation(self)
self.animation.setStartValue(QVariant(0))
self.animation.setEndValue(QVariant(180))
self.animation.setDuration(10000)
self.animation.start()
self.animation.valueChanged.connect(self.rot)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = GraphicsView()
w.resize(720, 720)
w.show()
sys.exit(app.exec())
Suppose we Have in python 3+
import OpenGL as gl
and I want to do something as
gl.GL.glClearColor(0.1, 0.2, 0.2, 1)
this doesn't work, but I'm curious to know if there is any way to do that, just import the main module and call other from the main.
import pygame as pg
from OpenGL import GL as gl
from OpenGL.GL import shaders as gls
import numpy as np
import ctypes
class App:
def __init__(self):
#initialise pygame
pg.init()
pg.display.set_mode((640,480), pg.OPENGL|pg.DOUBLEBUF)
self.clock = pg.time.Clock()
#initialise opengl
gl.glClearColor(0.1, 0.2, 0.2, 1)
self.shader = self.createShader("shaders/vertex.txt", "shaders/fragment.txt")
self.triangle = Triangle(self.shader)
self.mainLoop()
def createShader(self, vertexFilepath, fragmentFilepath):
with open(vertexFilepath,'r') as f:
vertex_src = f.readlines()
with open(fragmentFilepath,'r') as f:
fragment_src = f.readlines()
shader = gls.compileProgram(gls.compileShader(vertex_src, gl.GL_VERTEX_SHADER),
gls.compileShader(fragment_src, gl.GL_FRAGMENT_SHADER))
return shader
def mainLoop(self):
running = True
while (running):
#check events
for event in pg.event.get():
if (event.type == pg.QUIT):
running = False
#refresh screen
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
self.triangle.draw(self.shader)
pg.display.flip()
#timing
self.clock.tick()
framerate = int(self.clock.get_fps())
pg.display.set_caption(f"Running at {framerate} fps.")
self.quit()
def quit(self):
self.triangle.destroy()
gl.glDeleteProgram(self.shader)
pg.quit()
class Triangle:
def __init__(self, shader):
gl.glUseProgram(shader)
# x, y, z, r, g, b
self.vertices = (
-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
0.0, 0.5, 0.0, 0.0, 0.0, 1.0
)
self.vertices = np.array(self.vertices, dtype=np.float32)
self.vertex_count = 3
self.vao = gl.glGenVertexArrays(1)
gl.glBindVertexArray(self.vao)
self.vbo = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)
gl.glBufferData(gl.GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, gl.GL_STATIC_DRAW)
gl.glEnableVertexAttribArray(0)
gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 24, ctypes.c_void_p(0))
gl.glEnableVertexAttribArray(1)
gl.glVertexAttribPointer(1, 3, gl.GL_FLOAT, gl.GL_FALSE, 24, ctypes.c_void_p(12))
def draw(self, shader):
gl.glUseProgram(shader)
gl.glBindVertexArray(self.vao)
gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.vertex_count)
def destroy(self):
gl.glDeleteVertexArrays(1,(self.vao,))
gl.glDeleteBuffers(1,(self.vbo,))
if __name__ == "__main__":
app = App()
But I want to replace "from OpenGL import GL as gl" and "from OpenGL.GL import shaders as gls" to just one import something as import OpenGL as gl, and from gl I want to access the sub-modules and functions inside it using a complete path, something as gl.GL.shaders.compileShader(). Is there any way to do it in python?
If i try do this using complete path I got this error
AttributeError: module 'OpenGL.GL' has no attribute 'GL'
I am trying to add GraphicsLayoutWidget and LinearRegionItem, that two ratio is 4:1 or m:n, but I don't found any layout in pygtgraph.So I try to the code like below, but unfortunately it don't work and cast out traceback error info.
code
import pyqtgraph as pg
import numpy as np
from PyQt5.QtWidgets import *
class Chart(pg.GraphicsLayoutWidget):
def __init__(self):
super().__init__()
self.data = np.linspace(0, 2*np.pi, 100)
self.data = np.sin(self.data)
self.p = self.addPlot(y=self.data)
class LR(pg.GraphicsLayoutWidget):
def __init__(self, target):
super().__init__()
self.p = self.addPlot() # type:pg.PlotItem
self.target = target # type: pg.PlotItem
rg = (target.data[0], target.data[-1])
self.p.setXRange(rg[0], rg[1], padding=0)
self.lr = pg.LinearRegionItem([rg[0], rg[1]])
self.lr.sigRegionChanged.connect(self.onLRChanged)
self.p.addItem(self.lr)
def onLRChanged(self):
print(self.target, self.lr.getRegion())
self.target.setXRange(*self.lr.getRegion())
class Win(QWidget):
def __init__(self):
super().__init__()
lay = QVBoxLayout()
self.chart = Chart()
self.lr = LR(self.chart)
lay.addWidget(self.chart)
lay.addWidget(self.lr)
lay.setStretch(0, 4)
lay.setStretch(1, 1)
self.setLayout(lay)
app = QApplication([])
win = Win()
win.show()
app.exec()
image
error
The traceback info will show when user drag LinearRegionItem line in both side of the bottom graph(plot)
environment
Python 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] on win32
Name: pyqtgraph Version: 0.12.2
Name: numpy Version: 1.20.3
Name: PyQt5 Version: 5.15.4
The problem has nothing to do with the stretch factor but setting the range to the GraphicsLayoutWidget that expects a QRect, instead of the PlotItem that expects a tuple causing that exception. On the other hand you can improve how to place the initial range based on the range of the data, also it is better to use signals.
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
import pyqtgraph as pg
import numpy as np
class Chart(pg.GraphicsLayoutWidget):
def __init__(self, xdata, ydata):
super().__init__()
self.p = self.addPlot(x=xdata, y=ydata)
class LR(pg.GraphicsLayoutWidget):
range_changed = pyqtSignal(float, float)
def __init__(self, xmin, xmax):
super().__init__()
self.lr = pg.LinearRegionItem(values=(xmin, xmax))
self.p = self.addPlot()
self.p.addItem(self.lr)
self.lr.sigRegionChanged.connect(self.handle_region_changed)
def handle_region_changed(self, item):
self.range_changed.emit(*item.getRegion())
class Win(QWidget):
def __init__(self):
super().__init__()
xdata = np.linspace(0, 2 * np.pi, 100)
ydata = np.sin(xdata)
self.chart = Chart(xdata, ydata)
self.lr = LR(xdata.min(), xdata.max())
self.lr.range_changed.connect(self.chart.p.setXRange)
lay = QVBoxLayout(self)
lay.addWidget(self.chart, stretch=4)
lay.addWidget(self.lr, stretch=1)
def main():
app = QApplication([])
win = Win()
win.show()
app.exec()
if __name__ == "__main__":
main()
I am developing a chess GUI in Python 3.6.3 using PyQt5 5.9.1 (GUI framework) and python-chess 0.21.1 (chess library) on Windows 10. I want to get the value of a piece that was clicked on an SVG chessboard (provided by python-chess) so that I can then move that piece to another square.
After the first left mouse click and getting the piece, I want to get the second left mouse click from the user and get the square that the user clicked on. Then my chess GUI must move the piece from originating square to the target square.
So, here's my complete working code so far. Any hints or actual code additions are very welcome.
import chess
import chess.svg
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWidgets import QApplication, QWidget
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Chess Titan")
self.setGeometry(300, 300, 800, 800)
self.widgetSvg = QSvgWidget(parent=self)
self.widgetSvg.setGeometry(10, 10, 600, 600)
self.chessboard = chess.Board()
#pyqtSlot(QWidget)
def mousePressEvent(self, event):
if event.buttons() == Qt.LeftButton:
## How to get the clicked SVG chess piece?
# Envoke the paint event.
self.update()
#pyqtSlot(QWidget)
def paintEvent(self, event):
self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
self.widgetSvg.load(self.chessboardSvg)
if __name__ == "__main__":
chessTitan = QApplication([])
window = MainWindow()
window.show()
chessTitan.exec()
If size of chessboard is known, you can find the coordinates of the mouseclick from event.pos() resp.event.x(), event.y() depending on marginwidth and squaresize, see chess.svg.py line 129 ff.
edit Nov 25: event.pos() is in this example in MainWindow coordinates, to find the coordinates on chessboard all must be calculated from top left corner represented by self.svgX and self.svgY:
import chess
import chess.svg
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Chess Titan")
self.setGeometry(300, 300, 800, 800)
self.widgetSvg = QSvgWidget(parent=self)
self.svgX = 50 # top left x-pos of chessboard
self.svgY = 50 # top left y-pos of chessboard
self.cbSize = 600 # size of chessboard
self.widgetSvg.setGeometry(self.svgX,self.svgY, self.cbSize, self.cbSize)
self.coordinates = True
# see chess.svg.py line 129
self.margin = 0.05*self.cbSize if self.coordinates == True else 0
self.squareSize = (self.cbSize - 2 * self.margin) / 8.0
self.chessboard = chess.Board()
self.pieceToMove = [None, None]
#pyqtSlot(QWidget)
def mousePressEvent(self, event):
if self.svgX < event.x() <= self.svgX + self.cbSize and self.svgY < event.y() <= self.svgY + self.cbSize: # mouse on chessboard
if event.buttons() == Qt.LeftButton:
# if the click is on chessBoard only
if self.svgX + self.margin < event.x() < self.svgX + self.cbSize - self.margin and self.svgY + self.margin < event.y() < self.svgY + self.cbSize - self.margin:
file = int((event.x() - (self.svgX + self.margin))/self.squareSize)
rank = 7 - int((event.y() - (self.svgY + self.margin))/self.squareSize)
square = chess.square(file, rank) # chess.sqare.mirror() if white is on top
piece = self.chessboard.piece_at(square)
coordinates = '{}{}'.format(chr(file + 97), str(rank +1))
if self.pieceToMove[0] is not None:
move = chess.Move.from_uci('{}{}'.format(self.pieceToMove[1], coordinates))
self.chessboard.push(move)
print(self.chessboard.fen())
piece = None
coordinates= None
self.pieceToMove = [piece, coordinates]
else:
print('coordinates clicked')
# Envoke the paint event.
self.update()
else:
QWidget.mousePressEvent(self, event)
#pyqtSlot(QWidget)
def paintEvent(self, event):
self.chessboardSvg = chess.svg.board(self.chessboard, size = self.cbSize, coordinates = self.coordinates).encode("UTF-8")
self.widgetSvg.load(self.chessboardSvg)
if __name__ == "__main__":
chessTitan = QApplication([])
window = MainWindow()
window.show()
chessTitan.exec()
move white and black pieces alternating, they change the color if the same color is moved twice.
Below is the Python, PyQt5 and python-chess code for a fully functional chess GUI that has legal move detection built in, so chess piece movement behaves according to the rules of chess.
#! /usr/bin/env python
"""
This module is the execution point of the chess GUI application.
"""
import sys
import chess
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget
class MainWindow(QWidget):
"""
Create a surface for the chessboard.
"""
def __init__(self):
"""
Initialize the chessboard.
"""
super().__init__()
self.setWindowTitle("Chess GUI")
self.setGeometry(300, 300, 800, 800)
self.widgetSvg = QSvgWidget(parent=self)
self.widgetSvg.setGeometry(10, 10, 600, 600)
self.boardSize = min(self.widgetSvg.width(),
self.widgetSvg.height())
self.coordinates = True
self.margin = 0.05 * self.boardSize if self.coordinates else 0
self.squareSize = (self.boardSize - 2 * self.margin) / 8.0
self.pieceToMove = [None, None]
self.board = chess.Board()
self.drawBoard()
#pyqtSlot(QWidget)
def mousePressEvent(self, event):
"""
Handle left mouse clicks and enable moving chess pieces by
clicking on a chess piece and then the target square.
Moves must be made according to the rules of chess because
illegal moves are suppressed.
"""
if event.x() <= self.boardSize and event.y() <= self.boardSize:
if event.buttons() == Qt.LeftButton:
if self.margin < event.x() < self.boardSize - self.margin and self.margin < event.y() < self.boardSize - self.margin:
file = int((event.x() - self.margin) / self.squareSize)
rank = 7 - int((event.y() - self.margin) / self.squareSize)
square = chess.square(file, rank)
piece = self.board.piece_at(square)
coordinates = "{}{}".format(chr(file + 97), str(rank + 1))
if self.pieceToMove[0] is not None:
move = chess.Move.from_uci("{}{}".format(self.pieceToMove[1], coordinates))
if move in self.board.legal_moves:
self.board.push(move)
piece = None
coordinates = None
self.pieceToMove = [piece, coordinates]
self.drawBoard()
def drawBoard(self):
"""
Draw a chessboard with the starting position and then redraw
it for every new move.
"""
self.boardSvg = self.board._repr_svg_().encode("UTF-8")
self.drawBoardSvg = self.widgetSvg.load(self.boardSvg)
return self.drawBoardSvg
if __name__ == "__main__":
chessGui = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(chessGui.exec_())
a_manthey_67 and BoĊĦtjan Mejak, I've combined features from both of your solutions:
https://github.com/vtad4f/chess-ui/blob/master/board.py
The full version integrates AI player(s) with your board UI:
Run make to build https://github.com/vtad4f/chess-ai/
Run main.py to play a game https://github.com/vtad4f/chess-ui/
I've written a simple PyQt4 GUI that plays an OpenCV VideoCapture. This requires converting frames from numpy arrays to QImages. I'm using OpenCV so that I can detect circles using my findCircles method.
However, when I pass my frames to findCircles, the program crashes when the window is moved. This problem does not occur when I don't search for circles. I don't understand why this is happening, as I'm under the impression that the work is being done on a different thread than the GUI since I call findCircles from the run method of a QThread.
Note that I don't receive a normal error message in the console; Python crashes like such:
Here is the video file I've been using to test my player. I'm running Python 2.7.6 on Windows 8.1.
import sys
import cv2.cv as cv, cv2
from PyQt4.Qt import *
import time
def numpyArrayToQImage(array):
if array != None:
height, width, bytesPerComponent = array.shape
bytesPerLine = bytesPerComponent * width;
cv2.cvtColor(array, cv.CV_BGR2RGB, array)
return QImage(array.data, width, height, bytesPerLine, QImage.Format_RGB888)
return None
def findCircles(frame):
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurredFrame = cv2.medianBlur(grayFrame, 3)
circles = cv2.HoughCircles(blurredFrame, cv.CV_HOUGH_GRADIENT, 1, 30, param1=50, param2=30, minRadius=30, maxRadius=35)
if circles is not None:
for i in circles[0]:
cv2.circle(frame, (i[0], i[1]), i[2], (255, 0, 0), 1) # Perimeter
cv2.circle(frame, (i[0], i[1]), 3, (0, 255, 0), -1) # Center
class VideoThread(QThread):
frameProcessed = pyqtSignal(QImage)
def __init__(self, video, videoLabel):
QThread.__init__(self)
self.video = video
self.fps = self.video.get(cv.CV_CAP_PROP_FPS)
self.frameCount = self.video.get(cv.CV_CAP_PROP_FRAME_COUNT)
self.startingSecond = 0
self.videoLabel = videoLabel
def run(self):
clockAtStart = time.clock()
while True:
runtime = self.startingSecond + (time.clock() - clockAtStart)
currentFrame = int(runtime * self.fps)
if currentFrame < self.frameCount - 1:
self.video.set(cv.CV_CAP_PROP_POS_FRAMES, currentFrame)
frame = self.video.read()[1]
findCircles(frame) # Removing this line removes the issue
self.frameProcessed.emit(numpyArrayToQImage(frame))
time.sleep(.02)
else:
break
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
#pyqtSlot(QImage)
def updateVideoLabel (self, image):
self.videoLabel.setPixmap(QPixmap.fromImage(image))
self.videoLabel.update()
def initUI(self):
self.setGeometry(300, 300, 500, 375)
self.setMinimumHeight(250)
self.createWidgets()
self.addWidgets()
def startNewVideo(self):
self.video = cv2.VideoCapture(unicode(QFileDialog.getOpenFileName(self, "Open video").toUtf8(), encoding="UTF-8"))
self.videoThread = VideoThread(self.video, self.videoLabel)
self.videoThread.frameProcessed.connect(self.updateVideoLabel)
self.playVideoFrom(0)
def playVideoFrom(self, frame):
self.videoThread.startingSecond = frame / self.videoThread.fps
self.videoThread.start()
def createWidgets(self):
self.populateMenuBar()
self.videoLabel = QLabel()
self.videoLabel.setStyleSheet('background-color : black;');
def populateMenuBar(self):
self.menuBar = self.menuBar()
fileMenu = QMenu('File', self)
openAction = QAction('Open video...', self)
openAction.triggered.connect(self.startNewVideo)
fileMenu.addAction(openAction)
self.menuBar.addMenu(fileMenu)
def addWidgets(self):
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.videoLabel, 1)
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
centralWidget.setLayout(mainLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
player = MainWindow()
player.show()
sys.exit(app.exec_())
I've tested your program, and it crashes when it finds no circles as indicated in the error message:
Traceback (most recent call last):
File "test_opencv_tkinter.py", line 53, in run
findCircles(frame) # Removing this line removes the issue
File "test_opencv_tkinter.py", line 26, in findCircles
if len(circles) > 0:
TypeError: object of type 'NoneType' has no len()
I've made some changes in the findCircles(frame) function, as follows, and it runs without error, even when I move the window around on the screen.
def findCircles(frame):
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurredFrame = cv2.medianBlur(grayFrame, 3)
circles = cv2.HoughCircles(grayFrame,cv.CV_HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
if circles == None:
print "no circles found"
return
if len(circles) > 0:
print "found circles ", len(circles[0])
for i in circles[0]:
cv2.circle(frame, (i[0], i[1]), i[2], (255, 0, 0), 1) # Perimeter
cv2.circle(frame, (i[0], i[1]), 3, (0, 255, 0), -1) # Center