回到顶部 回到顶部
best-icon

使用行空板制作屏幕取色卡 中等

头像 HonestQiao 2022.11.17 92 1

步骤1 想法起源

在设计开发炫彩灯环控制器的过程中,对行空板的GUI函数,进行了较多的了解。

 

第一版的炫彩灯环控制器,选了16种颜色,然后生成色块,用于点击取色:

image.png

 

在这种情况下,每个色块,都使用 GUI.fill_round_rect() 画出来,并设置好onclick回调,这样子点击对应的色块的时候,就能知道点击的是谁,从而取的提前定以后的对应颜色。

 

后来,又进一步想,能不能通过一张色卡图片,点击不同图片的区域,通过点击位置的坐标,从而获得对应的颜色呢?

 

经过李亮大佬的指点,最终实现如下的屏幕取色卡功能:

image.png

 

步骤2 预备知识1:行空板的GUI处理

行空板的Python,提供了专用的unihiker库,其中有GUI处理的类。

从GUI处理类的调用方法中,有一个显示图像的方法,具体如下:

image.png

 

这个地方的cn书image,不仅可以直接传入一个图片文件的路径,还可以传入一个PIL.Image对象,具体代码如官方示例:

image.png

 

而通过PIL.Image对象,就可以很方便的打开一张图片,进行各种图形处理操作,包括取指定位置的颜色。

步骤3 预备知识2

上一步说了,可以通过PIL.Image对象,取指定位置的颜色,那具体是如何进行的呢?

 

其实很简单,代码如下:

 

代码
img = Image.open("imgs/color_chart.png")
color = img.getpixel(100, 100)

上述代码,就表示先打开imgs/color_chart.png图片,然后取得相对于图片左上角为原点的坐标(100,100)位置的像素的颜色。

 

但是有一点需要注意的是,上面的坐标(100,100),是相对于图片左上角的,不是相对于屏幕左上角的。

 

但我们在触摸屏幕时,通过触摸所获取的坐标,是屏幕坐标。因此,需要进行一些处理,将这两者相对应。

 

最简单的一个办法,就是让图片的宽度,与屏幕的宽度一样,并让图片显示到以屏幕左上角为原点的坐标(0,0)上,这样子,只要是点击了屏幕上图片的任一位置,其取得的屏幕坐标,都直接对应到了图片坐标上了。

 

因为在屏幕顶部,还需要显示其他的内容,所以可以将图片显示在屏幕上的坐标,往下移一下,例如显示到(0,30)的位置,那么通过屏幕触摸取得的坐标(x,y),对应到图片就是(x, y-30)。

 

 

要让图片的宽度,与屏幕的宽度一样,可以有两种办法。一种是图片的实际宽度,就等于屏幕的宽度,一种是通过PIL.Image来讲图片的宽度,调整大小,使得宽度等于屏幕的宽度。前者通过工具软件进行处理,后者直接在Python中编码即可。

 

通过PIL.Image调整图片宽度的方式如下:

代码
img = Image.open("imgs/color_chart.png")
img2 = img.resize((240,240))
img.close()

需要注意的是,Image.resize()会生成一个新的图片对象,而原有的不变。

 

步骤4 预备知识3:屏幕触摸坐标位置

在行空板的GUI处理类中,提供了两类获取屏幕点击事件的方式:

 

代码
# 控件的onclick触发
info_text = gui.draw_text(x=120, y=320, text='你好',origin='bottom' ,onclick=info_text_on_click)

# 鼠标的移动触发
def mouse_move(x, y):
    info_text.config(text="坐标:x={},y={}".format(x, y))
    print(x,y)

gui.on_mouse_move(mouse_move)

onclick触发调用的时候,只能知道有一次屏幕点击控件发生了,可以知道是在哪个控件上触发的,但是,并不知道具体点击的坐标位置。

 

on_mouse_move就可以。当在屏幕上触摸移动的时候,类似于在屏幕上移动鼠标,会实时的调用on_mouse_move对应的回调函数,并将当前坐标位置(x,y)做为参数传入。

然后,在回调函数中,就可以使用传入的x, y进行进一步处理了。

 

 

步骤5 逻辑设计

 

行空板_WS2812B电路原理图.drawio2.png

步骤6 代码编写

代码
# -*- coding: UTF-8 -*-
import sys
import time
from unihiker import GUI
from PIL import Image

# 屏幕鼠标移动回调
def mouse_move(x, y):
    global move_time, mouse_status, color_chart_image, mouse_color

    # 显示坐标值
    pos_text.config(x=0,text="坐标:({},{})".format(x, y))

    # 判断是否在色卡图片上移动
    if y>=30 and y < 30+240:
        # 在色卡图片中取色
        mouse_color = color_chart_image.getpixel((x, y-30))
    else:
        # 超出则使用(0,0,0)
        mouse_color = (0,0,0)

    # 显示颜色之
    color_text.config(x=100,text="颜色:({},{},{})".format(mouse_color[0],mouse_color[1],mouse_color[2]))

    # 更新预览图片颜色
    color_img.config(color=mouse_color)

    # 更新当前移动时间
    move_time = time.time()

    # 设置移动状态
    mouse_status = 1

# 打开色卡图片
color_chart_image_default = Image.open("imgs/color_chart.png")
# 调整色卡图片大小
color_chart_image = color_chart_image_default.resize((240,240)).convert('RGB')
# 关闭默认打开的色卡图片
color_chart_image_default.close()

# 初始化屏幕
gui = GUI()
gui.clear()

# 初始化屏幕标识文本
gui.draw_text(x=50, y=0, text="WS2812B色卡", font_size=13)
gui.draw_image(x=0,y=30,w=240,h=240,image=color_chart_image)
pos_text = gui.draw_text(x=40, y=300, text='鼠标坐标', font_size=10)
color_text = gui.draw_text(x=150, y=300, text='颜色', font_size=10)

# 初始化颜色预览色块
color_img = gui.fill_round_rect(x=224, y=304, w=14, h=14, r=2, color=(255,255,255))

# 设定中间量初始值
move_time = 0
mouse_status = 0
mouse_color = (0,0,0)

# 屏幕鼠标移动回调绑定
gui.on_mouse_move(mouse_move)

# 循环
while True:
    time.sleep(1)

步骤7 实际效果

评论

user-avatar
  • Nd0TAy8yduIE

    Nd0TAy8yduIE2022.11.21

    具体能干嘛呢

    0