Using other keys for the waitKey() function of opencv
Asked Answered
C

12

86

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?

Circuitry answered 24/1, 2013 at 4:42 Comment(0)
M
139

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 :)
Meyer answered 24/1, 2013 at 4:44 Comment(8)
Thanks @Abid ,This works with most of the keys, How do i use the Arrow Keys?Circuitry
I'm not getting any number for the arrow keys on OSXExsert
@mirosval: I am sorry, I don't have access to any OSX :(Meyer
On OSX, Upkey = 63232, Downkey = 63233, Leftkey = 63234, Rightkey = 63235Catamaran
i feel like i dont receive any codes for special keys - it might be because i am running it with Pyhton 3.8 (IDLE IDE) on Windows.Infielder
it often makes more sense when using the 'hex()' function. 2490368=0x260000 2621440=0x280000 2424832=0x250000 2555904=0x270000 32=0x20 3014656=0x2e0000Infielder
for the OSX values: 63232=0xf700 63233=0xf701 63234=0xf702 63235=0xf703Infielder
please be aware that higher bits (you should be able to look up the definition yourselves) are flag values for modifier keys like alt/sys/meta/num-loc and can apper idependently from other key presses. some platforms dont report any such keys.Infielder
I
26

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 ;)

Incompliant answered 13/12, 2013 at 22:23 Comment(3)
The platform dependence seems like a signed/unsigned integer problem. It should be easily resolved using bitwise operations, e.g. res = cv2.waitkey() & 0xEFFFFF.Ferrel
not checked it in detail again, but from my history, i think some of the higher bits are officially declared as flags. for the right interpretation and mask value, please search the web. (its definitely not at random!)Infielder
@Ferrel - No, it's not the sign bit. The sign bit is 0x8 and not 0x1. And these bits are flags for keyboard modifiers. And clearing the sign bit would be & 0x7fff....Incompliant
G
17

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. :)

Garton answered 5/11, 2015 at 21:25 Comment(2)
Wow, so it was about the modifiers... Nice, I almost never turn off NumLock. Side note: it's sometimes more convenient to count bits from 0 - i.e. Shift is at bit 16 (and the mask is (1 << 16). Also - just pressing Shift also returns a value - LShift is 0xffe1 and RShift 0xffe2. Modifiers apply there as well.Incompliant
not all platforms will return these bits - people doing portable programming might know quite well.Infielder
G
7

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.

Guadalquivir answered 10/3, 2021 at 22:18 Comment(1)
This is a really helpful contribution! Checking the OpenCV commit history, waitKeyEx() gets introduced in this commit from 2016, which is after I left my initial comment. Interestingly, the same commit patches the original waitKey() function so that it always gets masked as code & 0xff which has the same effect as the res % 2**16 in my own answer. Not very surprising, but super helpful to have it spelled out that the full keycode depends on the backend, which points us where to go for more info!Garton
E
6

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:

enter image description here

Evanesce answered 3/8, 2018 at 3:46 Comment(0)
F
3

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
Foxtrot answered 28/4, 2020 at 8:28 Comment(1)
the return of "-1" is not "normal" - it means the timeout has hit. that far the given comment is not really hitting the point. other than that: with a pass parameter of 0 the waitKey function never raises a timeout because it shall wait forever unless a keystroke is received. the decoding will probably never see those value - but in terms of paranoia coding and in terms of being free to choose an alternate timeout at any time its a nice to have state that i would keep.Infielder
R
2

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;
}
Russia answered 25/6, 2015 at 10:46 Comment(2)
You don't need to cast the characters to int, simply doing case 'a': will work.Stationer
when compiling with elevated warning levels you really might want to have some type casts. rather you should extract a "char" from the original int value for a single time. this step further can strip off any higher bits such as the ones used for the modifiers keys.Infielder
A
2

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.

Anya answered 17/10, 2016 at 11:41 Comment(2)
use bit operations, please. (cv:waitKey() & 255)Infielder
(if using a non-null-timeout a return value of -1 would mean the timeout was hit, thus its probably better to first assign the value to a variable, then test for -1, and if its something else then do the bit stripping operation for obtaining the desired key code.)Infielder
T
1

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

Titmouse answered 24/4, 2018 at 16:6 Comment(0)
I
0

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 
Itu answered 22/5, 2019 at 18:26 Comment(0)
S
0

This prints the key combination directly to the image:

z pressed an ctrl + z pressed

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'
Semicircle answered 13/4, 2020 at 13:24 Comment(1)
this might have some limitations, e.g. for character codes that are non-printable.Infielder
C
0
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
Chantay answered 14/2, 2023 at 16:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.