1. 功能分析
- 需要实现截图功能,可以采用【OpenCV-Python学习(5)—— OpenCV 图像像素的读写操作】,获取截取区域具体的像素值;
- 需要实现截图,就需要获取对应的截取区域,采用【OpenCV-Python学习(15)—— OpenCV 鼠标操作和响应(cv.setMouseCallback)】获取需要截图的区域;
- 截图成功后如果需要保存,采用【OpenCV-Python学习(2)—— OpenCV 图像的读取、显示和保存(cv.imread、cv.imshow、cv.imwrite)】实现截取图片的保存。
2. 代码逻辑分析
- 获取需要截取图片的地址,使用sys模块;
- 使用 cv.imread 读取传入的图片;
- 使用 np.ones_like 和 【OpenCV-Python学习(5)—— OpenCV 图像像素的读写操作】复制一份读取的图片;
- 创建一个窗口,监听这个窗口的鼠标事件;
- 左键点击起点: 当前次鼠标左键开始坐标;
- 开始后允许对移动中坐标进行记录;
- 截取区域边框矩形的随机颜色生成;
- 移动终点: 将上次绘制的结果给当前图片,为了将当前次移动过程中产生的绘制清除;
- 当前次移动结束的坐标;
- 绘制移动中的当前矩形;
- 最后终点: 当前次坐标点绘制结束坐标点,结束鼠标移动监听;
- 绘制当前次鼠标左键按下到放开起点和终点组成的矩形;
- 截取矩形区域并显示截取图片;
- 如果需要保存截图图片;
- 判断截取图片保存文件夹是否存在,不存在就创建;
- 生成随机的截取图片名称并保存,最后销毁显示截取图片窗口;
- 坐标点还原;
- 每10毫秒显示一次图片;
- 监听每10毫秒是否按退出键;
- 销毁所有窗口。
3. 截图函数
def screenshot(img_url):
global oldImg
img = cv.imread(img_url)
oldImg = np.ones_like(img)
oldImg[:] = img[:]
cv.namedWindow('screenshot_img')
cv.setMouseCallback('screenshot_img', draw_rectangle, img)
while True:
cv.imshow("screenshot_img", img)
if cv.waitKey(10) & 0xFF == 27:
break
cv.destroyAllWindows()
4. 鼠标事件回调
def draw_rectangle(event,x,y,flags,img):
global flagMove,startX,startY,endX,endY,oldImg,b,g,r
if event == cv.EVENT_LBUTTONDOWN:
startX,startY = x,y
flagMove = True
b,g,r = np.random.randint(0,256,size=3)
b,g,r = int(b),int(g),int(r)
if event == cv.EVENT_MOUSEMOVE and flagMove:
img[:] = oldImg[:]
endX,endY = x,y
cv.rectangle(img, (startX,startY), (endX,endY), (b,g,r), lineType=cv.LINE_AA)
if event == cv.EVENT_LBUTTONUP:
endX,endY = x,y
flagMove = False
cv.rectangle(img, (startX,startY), (endX,endY), (b,g,r), lineType=cv.LINE_AA)
roi = oldImg[startY:endY, startX:endX]
cv.imshow('roi', roi)
if cv.waitKey(0) == ord('s'):
if not os.path.exists(f'./out_images/'):
os.makedirs(f'./out_images/')
path_url = f"./out_images/random{np.random.randint(100,1000)}.jpg"
cv.imwrite(path_url, roi)
cv.destroyWindow("roi")
startX,startY = -1,-1
endX,endY = -1,-1
5. 完整实现截图功能代码
import sys
import os
import cv2 as cv
import numpy as np
flagMove = False
oldImg = None
startX,startY = -1,-1
endX,endY = -1,-1
b,g,r = 0,0,0
def screenshot(img_url):
global oldImg
img = cv.imread(img_url)
oldImg = np.ones_like(img)
oldImg[:] = img[:]
cv.namedWindow('screenshot_img')
cv.setMouseCallback('screenshot_img', draw_rectangle, img)
while True:
cv.imshow("screenshot_img", img)
if cv.waitKey(10) & 0xFF == 27:
break
cv.destroyAllWindows()
def draw_rectangle(event,x,y,flags,img):
global flagMove,startX,startY,endX,endY,oldImg,b,g,r
if event == cv.EVENT_LBUTTONDOWN:
startX,startY = x,y
flagMove = True
b,g,r = np.random.randint(0,256,size=3)
b,g,r = int(b),int(g),int(r)
if event == cv.EVENT_MOUSEMOVE and flagMove:
img[:] = oldImg[:]
endX,endY = x,y
cv.rectangle(img, (startX,startY), (endX,endY), (b,g,r), lineType=cv.LINE_AA)
if event == cv.EVENT_LBUTTONUP:
endX,endY = x,y
flagMove = False
cv.rectangle(img, (startX,startY), (endX,endY), (b,g,r), lineType=cv.LINE_AA)
roi = oldImg[startY:endY, startX:endX]
cv.imshow('roi', roi)
if cv.waitKey(0) == ord('s'):
if not os.path.exists(f'./out_images/'):
os.makedirs(f'./out_images/')
path_url = f"./out_images/random{np.random.randint(100,1000)}.jpg"
cv.imwrite(path_url, roi)
cv.destroyWindow("roi")
startX,startY = -1,-1
endX,endY = -1,-1
if __name__ == "__main__":
img_url = sys.argv[1]
screenshot(img_url)
6. 运行结果

7. 截图实例

8. 总结
- 由于没有对截图时超出图片坐标的处理,因此测试时,请常规操作,在图片内截图;
- 执行截图代码时带上截图图片的路径,实例:
python app.py ./images/lena.jpg