It is very useful to draw graphics with the mouse. In the following target tracking, we will use the mouse to mark the target to be tracked, and then track the target in real time, so today we will learn about some basic knowledge in OpenCV-mouse pen.
First need to understand a function:
cv2.setMouseCallback(windowName, MouseCallback , param=None)
Its various parameters are:
windowName: window name
MouseCallback: mouse response callback function
param: parameters passed by the response function
Here, we create a simple application, no matter where we double-click it, we can draw a circle on the image.
First, we create a mouse callback function, which is executed when a mouse event occurs. The function prototype is (this function is defined by ourselves, there is no such function in the OpenCV library, and the name can be defined arbitrarily):
MouseCallback (int event, int x, int y, int flags, void userdata)
The various parameters are:
event: a MouseEventTypes constant
x: the x coordinate of the
mouse y: the y coordinate of the mouse
flags: a MouseEventFlags constant
userdata: optional parameters
The mouse event can be anything related to the mouse, such as left button press, right button press, left button double click, etc. It provides us with the coordinates (x, y) of each mouse event. Through this event and location, we can do whatever we like. To list all available parameters, we run the following code in the pycharm terminal:
view plaincopy to clipboardprint?
1.import cv2 as cv
2.
3.events = [i for i in dir(cv) if 'EVENT' in i]
4.print( events )
If we look at the output, we will find a lot of parameter names:
view plaincopy to clipboardprint?
1.['EVENT_FLAG_ALTKEY', 'EVENT_FLAG_CTRLKEY', 'EVENT_FLAG_LBUTTON', 'EVENT_FLAG_MBUTTON', 'EVENT_FLAG_RBUTTON', 'EVENT_FLAG_SHIFTKEY', 'EVENT_LBUTTONDBLCLK', 'EVENT_LBUTTONDOWN', 'EVENT_LBUTTONUP', 'EVENT_MBUTTONDBLCLK', 'EVENT_MBUTTONDOWN', 'EVENT_MBUTTONUP', 'EVENT_MOUSEHWHEEL', 'EVENT_MOUSEMOVE', 'EVENT_MOUSEWHEEL', 'EVENT_RBUTTONDBLCLK', 'EVENT_RBUTTONDOWN', 'EVENT_RBUTTONUP']
Now we look at the event parameter in the MouseCallback function, which represents a MouseEventFlags constant:
MouseEventFlags :
cv.EVENT_FLAG_LBUTTON = 1, left-click and drag
cv.EVENT_FLAG_RBUTTON = 2, right-click and drag
cv.EVENT_FLAG_MBUTTON = 4, hold the middle button
cv.EVENT_FLAG_CTRLKEY = 8, press and hold ctrl
cv.EVENT_FLAG_SHIFTKEY = 16, hold down shift
cv.EVENT_FLAG_ALTKEY = 32, press and hold alt
Continue to look at the flags parameter in the MouseCallback function, which represents a MouseEventFlags constant:
cv.MouseEventTypes :
cv.EVENT_MOUSEMOVE = 0, mouse movement
cv.EVENT_LBUTTONDOWN = 1, press the left button
cv.EVENT_RBUTTONDOWN = 2, right click
cv.EVENT_MBUTTONDOWN = 3, press the middle button
cv.EVENT_LBUTTONUP = 4, left button release
cv.EVENT_RBUTTONUP = 5, right click to release
cv.EVENT_MBUTTONUP = 6, middle button release
cv.EVENT_LBUTTONDBLCLK = 7, double left click
cv.EVENT_RBUTTONDBLCLK = 8, right-click and double-click
cv.EVENT_MBUTTONDBLCLK = 9, Zhongjian double click
cv.EVENT_MOUSEWHEEL = 10, scroll wheel sliding
cv.EVENT_MOUSEHWHEEL = 11 horizontal scroll wheel sliding
Next we can start the experiment, creating a mouse callback function has a specific format, the format is the same in all places. It differs only in function. So, now we use the mouse callback function to do one thing, draw a circle where we double-click:
view plaincopy to clipboardprint?
1.import numpy as np
2.import cv2 as cv
3.
4.
5.def draw_circle(event, x, y, flags, param):
6. if event == cv.EVENT_LBUTTONDBLCLK:
7. cv.circle(img, (x, y), 100, (255, 0, 0), -1)
8.
9.
10.img = np.zeros((512, 512, 3), np.uint8)
11.cv.namedWindow('image')
12.cv.setMouseCallback('image', draw_circle)
13.while (1):
14. cv.imshow('image', img)
15. if cv.waitKey(20) & 0xFF == 27:
16. break
17.cv.destroyAllWindows()
The parameter we call here is EVENT_LBUTTONDBLCLK, which means that the mouse is double-clicked to trigger. If we double-click any area, a circle will be created with this as the center:
Mouse drawing graphics
Now we need to perform more advanced operations. In this case, we drag the mouse to draw a rectangle or circle (depending on the mode we choose) as in the "Drawing" application. Therefore, our mouse callback function has two parts, one for drawing a rectangle and the other for drawing a circle. This will be very helpful. In the later manual target tracking, we will manually mark these graphics with the mouse to complete real-time target tracking.
Now we come to implement a comprehensive example, this example will help you understand some ideas of image interaction:
Use the mouse to draw a picture on the image, you can draw a circle or a rectangle, press the q key to switch between the two modes. When the left button is pressed, it starts to draw, moves to where to draw, and ends when the left button is released. Sounds complicated, doesn't it? Step by step analysis:
· Draw with the mouse: Need to define the mouse callback function mouse_event
· Draw circle or rectangle: need to define a drawing mode mode
· Left click, move, release: need to capture three different events
· Start drawing, end drawing: need to define a drawing mark bit drawing
Okay, start code:
```python
view plaincopy to clipboardprint?
1. import numpy as np
2. import cv2 as cv
3.
4. drawing = False # true if mouse is pressed
5. mode = True # if True, draw rectangle. Press 'm' to toggle to curve
6. ix, iy = -1, -1
7.
8. mouse callback function
9.
10.def draw_circle(event, x, y, flags, param):
11. global ix, iy, drawing, mode
12. if event == cv.EVENT_LBUTTONDOWN:
13. drawing = True
14. ix, iy = x, y
15. elif event == cv.EVENT_MOUSEMOVE:
16. if drawing:
17. if mode:
18. cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
19. else:
20. cv.circle(img, (x, y), 5, (0, 0, 255), -1)
21. elif event == cv.EVENT_LBUTTONUP:
22. drawing = False
23. if mode:
24. cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
25. else:
26. cv.circle(img, (x, y), 5, (0, 0, 255), -1)
27.
28.
29.img = np.zeros((512, 512, 3), np.uint8)
30.cv.namedWindow('image')
31.cv.setMouseCallback('image', draw_circle)
32.while 1:
33. cv.imshow('image', img)
34. k = cv.waitKey(1) & 0xFF
35. if k == ord('q'):
36. mode = not mode
37. elif k == 27:
38. break
39.cv.destroyAllWindows()
effect:
ok, done.
But what if we want to create an unfilled rectangle?
Then we need to modify the code. As mentioned in the previous section, functions such as drawing rectangle function and drawing circle function. When their last parameter is -1, it means solid, and when it is greater than 0, it is Hollow, if we define it as 1, then the thickness of the outline of the drawn figure is 1. Let’s look at the code:
view plaincopy to clipboardprint?
1. import numpy as np
2. import cv2 as cv
3.
4. drawing = False # true if mouse is pressed
5. mode = True # if True, draw rectangle. Press 'm' to toggle to curve
6. ix, iy = -1, -1
7.
8.
9. # mouse callback function
10.def draw_circle(event, x, y, flags, param):
11.global ix, iy, drawing, mode
12.if event == cv.EVENT_LBUTTONDOWN:
13. drawing = True
14. ix, iy = x, y
15. elif event == cv.EVENT_MOUSEMOVE:
16. if drawing:
17. if mode:
18. tmp = img.copy()
19. cv.rectangle(tmp, (ix, iy), (x, y), (0, 255, 0), 1)
20. cv.imshow('image', tmp)
21. elif event == cv.EVENT_LBUTTONUP:
22. drawing = False
23. if mode:
24. cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1)
25.
26.
27.img = np.zeros((512, 512, 3), np.uint8)
28.cv.namedWindow('image')
29.cv.setMouseCallback('image', draw_circle)
30.cv.imshow("image",img)
31.while 1:
32. k = cv.waitKey(1) & 0xFF
33. if k == 27:
34. break
35.cv.destroyAllWindows()
Let's look at the effect:
Now we can also modify the code. We cancel the function executed by the parameter statement of EVENT_LBUTTONUP, so that when we draw the next rectangle, the previous one will be automatically cleared:
view plaincopy to clipboardprint?
1. import numpy as np
2. import cv2 as cv
3.
4. drawing = False # true if mouse is pressed
5. mode = True # if True, draw rectangle. Press 'm' to toggle to curve
6. ix, iy = -1, -1
7.
8.
9. # mouse callback function
10.def draw_circle(event, x, y, flags, param):
11. global ix, iy, drawing, mode
12. if event == cv.EVENT_LBUTTONDOWN:
13. drawing = True
14. ix, iy = x, y
15. elif event == cv.EVENT_MOUSEMOVE:
16. if drawing:
17. if mode:
18. tmp = img.copy()
19. cv.rectangle(tmp, (ix, iy), (x, y), (0, 255, 0), 1)
20. cv.imshow('image', tmp)
21. elif event == cv.EVENT_LBUTTONUP:
22. drawing = False
23. # if mode:
24. # cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1)
25.
26.
27.img = np.zeros((512, 512, 3), np.uint8)
28.cv.namedWindow('image')
29.cv.setMouseCallback('image', draw_circle)
30.cv.imshow("image",img)
31.while 1:
32. k = cv.waitKey(1) & 0xFF
33. if k == 27:
34. break
35.cv.destroyAllWindows()
effect:
At this point, even if the mouse drawing part of OpenCV is over, if you want to master it, you should practice more by yourself.
Check the article summary page https://blog.csdn.net/weixin_44237705/article/details/107864965
More openvino technical information can be exchanged in the group~