Python Threading for Camera - python

I am trying to put the camera footage into a different thread as the cv2.wait() does not work correctly anymore for access keys even when using an '& and hexadecimal'.
Does anyone know what I have done wrong with the daemon thread I have created for displaying camera footage in the main as when placed in the main while loop it fails while loop?
How do I use a thread to continuously display camera footage in my while loop in the main program?
quote My thread for the ViewCamera function isn't working right - can anyone help?
from djitellopy import Tello
# Access the telopy libray.
import cv2, math, time
from time import sleep, perf_counter
from threading import Thread
stop = True
def ViewCamera():
global stop
while stop == True:
try:
#camera window
img = frame_read.frame
cv2.imshow("drone", img)
print ('thread test')
except Exception as e:
print ("Cerror is : ,", e)
drone = Tello()
'''
create an instance of the Tellopy libray
drone.connect() #connect to drone using wifi
drone.streamon()
#make use of a data stream to drone to pass on keyboard commands
#frame_read = drone.get_frame_read() #read cammera data using frame per frame rate
'''
key = 0
# drone.takeoff()
if __name__ == "__main__":
print ('main program')
# Create a camera thread - runs in background.
t1 = Thread(target=ViewCamera, args=())
t1.daemon = True
print('starting thread')
t1.start()
while True:
key = ord(input('please enter letter'))
if key == ord('j'):
drone.land()
print('stopping thread')
stop = False
break
elif key == ord('w'): # Forward
drone.move_forward(30)
print('moving forwards')
elif key == ord('s'): # Move backwards
drone.move_back(30)
elif key == ord('a'): # Move left
drone.move_left(30)
elif key == ord('d'): # Move right
drone.move_right(30)
elif key == ord('e'): # Rotate right
drone.rotate_clockwise(30)
elif key == ord('q'): # Rotate left
drone.rotate_counter_clockwise(30)
elif key == ord('r'): # Move up
drone.move_up(30)
elif key == ord('f'): # Move down
drone.move_down(30)
print('stopping thread')
t1.join()
drone.land()
The threading daemon isn't seeming to work it should be running in background and continually allowing the camera images in a window to be viewed - any ideas why it is not?

Related

how to end a while loop by pressing a key

I'm trying to write a code so that a webcam will take a picture every hour for an undetermined amount of time (2 weeks for now). Here's what I have so far (which works) :
t0=time.perf_counter()
time_max=3600*24*14
time_step= 3600
while(True):
tc=time.perf_counter()
crit = tc-t0
if (crit>time_max) :
cap.release()
break
cap.open(num_cam,api)
cap.set(cv2.CAP_PROP_FOCUS,70)
ret=cap.grab() #takes a picture
tst,frm=cap.retrieve()
cv2.imwrite('test1h_'+str(np.round(crit,2))+'_f70.png',frm)
cap.release()
time.sleep(time_step)
pass
I would like for this loop to stop if I press 'q' for example, and for the webcam to take a picture if I press 'p', how could I implement that ? I read you can you can use cv2.waitKey but I don't know where to put that in the code. I also read that you can use the nodule "keyboard" but that it requires a root in linux and I work on windows.
You can just use this:
if cv.waitKey(20) % 0xFF == ord("d"):
break
So for example if you want to display a video while not pressing the "d" key, this should work:
while True:
isTrue, frame = capture.read()
cv.imshow("Video", frame)
if cv.waitKey(20) % 0xFF == ord("d"):
break
capture.realease()
cv.destroyAllWindows()
Edit: Had mixed up 'char' and 'key', fixed it now.
If you're okay with not using cv2, I would suggest this using pynput:
from pynput import keyboard
def on_press(key):
print(key)
listener = keyboard.Listener(on_press=on_press)
listener.start()
In your case, you could implement it like this:
import time
from pynput import keyboard
t0=time.perf_counter()
time_max=3600*24*14
time_step= 3600
def on_press(key):
if key.char=='p':
#Take picture
cap.open(num_cam,api)
cap.set(cv2.CAP_PROP_FOCUS,70)
ret=cap.grab()
tst,frm=cap.retrieve()
cv2.imwrite('test1h_'+str(np.round(crit,2))+'_f70.png',frm)
cap.release()
elif key.char=='q':
#Interrupt
exit()
listener = keyboard.Listener(on_press=on_press)
listener.start()
while(True):
tc=time.perf_counter()
crit = tc-t0
if (crit>time_max) :
cap.release()
break
cap.open(num_cam,api)
cap.set(cv2.CAP_PROP_FOCUS,70)
ret=cap.grab() #takes a picture
tst,frm=cap.retrieve()
cv2.imwrite('test1h_'+str(np.round(crit,2))+'_f70.png',frm)
cap.release()
time.sleep(time_step)
pass

Detect a key pressed within a while Python

I want to detect a key pressed in python without using "with", because I want it to show a text in a while
all this with the pynput library:
import time
from pynput import keyboard
i = 0
while True:
if event.key == keyboard.Key.esc:
break
else:
if a == "hello":
print("y")
else:
print("n")
if i % 2 = 0:
a = "hello"
else
a = "good bye"
i += 1
print(a)
time.sleep(2)
pynput's Events blocks by default. You can .get to limit how long it blocks for:
from pynput import keyboard
import time
i = 0
a = "start"
while True:
if a == "hello":
print("y")
else:
print("n")
if i % 2 == 0:
a = "hello"
else:
a = "good bye"
i += 1
print(a)
# Not needed anymore, we're going to block waiting for key events for 2 seconds
# time.sleep(2)
with keyboard.Events() as events:
# Block at most for two seconds
event = events.get(2.0)
if event is not None:
if event.key == keyboard.Key.esc:
break
This won't necessarily always block for two seconds if the user presses some other key. You can either add code to check for that condition and keep calling events.get till enough time has passed, or use keyboard.Listener to react to events in real time.

Python Key Logger with Duration and Multiple Keys

I am trying to write a key logger in python that determines the length of time a key is pressed - key pressed through release - while also detecting if another key is pressed. For example, someone presses w for 4 seconds. While holding W, they also press S and hold S for X amount of time. I think this may need to be multithreaded but I am not sure how to handle this in python.
This is code I found that tracks the length of a key press. It just needs to be threaded, I think.
import time
def callb(key): #what to do on key-release
ti1 = str(time.time() - t)[0:5] #converting float to str, slicing the float
print("The key",key," is pressed for",ti1,'seconds')
return False #stop detecting more key-releases
def callb1(key): #what to do on key-press
return False #stop detecting more key-presses
with keyboard.Listener(on_press = callb1) as listener1: #setting code for listening key-press
listener1.join()
t = time.time() #reading time in sec
with keyboard.Listener(on_release = callb) as listener: #setting code for listening key-release
listener.join()
Use hook method to get all events
import keyboard
HISTORY = {}
def key_recording(e):
if e.name not in HISTORY and e.event_type == keyboard.KEY_DOWN:
HISTORY[e.name] = e.time
elif e.name in HISTORY and e.event_type == keyboard.KEY_UP:
print(f"The key {e.name} is pressed for {round(e.time - HISTORY.pop(e.name), 3)} seconds")
remove = keyboard.hook(key_recording)
try:
input("Press any key to exit")
except KeyboardInterrupt:
pass
finally:
remove()

Ending a thread that contains an infinite loop

I'm trying to use python to turn on some RGB lights after motion is detected. My code is below but I can't get the thread to end and switch off the LEDS. All that happening is I get stuck after keyboard interrupt.
Essentially when I run the code it works to detect movement and switch the lights on but then when I try to end the program with a keyboard interupt exception either the program hangs and doesn't stop or it stops but the LEDs don't switch off and stay lit. I've looked at various pages about how to stop a thread running but none of it has helped. Below are the articles I've looked at. I think my issue is that the thread running the lighting pattern loop isn't stopping so when I try to turn each LED off its turned back on immediately but I'm not sure.
I can't get the thread to stop any way I've tried. Any help would be much appreciated.
How to stop a looping thread in Python?
https://www.oreilly.com/library/view/python-cookbook/0596001673/ch06s03.html
https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
Threading an Infinite Loop
Stopping a python thread running an Infinite Loop
Threading infinite loop in python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 1 10:10:25 2020
#author: thomas
"""
import RPi.GPIO as GPIO
import time
import subprocess
import argparse
from neopixel import *
import datetime as dt
from threading import Thread
from threading import enumerate
from threading import Event as EV
import sys
global stop
GPIO.setmode(GPIO.BCM)
# LED strip configuration:
LED_COUNT = 288 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0
LED_STRIP = ws.SK6812_STRIP_RGBW
#LED_STRIP = ws.SK6812W_STRIP
# Define functions which animate LEDs in various ways.
def wheel(pos):
"""Generate rainbow colors across 0-255 positions."""
if pos < 85:
return Color(pos * 3, 255 - pos * 3, 0)
elif pos < 170:
pos -= 85
return Color(255 - pos * 3, 0, pos * 3)
else:
pos -= 170
return Color(0, pos * 3, 255 - pos * 3)
def colorWipe(strip, color, wait_ms=20):
"""Wipe color across display a pixel at a time."""
for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
time.sleep(wait_ms/1000.0)
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
while not stop:
for j in range(256*iterations):
for i in range(strip.numPixels()):
strip.setPixelColor(i, wheel(((i * 256 // strip.numPixels()) + j) & 255))
strip.show()
time.sleep(wait_ms/1000.0)
class RainbowLights(Thread):
def __init__(self, name="RainbowLights"):
self._stopevent = EV()
self.sleeppreiod = 1.0
Thread.__init__(self, name=name)
def run(self):
while not self._stopevent.isSet():
rainbowCycle(strip)
self._stopevent.wait(self._sleepperiod)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
args = parser.parse_args()
# Create NeoPixel object with appropriate configuration.
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
# Intialize the library (must be called once before other functions).
strip.begin()
print ('Press Ctrl-C to quit.')
if not args.clear:
print('Use "-c" argument to clear LEDs on exit')
GPIO.setup(22, GPIO.IN) #PIR
rta = "none"
time1 = "none"
stop = False
RainbowLights = RainbowLights()
try:
time.sleep(2) # to stabilize sensor
while True:
trigger = GPIO.input(22)
if trigger == 1:
print("Motion Detected...")
if rta == "running":
print("Lights Already On")
else:
RainbowLights.start()
rta = "running"
time1 = dt.datetime.now()
time.sleep(5) #to avoid multiple detection
elif trigger == 0:
print("No Motion...")
print("Lights turned on at " + str(time1))
time.sleep(0.1) #loop delay, should be less than detection delay
except KeyboardInterrupt:
RainbowLights._stopevent.set()
stop = True
time.sleep(5)
if args.clear:
colorWipe(strip, Color(0,0,0), 10)
GPIO.cleanup()
Reduced to a minimal example so it can run without hardware. Comments added for fixes. The main problem was stop was only checked after 256*iterations*wait_ms/1000.0 or 25.6 seconds, so stopping appeared unresponsive. A few other bugs as well. Global stop is sufficient to end the thread so the Event wasn't needed.
import time
import argparse
from threading import Thread
import sys
global stop
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
while not stop:
for j in range(256*iterations):
if stop: break # add stop check here for responsiveness.
print(f'rainbowCycle')
time.sleep(wait_ms/1000.0)
print('stopping...')
class RainbowLights(Thread):
def __init__(self, name="RainbowLights"):
print('__init__')
Thread.__init__(self, name=name)
def run(self):
print('run')
rainbowCycle(strip)
print('stopped')
if __name__ == '__main__':
strip = None
print('Press Ctrl-C to quit.')
rta = "none"
stop = False
rainbow_lights = RainbowLights() # renamed variable so it doesn't replace the class.
try:
time.sleep(2) # to stabilize sensor
while True:
trigger = 1 # pretend some motion
if trigger == 1:
print("Motion Detected...")
if rta == "running":
print("Lights Already On")
else:
rainbow_lights.start()
rta = "running"
time.sleep(5) #to avoid multiple detection
elif trigger == 0:
print("No Motion...")
time.sleep(0.1) #loop delay, should be less than detection delay
except KeyboardInterrupt:
print('KeyboardInterrupt')
print('stop')
stop = True
Press Ctrl-C to quit.
__init__
Motion Detected...
run
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
rainbowCycle
KeyboardInterrupt
stop
stopping...
stopped

Python script does not exit after function run

I have a following program that simply reads what buttons are pressed using keyboard and in case user hits Escape button, the script should stop working. The problem is that it does not do it - it stops printing buttons but does not end its operation. I tried adding sys.exit() function but without success.
Any suggestions would be appreciated!
from __future__ import print_function
from inputs import get_key
from inputs import DeviceManager
def main():
devices = DeviceManager()
dictionaries = devices.codes
qt = False
while qt == False:
events = get_key()
for event in events:
if (event.code in dictionaries["Key"].values() and event.code != "KEY_ESC" and event.state == 1):
print(event.code, event.state)
elif (event.code in dictionaries["Key"].values() and event.code == "KEY_ESC" and event.state == 1):
qt = True
break
return
if __name__ == "__main__":
main()
As suggested in comments it was package-connected issue. In this case the proper solution to problem was using try statement:
from __future__ import print_function
from inputs import get_key
from inputs import DeviceManager
def main():
devices = DeviceManager()
dictionaries = devices.codes
qt = False
try:
while True:
events = get_key()
for event in events:
if (event.code in dictionaries["Key"].values() and event.state == 1):
print(event.code, event.state)
except KeyboardInterrupt:
return
if __name__ == "__main__":
main()
There are 2 loops in the code, while and for. You are breaking only the for loop. You should break the while loop too.

Categories