键盘响应中有一个函数叫做waitKey
,所有的获取键盘键值都是通过waitKey函数实现的。
用户通过敲击键盘,操作系统会返回键值给各个应用程序,当返回键值给OpenCV的时候,如果我们有自己定义的接收返回值的方法,就会按照我们定义的方法对返回值进行处理。
键盘属于外部设备,由操作系统负责监听响应,当键盘发出响应被操作系统接收后,操作系统根据发出注册的应用程序返回接收到的键盘值。
# 例如借助if-elif-else来处理我们需要的键值
if <expr>:
<statement(s)>
elif <expr>:
<statement(s)>
elif <expr>:
<statement(s)>
...
else:
<statement(s)>
例如我们可以按照如下设定:
def keyboard_demo():
image = cv.imread(r"F:\python\opencv-4.x\samples\data\butterfly.jpg")
cv.namedWindow("keyboard_demo", cv.WINDOW_AUTOSIZE)
cv.imshow("keyboard_demo", image)
while True:
c = cv.waitKey(10) # 停顿10ms
# ESC
if c == 27:
break
# key = 0
elif c == 48:
cv.imshow("keyboard_demo", image)
# key = 1
elif c == 49:
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
cv.imshow("keyboard_demo", hsv)
# key = 2
elif c == 50:
ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)
cv.imshow("keyboard_demo", ycrcb)
# key = 3
elif c == 51:
rgb = cv.cvtColor(image, cv.COLOR_BGR2RGB)
cv.imshow("keyboard_demo", rgb)
else:
if c != -1:
print("Key: ", c, "is not define.")
cv.waitKey(0)
cv.destroyAllWindows()
结果示例:
从左往右依次是BGR/HSV/YCrCb/RGB:
如果键入了没有定义的键值就会按照else中写的返回一个结果如下图所示:
和键盘一样,鼠标属于外部设备,由操作系统负责监听响应,当鼠标发出响应被操作系统接收后,操作系统根据发出注册的应用程序返回接收到的鼠标值。
注册与回调过程非常类似滚动条的操作。
鼠标支持的事件:
1.EVENT_LBUTTONDOWN
2.EVENT_MOUSEMOVE
3.EVENT_LBUTTONUP
# 以上是三个非常重要的鼠标事件,这三个动作要在一套动作中完成
鼠标左键按下、鼠标移动、鼠标左键弹起
# 鼠标回调函数
1. cv2.setMouseCallback(windowName, onMouse, param=None)
# windowName:窗口名称
# onMouse:鼠标响应函数
# param:响应函数传递的的参数
# 鼠标响应函数
2. onMouse(event, x, y, flags, param)
# event:鼠标事件,可用参数对应值代替
# x:鼠标x坐标
# y:鼠标y坐标
# flags:鼠标状态,可用参数对应值代替
# param:param是用户定义的传递到setMouseCallback函数调用的参数
绘制矩形:
鼠标绘制矩形:
# 鼠标操作绘制矩形
b1 = cv.imread(r"F:\python\opencv-4.x\samples\data\starry_night.jpg")
img = np.copy(b1)
# (x1, y1)表示左上角,(x2, y2)表示右下角点
x1 = -1
x2 = -1
y1 = -1
y2 = -1
# 定义绘制矩形的注册函数
def mouse_drawing_rectangle(event, x, y, flags, parm):
# 全局参数
global x1, y1, x2, y2
# 鼠标放下,赋值左上角点给x1,y1
if event == cv.EVENT_LBUTTONDOWN:
x1 = x
y1 = y
# 鼠标移动
if event == cv.EVENT_MOUSEMOVE:
# x1,y1初始值都是-1,如果移动过程<0说明鼠标没有摁下
if x1 < 0 or y1 < 0:
return
x2 = x
y2 = y
dx = x2 - x1
dy = y2 - y1
# 移动有一定距离才会绘制
if dx > 0 and dy > 0:
# 矩形绘制到b1(读入的图片)上
# img是原图
b1[:, :, :] = img[:, :, :] # 用原图覆盖擦除之前的绘制结果
cv.putText(b1, "searching...", (x1, y1-5), cv.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255), 2)
cv.rectangle(b1, (x1, y1), (x2, y2), (255, 0, 255), 2, 8, 0) # 移动过程中用紫色线
if event == cv.EVENT_LBUTTONUP:
x2 = x
y2 = y
dx = x2 - x1
dy = y2 - y1
if dx > 0 and dy > 0:
# 矩形绘制到b1(读入的图片)上
# img是原图
b1[:, :, :] = img[:, :, :] # 用原图覆盖擦除之前的绘制结果
cv.putText(b1, "Moon", (x1, y1-5), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
cv.rectangle(b1, (x1, y1), (x2, y2), (0, 0, 255), 2, 8, 0) # 鼠标抬起之后用红色线
# 重新赋值为下一次绘制做准备
x1 = -1
y1 = -1
x2 = -1
y2 = -1
def mouse_demo():
cv.namedWindow("mouse_demo", cv.WINDOW_AUTOSIZE)
# 实时关注mouse_demo画布上的响应,如果发生mouse_drawing中定义的事件,就返回响应
cv.setMouseCallback("mouse_demo", mouse_drawing_rectangle) # 绘制矩形
while True:
cv.imshow("mouse_demo", b1) # 绘制矩形
# 每过10ms就获取一次键盘键值,默认是-1,ESC键是27
c = cv.waitKey(10)
if c == 27:
break
cv.destroyAllWindows()
结果示例:
鼠标绘制圆形:
# 鼠标操作绘制圆形
b2 = cv.imread(r"F:\python\opencv-4.x\samples\data\starry_night.jpg")
img2 = np.copy(b2)
# (c1, c2)表示圆心坐标,r1表示半径
c1 = -1
c2 = -1
# 定义圆形的注册函数
def mouse_drawing_circle(event, x, y, flags, parm):
# 全局参数
global c1, c2, r1
# 鼠标放下,赋值左上角点给x1,y1
if event == cv.EVENT_LBUTTONDOWN:
c1 = x
c2 = y
# 鼠标移动
if event == cv.EVENT_MOUSEMOVE:
# c1,c2初始值都是-1,如果移动过程<0说明鼠标没有摁下
if c1 < 0 or c2 < 0:
return
dr = int(math.sqrt(pow((x-c1), 2) + pow((y-c2), 2)))
# 移动有一定距离才会绘制
if dr > 0:
# 圆形绘制到b1(读入的图片)上
# img是原图
b2[:, :, :] = img2[:, :, :] # 用原图覆盖擦除之前的绘制结果
cv.circle(b2, (c1, c2), dr, (255, 0, 255), 2, cv.LINE_8) # 移动过程中用紫色线
if event == cv.EVENT_LBUTTONUP:
dr = int(math.sqrt(pow((x - c1), 2) + pow((y - c2), 2)))
if dr > 0:
# 圆形绘制到b1(读入的图片)上
# img是原图
b2[:, :, :] = img2[:, :, :] # 用原图覆盖擦除之前的绘制结果
cv.circle(b2, (c1, c2), dr, (0, 0, 255), 2, cv.LINE_8) # 移动过程中用红色线
# 重新赋值为下一次绘制做准备
c1 = -1
c2 = -1
def mouse_demo():
cv.namedWindow("mouse_demo", cv.WINDOW_AUTOSIZE)
# 实时关注mouse_demo画布上的响应,如果发生mouse_drawing中定义的事件,就返回响应
cv.setMouseCallback("mouse_demo", mouse_drawing_circle) # 绘制圆形
while True:
cv.imshow("mouse_demo", b2) # 绘制圆形
# 每过10ms就获取一次键盘键值,默认是-1,ESC键是27
c = cv.waitKey(10)
if c == 27:
break
cv.destroyAllWindows()
结果示例:
其他有趣的实现
同时还可以实现一些有意思的功能比如实现实时响应截取
以及类似qq截图的功能
的,只有截图部分是亮的,其余部分是暗的。
下面代码我是单独写在一个包里面的,如果需要的话可以把他们在上面的类中调用自己试一试也是很有趣的。
import cv2 as cv
import numpy as np
# 图片区域显示
def rectangle_space(img, x1, x2, y1, y2):
# img = cv.imread(r"F:\python\opencv-4.x\samples\data\starry_night.jpg")
# cv.imshow("img", img)
# img2 = img[0:256, 256:512, 1:2] # 第一个0:256表示高度所在位置,第二个0:256表示宽度所在位置,第三个1:2表示输出通道数
# cv.imshow("rectangle_space", img2)
cv.imshow("rectangle_space", img[y1:y2, x1:x2, 0:3])
cv.waitKey(1)
# 除了截图部分其余均变暗
def rectangle_dark(img, x1, x2, y1, y2):
# img = cv.imread(r"F:\python\opencv-4.x\samples\data\starry_night.jpg")
# cv.imshow("img", img)
# img2 = np.zeros_like(img)
# img2[:, :, :] = (np.uint8(60), np.uint8(60), np.uint8(60))
# img2[0:256, 256:512, :] = 0
# result = cv.subtract(img, img2)
# cv.imshow("result", result)
img2 = np.zeros_like(img)
img2[:, :, :] = (np.uint8(60), np.uint8(60), np.uint8(60))
img2[y1:y2, x1:x2, :] = 0
result = cv.subtract(img, img2)
cv.imshow("mouse_demo", result)
cv.waitKey(1000)
# 当前程序执行部分
if __name__ == '__main__':
print("Hello world.")
rectangle_dark()
结果示例:
左图为实时截取,右图为类似qq截图的实现
本系列所有OpenCv相关的代码示例和内容均来自博主学习的网站:opencv_course