Note: self.bitmap.draw_text(0,0,220+p,20, 'A', 1) where 220+p is the coordinates x, and 20 is y of screen
Why is the code showing the character in the same positions, even though I have conditioned to move the position? I tried to do it in another way and the 'A' always came ahead regardless of whether I added p+30. I want use it to create a chatbox with RGSS (Rpg Maker XP).
The result of this code works, I wrote this code, but it works not as intended. It Show the button that I pressed, but when I press A and B, the A is always in the first coordinates then came B: "AB" is showed but never "BA" even if I pressed B first.
class Sprite_Texto < Sprite
def initialize
super(nil)
self.bitmap = Bitmap.new(150,20)
self.ox = 100
self.z = 999
self.bitmap.font.size = 14
self.bitmap.font.bold = true #negrito
self.bitmap.font.name = "Verdana"
end
def escrever
self.bitmap = Bitmap.new(700,700)
p = 0
teste = Win32API.new("user32","GetAsyncKeyState",['i'],'i').call(0x10)
teste2 = Win32API.new("user32","GetAsyncKeyState",['i'],'i').call(0x41)
teste3 = Win32API.new("user32","GetAsyncKeyState",['i'],'i').call(0x42)
if teste2 > 0
p = p+30
self.bitmap.draw_text(0,0,220+p,20, 'A', 1)
else
if teste3 > 0
p = p+30
self.bitmap.draw_text(0,0,220+p,20, 'B', 1)
end
end
end
end
I have a question, its more an OS-based one.
I'm playing a video game and I want to be able to put a textual timer ontop of the game's screen as if it was a part of the game itself.
Now, I can write a program in any language that displays a TextBox with a timer on the screen, but if I run it, the game's process (lets call it game.exe) "loses" its focus and I get my TextBox focused and interactive by the OS.
Is there any option to display that text "ontop" of the game.exe that comes from an entire different process? as if there were "layers" to the screen. Also, this text shouldn't be intractable, clickable or make the game.exe process lose its focus.
Here's a very simple example I drew:
Thanks a lot!
Solved this using a window trick with python and tkinter with some windows api stuff.
The trick is to create a transparent non-clickable window and keep it always on top.
I've basically combined this answer with a bunch of simpler stuff like removing window's border and set to auto fullscreen.
from tkinter import *
import time
import win32gui
import win32api
from win32api import GetSystemMetrics
# WIDTH = 500
# HEIGHT = 500
WIDTH = GetSystemMetrics(0)
HEIGHT = GetSystemMetrics(1)
LINEWIDTH = 1
TRANSCOLOUR = 'gray'
title = 'Virtual whiteboard'
global old
old = ()
global HWND_t
HWND_t = 0
tk = Tk()
# tk.title(title)
tk.lift()
tk.wm_attributes("-topmost", True)
tk.wm_attributes("-transparentcolor", TRANSCOLOUR)
tk.attributes('-fullscreen', True)
state_left = win32api.GetKeyState(0x01) # Left button down = 0 or 1. Button up = -127 or -128
canvas = Canvas(tk, width=WIDTH, height=HEIGHT, highlightthickness=0)
canvas.pack()
canvas.config(cursor='tcross')
canvas.create_rectangle(0, 0, WIDTH, HEIGHT, fill=TRANSCOLOUR, outline=TRANSCOLOUR)
canvas.create_text(WIDTH/2,HEIGHT/2,fill="white",font="Arial 20", text="TEXT GOES HERE")
def putOnTop(event):
event.widget.unbind('<Visibility>')
event.widget.update()
event.widget.lift()
event.widget.bind('<Visibility>', putOnTop)
def drawline(data):
global old
if old !=():
canvas.create_line(old[0], old[1], data[0], data[1], width=LINEWIDTH)
old = (data[0], data[1])
def enumHandler(hwnd, lParam):
global HWND_t
if win32gui.IsWindowVisible(hwnd):
if title in win32gui.GetWindowText(hwnd):
HWND_t = hwnd
win32gui.EnumWindows(enumHandler, None)
tk.bind('<Visibility>', putOnTop)
tk.focus()
running = 1
while running == 1:
try:
tk.update()
time.sleep(0.01)
if HWND_t != 0:
windowborder = win32gui.GetWindowRect(HWND_t)
cur_pos = win32api.GetCursorPos()
state_left_new = win32api.GetKeyState(0x01)
if state_left_new != state_left:
if windowborder[0] < cur_pos[0] and windowborder[2] > cur_pos[0] and windowborder[1] < cur_pos[1] and windowborder[3] > cur_pos[1]:
drawline((cur_pos[0] - windowborder[0] - 5, cur_pos[1] - windowborder[1] - 30))
else:
old = ()
except Exception as e:
running = 0
print("error %r" % (e))
Ok, so I've been tasked with creating a VERY simple GUI at work (I'm an intern). The task is to eventually connect to a machine and process real data, but right now I'm working on randomly generated sine data with noise. I've chose to work in Python 3.0, and use wxpython to create my GUI components.
As I want everything to appear on the same window, I'm using panels (hence wx.lib.plot.PlotCanvas rather than something like matplotlib.pyplot)
The problem that I have is that over time, the plot seems to 'expand' off of the panel. This is temporarily solved when I manually resize the window, but resumes again immediately after (you need to run the code to see what I mean).
Expansion over time in panel
Another problem (that has bugged me since I have started writing the code) is that sometimes when I resize the window (manually) or minimize it and then maximize it again, the timer randomly starts and stops.
I have tried all sorts of things (changing padding in sizers, extra arguments, changing time between refreshes GetBestSize()) but I believe that I simply don't understand wxpython well enough to identify where the problem is
I would really appreciate any help you can shed on either of these problems (I don't know, they might even be linked to each other).
FYI: I am not an experienced coder, and my code is not finished (I have more functions to code, but I feel like I should resolve this first). I have constructed this code by looking at different techniques from various tutorials and websites like stackoverflow, so I know it's not formatted well and could definitely be made more efficient. Also, I have removed some parts just to be safe about confidentiality - nothing important, just strings in messages.
PS: If you do have an easier way to do the whole plot/update thing that doesn't have this problem (preferably still in wx) I would be thrilled to hear that as well
And here's my code:
EDIT: Solved the expanding problem by using self.p2.SetSize((W+0,L+0)) instead of (self.p2.GetBestSize())
EDIT: Made transitions much smoother by just regenerating data and redrawing it on existing canvas in the evt_timer function (instead of recreating the whole canvas, which gave a blink-y appearance if you know what I mean)
import wx
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import leastsq
import wx.lib.plot as plot
import time
import os
wildcard = "Text File (*.txt)|*.txt|"\
"Picture (*.png)|*.png|"\
"All files (*.*)|*.*"#This wildcard shows the options for file endings in the "SAVE" tab - see OnSave(self,event)
wildcard2 = "Picture (*.png)|*.png|"\
"Text File (*.txt)|*.txt|"\
"All files (*.*)|*.*"
class PlotCanvas(plot.PlotCanvas):
def __init__(self,parent,id,size,accepted):
"""
This randomly generates sine data (with noise) and plots it to a panel.
Incorporated as a separate class instead of instatiating it as a plot.PlotCanvas object
to overcome an issue of the size of the plot in the panel.
"""
plot.PlotCanvas.__init__(self,parent,id,style=wx.BORDER_SUNKEN,size = size)
N = 100 # number of data points
self.t = np.linspace(0, 4*np.pi, N)
f = 1.15247 # Optional!! Advised not to use
self.data = 3.0*np.sin(f*self.t+0.001) + 0.5 + np.random.randn(N) # create artificial data with noise
guess_mean = np.mean(self.data)
guess_phase = 0
guess_freq = 1
guess_amp = 1
optimize_func = lambda x: x[0]*np.sin(x[1]*self.t+x[2]) + x[3] - self.data
est_amp, est_freq, est_phase, est_mean = leastsq(optimize_func, [guess_amp, guess_freq, guess_phase, guess_mean])[0]
fine_t = np.arange(0,max(self.t),0.1)
data_fit=est_amp*np.sin(est_freq*fine_t+est_phase)+est_mean
multiplier = 1
dataset1 = [(x,[d for d in self.data][[td for td in self.t].index(x)])for x in [td for td in self.t]]
fitdata1 = [(x,[df for df in data_fit][[tf for tf in fine_t].index(x)]) for x in [tf for tf in fine_t]]
dataset =[(x,y*multiplier) for (x,y) in dataset1]
fitdata = [(x,y*multiplier) for (x,y) in fitdata1]
self.data = dataset
self.data2 = fitdata
line = plot.PolyLine(self.data,legend = 'random',colour = 'light blue', width =2)
line2 = plot.PolyLine(self.data2,legend = 'sineline',colour ='black',width =2)
a = []
if "D" in accepted:
a.append(line)
if "S" in accepted:
a.append(line2)
if "G" in accepted:
pass
if "L" in accepted:
pass
gc = plot.PlotGraphics(a,'Line Graph','X','Y')
xmin = self.t[0]-0.01*(self.t[-1]-self.t[0])
xmax = self.t[-1]+0.01*(self.t[-1]-self.t[0])
self.Draw(gc,xAxis=(xmin,xmax),yAxis=(min([x[1] for x in dataset])-0.01*(max([x[1] for x in dataset])-min([x[1] for x in dataset])),
max([x[1] for x in dataset])+0.01*(max([x[1] for x in dataset])-min([x[1] for x in dataset]))))
#self.showLegend = True
#self.enableZoom = True
def Dialog(self, parent, message, c):# Will be used to notify the user of errors/processes
if c == "W":
caption = "Warning!"
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_WARNING)
elif c == "I":
caption = "Information"
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()#Destroys dialog on close
class Frame(wx.Frame):
"""
This is the main class. In it, we declare the separate panels, canvas, menubar, buttons and sizers.
"""
def __init__(self,parent,id,title):
wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition)
self.CurrentDirectory = os.getcwd()
self.timer=wx.Timer(self)#Instantiating the timer
self.count=0
self.Bind(wx.EVT_TIMER,self.evt_timer)#Binding it to itself so that it is always triggered
self.Bind(wx.EVT_PAINT,self.paint)
menubar = wx.MenuBar()
fileMenu = wx.Menu() #Creating the Menubar at the top
#Creating 3 menus: fileMenu,fit,and help
save = wx.Menu()
z = wx.MenuItem(save,wx.ID_ANY,'Save Raw Data\tCtrl+D')
self.Bind(wx.EVT_MENU,self.OnSave,z)
save.Append(z)
z= wx.MenuItem(save,wx.ID_ANY,'Save Image\tCtrl+I')
self.Bind(wx.EVT_MENU,self.OnSaveImage,z)
save.Append(z)
fileMenu.AppendSubMenu(save,'&Save')
fileMenu.AppendSeparator()
z = wx.MenuItem(fileMenu, wx.ID_EXIT, '&Quit\tCtrl+W')
self.Bind(wx.EVT_MENU, self.OnQuit, z)
fileMenu.Append(z)
fit = wx.Menu()#Making a check menu
self.gaussian = fit.Append(wx.ID_ANY,'Gaussian',kind = wx.ITEM_CHECK)
#self.Bind(wx.EVT_MENU,self.ToggleGaussian,self.gaussian)
fit.Check(self.gaussian.GetId(),False)
self.sine = fit.Append(wx.ID_ANY,'Sine',kind = wx.ITEM_CHECK)
#self.Bind(wx.EVT_MENU,self.ToggleSine,self.sine)
fit.Check(self.sine.GetId(),False)
self.linear = fit.Append(wx.ID_ANY,'Linear',kind=wx.ITEM_CHECK)
#self.Bind(wx.EVT_MENU,self.ToggleLinear,self.linear)
fit.Check(self.linear.GetId(),False)
help = wx.Menu()
z = wx.MenuItem(help,wx.ID_ANY,'&About\tCtrl+H')
self.Bind(wx.EVT_MENU,self.OnHelp,z)
help.Append(z)
menubar.Append(fileMenu, '&File')
menubar.Append(fit, '&Fit')
menubar.Append(help, '&Help')#adding menus to menubar
self.SetMenuBar(menubar)#formatting the frame with menubar
self.sp = wx.SplitterWindow(self)#Splitting the window into 2 panels
self.p1 = wx.Panel(self.sp,style = wx.SUNKEN_BORDER)#For buttons and user events
self.p2 = wx.Panel(self.sp,style = wx.SUNKEN_BORDER)#For display of the plot
self.sp.SplitVertically(self.p1,self.p2,300)
sizer = wx.GridBagSizer(3, 3)#Versatile sizer for layout of first panel self.p1
bitmappath = self.CurrentDirectory + "\\BITMAPS"
bmp = wx.Bitmap(bitmappath+"\\SAVE.BMP",wx.BITMAP_TYPE_BMP)
self.saveBtn = wx.BitmapButton(self.p1,wx.ID_ANY,bitmap = bmp,size =(bmp.GetWidth()+10,bmp.GetHeight()+10))
self.Bind(wx.EVT_BUTTON,self.OnSave,self.saveBtn)
sizer.Add(self.saveBtn, (0, 0), wx.DefaultSpan, wx.ALL,5)
bmp = wx.Bitmap(bitmappath +"\\START.BMP",wx.BITMAP_TYPE_BMP)
self.startBtn = wx.BitmapButton(self.p1,-1,bitmap = bmp,size =(bmp.GetWidth()+10,bmp.GetHeight()+10))# A button that starts and stops the plotting
self.startBtn.startval = "START"
self.Bind(wx.EVT_BUTTON,self.paint,self.startBtn)
sizer.Add(self.startBtn, (0, 1), wx.DefaultSpan,wx.ALL,5)
sizer1 = wx.BoxSizer(wx.VERTICAL)
W,L = self.p2.GetSize()
self.p2.canvas = PlotCanvas(self.p2,wx.ID_ANY,(W,L),["D"])
sizer1.Add(self.p2.canvas,1,wx.ALL,0,0)
self.p2.SetSizerAndFit(sizer1)
self.p1.SetSizerAndFit(sizer)
self.p2.SetSizerAndFit(sizer1)
self.p2.SetSize(W,L)
self.Maximize(True)
self.Centre()
self.Show()
############### event methods ###########
def paint(self,event):
"""
Updates the canvas based on the value of the startbtn(not the image). Bound to self.timer.
"""
bitmappath = self.CurrentDirectory + "\\BITMAPS"
if self.startBtn.startval == "START":
self.timer.Start(1)# increase the value for more time
bmp = wx.Bitmap(bitmappath + "\\STOP.BMP",wx.BITMAP_TYPE_BMP)
self.startBtn.SetBitmap(bmp)
self.startBtn.startval = "STOP"
elif self.startBtn.startval == "STOP":
self.timer.Stop()
bmp = wx.Bitmap(bitmappath+ "\\START.BMP",wx.BITMAP_TYPE_BMP)
self.startBtn.SetBitmap(bmp)
self.startBtn.startval = "START"
def evt_timer(self,event):
self.count +=1
if self.count== 10:# By increasing count (or the number in self.timer.Start()) you can increase the interval between updates
#self.p2.canvas.Clear()
sizer1 = wx.BoxSizer(wx.VERTICAL)
W,L = self.p2.GetSize()
a = ["D"]
if self.sine.IsChecked():
a.append("S")
elif self.linear.IsChecked():
a.append("L")
elif self.gaussian.IsChecked():
a.append("G")
self.p2.canvas = PlotCanvas(self.p2,wx.ID_ANY,(W,L),a)
sizer1.Add(self.p2.canvas,1,wx.ALL,0,0)
self.p2.SetSizerAndFit(sizer1)
self.p2.SetSize(self.p2.GetBestSize())
self.count=0 # reset the count
def Dialog(self, parent, message, c):# Will be used to notify the user of errors/processes
if c == "W":
caption = "Warning!"
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_WARNING)
elif c == "I":
caption = "Information"
dlg = wx.MessageDialog(parent, message, caption, wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()#Destroys dialog on close
def OnSave(self,event):#Triggered by menubar and button
try:
rawdata = self.p2.canvas.data
raw_X =[x[0] for x in rawdata]
raw_Y =[x[1] for x in rawdata]
dlg = wx.FileDialog(#Code for this from http://www.blog.pythonlibrary.org
self, message="Save file as ...",
defaultDir=self.CurrentDirectory,
defaultFile=str(time.ctime()), wildcard=wildcard, style=wx.FD_SAVE
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
f = open(path+".txt","w+")
for i in range(len(raw_X)):
f.write(str(raw_X[i])+"\t"+str(raw_Y[i])+"\n")
f.close()
self.Dialog(None,"File successfully saved","I")
except UnboundLocalError:#Catch error when user closes save window without selecting any directory or filename
pass
def OnSaveImage(self,event):
try:
rawdata = self.p2.canvas.data
raw_X = [x[0] for x in rawdata]
raw_Y = [x[1] for x in rawdata]
dlg = wx.FileDialog(
self, message="Save file as ...",
defaultDir=self.CurrentDirectory,
defaultFile=str(time.ctime()), wildcard=wildcard2, style=wx.FD_SAVE
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
fig1 = plt.figure()
plt.plot(raw_X,raw_Y)
plt.title("Raw Data")
fig1.savefig(path+".png")
self.Dialog(None,"File successfully saved","I")
except UnboundLocalError:
pass
def OnMultiply(self,e):
try:
factor = self.x.GetValue()
factor = float(factor)
self.IntegrationTime = factor
except ValueError as e:
self.Dialog(None,str(e),"W")
def OnQuit(self, e):
self.Close()
def OnHelp(self,e):
self.Dialog(None,"N/A","I")
def ToggleSine(self,e):
pass
def ToggleLinear(self,e):
self.Dialog(None,"Not added yet","W")
def ToggleGaussian(self,e):
self.Dialog(None,"Not added yet","W")
if __name__ =="__main__":
app=wx.App()
Frame(None,-1,"N/A")
app.MainLoop()
I'm running python3.6 with openCV on the Raspberry pi(OS is Raspbian)
The approximate structure of the code is as follows.
The image is captured at time interval(3~5 min).
Captured image is processed in functions and returns measure(kind of accuracy)
Iterate 1.~2. until end_check() returns True
Problem is that the most recent taken image is out of date. It looks it was taken almost 10 minutes ago. All images recently taken are late. But the images taken at the beginning seem to be timed. And the time recorded in all .jpg files entered correctly
+It looks this problem is occured after more than a hour. (20~22 iterates)
Images are captured with cam0.read() in the cv2 package. Below is main part of the code. It is quite long to upload full code. It someone request, I will update.
def run(interval,model_list):
cam0 = cv2.VideoCapture(0) #Only cam0 is used. cam2 is just to record.
camdir = "/home/pi/capstone/cam0/"
cam2 = cv2.VideoCapture(1)
cam2dir = "/home/pi/capstone/cam2/"
runNo = 0
acc_list = list()
error_list = list()
end = False
while(end == False):
print(runNo,"th run")
img_name = "%s.jpg" %runNo
frame, res = cam0.read() #`res` is the image which will be processed
cv2.imwrite(os.path.join(camdir,img_name),res)
_ , cam2pic = cam2.read()
cv2.imwrite(os.path.join(cam2dir,img_name),cam2pic)
try:
temp = Real(res)
mat = temp.match(model_list)
acc_list.append([mat,runNo])
print("Accuracy=", mat)
except ValueError:
acc_list.append(["ValueError",runNo])
error_list.append(["ValueError",runNo])
except AttributeError:
acc_list.append(["AttributeError", runNo])
error_list.append(["AttributeError",runNo])
except SmallObjectError:
acc_list.append(["SmallObjectError", runNo])
error_list.append(["SmallObjectError",runNo])
runNo = runNo+1
endNo = 40
if(runNo/2 > endNo):
end_check(res, end)
elif(runNo > endNo):
end = True
sleep(interval*60)
with open("acc_list.txt", "w") as output: #records for tracking errors
output.write(str(acc_list))
with open("err_list.txt", "w") as output:
output.write(str(error_list))
cam0.release()
cam2.release()
run(3.5,model_list)
(+) Some newly found things and guess
The images time gap is getting bigger with code running
Code finally showed OpenCV Error
It looks kind of Video signal is stored in RAM on R-pi and .read() returning out-dated image in RAM
Stored Video signal in RAM araise resource problem
Below is the OpenCV Error
OpenCV Error: Assertion failed (dsize.area() > 0 || (inv_scale_x > 0 && inv_scale_y > 0)) in resize, file /home/pi/opencv/opencv-3.4.0/modules/imgproc/src/resize.cpp, line 4045
Traceback (most recent call last):
File "runpi.py", line 264, in <module>
run(3.5,model_list)
File "runpi.py", line 234, in run
mat = temp.match(model_list)
File "runpi.py", line 184, in match
self.__resize(model.get_m_inform())
File "runpi.py", line 147, in __resize
self.mask = cv2.resize(self.mask, None, fx=reratio, fy=reratio, interpolation = inter_method)
cv2.error: /home/pi/opencv/opencv-3.4.0/modules/imgproc/src/resize.cpp:4045: error: (-215) dsize.area() > 0 || (inv_scale_x > 0 && inv_scale_y > 0) in function resize
(+) Some part of code araising Error
This is __.resize() method. When I process the image that occured OpenCV Error manually, it works well even if OpenCV Error pointing out kind of image size matter. So I thought it is not matter of image itself or size got from md_inf(). Anyway Here is code.
def __resize(self, md_inf):
#md_inf = [219, 122, 132, 171, 262] <-sample
reratio = md_inf[0]/self.y
if(reratio>1):
inter_method = cv2.INTER_LINEAR
else:
inter_method = cv2.INTER_AREA
###below is line 147###
self.mask = cv2.resize(self.mask, None, fx=reratio, fy=reratio, interpolation = inter_method)
temp = np.zeros((md_inf[3], md_inf[4]), np.uint8)
m_cx, m_cy = md_inf[1:3]
_, contour, _ = cv2.findContours(self.mask, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
total_contour = contour[0]
for ctr in contour[1:]:
total_contour = np.concatenate((total_contour, ctr), axis =0)
mmt = cv2.moments(total_contour)
if(mmt['m00'] < 7500):
raise SmallObjectError
self.cy = int(mmt['m10']/mmt['m00']) #y is horrizon axis
self.cx = int(mmt['m01']/mmt['m00']) #x is vertical axis
x, y = self.mask.shape
adjust = m_cx - self.cx + x - temp.shape[0]
if(adjust > 0):
m_cx = m_cx - adjust
temp[(m_cx-self.cx):(m_cx-self.cx) +x, (m_cy-self.cy):(m_cy-self.cy) +y] = self.mask
self.mask = temp
I agree with Mark Serchell's comment. The way I am using is to set variable to time + x seconds and check. OpenCV have useful feature for skiping frames like cam.grab(). It will just read that frame from buffer but will not do anything with it. In that way you can avoid "suffering from buffering". Simple code would be:
import cv2
import time
cam = cv2.VideoCapture(url)
ret,frame = cam.read()
timeCheck = time.time()
future = 10*60 # delay
while ret:
if time.time() >= timeCheck:
ret,frame = cam.read()
# Do your staff here
timeCheck = time.time()+future
else:
# Read from buffer, but skip it
ret = cam.grab() # note that grab() function returnt only status code,not the frame