上网课期间,很多同学(包括老师)都会选择(提倡)截屏来记录笔记,然后课后再进行整理。但是往往越截越多,到后来干脆每张都截,课后面对几十张的照片直接泄了气,不写了。另外有些同学,继续保持在课堂上的习惯,手写笔记。但是没了黑板的帮助,老师又默认PPT上的重点大家都会截图,往往过的非常快,手写时间根本不够,最后笔记跟不上,越落越多,最后也泄了气,不写了
那么,如果既想截图,又想快速写笔记,还想着摸鱼,该怎么办呢?
当然是制作工具了 ———— 智能截屏
pip
即可,大家自行百度既让要操作简单,那么图形化必然少不了,用户也可能需要自己设置截图区域
这里和上一篇文章的截图部分很像,就不做过多分析
代码大家自行研究,还是封装一个模块ScreenArea.py
import tkinter as tk
import pyautogui
#鼠标左键按下
def button_1(event):
global x, y ,xstart,ystart
x, y = event.x, event.y
xstart,ystart = event.x, event.y
xstart,ystart = event.x, event.y
cv.configure(height=1)
cv.configure(width=1)
cv.place(x=event.x, y=event.y)
#鼠标左键按下并移动
def b1_Motion(event):
global x, y
x, y = event.x, event.y
global cv
cv.configure(height = event.y - ystart)
cv.configure(width = event.x - xstart)
#鼠标左键松开
def buttonRelease_1(event):
global x, y,xstart,ystart
x, y = event.x, event.y
if x == xstart and y == ystart:
return
global cv
global root
Pstart=[0,0]
cv.place_forget()
root.attributes("-alpha", 0)
root.destroy()
# 退出
def sys_out(even = True):
global root
#from tkinter import messagebox
#if messagebox.askokcancel('Exit','Confirm to exit?'):
root.destroy()
def SelectArea():
global root
root = tk.Tk()
root.overrideredirect(True) # 隐藏窗口的标题栏
# root.attributes("-alpha", 0.3) # 窗口透明度70 %
root.attributes("-alpha", 0.3) # 窗口透明度60 %
root.attributes("-topmost", 1)
#root.geometry("300x200+10+10") # 设置窗口大小与位置
root.geometry("{0}x{1}+0+0".format(root.winfo_screenwidth(), root.winfo_screenheight()))
root.configure(bg="black")
# 再创建1个Canvas用于圈选
global cv, x, y, xstart, ystart
cv = tk.Canvas(root)
x, y = 0, 0
xstart,ystart = 0 ,0
# 绑定事件到Esc键,当按下Esc键就会调用sys_out函数,弹出对话框
root.bind('' ,sys_out)
root.bind("" , button_1)
root.bind("" , b1_Motion)
root.bind("" , buttonRelease_1)
root.mainloop()
return (xstart,ystart,x - xstart,y - ystart) # 左上角坐标,宽,高
if __name__ == "__main__":
print(SelectArea())
虽然智能过滤了相似的图片,但是图片量仍然很大,所以要让用户可以自行选择保存路径
使用 tkinter
的文件选择框 主程序 screenAI.py
中 实现
import screenArea
from tkinter import filedialog
import time
def StartscreenAI(): # 一会儿可以绑定快捷键
global x,y,width,height
x,y,width,height = screenArea.SelectArea() # 获取截图区域
global save_path
save_path = filedialog.askdirectory()
print(save_path)
if __name__ == "__main__":
time.sleep(3) # 给操作者一个反应的时间
StartscreenAI()
这里为了过滤相似的图片,我们用到了一些图像处理算法,为了更加精确和灵活,我一下采用了五种算法
五个算法根据场景进行加权平均得到相似值。这里封装一个模块进行实现 imageAI.py
import cv2
import numpy as np
N = 16 # 压缩程度,越大越精确,但是空间和时间越多 注意为 2 的次幂
def aHash(img):
# 均值哈希算法
# 缩放为N*N
global N
img = cv2.resize(img, (N, N))
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# s为像素和初值为0,hash_str为hash值初值为''
s = 0
hash_str = ''
# 遍历累加求像素和
for i in range(N):
for j in range(N):
s = s+gray[i, j]
# 求平均灰度
avg = s/N/N
# 灰度大于平均值为1相反为0生成图片的hash值
for i in range(N):
for j in range(N):
if gray[i, j] > avg:
hash_str = hash_str+'1'
else:
hash_str = hash_str+'0'
return hash_str
def dHash(img):
global N
# 差值哈希算法
# 缩放N * N
img = cv2.resize(img, (N + 1, N))
# 转换灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hash_str = ''
# 每行前一个像素大于后一个像素为1,相反为0,生成哈希
for i in range(N):
for j in range(N):
if gray[i, j] > gray[i, j+1]:
hash_str = hash_str+'1'
else:
hash_str = hash_str+'0'
return hash_str
def pHash(img):
# 感知哈希算法
# 缩放4n * 4n
global N
img = cv2.resize(img, (4 * N, 4 * N)) # , interpolation=cv2.INTER_CUBIC
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 将灰度图转为浮点型,再进行dct变换
dct = cv2.dct(np.float32(gray))
# opencv实现的掩码操作
dct_roi = dct[0:N, 0:N]
hash = []
avreage = np.mean(dct_roi)
for i in range(dct_roi.shape[0]):
for j in range(dct_roi.shape[1]):
if dct_roi[i, j] > avreage:
hash.append(1)
else:
hash.append(0)
return hash
def cmpHash(hash1, hash2):
# Hash值对比
# 算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
# 对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
# 汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
N = 0
# hash长度不同则返回-1代表传参出错
if len(hash1) != len(hash2):
return -1
# 遍历判断
for i in range(len(hash1)):
# 不相等则n计数+1,n最终为相似度
if hash1[i] != hash2[i]:
N = N + 1
return N
def calculate(image1, image2):
# 灰度直方图算法
# 计算单通道的直方图的相似值
hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
# 计算直方图的重合度
degree = 0
for i in range(len(hist1)):
if hist1[i] != hist2[i]:
degree = degree + \
(1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
else:
degree = degree + 1
degree = degree / len(hist1)
return float(degree)
def classify_hist_with_split(image1, image2, size=(256, 256)):
# RGB每个通道的直方图相似度
# 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值
image1 = cv2.resize(image1, size)
image2 = cv2.resize(image2, size)
sub_image1 = cv2.split(image1)
sub_image2 = cv2.split(image2)
sub_data = 0
for im1, im2 in zip(sub_image1, sub_image2):
sub_data += calculate(im1, im2)
sub_data = sub_data / 3
return float(sub_data)
在主程序中控制截图与保存 screenAI.py
import screenArea
import imageAI
from tkinter import filedialog
import time
import os
import cv2
import numpy as np
import pyautogui
def ScreenCut():
global x,y,width,height
return pyautogui.screenshot(region = (x,y,width,height))
def SaveFile(img):
global pic_cnt
global save_path
pic_cnt += 1
print('保存了图片',save_path + '/' + str(pic_cnt) + '.png')
img.save(save_path + '/' + str(pic_cnt) + '.png')
def StartscreenAI(): # 一会儿可以绑定快捷键
global x,y,width,height
x,y,width,height = screenArea.SelectArea() # 获取截图区域
global save_path
try:
save_path = filedialog.askdirectory()
except:
print('已取消')
return
global pic_cnt
pic_cnt = 0
try:
filenames = os.listdir(save_path)
except:
print('已取消(或无效路径)')
return
for filename in filenames:
try:
if pic_cnt < int(filename.replace('.png','')):
pic_cnt = int(filename.replace('.png',''))
except:
pass
# 一个小小的优化,自动找到未被使用的编号,防止多次启动覆盖
lstimg = ScreenCut()
lstcv2img = cv2.cvtColor(np.asarray(lstimg), cv2.COLOR_RGB2BGR)
lstdhash = imageAI.dHash(lstcv2img)
lstahash = imageAI.aHash(lstcv2img)
lstphash = imageAI.pHash(lstcv2img)
SaveFile(lstimg)
global SCREENCUT
SCREENCUT = True
while SCREENCUT:
nowimg = ScreenCut()
nowcv2img = cv2.cvtColor(np.asarray(nowimg), cv2.COLOR_RGB2BGR)
nowdhash = imageAI.dHash(nowcv2img)
nowahash = imageAI.aHash(nowcv2img)
nowphash = imageAI.pHash(nowcv2img)
nowcalculate = round(imageAI.calculate(nowcv2img,lstcv2img),8)
nowclassify_hist_with_split = imageAI.classify_hist_with_split(nowcv2img,lstcv2img)
dn1 = imageAI.cmpHash(lstdhash,nowdhash)
an1 = imageAI.cmpHash(lstahash,nowahash)
pn1 = imageAI.cmpHash(lstphash,nowphash)
arv = ((imageAI.N * imageAI.N - dn1) / imageAI.N / imageAI.N * 2 + (imageAI.N * imageAI.N - an1) / imageAI.N / imageAI.N + (imageAI.N * imageAI.N - pn1) / imageAI.N / imageAI.N + nowcalculate) / 5 # PPT 的较好算法
if arv < 0.85: # ppt的较好参数
SaveFile(nowimg)
lstcv2img = nowcv2img
lstdhash = nowdhash
lstahash = nowahash
lstphash = nowphash
if __name__ == "__main__":
time.sleep(3) # 给操作者一个反应的时间
StartscreenAI()
到目前为止,一次启动已经做好
接下来,为了多课程之间的切换和停止,我们给程序增加一些快捷键 screenAI.py
注意,因为StartscreenAI
中有死循环,会影响keyboard
的循环,所以要停止的检测要在while
循环中用is_pressed
import screenArea
import imageAI
from tkinter import filedialog
import time
import os
import cv2
import numpy as np
import pyautogui
import keyboard
import threading
SCREENCUT = False
def ScreenCut():
global x,y,width,height
return pyautogui.screenshot(region = (x,y,width,height))
def SaveFile(img):
global pic_cnt
global save_path
pic_cnt += 1
print('保存了图片',save_path + '/' + str(pic_cnt) + '.png')
img.save(save_path + '/' + str(pic_cnt) + '.png')
def StartscreenAI(): # 一会儿可以绑定快捷键
global SCREENCUT
if SCREENCUT != False:
print('已开始,ctrl+alt+e 停止')
return
global x,y,width,height
x,y,width,height = screenArea.SelectArea() # 获取截图区域
global save_path
try:
save_path = filedialog.askdirectory()
except:
print('已取消')
return
global pic_cnt
pic_cnt = 0
try:
filenames = os.listdir(save_path)
except:
print('已取消(或无效路径)')
return
for filename in filenames:
try:
if pic_cnt < int(filename.replace('.png','')):
pic_cnt = int(filename.replace('.png',''))
except:
pass
print('选择了路径: %s 已有编号 %d' % (save_path,pic_cnt))
# 一个小小的优化,自动找到未被使用的编号,防止多次启动覆盖
lstimg = ScreenCut()
lstcv2img = cv2.cvtColor(np.asarray(lstimg), cv2.COLOR_RGB2BGR)
lstdhash = imageAI.dHash(lstcv2img)
lstahash = imageAI.aHash(lstcv2img)
lstphash = imageAI.pHash(lstcv2img)
SaveFile(lstimg)
SCREENCUT = True
while SCREENCUT:
if keyboard.is_pressed('ctrl+alt+e'):
SCREENCUT = False
nowimg = ScreenCut()
nowcv2img = cv2.cvtColor(np.asarray(nowimg), cv2.COLOR_RGB2BGR)
nowdhash = imageAI.dHash(nowcv2img)
nowahash = imageAI.aHash(nowcv2img)
nowphash = imageAI.pHash(nowcv2img)
nowcalculate = round(imageAI.calculate(nowcv2img,lstcv2img),8)
nowclassify_hist_with_split = imageAI.classify_hist_with_split(nowcv2img,lstcv2img)
dn1 = imageAI.cmpHash(lstdhash,nowdhash)
an1 = imageAI.cmpHash(lstahash,nowahash)
pn1 = imageAI.cmpHash(lstphash,nowphash)
arv = ((imageAI.N * imageAI.N - dn1) / imageAI.N / imageAI.N * 2 + (imageAI.N * imageAI.N - an1) / imageAI.N / imageAI.N + (imageAI.N * imageAI.N - pn1) / imageAI.N / imageAI.N + nowcalculate) / 5 # PPT 的较好算法
if arv < 0.85: # ppt的较好参数
SaveFile(nowimg)
lstcv2img = nowcv2img
lstdhash = nowdhash
lstahash = nowahash
lstphash = nowphash
print('截图已结束')
if __name__ == "__main__":
keyboard.add_hotkey('ctrl+alt+b',StartscreenAI)
keyboard.wait()
大功告成,希望可以帮助到专心学习的你
希望大家在评论区分享更好的做法
希望大家关注,评论,点赞哦