Get screnn shot in python3.7 by win32gui will cause memory leak - python-3.x

Win10, python3.7
My code like this:
import win32gui, win32ui, win32con, win32api
screen_w = 2880
screen_h = 1800
x0 = int(screen_w * 0.866)
y0 = int(screen_h * 0.14)
ww = 220
hh = 70
def window_capture(filename):
hwnd = 0
hwndDC = win32gui.GetWindowDC(hwnd)
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()
saveBitMap = win32ui.CreateBitmap()
saveBitMap.CreateCompatibleBitmap(mfcDC, ww, hh)
saveDC.SelectObject(saveBitMap)
saveDC.BitBlt((0, 0), (ww, hh), mfcDC, (x0, y0), win32con.SRCCOPY)
saveBitMap.SaveBitmapFile(saveDC, filename)
#------------------
win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)
#------------------
count = 0
while 1:
window_capture('temp.png')
count += 1
if int(count/1000) == float(count/1000):
print(count)
Firstly, I didn`t add DeleteObject and DeleteDC to release memory. The process will stop after about 10000 times window_capture.
But after I add them, I still can see the memory increase in task manager. Finally, after about 130000 times, the process stop again.
Does that mean I haven`t release all the memories? In my project, I need capture screen shot for a long time. How can I solve this problem?
Thank you!

Caveat: I don't know Python.
From Win32 perspective, you should not delete a GDI object while it is still selected into any DC (Device Context). You are doing precisely that here:
win32gui.DeleteObject(saveBitMap.GetHandle())
The typical Win32 scenario is to save a handle of the object previously selected into DC (any of the Select...() functions return that), and re-select it into the DC when you are done with your own object.
Alternatively, you can use SaveDC / RestoreDC pair if you need to restore multiple objects.

Related

Raspberry Pi Pico keeps crashing every since I started using both cores

I'm new to pico, only using arduinos before. I'm trying to make a simple rotary encoder program that displays a value from 0-12 on an 0.96 oled display, and lights up that many leds on a strip.
I wanted to try out using multiple cores, as interrupts made the leds not run smooth when I had them just cycling (everything would be paused while the encoder was being turned)
However, when I run this program, aside from the encoder being bouncy, the pico would crash maybe 30 seconds into running the program, making a mess on the display and stopping the code. I feel like there's some rule of using multiple cores that I completely ignored.
Here's the code:
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import _thread
import utime
import neopixel
#general variables section
numOn = 0
#Encoder section
sw = Pin(12,Pin.IN,Pin.PULL_UP)
dt = Pin(11,Pin.IN)
clk = Pin(10,Pin.IN)
encodeCount = 0
lastClk = clk.value()
lastButton = False
#Encoder thread
def encoder(): #don't mind the indentation here,
#stackoverflow kinda messed up the code block a bit.
while True:
#import stuff that I shouldn't need to according to tutorials but it doesn't work without
global encodeCount
global lastClk
global clk
import utime
if clk.value() != lastClk:
if dt.value() != clk.value():
encodeCount += 1
else:
encodeCount -= 1
if encodeCount > 12:
encodeCount = 0
elif(encodeCount < 0):
encodeCount = 12
lastClk = clk.value()
print(encodeCount)
utime.sleep(0.01)
_thread.start_new_thread(encoder,())
#LED section
numLed = 12
ledPin = 26
led = neopixel.NeoPixel(machine.Pin(ledPin),numLed)
#Screen Section
WIDTH = 128
HEIGHT = 64
i2c = I2C(0,scl=Pin(17),sda=Pin(16),freq=200000)
oled = SSD1306_I2C(WIDTH,HEIGHT,i2c)
#loop
while True:
for i in range(numLed):
led[i] = (0,0,0)
for i in range(encodeCount):
led[i] = (100,0,0)
led.write()
#Display section
oled.fill(0)
oled.text(f'numLed: {numOn}',0,0)
oled.text(f'counter: {encodeCount}',0,40)
oled.show()
I'm probably doing something stupid here, I just don't know what.
Also, any suggestions on simply debouncing the encoder would be very helpful.
Any help would be appreciated! Thanks!
Update: The code above bricked the pico, so clearly I'm doing something very very wrong. _thread start line stopped it from crashing again, so the problem is there.
Same issue with very similar code on a Raspberry Pico W. I specify the 'W' because my code works without crashing on an earlier Pico.
I'm wondering if the low level networking functions might be using the 2nd core and causing a conflict.
I'm adding thread locking to see if passing a baton helps, the link below has an example, eg:
# create a lock
lck= _thread.allocate_lock()
# Function that will block the thread with a while loop
# which will simply display a message every second
def second_thread():
while True:
# We acquire the traffic light lock
lck.acquire()
print("Hello, I'm here in the second thread writting every second")
utime.sleep(1)
# We release the traffic light lock
lck.release()

Pyueye image saving with wrong resolution

personally pretty new to programming and I am trying to save a high mp Image from an IDS camera using the pyueye module with python.
my Code works to save the Image, but the Problem is it saves the Image as a 1280x720 Image inside a 4192x3104
I have no idea why its saving the small Image inside the larger file and am asking if anyone knows what i am doing wrong and how can I fix it so the Image is the whole 4192x3104
from pyueye import ueye
import ctypes
hcam = ueye.HIDS(0)
pccmem = ueye.c_mem_p()
memID = ueye.c_int()
hWnd = ctypes.c_voidp()
ueye.is_InitCamera(hcam, hWnd)
ueye.is_SetDisplayMode(hcam, 0)
sensorinfo = ueye.SENSORINFO()
ueye.is_GetSensorInfo(hcam, sensorinfo)
ueye.is_AllocImageMem(hcam, sensorinfo.nMaxWidth, sensorinfo.nMaxHeight,24, pccmem, memID)
ueye.is_SetImageMem(hcam, pccmem, memID)
ueye.is_SetDisplayPos(hcam, 100, 100)
nret = ueye.is_FreezeVideo(hcam, ueye.IS_WAIT)
print(nret)
FileParams = ueye.IMAGE_FILE_PARAMS()
FileParams.pwchFileName = "python-test-image.bmp"
FileParams.nFileType = ueye.IS_IMG_BMP
FileParams.ppcImageMem = None
FileParams.pnImageID = None
nret = ueye.is_ImageFile(hcam, ueye.IS_IMAGE_FILE_CMD_SAVE, FileParams, ueye.sizeof(FileParams))
print(nret)
ueye.is_FreeImageMem(hcam, pccmem, memID)
ueye.is_ExitCamera(hcam)
The size of the image depends on the sensor size of the camera.By printing sensorinfo.nMaxWidth and sensorinfo.nMaxHeight you will get the maximum size of the image which the camera captures. I think that it depends on the model of the camera. For me it is 2056x1542.
Could you please elaborate on the last sentence of the question.

tensorflow workers start before the main thread could initialize variables

I am trying to use tf.train.batch to run enqueue images in multiple threads. When the number of threads is 1, the code works fine. But when I set a higher number of threads I receive an error:
Failed precondition: Attempting to use uninitialized value Variable
[[Node: Variable/read = Identity[T=DT_INT32, _class=["loc:#Variable"], _device="/job:localhost/replica:0/task:0/cpu:0"](Variable)]]
The main thread has to run for some time under one second to index the database of folders and put it into tensor.
I tried to use sess.run([some_image]) before running tf.train.bath loop. In that case workers fail in the background first with the same error, and after that I receive my images.
I tried to use time.sleep(), but it does not seem to be possible to delay the workers.
I tried adding a dependency to the batch:
g = tf.get_default_graph()
with g.control_dependencies([init_one,init_two]):
example_batch = tf.train.batch([my_image])
where init_one, and init_two are tf.initialize_all(variables) and tf.initialize_local_variables()
the most relevant issue I could find is at: https://github.com/openai/universe-starter-agent/issues/44
Is there a way I could ask the synchronize worker threads with the main thread so that they don't race first and die out ?
A similar and easy to reproduce error with variable initialization happens when set up the epoch counter to anything that is not None Are there any potential solutions ? I've added the code needed to reproduce the error below:
def index_the_database(database_path):
"""indexes av4 database and returns two tensors of filesystem path: ligand files, and protein files"""
ligand_file_list = []
receptor_file_list = []
for ligand_file in glob(os.path.join(database_path, "*_ligand.av4")):
receptor_file = "/".join(ligand_file.split("/")[:-1]) + "/" + ligand_file.split("/")[-1][:4] + '.av4'
if os.path.exists(receptor_file):
ligand_file_list.append(ligand_file)
receptor_file_list.append(receptor_file)
index_list = range(len(ligand_file_list))
return index_list,ligand_file_list, receptor_file_list
index_list,ligand_file_list,receptor_file_list = index_the_database(database_path)
ligand_files = tf.convert_to_tensor(ligand_file_list,dtype=tf.string)
receptor_files = tf.convert_to_tensor(receptor_file_list,dtype=tf.string)
filename_queue = tf.train.slice_input_producer([ligand_files,receptor_files],num_epochs=10,shuffle=True)
serialized_ligand = tf.read_file(filename_queue[0])
serialized_receptor = tf.read_file(filename_queue[1])
image_one = tf.reduce_sum(tf.exp(tf.decode_raw(serialized_receptor,tf.float32)))
image_batch = tf.train.batch([image_one],100,num_threads=100)
init_two = tf.initialize_all_variables()
init_one = tf.initialize_local_variables()
sess = tf.Session()
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess,coord=coord)
sess.run([init_one])
sess.run([init_two])
while True:
print "next"
sess.run([image_batch])

(WinApi) ChangeDisplaySettingsEx does not work

I'm trying to write a python script to switch the primary monitor.
I have 3 Monitors (one is plugged into my i5's graphics chip, and 2 are plugged into a ATI HD7870)
I wrote the following script:
import win32api as w
import win32con as c
i = 0
workingDevices = []
def setPrimary(id):
global workingDevices
return w.ChangeDisplaySettingsEx(
workingDevices[id].DeviceName,
w.EnumDisplaySettings(
workingDevices[id].DeviceName,
c.ENUM_CURRENT_SETTINGS
),
c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_RESET) \
== c.DISP_CHANGE_SUCCESSFUL
while True:
try:
Device = w.EnumDisplayDevices(None, i, 1)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
break
print("Num Devices: ", len(workingDevices))
for dev in workingDevices:
print("Name: ", dev.DeviceName)
Invoking it leads to:
In [192]: %run test.py
Num Devices: 3
Name: \\.\DISPLAY1
Name: \\.\DISPLAY2
Name: \\.\DISPLAY7
In [193]: setPrimary(0)
Out[193]: True
In [194]: setPrimary(1)
Out[194]: True
In [195]: setPrimary(2)
Out[195]: True
So far it looks great, but the problem is: nothing changes. My monitors flicker shortly because of the CDS_RESET but the primary screen does not change, although ChangeDisplaySettingsEx returns DISP_CHANGE_SUCCESSFUL
Does anyone have an Idea why?
(I use Python 3.5.1 and PyWin32 build 220)
PS I use 1 as the third arg for EnumDisplayDevices because the msdn states it should be set to one, although the PyWin help says it should be set to 0.
But the behaviour of the script does not change independent of this value beeing one or zero
Ok, I found the solution.
Apperantly the primary monitor must always be at position (0, 0).
So when I tried to set another monitor to primary its position was set to (0, 0) which caused it to intersect with the old primary one.
It seems the way to go is to update the positions of all Monitors, and write those changes to the registry, and then once this is done apply the changes by calling ChangeDisplaySettingsEx() with default parameters.
This is my new (now working) code:
import win32api as w
import win32con as c
def load_device_list():
"""loads all Monitor which are plugged into the pc
The list is needed to use setPrimary
"""
workingDevices = []
i = 0
while True:
try:
Device = w.EnumDisplayDevices(None, i, 0)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
return workingDevices
def setPrimary(id, workingDevices, MonitorPositions):
"""
param id: index in the workingDevices list.
Designates which display should be the new primary one
param workingDevices: List of Monitors returned by load_device_list()
param MonitorPositions: dictionary of form {id: (x_position, y_position)}
specifies the monitor positions
"""
FlagForPrimary = c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_NORESET
FlagForSec = c.CDS_UPDATEREGISTRY | c.CDS_NORESET
offset_X = - MonitorPositions[id][0]
offset_Y = - MonitorPositions[id][1]
numDevs = len(workingDevices)
#get devmodes, correct positions, and update registry
for i in range(numDevs):
devmode = w.EnumDisplaySettings(workingDevices[i].DeviceName, c.ENUM_CURRENT_SETTINGS)
devmode.Position_x = MonitorPositions[i][0] + offset_X
devmode.Position_y = MonitorPositions[i][1] + offset_Y
if(w.ChangeDisplaySettingsEx(workingDevices[i].DeviceName, devmode,
FlagForSec if i != id else FlagForPrimary) \
!= c.DISP_CHANGE_SUCCESSFUL): return False
#apply Registry updates once all settings are complete
return w.ChangeDisplaySettingsEx() == c.DISP_CHANGE_SUCCESSFUL;
if(__name__ == "__main__"):
devices = load_device_list()
for dev in devices:
print("Name: ", dev.DeviceName)
MonitorPositions = {
0: (0, -1080),
1: (0, 0),
2: (1920, 0)
}
setPrimary(0, devices, MonitorPositions)

How to manually set the toggle state of wxpython platebutton

I am building an application using platebutton iin wxpython. The problem is that I am not able to manually SetState of the toogle buton. I used SetState(0) but it does not change the state of toggle button. Any help would be great. Thanks. Sample code:
self.infinity= platebutton.PlateButton(self._ribbon,wx.ID_NEW, bmp = wx.Bitmap('infinity.bmp'), pos = (0,0), size = (38,18), style= platebutton.PB_STYLE_NOBG |platebutton.PB_STYLE_TOGGLE)
def OnInfinityToggled(self,event):
if event.GetEventObject().IsPressed():
self.popupmenu = wx.Menu()
Session = self.popupmenu.Append(-1, "Session")
self.Bind(wx.EVT_MENU, self.SessionMenu, Session)
self.PopupMenu(self.popupmenu,(2,23))
else:
pass
def SessionMenu(self, event):
print 5
self.infinity.SetState(0)
self.infinity.Raise()
PLATE_NORMAL = 0
PLATE_PRESSED = 1
PLATE_HIGHLIGHT = 2
SetState(0) means set to normal.
Here's how I managed to toggle state:
btn._ToggleState()
btn._pressed = True
I had the same problem. Playing around I managed to resolve my problem with
button._SetState(ix)
button.Refresh()
where ix = your choice of state.

Resources