ESP32+MicroPython随机颜色生成器

概述

本文档将介绍一个基于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)




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunsunyu03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值