OpenCV keyboard variable input changes with different inputs - python

I know I can use an elif statement for each individual letter I want to try but I feel like there would be a cleaner way of not needing 26 different elif statements. I also need to be able to save the file name as the key that was pressed, so for each key they are differentiated. Any ideas?
`
k=cv2.waitKey(1)
if k % 256 == 27:
print("Clsoed with escape key")
break
elif k == ord("a"):
#Saving the image to a folder dependent on which letter we're on
cv2.imwrite('C:\\Users\\Desktop\\%s.jpg'%(k), frame)
`
I could do elif for ord("b") and so on, but I feel this doesn't make the cleanest of code.

Related

trying to simplify some boolean statements in python

I'm "newish" to python programming. I'm trying my best to make my code look nice and function well. I'm using Pycharm as my IDE. I'm doing something for myself. I play tabletop RPG's and I'm attempting to create a character creator for a game I play. I have everything working well, but Pycharm is telling me that "Expression can be simplified" and "PEP 8: E712 comparison to True should be 'if cond is not True:' or 'if not cond:'"
Here is the code in question:
fname = False
while fname != True:
new_character.firstName = input('What would you like your first name to be?\n').capitalize()
if 1 >= len(new_character.firstName) or len(new_character.firstName) > 20:
print('Name does not meet length requirements. Please try again.')
if new_character.firstName.isalpha() != True:
print('Please do not use numbers or special characters in your name. Please try again.')
if (1 < len(new_character.firstName) < 20) and (new_character.firstName.isalpha() == True):
fname = True
Pycharm is telling me that my "while fname != True:" is the part that can be simplified as well as the "if new_character.firstName.isalpha() != True:".
I've tried googling a solution for what I'm doing, but most of them are for something kinda like what I'm asking, but never with the != True portion. I've even reached out to one of my friends that's a python programmer, but I haven't heard back yet.
Again, I want to state that as it is now, the code works correctly the way it is written, I'm just wanting to understand if there is a way to make the code look cleaner/neater or do the same function and be simplified somehow.
Any pointers on how to potentially simplify those lines of code and maintain the functionality would be greatly appreciated.
Here's one way you could rewrite this code to make it easier to read, and more efficient:
# Loop until the user provides a good input
while True:
# Set a temp variable, don't constantly reassign to the new_character.firstName attribute
name = input('What would you like your first name to be?\n').capitalize()
# If the name isn't between 2 and 20 characters, start the loop over at the beginning
if not (1 < len(name) <= 20):
print('Name does not meet length requirements. Please try again.')
continue
# If the name contains anything other than letters, start the loop over at the beginning
if not name.isalpha():
print('Please do not use numbers or special characters in your name. Please try again.')
continue
# You can only reach this break if the name "passed" the two checks above
break
# Finally, assign the character name
new_character.firstName = name
One thing you could do to simplify further is to check both conditions at the same time, and print a more helpful error message that re-states the requirements explicitly:
NAME_ERROR_MESSAGE = """
Invalid name '{name}'. Your character's name
must be between 2 and 20 characters long, and
contain only letters. Please try again.
"""
while True:
name = input('What would you like your first name to be?\n').capitalize()
if (1 < len(name) <= 20) and name.isalpha():
new_character.firstName = name
break
print(NAME_ERROR_MESSAGE.format(name=name)

python using ord() with getch() to get unicode

i am learning python at the moment and i tried to get keyboard input, without the need to press the enter key with getch() and ord() in order to work with the (at least for me) gibberish that returns from getch().
in my understanding getch() returns a byte stream, and ord does translate that byte data into unicode. and if iam not wrong there are keys like the arrow keys (this is my intention, to build a cmd "ui" to navigate) that are seperated into different unicode values.
so far, after trying myself and searching the web i come up with a soultion, provided by a person on the internet(information only for not claimig someone elses code as mine)
import msvcrt
while True:
key = ord(msvcrt.getch())
if key == 27: #ESC
break
elif key == 13: #Enter
print("select")
elif key == 224: #thing i do not understand
key = ord(msvcrt.getch()) #thing i do not understand
if key == 80: #Down arrow
print("moveDown")
elif key == 72: #Up arrow
print("moveUp")
elif key == 77: #Right arrow
print("moveRight")
elif key == 75: #Left arrow
print("moveLeft")
this works fine, but the thing that i do not understand is, why it is necessary to make the second variable assignment. in my understanding getch() should return the value instantly, so i do not understand where the second key = ord... statement gets the data to assign it to the key variable.
I would appreciate an explanation.
From the documentation for msvcrt.getch:
msvcrt.getch()
Read a keypress and return the resulting character as a byte string.
Nothing is echoed to the console. This call will block if a keypress
is not already available, but will not wait for Enter to be pressed.
If the pressed key was a special function key, this will return '\000'
or '\xe0'; the next call will return the keycode. The Control-C keypress
cannot be read with this function.
So, if a special function key (e.g. an arrow key) was pressed, we have to test for 0xE0 (224) and then read the next value.

How can I get upper case at the cv2 wait key?

I want to get the upper case key input by the wait key which in cv2.
I couldn't find the solution.
I tried these methods but it wasn't work.
pressed_key = cv2.waitKey(1) & 0xFF
pressed_key = cv2.waitKey(1)
if pressed_key == ord('A'):
This code works for me:
while True:
x = cv2.waitKey(1)
if x == ord('A'):
break
As #Demi-Lune suggests, the wait time is probably to small. It works in my code because it is a small loop. I guess yours is not. So you should increase it, or set it to 0 - depending on your application.
If some things don't show up with waitKey(0), you might need a code refactor. You could open a new question about that.

Index Out Of Range When Artificially Limited

when I run this program, sometimes I receive an error.This error however is not possible as I am using an 8x8 grid and I limit the inputs so that they can only be numbers from 0-7, to obey the fact that list indexes start at 0.
The user must input coordinates (1-8),(A-H) and the program will check to see if those coordinates are correct, by systematically going through the CompShips list and repeatedly comparing those coordinates to ones given by the user. If the cords match, then a message will appear and a "Z" will change to an "X" on those coordinates, indicating a HIT. If the guess does not match, a "Z" will change to an "M" on those coordinates indicating a MISS.
CompShips=[[1,0],[1,1],[2,2],[2,3],[2,4],[3,0],[3,1],[3,2],[5,4],[5,5],[5,6],[5,7],[1,7],[2,7],[3,7],[4,7],[5,7]]
FRow1=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow2=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow3=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow4=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow5=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow6=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow7=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow8=["Z","Z","Z","Z","Z","Z","Z","Z",]
def PrintFireBoard():
print(Index)
print(FRow1)
print(FRow2)
print(FRow3)
print(FRow4)
print(FRow5)
print(FRow6)
print(FRow7)
print(FRow8)
FireBoard=[FRow1,FRow2,FRow3,FRow4,FRow5,FRow6,FRow7,FRow8]
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
#As Lists start at 0
FireRow=int(FireRow)-1
if FireIndex==("A"):
FireIndex=0
elif FireIndex==("B"):
FireIndex=1
elif FireIndex==("C"):
FireIndex=2
elif FireIndex==("D"):
FireIndex=3
elif FireIndex==("E"):
FireIndex=4
elif FireIndex==("F"):
FireIndex=5
elif FireIndex==("G"):
FireIndex=6
elif FireIndex==("H"):
FireIndex=7
Guess=[FireRow,FireIndex]
#Check To See If Correct
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow)
print(FireIndex)
FireBoard[[FireRow][FireIndex]]=("H")
PrintFireBoard()
else:
print("MISS")
print(FireRow)
print(FireIndex)
FireBoard[[FireRow][FireIndex]]=("M")
PrintFireBoard()
I receive the error:
IndexError: string index out of range
Looks like these two lines
FireBoard[[FireRow][FireIndex]]=("H")
FireBoard[[FireRow][FireIndex]]=("M")
should be
FireBoard[FireRow][FireIndex]="H"
FireBoard[FireRow][FireIndex]="M"
Explanation: In your old code, FireBoard[[FireRow][FireIndex]]=("H")
[FireRow][FireIndex] means, given a list [FireRow] (which contains just one element), get the FireIndex-th element. This is not what you're trying to do.
For example [3][0] returns 3, and [3][1] gives IndexError.
Take a look at How to define a two-dimensional array in Python
Also note that ("H") is the same as the string "H". There is no need to add parentheses.
Here is a much cleaner code!
CompShips=[[1,0],[1,1],[2,2],[2,3],
[2,4],[3,0],[3,1],[3,2],
[5,4],[5,5],[5,6],[5,7],
[1,7],[2,7],[3,7],[4,7],
[5,7]]
FRow=[["Z"]*8]*8 #1 More Pythonic
def PrintFireBoard():
#print(Index)
for i in range(0,8):
print(FRow[i])
FireBoard=FRow[:] #NOTE THIS ONE!!!
mydict = {}
for i,key in enumerate(["A","B","C","D","E","F","G","H"]): #2 More Pythonic
mydict[key] = i
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
FireRow=int(FireRow)-1
FireIndex = mydict[FireIndex]
Guess=[FireRow,FireIndex]
print(Guess)
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow,FireIndex)
FireBoard[FireRow][FireIndex]="H" #3 your problem here
PrintFireBoard()
else:
print("MISS")
print(FireRow,FireIndex)
FireBoard[FireRow][FireIndex]="M"
PrintFireBoard()
1) As explained in the comments that's just a more nicer way to create a list of lists!. Remember DRY principle! Do Not Repeat yourself!
2) Instead of having all that if else to convert the 'A' to 0. You can use a dictionary lookup instead!
3) Your problem seems to be here! correct this to FireBoard[FireRow][FireIndex]="H"
PS: NOTE THIS ONE!!!: I'm not just making FireBoard as an alias to FRow! I'm copying it into a FireBoard as a new list! There's a subtle difference read about it here. I'm doing this incase you don't want your original FRow list to be modified!
The indentation in your question was off. I think that all the code from
Guess=[FireRow,FireIndex]
until the end should be preceded by 4 spaces.
I've removed print(Index) since it was not defined.
To access FireBoard use:
FireBoard[FireRow][FireIndex]
Instead of
FireBoard[[FireRow][FireIndex]]
This should be working
CompShips=[[1,0],[1,1],[2,2],[2,3],[2,4],[3,0],[3,1],[3,2],[5,4],
[5,5],[5,6],[5,7],[1,7],[2,7],[3,7],[4,7],[5,7]]
FRow1=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow2=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow3=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow4=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow5=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow6=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow7=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow8=["Z","Z","Z","Z","Z","Z","Z","Z",]
def PrintFireBoard():
print(FRow1)
print(FRow2)
print(FRow3)
print(FRow4)
print(FRow5)
print(FRow6)
print(FRow7)
print(FRow8)
FireBoard=[FRow1,FRow2,FRow3,FRow4,FRow5,FRow6,FRow7,FRow8]
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
#As Lists start at 0
FireRow=int(FireRow)-1
if FireIndex==("A"):
FireIndex=0
elif FireIndex==("B"):
FireIndex=1
elif FireIndex==("C"):
FireIndex=2
elif FireIndex==("D"):
FireIndex=3
elif FireIndex==("E"):
FireIndex=4
elif FireIndex==("F"):
FireIndex=5
elif FireIndex==("G"):
FireIndex=6
elif FireIndex==("H"):
FireIndex=7
Guess=[FireRow,FireIndex]
#Check To See If Correct
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow)
print(FireIndex)
FireBoard[FireRow][FireIndex]=("H")
PrintFireBoard()
else:
print("MISS")
print(FireRow)
print(FireIndex)
FireBoard[FireRow][FireIndex]=("M")
PrintFireBoard()

Using other keys for the waitKey() function of opencv

I'm working on a program (python ,opencv) in which I use the spacebar to go to the next frame, and Esc to exit the program. These are the only two keys i've got working. I tried to find out about more keys , tried various codes for them but didnt work. especially arrow keys.
I found this about waitkey, but it doesn't work.
So my question is, How do I catch other keys besides esc and spacebar to trigger certain functions in my python-opencv program?
You can use ord() function in Python for that.
For example, if you want to trigger 'a' key press, do as follows :
if cv2.waitKey(33) == ord('a'):
print "pressed a"
See a sample code here: Drawing Histogram
UPDATE :
To find the key value for any key is to print the key value using a simple script as follows :
import cv2
img = cv2.imread('sof.jpg') # load a dummy image
while(1):
cv2.imshow('img',img)
k = cv2.waitKey(33)
if k==27: # Esc key to stop
break
elif k==-1: # normally -1 returned,so don't print it
continue
else:
print k # else print its value
With this code, I got following values :
Upkey : 2490368
DownKey : 2621440
LeftKey : 2424832
RightKey: 2555904
Space : 32
Delete : 3014656
...... # Continue yourself :)
The keycodes returned by waitKey seem platform dependent.
However, it may be very educative, to see what the keys return
(and by the way, on my platform, Esc does not return 27...)
The integers thay Abid's answer lists are mosty useless to the human mind
(unless you're a prodigy savant...). However, if you examine them in hex,
or take a look at the Least Significant Byte, you may notice patterns...
My script for examining the return values from waitKey is below:
#!/usr/bin/env python
import cv2
import sys
cv2.imshow(sys.argv[1], cv2.imread(sys.argv[1]))
res = cv2.waitKey(0)
print('You pressed %d (0x%x), LSB: %d (%s)' % (res, res, res % 256,
repr(chr(res%256)) if res%256 < 128 else '?'))
You can use it as a minimal, command-line image viewer.
Some results, which I got:
q letter:
You pressed 1048689 (0x100071), LSB: 113 ('q')
Escape key (traditionally, ASCII 27):
You pressed 1048603 (0x10001b), LSB: 27 ('\x1b')
Space:
You pressed 1048608 (0x100020), LSB: 32 (' ')
This list could go on, however you see the way to go, when you get 'strange' results.
BTW, if you want to put it in a loop, you can just waitKey(0) (wait forever), instead of ignoring the -1 return value.
EDIT: There's more to these high bits than meets the eye - please see Andrew C's answer (hint: it has to do with keyboard modifiers like all the "Locks" e.g. NumLock).
My recent experience shows however, that there is a platform dependence - e.g. OpenCV 4.1.0 from Anaconda on Python 3.6 on Windows doesn't produce these bits, and for some (important) keys is returns 0 from waitKey() (arrows, Home, End, PageDn, PageUp, even Del and Ins). At least Backspace returns 8 (but... why not Del?).
So, for a cross platform UI you're probably restricted to W, A, S, D, letters, digits, Esc, Space and Backspace ;)
The answers which have already been posted suggest that some of the unusual values obtained by waitKey are due to platform differences. Below, I propose that (at least on some platforms) the apparently odd behaviour of waitKey is due to keyboard modifiers. This post looks similar to Tomasz's answer because I initially wrote this as an edit, which was rejected.
The keycodes returned by waitKey change depending on which modifiers are enabled. NumLock, CapsLock, and the Shift, Ctrl, and Alt keys all modify the keycode returned by waitKey by enabling certain bits above the two Least Significant Bytes. The smallest of these flags is Shift at 0x10000.
A modified version of the script Tomasz posted is given below:
#!/usr/bin/env python
import cv2
import sys
cv2.imshow(sys.argv[1], cv2.imread(sys.argv[1]))
res = cv2.waitKey(0)
print 'You pressed %d (0x%x), 2LSB: %d (%s)' % (res, res, res % 2**16,
repr(chr(res%256)) if res%256 < 128 else '?')
Which give the following results:
q letter with NumLock:
You pressed 1048689 (0x100071), 2LSB: 113 ('q')
Escape key with CapsLock but not NumLock:
You pressed 131099 (0x2001b), 2LSB: 27 ('\x1b')
Space with Shift and NumLock:
You pressed 1114144 (0x110020), 2LSB: 32 (' ')
Right Arrow Key with Control, NumLock off:
You pressed 327507 (0x4ff53), 2LSB: 65363 ('S')
I hope that helps to explain the unusual behaviour of waitKey and how to get the actual key pressed regardless of the state of NumLock and CapLock. From here it's relatively simple to do something like:
ctrlPressed = 0 != res & (1 << 18)
...as the "control key" flag is (counting the least significant bit as bit 0) bit 18. Shift is at bit 16, the state of CapsLock at bit 17, Alt is at bit 19, and NumLock is at bit 20. As Tomasz was kind enough to point out, just pressing Shift on its own also returns a value, with distinct values for LShift and RShift (still with all these modifiers just described). I encourage you to double-check all of these modifiers and values on your own platform before relying on them. :)
As to me, the below code does't work, when it runs,the image will step to the next quickly without your press:
import cv2
img = cv2.imread('sof.jpg') # load a dummy image
while(1):
cv2.imshow('img',img)
k = cv2.waitKey(33)
if k==27: # Esc key to stop
break
elif k==-1: # normally -1 returned,so don't print it
continue
else:
print k # else print its value
But this works:
def test_wait_key():
lst_img_path = [
'/home/xy/yy_face_head/face_det_test/111.png',
'/home/xy/yy_face_head/face_det_test/222.png'
#.....more path ...
]
for f_path in lst_img_path:
img = cv2.imread(f_path)
cv2.imshow('tmp', img)
c = cv2.waitKey(0) % 256
if c == ord('a'):
print "pressed a"
else:
print 'you press %s' % chr(c)
Output as below:
Interesting nobody has mentioned cv2.waitKeyEx() as described in this answer of another Stack Overflow thread. OpenCV's documentation on cv2.waitKeyEx() reads as follows:
Similar to waitKey, but returns full key code.
Note
Key code is implementation specific and depends on used backend:
QT/GTK/Win32/etc
So, some attention may be required for cross-platform implementations. However, for me this was by far the easiest and most straight forward solution to get arrow keys etc. working on Windows.
For C++:
In case of using keyboard characters/numbers, an easier solution would be:
int key = cvWaitKey();
switch(key)
{
case ((int)('a')):
// do something if button 'a' is pressed
break;
case ((int)('h')):
// do something if button 'h' is pressed
break;
}
With Ubuntu and C++ I had problems with the Character/Integer cast. I needed to use cv::waitKey()%256 to obtain the correct ASCII value.
The answer that works on Ubuntu18, python3, opencv 3.2.0 is similar to the one above. But with the change in line cv2.waitKey(0). that means the program waits until a button is pressed.
With this code I found the key value for the arrow buttons: arrow up (82), down (84), arrow left(81) and Enter(10) and etc..
import cv2
img = cv2.imread('sof.jpg') # load a dummy image
while(1):
cv2.imshow('img',img)
k = cv2.waitKey(0)
if k==27: # Esc key to stop
break
elif k==-1: # normally -1 returned,so don't print it
continue
else:
print k # else print its value
If you want to pause the program to take screenshots of the progress
(shown in let's say cv2.imshow)
cv2.waitKey(0) would continue after pressing "Scr" button (or its combination), but you can try this
cv2.waitKey(0)
input('')
cv2.waitkey(0) to give the program enough time to process everything you want to see in the imshow and input('')
to make it wait for you to press Enter in the console window
this works on python 3
I too found this perplexing.
I'm running Ubuntu 18 and found the following:
If the cv.imshow window has focus, you'll get one set of values in the terminal - like the ASCII values discussed above.
If the Terminal has focus, you'll see different values. IE- you'll see "a" when you press the a key (instead of ASCII value 97) and "^]" instead of "27" when you press Escape.
I didn't see the 6 digit numbers mentioned above in either case and I used similar code. It seems the value for waitKey is the polling period in mS. The dots illustrate this.
Run this snippet and press keys while focus is on the test image, then click on the terminal window and press the same keys.
import cv2
img = cv2.imread('test.jpg')
cv2.imshow('Your test image', img)
while(1):
k = cv2.waitKey(300)
if k == 27:
break
elif k==-1:
print "."
continue
else:
print k
This prints the key combination directly to the image:
The first window shows 'z' pressed, the second shows 'ctrl' + 'z' pressed. When a key combination is used, a question mark appear.
Don't mess up with the question mark code, which is 63.
import numpy as np
import cv2
im = np.zeros((100, 300), np.uint8)
cv2.imshow('Keypressed', im)
while True:
key = cv2.waitKey(0)
im_c = im.copy()
cv2.putText(
im_c,
f'{chr(key)} -> {key}',
(10, 60),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(255,255,255),
2)
cv2.imshow('Keypressed', im_c)
if key == 27: break # 'ESC'
flag = True
while flag:
cv2.imshow("result", image_to_show)
key = cv2.waitKey(0)
if key == ord('b'): # pressed a key
<Do something>
elif key == ord('b'): # pressed b key
<Do something>
elif key == 27: # pressed Esc key
flag = False

Categories