概述
本文档将介绍一个基于MicroPython环境下,为ESP32(基本含有MicroPython环境中都可以使用)开发板上的WS2812B灯珠设计的随机颜色生成器。此生成器包括了一个自定义的随机数生成器Random
类和一个用于生成随机颜色的RandomColor
类。该方案特别适合于那些固件中未包含标准随机数生成功能的情况。
优点
- 独立性:由于集成了自定义的随机数生成器,使得代码在缺乏系统级随机数支持的情况下也能正常运行。
- 灵活性:通过
RandomColor
类的set_level
方法,用户可以轻松调整生成颜色的亮度级别。 - 避免重复颜色:
get_rgb
方法尝试确保生成的颜色不在排除列表colors
中,增加了颜色选择的独特性。 - 易于集成:可以直接应用于控制WS2812B灯珠,适用于各种装饰或指示用途。
缺点
- 随机性限制:虽然实现了基本的线性同余发生器(LCG),但其周期长度受限于
2^32
,对于要求极高随机性的应用可能不够理想。 - 性能考虑:在某些情况下,尤其是在循环中频繁调用
get_rgb
方法时,可能会遇到性能瓶颈,尤其是当需要避开特定颜色时的重试机制。 - HSV到RGB转换的精度:转换过程中的一些简化处理(如直接对色调值进行取模运算)可能会影响颜色准确性。
使用方法
初始化
首先实例化RandomColor
对象,可以通过level参数指定亮度等级:
randomColor = RandomColor(level=0) # level范围从0到5,默认是3
调整亮度等级
若是自带的亮度亮度没有合适的可以更改set_level方法下的
self.value = {0: 2, 1: 64, 2: 128, 3: 192, 4: 224, 5: 255}[level]
可以添加或减少键值对,或者更改值,更改完成后,使用这个新的映射关系替换原来的self.value
获取随机颜色
要获取一个不与给定列表中的颜色重复的随机颜色,可以使用get_rgb
方法:
exclude_colors = [(255, 0, 0), (0, 255, 0)] # 假设这些颜色是我们想避开的
# colors可以为空
new_color = randomColor.get_rgb(colors=exclude_colors)
调整已有颜色的亮度
如果需要根据当前亮度等级调整已有的颜色,可利用adjust_to_level
方法:
adjusted_color = randomColor.adjust_to_level((128, 128, 128))
结论
这个随机颜色生成器提供了一种简单且有效的方法来为WS2812B灯珠生成随机颜色,尤其适用于MicroPython环境下的ESP32项目。尽管存在一些局限性,但对于大多数应用场景来说,它已经足够灵活和强大。此外,通过调整new_v
字典中的值,可以更精确地控制不同亮度等级对应的明度值,以满足不同的亮度需求。
WS2812B灯板中显示的效果
代码
from Color import randomColor#导入随机颜色模块(将代颜色生成码放入Color.py文件中)
from WS2812B import ws2812b#导入WS2812B显示模块(自制模块)
randomColor.set_level(0)#设置最低亮度
colors=[]#存放使用过的颜色
def get():
'''获取颜色'''
c=randomColor.get_rgb(colors)
colors.append(c)
return c
#显示字符
ws2812b.show_char('A',(0,1),get())
ws2812b.show_char('B',(0,6),get())
ws2812b.show_char('C',(0,11),get())
ws2812b.show_char('D',(0,16),get())
ws2812b.show_char('E',(0,21),get())
#写入内容
ws2812b.write()
显示效果
这是在同一亮度等级下显示的内容,颜色亮度基本一致
源码
import time
# 自定义随机数生成器
class Random:
def __init__(self, seed=None):
if seed is None:
self._seed = int(time.time() * 1000) # 更精确的时间戳
else:
self._seed = seed
self.multiplier = 1664525
self.increment = 1013904223
self.modulus = 2 ** 32
def next_int(self):
self._seed = (self.multiplier * self._seed + self.increment) % self.modulus
return self._seed
def randint(self, a, b):
return a + int((b - a + 1) * (self.next_int() / self.modulus))
def getrandbits(self, n):
"""最大支持 32 位随机数"""
return self.next_int() >> (32 - n)
random = Random()
class RandomColor:
'''随机颜色生成器'''
def __init__(self, level=3):
self.set_level(level)
def set_level(self, level):
'''设置颜色亮度'''
self.level = level
# 映射亮度等级到明度值 V(HSV 中的 V)
self.value = {0: 2, 1: 64, 2: 128, 3: 192, 4: 224, 5: 255}[level]
def get_rgb(self, colors=[]):
'''
生成随机颜色,确保不在 exclude_colors 列表中
:param colors: 不希望生成的颜色列表,例如 [(255,0,0), (0,255,0)]
:return: RGB 元组
'''
h = random.getrandbits(8) # 模拟 getrandbits(8)
s = 255 # 固定饱和度
v = self.value # 固定亮度
new_color = self._hsv_to_rgb(h, s, v)
count = 0
while new_color in colors and count < 10:
h = (h + 32) % 256 # 色调偏移
new_color = self._hsv_to_rgb(h, s, v)
count += 1
return new_color
def adjust_to_level(self, color):
"""
将给定颜色调整到当前亮度等级
:param color: 要调整的颜色 (r, g, b)
:return: 调整后的颜色 (r, g, b)
"""
if not color: # 如果传入空值,返回黑色
return (0, 0, 0)
r, g, b = color
# 将RGB转换为HSV
h, s, v = self._rgb_to_hsv(r, g, b)
# 使用当前亮度等级替换原亮度
new_v = {0: 2, 1: 64, 2: 128, 3: 192, 4: 224, 5: 255}[self.level]
# 转换回RGB
return self._hsv_to_rgb(h * 255, s * 255, new_v)
def _rgb_to_hsv(self, r, g, b):
"""
RGB转HSV (辅助方法)
:return: (h, s, v) 各分量范围 0-1
"""
r, g, b = r / 255.0, g / 255.0, b / 255.0
max_val = max(r, g, b)
min_val = min(r, g, b)
diff = max_val - min_val
# 计算色调(H)
if diff == 0:
h = 0
elif max_val == r:
h = (60 * ((g - b) / diff) + 360) % 360
elif max_val == g:
h = (60 * ((b - r) / diff) + 120) % 360
else:
h = (60 * ((r - g) / diff) + 240) % 360
# 计算饱和度(S)
s = 0 if max_val else diff / max_val
# 计算明度(V)
v = max_val
return (h / 360.0, s, v)
def _hsv_to_rgb(self, h, s, v):
'''HSV转RGB'''
h,s,v = h % 256,s / 255.0,v / 255.0
i = h // 42.5
f = h % 42.5
p = v * (1 - s)
q = v * (1 - s * f / 42.5)
t = v * (1 - s * (1 - f / 42.5))
if i == 0:
r, g, b = v, t, p
elif i == 1:
r, g, b = q, v, p
elif i == 2:
r, g, b = p, v, t
elif i == 3:
r, g, b = p, q, v
elif i == 4:
r, g, b = t, p, v
else:
r, g, b = v, p, q
return (int(r * 255),int(g * 255),int(b * 255))
# 实例化对象
randomColor = RandomColor(level=0)