光标画图程序

写这个程序的缘由是现在疫情期间我们学生在家用在线办公软件上网络课,老师在投屏时学生可以在老师屏幕上“注释”(做记号,写字,画画等),这样可以很好的与老师互动。但是“注释”并不能显示图片,为了达成我的一个骚主意,在老师屏幕上画一个卢本伟,我面向百度编程写了这个Python程序。

视频

水了两个视频:

  1. 当你在老师网络课的屏幕上画画

  2. 我竟然用windows自带画图工具画了一个炮姐!

以后决定干啥都水个视频

源代码

项目地址:https://github.com/HK-SHAO/cursor_painter

其中dist文件夹有exe程序可以直接运行,不需要安装Python等环境。

其实代码很简单,这也多亏了Python超简单的语法和强大的库(自从用了python以后编程能力节节败退,Lua,Java,C已经忘完了)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
from PIL import Image, ImageFilter, ImageGrab
from pynput.mouse import Button, Controller
from pynput import keyboard
import time

mouse = Controller()
p = None
img = None
isB = False


def click(x, y):
mouse.position = (x, y)
mouse.click(Button.left, 1)


def rgb_distance(rgb_1, rgb_2):
r1, g1, b1 = rgb_1
r2, g2, b2 = rgb_2
return ((r1-r2)**2+(g1-g2)**2+(b1-b2)**2)**0.5


def draw(s, pt=p, n=1, m='00', r=1, t=220, st=0.01):
global img
img = Image.open(s)
img = img.resize((int(img.width*n), int(img.height*n)))
pt = p

if m[0] == '0':
img = img.filter(ImageFilter.SMOOTH).filter(
ImageFilter.CONTOUR).convert('L')
else:
img = img.convert('L')

pixels = img.load()
for x in range(img.width):
for y in range(img.height):

if isB:
print('已中止')
return

pix = pixels[x, y]
if r*pix < r*t:
if m[1] == '0' or (x % 2 == 0 and y % 2 == 0):
click(pt[0]+x, pt[1]+y)
time.sleep(st)


def color(s, n=1, st=0.01):
global img
colors, pos = [], []
print("先将光标移动到画板上回车,再将光标移动到颜色按钮回车\n最后输入s并回车从当前光标位置开始绘制,输入q并回车退出")
while True:
input_str = input()
if input_str == 's':
break
elif input_str == 'q':
return
mp = mouse.position
if len(pos) == 0:
mp = (mp[0]-2, mp[1]-2)
c = ImageGrab.grab().getpixel(mp)
pos.append(mp)
colors.append(c)
print('{} {}'.format(c, mp))

mp = mouse.position
img = Image.open(s)
img = img.resize((int(img.width*n), int(img.height*n))).convert('RGB')
pixels = img.load()
while True:
for x in range(img.width):
for y in range(img.height):

if isB:
print('已中止')
return

pix = pixels[x, y]
ds = []
for c in colors:
ds.append(rgb_distance(c, pix))
index = ds.index(min(ds))
if index != 0:
click(pos[index][0], pos[index][1])
click(mp[0]+x, mp[1]+y)
time.sleep(st)
if input('输入s再画一个,回车则结束:') != 's':
return


def on_release(key):
if key == keyboard.Key.esc:
global isB
isB = True


listener = keyboard.Listener(on_release=on_release)
listener.start()

print("""对象:
p:光标所在位置 mouse:鼠标
time:时间 img:图像
命令:
draw(s图片地址,pt点坐标,n缩放倍数,m模式,r是否反转,t下笔阈值,st延迟时间):绘制黑白图片
例如 draw('img.png') 或 draw('img.png', pt=[200, 300], n=1, m='00', r=-1, t=220, st=0)
color(s图片地址,n缩放倍数,st延迟时间):绘制彩色图片
例如 color('img.png', n=0.1)
click(横坐标,纵坐标):点击某位置
例如 click(200, 300)
模式:
第1个数字: 第2个数字:
0:去噪边缘灰度化 0:正常
1:只进行灰度化 1:稀疏

注意:
1.使用 CTRL+C 退出程序,绘制中按下ESC键中止
2.还可执行其它的python命令,如 img.show() 显示图片
""")

while True:
isB = False
i = input('>>> ')
p = mouse.position
try:
o = eval(i)
if o != None:
print(o)
except Exception as e:
print(e)

关于颜色相似度

不管是RGB,HSV,Lab还是其它,色彩可以表示成三维向量(当然更高维也可以),颜色所分布的空间就是色彩空间。颜色相似度也就是两个颜色在色彩空间中的距离,距离越小相似度越大,认为两个颜色相近。上面程序在运行时会选择相似度较大的色彩进行绘制。Lab色彩空间比较符合人类视觉习惯,但是我使用后感觉效果很差,不知道是不是我的程序有问题,所以最后还是使用了RGB。

在线颜色转换的网址:https://www.qtccolor.com/tool/rgb.aspx

这里再给出RGB转Lab的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def rgb2lab(rgb):
r = rgb[0] / 255.0 # rgb range: 0 ~ 1
g = rgb[1] / 255.0
b = rgb[2] / 255.0

# gamma 2.2
if r > 0.04045:
r = pow((r + 0.055) / 1.055, 2.4)
else:
r = r / 12.92

if g > 0.04045:
g = pow((g + 0.055) / 1.055, 2.4)
else:
g = g / 12.92

if b > 0.04045:
b = pow((b + 0.055) / 1.055, 2.4)
else:
b = b / 12.92

# sRGB
X = r * 0.436052025 + g * 0.385081593 + b * 0.143087414
Y = r * 0.222491598 + g * 0.716886060 + b * 0.060621486
Z = r * 0.013929122 + g * 0.097097002 + b * 0.714185470

# XYZ range: 0~100
X = X * 100.000
Y = Y * 100.000
Z = Z * 100.000

# Reference White Point

ref_X = 96.4221
ref_Y = 100.000
ref_Z = 82.5211

X = X / ref_X
Y = Y / ref_Y
Z = Z / ref_Z

# Lab
if X > 0.008856:
X = pow(X, 1 / 3.000)
else:
X = (7.787 * X) + (16 / 116.000)

if Y > 0.008856:
Y = pow(Y, 1 / 3.000)
else:
Y = (7.787 * Y) + (16 / 116.000)

if Z > 0.008856:
Z = pow(Z, 1 / 3.000)
else:
Z = (7.787 * Z) + (16 / 116.000)

Lab_L = round((116.000 * Y) - 16.000, 2)
Lab_a = round(500.000 * (X - Y), 2)
Lab_b = round(200.000 * (Y - Z), 2)

return [Lab_L, Lab_a, Lab_b]

计算距离

1
2
3
4
def lab_distance(rgb_1, rgb_2):
l1, a1, b1 = rgb2lab(rgb_1)
l2, a2, b2 = rgb2lab(rgb_2)
return ((l1-l2)**2+(a1-a2)**2+(b1-b2)**2)**0.5

当然计算RGB的距离也一样

1
2
3
4
def rgb_distance(rgb_1, rgb_2):
r1, g1, b1 = rgb_1
r2, g2, b2 = rgb_2
return ((r1-r2)**2+(g1-g2)**2+(b1-b2)**2)**0.5
作者

烧风

发布于

2020-02-18

更新于

2021-07-11

许可协议

评论