How to run thermal camera mlx90640 concurrently with countdown timers - python-3.x

The enclosed Python code for Raspberry Pi 4 runs separately each function without any problem countdown() and RunThermalCam(), but when running both functions concurrently the timers stop and camera image freeze. My understanding is camera is heavily processor usage so I used multiprocessing, but it gives the following error which I couldn't figure out. The code should first runs GUI then once "Start" button is hit, modules (PWM) runs with countdown timers for each module along with thermal camera.
XIO: fatal IO error 25 (Inappropriate ioctl for device) on X server ":0"
after 1754 requests (1754 known processed) with 38 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python3: ../../src/xcb_io.c:269: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Process ended with exit code -6.
import RPi.GPIO as GPIO
from adafruit_blinka import Enum, Lockable, agnostic
import csv, datetime
from tkinter import *
from tkinter.filedialog import asksaveasfile
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
import multiprocessing
def first():
print("first new time is up \n")
#stop module (1)
def second():
print("second new time is up \n")
#stop module (2)
def third():
print("third new time is up \n")
#stop module (3)
#Create interface#
root = Tk()
root.geometry("1024x600")
root.title("Countdown Timer")
def modules():
if (clockTime[0] == 0 or clockTime[0] == -1):
first()
if(clockTime[1] == 0 or clockTime[1] == -1):
second()
if(clockTime[2] == 0 or clockTime[2] == -1):
third()
#initialize timers lists
timers_number = 3
hrString=[0]*timers_number
minString=[0]*timers_number
secString=[0]*timers_number
totalSeconds = [0]*timers_number
totalMinutes = [0]*timers_number
totalHours = [0]*timers_number
for i in range(timers_number):
hrString[i] = StringVar()
hrString[i].set("00")
for i in range(timers_number):
minString[i] = StringVar()
minString[i].set("00")
for i in range(timers_number):
secString[i] = StringVar()
secString[i].set("00")
#Get User Input
hourTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=hrString[0]).place(x=170, y=100)
minuteTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=minString[0]).place(x=220, y=100)
secondTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=secString[0]).place(x=270, y=100)
hourTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=hrString[1]).place(x=170, y=180)
minuteTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=minString[1]).place(x=220, y=180)
secondTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=secString[1]).place(x=270, y=180)
hourTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=hrString[2]).place(x=170, y=260)
minuteTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=minString[2]).place(x=220, y=260)
secondTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=secString[2]).place(x=270, y=260)
def RunThermalCam():
thermal_mapfile = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')
thermal_mapfile = thermal_mapfile[:16] #limit thermal file name to 16 characters
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) # setup I2C
mlx = adafruit_mlx90640.MLX90640(i2c) # begin MLX90640 with I2C comm
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ # set refresh rate 2Hz
mlx_shape = (24,32)
print("Initialized")
# setup the figure for plotting
plt.ion() # enables interactive plotting
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0,vmax=60) #start plot with zeros
cbar = fig.colorbar(therm1) # setup colorbar for temps
cbar.set_label('Temperature [$^{\circ}$C]',fontsize=14) # colorbar label
#frame = np.zeros((24*32,)) # setup array for storing all 768 temperatures
t_array = []
frame = [0] * 768
while True:
t1 = time.monotonic()
try:
mlx.getFrame(frame) # read MLX temperatures into frame var
data_array = (np.reshape(frame,mlx_shape)) # reshape to 24x32
therm1.set_data(np.fliplr(data_array)) # flip left to right
therm1.set_clim(vmin=np.min(data_array),vmax=np.max(data_array)) # set bounds
cbar.update_normal(therm1) # update colorbar range
plt.title(f"Max Temp: {np.max(data_array):.1f}C")
plt.pause(0.001) # required
t_array.append(time.monotonic()-t1)
print('Sample Rate: {0:2.1f}fps'.format(len(t_array)/np.sum(t_array)))
#except AttributeError:
# continue
except ValueError:
continue # if error, just read again
for h in range(24):
for w in range(32):
t = frame[h*32 + w]
frame = list(np.around(np.array(frame),1)) #round array elements to one decimal point
with open("/home/pi/MOC/Thermal_Camera/"+thermal_mapfile+".csv","a") as thermalfile:
writer = csv.writer(thermalfile,delimiter=" ")
writer.writerow([time.time(),frame])
def countdown():
for i in range (timers_number):
if(clockTime[i] > -1):
totalMinutes[i], totalSeconds[i] = divmod(clockTime[i], 60)
if(totalMinutes[i]>60):
totalHours[i], totalMinutes[i] = divmod(totalMinutes[i], 60)
hrString[i].set("{0:2d}".format(totalHours[i]))
minString[i].set("{0:2d}".format(totalMinutes[i]))
secString[i].set("{0:2d}".format(totalSeconds[i]))
if(clockTime[i] == 0): #time is up
hrString[i].set("00")
minString[i].set("00")
secString[i].set("00")
modules()
if(clockTime[i] != -1): #timer is paused
clockTime[i] -= 1
if(clockTime[i] != -1):
root.after(1000, countdown)
p1 = multiprocessing.Process(target = RunThermalCam)
p2 = multiprocessing.Process(target = countdown)
def starttimer():
#Start_modules()
global clockTime
clockTime = [0]*timers_number
try:
#global clockTime
for i in range (timers_number):
clockTime[i] = int(hrString[i].get())*3600 + int(minString[i].get())*60 + int(secString[i].get())
except:
print("Incorrect values")
countdown()
RunThermalCam()
#p1.start()
#p2.start()
#p1.join()
#p2.join()
def stop():
for i in range (timers_number):
clockTime[i] = 0
def pause():
for i in range (timers_number):
clockTime[i] = -1
modules()
def GUI():
setTimeButton = Button(root, text='START', bd='5', command=starttimer).place(x=200, y=500)
setTimeButton = Button(root, text='STOP', bd='5', command=stop).place(x=350, y=500)
setTimeButton = Button(root, text='PAUSE', bd='5', command=pause).place(x=500, y=500)
root.mainloop()
if __name__ == '__main__':
GUI()

Your code isn't really using multiprocessing.
When you click the start button, tkinter processes the event, and calls the starttimer callback.
This in turn calls RunThermalCam in the current process.
This is a problem, because RunThermalCam has an infinite loop inside it.
So basically, since RunThermalCam runs forever, starttimer will never return. That means that tkinter's event processing grinds to a halt.

I found it is more efficient to use PyQt library instead of tkinter. Timers and other peripherals are running smoothly in parallel with the Thermal Camera Moreover, no need to multiprocessing or multithreading.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication
import RPi.GPIO as GPIO
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
from adafruit_blinka import Enum, Lockable, agnostic
import csv
import datetime
font_1 = "color: blue; font: bold 12px;"
font_2 = "color: blue; font:14px;"
line0 = 0
line1 = 20
line2 = 70
line3 = 120
line4 = 170
line12 = 500
def run_thermal_cam():
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) # setup I2C for thermal camera
thermal_mapfile = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')
thermal_mapfile = thermal_mapfile[:16] #limit thermal file name to 16 characters
print("Thermal cam is ON")
mlx = adafruit_mlx90640.MLX90640(i2c) # begin MLX90640 with I2C comm
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ # set refresh rate 2Hz
mlx_shape = (24,32)
print("Initialized")
# setup the figure for plotting
plt.ion() # enables interactive plotting
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0,vmax=60) #start plot with zeros
cbar = fig.colorbar(therm1) # setup colorbar for temps
cbar.set_label('Temperature [$^{\circ}$C]',fontsize=14) # colorbar label
t_array = []
frame = [0] * 768
t1 = time.monotonic()
while True:
try:
mlx.getFrame(frame) # read MLX temperatures into frame var
data_array = (np.reshape(frame,mlx_shape)) # reshape to 24x32
therm1.set_data(np.fliplr(data_array)) # flip left to right
therm1.set_clim(vmin=np.min(data_array),vmax=np.max(data_array)) # set bounds
cbar.update_normal(therm1) # update colorbar range
plt.title(f"Max Temp: {np.max(data_array):.1f}C")
plt.pause(0.001) # required
t_array.append(time.monotonic()-t1)
except ValueError:
continue # if error, just read again
for h in range(24):
for w in range(32):
t = frame[h*32 + w]
frame = list(np.around(np.array(frame),1)) #round array elements to one decimal point
with open("/home/pi/Thermal_Camera/"+thermal_mapfile+".csv","a") as thermalfile:
writer = csv.writer(thermalfile,delimiter=" ")
unix_time = time.time()
formatted_time = datetime.datetime.fromtimestamp(unix_time).strftime('%H:%M:%S')
writer.writerow([formatted_time,frame])
class TimerApp(QtWidgets.QWidget):
def __init__(self):
super().__init__()
# Create layout
self.setGeometry(0, 0, 1024, 600)
self.setWindowTitle("Thermal Camera")
self.setStyleSheet(font_2) #control timers color & font
# Create countdown timers
self.timer1 = QtWidgets.QTimeEdit(self)
self.timer1.setDisplayFormat("HH:mm:ss")
self.timer1.setGeometry(QtCore.QRect(920, line2-10, 85, 25))
self.timer1.setTime(QtCore.QTime(0, 0, 0))
self.timer2 = QtWidgets.QTimeEdit(self)
self.timer2.setDisplayFormat("HH:mm:ss")
self.timer2.setGeometry(QtCore.QRect(920, line3-10, 85, 25))
self.timer2.setTime(QtCore.QTime(0, 0, 0))
self.timer3 = QtWidgets.QTimeEdit(self)
self.timer3.setDisplayFormat("HH:mm:ss")
self.timer3.setGeometry(QtCore.QRect(920, line4-10, 85, 25))
self.timer3.setTime(QtCore.QTime(0, 0, 0))
# Create start button
self.start_button = QtWidgets.QPushButton("Start", self)
self.start_button.setGeometry(250, line12, 55, 55)
self.start_button.clicked.connect(self.start)
# Connect start button to start function
self.start_button.clicked.connect(self.start)
# Create timer
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.countdown)
def start(self):
self.timer.start(1000) # start all timers #
run_thermal_cam()
def countdown(self):
if self.timer1.time() > QtCore.QTime(0, 0, 0):
new_time = self.timer1.time().addSecs(-1)
self.timer1.setTime(new_time)
if self.timer2.time() > QtCore.QTime(0, 0, 0):
new_time = self.timer2.time().addSecs(-1)
self.timer2.setTime(new_time)
if self.timer3.time() > QtCore.QTime(0, 0, 0):
new_time = self.timer3.time().addSecs(-1)
self.timer3.setTime(new_time)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
timer_app = TimerApp()
timer_app.show()
sys.exit(app.exec_())

Related

Multiprocessing code in a game isn't working

My problem is that when I do a multiprocessing code it isn't working for a script I wrote.
The code I am writing is for a clicker game by the way.
Here's the code I tried. What I was hopping it would do was to open a Tk window, which it does, but the part that's wrong is every 0.6 seconds 1 is added to score, but that isn't happening. The part that isn't working is the def autopoints and bellow that
from tkinter import *
import time
import multiprocessing
root = Tk()
c = Canvas(root, width=100, height=100)
score = 0
PointsPerClick = 10
PriceForUpgrade = 100
pointsfromautogen = 1
timeforautogen = 0.6
priceforautogen = 500
pricefortimeautogen = 2000
root.title("Clicker Game")
#this is basically the code for the text in the window
scoretext = StringVar()
scoretext.set(score)
score_label = Label(root, textvariable = scoretext)
upgradecosttext = StringVar()
upgradecosttext.set(PriceForUpgrade + 10)
upgradecost_label = Label(root, textvariable = upgradecosttext)
pointsperclicktext = StringVar()
pointsperclicktext.set(PointsPerClick)
pointsperclicktext_label = Label(root, textvariable = pointsperclicktext)
pointsfromautogentext = StringVar()
pointsfromautogentext.set(pointsfromautogen)
pointsfromautogentext_label = Label(root, textvariable = pointsfromautogentext)
#code for the buttons
def bAaction():
global score
score += PointsPerClick
scoretext.set(score)
def bBaction():
global score
global PriceForUpgrade
if score > PriceForUpgrade:
global PointsPerClick
score -= PriceForUpgrade
PointsPerClick += 5
PriceForUpgrade += 150
upgradecosttext.set(PriceForUpgrade + 1)
pointsperclicktext.set(PointsPerClick)
else:
print('Not enough. Need more score')
def bCaction():
global pointsfromautogen
global priceforautogen
if score > priceforautogen:
pointsfromautogen += 10
pointsfromautogentext.set(priceforautogen + 1)
priceforautogen += 100
#code for the auto generator (aka the part that isn't working)
def autopoints():
time.sleep(0.1)
score + pointsfromautogen
scoretext.set(score)
if __name__ == '__main__':
ap = multiprocessing.Process(target=autopoints)
ap.start()
ap.join()
def bDaction():
if score < pricefortimeautogen:
if timeforautogen > 0.5:
timeforautogen - 0.1
pricefortimeautogen + 2000
else:
print('At max level or not enough points')
#all of the buttons
buttonA = Button(root, text='Points Generator', command=bAaction)
buttonB = Button(root, text='Upgrade', command=bBaction)
buttonC = Button(root, text ='Auto Points Upgrade', command=bCaction)
buttonD = Button(root, text='Speed Up Auto Points', command=bDaction)
#just packing everything needed
buttonA.pack()
buttonB.pack()
buttonC.pack()
buttonD.pack()
score_label.pack()
upgradecost_label.pack()
pointsperclicktext_label.pack()
pointsfromautogentext_label.pack()
c.pack()
root.mainloop()

Tkinter program displays blank screen on linux, works on windows

I've been writing this code for a slideshow program in Linux. The problem I'm having is that when run from a windows environment it works perfectly (Full-screen resized images), however when run from a virtual Linux (Ubuntu x64) environment a blank white canvas appears with no images being displayed.
The code:
from PIL import Image, ImageTk
import tkinter as tk
import os
import glob
import random
class App(tk.Tk):
def __init__(self, image_files, delay):
tk.Tk.__init__(self)
self.w = self.winfo_screenwidth()
self.h = self.winfo_screenheight()
self.overrideredirect(1)
self.geometry("%dx%d+0+0" % (self.w, self.h))
self.delay = delay
self.pictures = []
self.track_img_ndex = 0
for img in image_files:
self.pictures.append(img)
self.picture_display = tk.Label(self)
self.picture_display.pack(expand=True, fill="both")
def show_slides(self):
if self.track_img_ndex < len(self.pictures):
x = self.pictures[self.track_img_ndex]
self.track_img_ndex +=1
original_image = Image.open(x)
resized = original_image.resize((self.w, self.h),Image.ANTIALIAS)
new_img = ImageTk.PhotoImage(resized)
self.picture_display.config(image=new_img)
self.picture_display.image = new_img
self.title(os.path.basename(x))
self.after(self.delay, self.show_slides)
else:
print("End of list!")
delay = 5000
playlist = glob.glob(r'\mnt\hgfs\E\Images\*.*')
random.shuffle(playlist)
image_files = playlist
app = App(image_files, delay)
app.show_slides()
app.mainloop()
Any help would be appreciated!
winfo_screenwidth() and winfo_screenheight() give not correct display size on Linux. Use full-screen mode to fix it.
The code:
from PIL import Image, ImageTk
import tkinter as tk
import os
import glob
import random
class App(tk.Tk):
def __init__(self, image_files, delay):
tk.Tk.__init__(self)
# start window size (any)
self.w = 500
self.h = 500
self.attributes("-fullscreen", True) # Activate full-screen mode
# Change full-screen mode bind
self.bind("<F11>", lambda event: self.attributes("-fullscreen",
not self.attributes("-fullscreen")))
# Bind full-screen mode exit
self.bind("<Escape>", lambda event: self.attributes("-fullscreen", False))
self.geometry("%dx%d+100+100" % (self.w, self.h))
self.delay = delay
self.pictures = []
self.track_img_ndex = 0
for img in image_files:
self.pictures.append(img)
self.picture_display = tk.Label(self)
self.picture_display.pack(expand=True, fill="both")
def show_slides(self):
if self.track_img_ndex < len(self.pictures):
x = self.pictures[self.track_img_ndex]
self.track_img_ndex += 1
original_image = Image.open(x)
window_size_now = (self.winfo_width(), self.winfo_height()) # Getting current window size :
resized = original_image.resize(window_size_now, Image.ANTIALIAS)
new_img = ImageTk.PhotoImage(resized)
self.picture_display.config(image=new_img)
self.picture_display.image = new_img
self.title(os.path.basename(x))
self.after(self.delay, self.show_slides)
else:
print("End of list!")
_delay = 5000
playlist = glob.glob(r'/home/yaroslav_admin/PycharmProjects/LearnPython_01/imgs/*.*')
random.shuffle(playlist)
_image_files = playlist
app = App(_image_files, _delay)
app.after(100, app.show_slides) # delayed start,
# because tkinter need some time to count full-screen window size in main loop !
app.mainloop()

why the recording file is empty in python

I am trying to record my desktop screen and record the audio from microphone simentensously with the help of this python script.
Now when i run only the screen capture part the code works perfectly fine but when i try to run both sound recording and screen capture combine code as shown in below code. my video and audio both file does not open. (0 bytes) or very less size file.
How can i solve this problem.
updated Code
now i am able to record voice properly but the video file is not opening?
import datetime
import tkinter as tk
from tkinter import *
from tkinter import ttk ,FLAT
from PIL import Image, ImageTk, ImageGrab
import cv2
import numpy as np
import threading
import win32api
import pyaudio
import wave
VIDEO_SIZE = (800 , 420) #(960, 540)
p = ImageGrab.grab()
a, b = p.size
chunk = 1024
sample_format = pyaudio.paInt16
channels = 2
fs = 44100
frames = []
g = pyaudio.PyAudio()
date = datetime.datetime.now()
filename='rec_%s-%s-%s-%s-%s-%s.mp4' % (date.year, date.month, date.day,date.hour, date.minute, date.second)
#fourcc = cv2.VideoWriter_fourcc(*'XVID')
frame_rate = 24
cap = cv2.VideoCapture(0)
out = cv2.VideoWriter()
def screen_capturing():
global capturing
capturing = True
while capturing:
img = ImageGrab.grab()
frame = np.array(img)
sc = np.array(img)
_xs,_ys = win32api.GetCursorPos()
cv2.circle(frame,(_xs,_ys),20,(255,255,0), 2)
sc = cv2.resize(sc, VIDEO_SIZE)
tkimage.paste(Image.fromarray(sc))
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
out.write(frame)
def start_screen_capturing():
if not out.isOpened():
out.open(filename, 0x31637661, frame_rate,(VIDEO_SIZE))
t1=threading.Thread(target=screen_capturing, daemon=True)
t1.start()
def stop_screen_capturing():
global capturing
capturing = False
out.release()
def voice_recording():
global recording
while recording:
data = stream.read(chunk)
frames.append(data)
def start_voice_recording():
global stream
stream = g.open(format=sample_format,channels=channels,rate=fs,frames_per_buffer=chunk,input=True)
global recording
recording = True
print('capturing')
t2 = threading.Thread(target=voice_recording) # daemon=True
t2.start()
def stop_voice_recording():
#global recording
recording =False
print(' complete')
filename='test'
filename = filename+".wav"
wf = wave.open(filename,'wb')
wf.setnchannels(channels)
wf.setsampwidth(g.get_sample_size(sample_format))
wf.setframerate(fs)
wf.writeframes(b''.join(frames))
wf.close()
root = tk.Tk()
root.title('Screen Recorder')
root.geometry('+260+70')
tkimage = ImageTk.PhotoImage(Image.new('RGB', VIDEO_SIZE, (0,0,0)))
w, h = VIDEO_SIZE
vbox = tk.Label(root, image=tkimage, width=w, height=h, bg='black')
vbox.pack(pady=10,padx=25)
frame = tk.Frame(root)
frame.pack()
start_cap = tk.Button(frame, text='Start screen Recording', width=30, command=start_screen_capturing)
start_cap.grid(row=0, column=0)
stop_cap = tk.Button(frame, text='Stop screen Recording', width=30, command=stop_screen_capturing)
stop_cap.grid(row=0, column=1)
start_voice = tk.Button(frame, text='Start voice Recording', width=30, command=start_voice_recording)
start_voice.grid(row=0, column=2)
stop_voice = tk.Button(frame, text='Stop voice Recording', width=30, command=stop_voice_recording)
stop_voice.grid(row=0, column=3)
root.mainloop()

PyQt4 video player crashes when moving window

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

subclassed QGraphicsItem not getting mouse events when used as module [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm using Pyside to create an interactive subclassed QGraphicsView - containing some subclassed QGraphicsItems.
It works well in its own module and receives mouse events.
But when used as a module from another file, and incorporated into another Layout - my mouse events are not being triggered.
However .itemChange is working.
Everything except the mouse events.
I am not using tracking events such as hover. I am using mousePressEvent and mouseReleaseEvent.
I have seen c++ responses about setting "setMouseTracking" but this is for widgets and my QGraphicsItems have been added as items not widgets. So when I call this funcion it tells me it doesn't exist for items. Also that seems to be for hover type of events - which I am not needing.
I believe I am subclassing properly and I pass on the events to the parent class. As I said at the start - my code works fine in a standalone file.
Any ideas what I've forgotten to do ?
Here is the standalone - working program:
Save as test_subclass_module.py
import sys
import weakref
import math
from PySide import QtCore, QtGui
###
class Edge(QtGui.QGraphicsItem):
Type = QtGui.QGraphicsItem.UserType + 2
def __init__(self, sourceNode, destNode):
QtGui.QGraphicsItem.__init__(self)
#
self.sourcePoint = QtCore.QPointF()
self.destPoint = QtCore.QPointF()
self.setAcceptedMouseButtons(QtCore.Qt.NoButton)
self.source = weakref.ref(sourceNode)
self.dest = weakref.ref(destNode)
self.source().addEdge(self)
self.dest().addEdge(self)
self.set_index()
self.adjust()
def type(self):
return Edge.Type
def sourceNode(self):
return self.source()
def setSourceNode(self, node):
self.source = weakref.ref(node)
self.adjust()
def destNode(self):
return self.dest()
def setDestNode(self, node):
self.dest = weakref.ref(node)
self.adjust()
def set_index(self):
self.setToolTip(self.source().label)
def adjust(self):
# do we have a line to draw ?
if self.source() and self.dest():
line = QtCore.QLineF(self.mapFromItem(self.source(), 0, 0), self.mapFromItem(self.dest(), 0, 0))
length = line.length()
if length > 20:
edgeOffset = QtCore.QPointF((line.dx() * 10) / length, (line.dy() * 10) / length)
self.prepareGeometryChange()
self.sourcePoint = line.p1() + edgeOffset
self.destPoint = line.p2() - edgeOffset
else: # want to make sure line not drawn
self.prepareGeometryChange()
self.sourcePoint = self.destPoint
def boundingRect(self):
# do we have a line to draw ?
if not self.source() or not self.dest():
return QtCore.QRectF()
else:
extra = 1
return QtCore.QRectF(self.sourcePoint,
QtCore.QSizeF(self.destPoint.x() - self.sourcePoint.x(),
self.destPoint.y() - self.sourcePoint.y())).normalized().adjusted(-extra, -extra, extra, extra)
def paint(self, painter, option, widget):
if self.source() and self.dest():
# Draw the line itself.
line = QtCore.QLineF(self.sourcePoint, self.destPoint)
if line.length() > 0.0:
painter.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
painter.drawLine(line)
###
class Node(QtGui.QGraphicsItem):
Type = QtGui.QGraphicsItem.UserType + 1
def __init__(self, graphWidget, time, temp, pos):
QtGui.QGraphicsItem.__init__(self)
self.graph = weakref.ref(graphWidget)
self.edgeList = []
self.set_index(pos)
self.newPos = QtCore.QPointF()
self.setFlag(QtGui.QGraphicsItem.ItemIsMovable)
self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges)
self.setCacheMode(self.DeviceCoordinateCache)
self.setZValue(-1)
#
self.temp = temp
self.time = time
x,y = self.map_temptime_to_pos()
self.setPos(x,y)
self.marker = False
def type(self):
return Node.Type
def addEdge(self, edge):
self.edgeList.append(weakref.ref(edge))
def set_index(self, index):
self.index = index
self.label = "Step %d" % index
self.setToolTip(self.label)
def get_prev_edge(self):
index = 1000
edge = False
for e in self.edgeList:
sn = e().source().index
dn = e().dest().index
if sn < index:
index = sn
edge = e
if dn < index:
index = dn
edge = e
return edge
def get_next_edge(self):
index = -1
edge = False
for e in self.edgeList:
sn = e().source().index
dn = e().dest().index
if sn > index:
index = sn
edge = e
if dn > index:
index = dn
edge = e
return edge
def map_temptime_to_pos(self):
x = self.time * self.graph().graph_width_ratio
y = self.graph().size[3] - self.temp * self.graph().graph_height_ratio
return (x,y)
def boundingRect(self):
adjust = 2.0
return QtCore.QRectF(-10 - adjust, -10 - adjust,
22 + adjust, 23 + adjust)
def paint(self, painter, option, widget):
painter.drawLine(QtCore.QLineF(6,-40,6,-2))
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(QtCore.Qt.lightGray)
painter.drawEllipse(-10, -10, 20, 20)
gradient = QtGui.QRadialGradient(0, 0, 22)
if option.state & QtGui.QStyle.State_Sunken: # selected
gradient.setColorAt(0, QtGui.QColor(QtCore.Qt.darkGreen).lighter(120))
else:
gradient.setColorAt(1, QtCore.Qt.blue)
painter.setBrush(QtGui.QBrush(gradient))
painter.setPen(QtGui.QPen(QtCore.Qt.black, 0))
painter.drawEllipse(-6, -6, 12, 12)
def itemChange(self, change, value):
if change == QtGui.QGraphicsItem.ItemPositionChange:
for edge in self.edgeList:
edge().adjust()
return QtGui.QGraphicsItem.itemChange(self, change, value)
def mousePressEvent(self, event):
if not self.graph().inhibit_edit:
self.update()
print "Node pressed"
QtGui.QGraphicsItem.mousePressEvent(self, event)
def mouseReleaseEvent(self, event):
if not self.graph().inhibit_edit:
self.update()
print "Node released"
#
QtGui.QGraphicsItem.mouseReleaseEvent(self, event)
###
class GraphWidget(QtGui.QGraphicsView):
def __init__(self):
QtGui.QGraphicsView.__init__(self)
self.size = (-30, 30, 600, 400)
#
scene = QtGui.QGraphicsScene(self)
scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex)
scene.setSceneRect(self.size[0],self.size[1],self.size[2],self.size[3])
self.setScene(scene)
self.setCacheMode(QtGui.QGraphicsView.CacheBackground)
self.setRenderHint(QtGui.QPainter.Antialiasing)
self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
#
self.maxtemp = 300
self.maxtime = 160
self.nodecount = 0
self.calc_upper_limits()
#
self.scale(0.8, 0.8)
self.setMinimumSize(600, 400)
self.setWindowTitle(self.tr("Elastic Nodes"))
self.inhibit_edit = False
def calc_upper_limits(self):
self.toptemp = (self.maxtemp / 100 + 1) * 100
self.toptime = (int(self.maxtime) / 30 + 1) * 30
self.graph_width_ratio = float(self.size[2]) /self.toptime
self.graph_height_ratio = float(self.size[3]) / self.toptemp
def add_node(self, time, temp, marker=False, pos=-1):
self.nodecount += 1
scene = self.scene()
# Insert Node into scene
node = Node(self, time, temp, self.nodecount)
scene.addItem(node)
# Insert new edges
nodes = self.get_ordered_nodes()
if len(nodes) > 1:
e = Edge(nodes[-2], node)
scene.addItem(e)
# cleanup edge tooltips
for n in self.get_ordered_nodes():
edges = n.edgeList
for e in edges:
e().set_index()
def get_ordered_nodes(self):
nodes = [item for item in self.scene().items() if isinstance(item, Node)]
nodes.sort(key=lambda n: n.index)
return nodes
def keyPressEvent(self, event):
key = event.key()
if key == QtCore.Qt.Key_Plus:
self.scaleView(1.2)
elif key == QtCore.Qt.Key_Minus:
self.scaleView(1 / 1.2)
else:
QtGui.QGraphicsView.keyPressEvent(self, event)
def mousePressEvent(self, event):
print "GraphWidget mouse"
QtGui.QGraphicsView.mousePressEvent(self, event)
def wheelEvent(self, event):
self.scaleView(math.pow(2.0, -event.delta() / 240.0))
def scaleView(self, scaleFactor):
factor = self.matrix().scale(scaleFactor, scaleFactor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width()
if factor < 0.07 or factor > 100:
return
self.scale(scaleFactor, scaleFactor)
def drawBackground(self, painter, rect):
sceneRect = self.sceneRect()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
widget = GraphWidget()
widget.add_node(0, 25)
widget.add_node(30, 100)
widget.add_node(60, 200)
widget.show()
sys.exit(app.exec_())
Here is the parent program - which does not get the mouse events:
Called test_toplevel.py
# import user interface etc
from PySide import QtCore, QtGui
from test_tabs_ui import Ui_Form
from test_subclass_module import *
import sys
Programs = {"Gen13": {"steps": [[0, 0, 0], [0, 30, 30], [0, 60, 60], [0, 77, 77]]
}}
###-----------------------------------------------------------
### The dialog
class Nusku_tab_Add_kiln(QtGui.QWidget):
""" Create dialog to add/delete kilns from controlled kilns """
def __init__(self, parent=None):
# Get the UI loaded
super(Nusku_tab_Add_kiln, self).__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.current = Programs['Gen13']
# draw program in graphicsView
# swap out the standin
self.ui.graphLayout.removeWidget(self.ui.graphicsView)
self.ui.graphicsView.setParent(None)
self.ui.graphicsView.deleteLater()
self.graph = GraphWidget()
self.ui.graphLayout.addWidget(self.graph)
self.draw_graph()
def choose_program(self):
pass
def draw_graph(self):
graph = self.graph
graph.inhibit_edit = True
steps = self.current['steps']
for s in steps:
print s
graph.add_node(s[1],s[2])
###------------------------------------------------
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
prog = Nusku_tab_Add_kiln()
prog.show()
sys.exit(app.exec_())
For sake of completeness. Here is the ui file it imports:
test_tabs_ui.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test_tabs.ui'
#
# Created: Wed Dec 05 15:20:02 2012
# by: pyside-uic 0.2.14 running on PySide 1.1.1
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(595, 540)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.tabWidget = QtGui.QTabWidget(Form)
self.tabWidget.setObjectName("tabWidget")
self.Tab_Program = QtGui.QWidget()
self.Tab_Program.setObjectName("Tab_Program")
self.verticalLayout_2 = QtGui.QVBoxLayout(self.Tab_Program)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.frame_graph_status = QtGui.QFrame(self.Tab_Program)
self.frame_graph_status.setFrameShape(QtGui.QFrame.StyledPanel)
self.frame_graph_status.setFrameShadow(QtGui.QFrame.Raised)
self.frame_graph_status.setObjectName("frame_graph_status")
self.horizontalLayout_7 = QtGui.QHBoxLayout(self.frame_graph_status)
self.horizontalLayout_7.setSpacing(0)
self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.frame_program = QtGui.QFrame(self.frame_graph_status)
self.frame_program.setFrameShape(QtGui.QFrame.StyledPanel)
self.frame_program.setFrameShadow(QtGui.QFrame.Raised)
self.frame_program.setObjectName("frame_program")
self.graphLayout = QtGui.QVBoxLayout(self.frame_program)
self.graphLayout.setContentsMargins(-1, 0, -1, 0)
self.graphLayout.setObjectName("graphLayout")
self.graphicsView = QtGui.QGraphicsView(self.frame_program)
self.graphicsView.setObjectName("graphicsView")
self.graphLayout.addWidget(self.graphicsView)
self.horizontalLayout_7.addWidget(self.frame_program)
self.verticalLayout_2.addWidget(self.frame_graph_status)
self.widget_prog = QtGui.QWidget(self.Tab_Program)
self.widget_prog.setObjectName("widget_prog")
self.prog_layout = QtGui.QGridLayout(self.widget_prog)
self.prog_layout.setContentsMargins(4, 4, 4, 4)
self.prog_layout.setSpacing(0)
self.prog_layout.setContentsMargins(0, 0, 0, 0)
self.prog_layout.setObjectName("prog_layout")
self.verticalLayout_2.addWidget(self.widget_prog)
self.tabWidget.addTab(self.Tab_Program, "")
self.Tab_alarms = QtGui.QWidget()
self.Tab_alarms.setObjectName("Tab_alarms")
self.alarms_tab_layout = QtGui.QVBoxLayout(self.Tab_alarms)
self.alarms_tab_layout.setObjectName("alarms_tab_layout")
self.tabWidget.addTab(self.Tab_alarms, "")
self.Tab_settings = QtGui.QWidget()
self.Tab_settings.setObjectName("Tab_settings")
self.settings_tab_layout = QtGui.QVBoxLayout(self.Tab_settings)
self.settings_tab_layout.setObjectName("settings_tab_layout")
self.tabWidget.addTab(self.Tab_settings, "")
self.Tab_pid = QtGui.QWidget()
self.Tab_pid.setObjectName("Tab_pid")
self.verticalLayout_8 = QtGui.QVBoxLayout(self.Tab_pid)
self.verticalLayout_8.setSpacing(0)
self.verticalLayout_8.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_8.setObjectName("verticalLayout_8")
self.scrollArea_2 = QtGui.QScrollArea(self.Tab_pid)
self.scrollArea_2.setWidgetResizable(True)
self.scrollArea_2.setObjectName("scrollArea_2")
self.scrollAreaWidgetContents_2 = QtGui.QWidget()
self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 569, 494))
self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2")
self.PID_tab_layout = QtGui.QVBoxLayout(self.scrollAreaWidgetContents_2)
self.PID_tab_layout.setSpacing(0)
self.PID_tab_layout.setContentsMargins(0, 0, 0, 0)
self.PID_tab_layout.setObjectName("PID_tab_layout")
self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2)
self.verticalLayout_8.addWidget(self.scrollArea_2)
self.tabWidget.addTab(self.Tab_pid, "")
self.verticalLayout.addWidget(self.tabWidget)
self.retranslateUi(Form)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(Form)
Form.setTabOrder(self.tabWidget, self.graphicsView)
Form.setTabOrder(self.graphicsView, self.scrollArea_2)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.graphicsView.setToolTip(QtGui.QApplication.translate("Form", "decimal point", None, QtGui.QApplication.UnicodeUTF8))
self.graphicsView.setStatusTip(QtGui.QApplication.translate("Form", "Accuracy can be increased at lower temperatures", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Tab_Program), QtGui.QApplication.translate("Form", "Program", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Tab_alarms), QtGui.QApplication.translate("Form", "Alarms", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Tab_settings), QtGui.QApplication.translate("Form", "Settings", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Tab_pid), QtGui.QApplication.translate("Form", "PID", None, QtGui.QApplication.UnicodeUTF8))
because there is an answer - which reasonably asks me to delete my answer - I have to answer the question with my own answer to close it. After waiting 3 days... hopefully I can delete it - but probably not as it has an answer..
I downloaded and tried your application and saw it more or less working
(although the cursor position gets wrong in test_toplevel.py).
After removing graph.inhibit_edit = False also the cursor stays right.
So is the problem already solved? Then it would be very helpful to remove your
question or mak it as resolved. Or please clarify the question.

Resources