我有一大堆可寻址的WS2811LED串和一块ESP-CAM板(一块带摄像头的ESP32开发板)。只有一个可能的项目可以使用这些组件来完成。把杂乱无章的灯光变成更有组织的东西。
作为额外的好处,我最终用JavaScript复制了图像处理代码,因此您甚至不需要在ESP32板上安装摄像头-您只需使用普通的开发板来驱动LED即可。
您可以在下面的视频中看到我努力的结果,我将在下面的文本中详细介绍代码。
如果您想自己做这件事,那么您将需要某种类型的ESP32开发板,当然,您还需要某种可寻址的LED。我使用FastLED库来驱动LED,因此只需稍加修改代码,您就可以支持几乎任何可寻址的LED。
我们的挑战归结为一个非常基本的问题,即从摄像机获取图像流时,每个LED在2D空间中的大致位置。完成此操作后,将每个LED的x和y位置映射到包含您想要显示的图案的帧缓冲区就是一个简单的问题。
有一堆模板代码来初始化ESP-CAM-我从这里的示例代码中获得了灵感,并复制了我需要的部分来启动和运行相机。
我所做的一个重要更改是仅以最低帧大小捕获灰度图像:
我们的Frame类获取像素的副本以及图像的宽度和高度。
像素=(uint8_t*)malloc(FB-&>;高度*FB-&>;宽度);memcpy(像素,FUF-&>;BUF,FB-&>;高度*FB-&>宽度);WIDTH=FB-&>宽度;高度=FB-&>;高度;长度=FB-&>;宽度*FB-&>;高度;
对于此代码的JavaScript版本,情况稍微复杂一些。最大的问题之一是我们需要在HTTPS上运行才能访问摄像头-在稍后的…上有更多内容。。
常量流=等待导航器。媒体设备。getUserMedia({video:{facingMode:";Environment";},dio:false,});const canPlayListener=()=>;{//视频加载完毕,我们可以在VideoReady(Video);video上抓帧。removeEventListener(";CanPlay";,canPlayListener);};视频。addEventListener(";canPlay";,canPlayListener);视频。srcObject=流;视频。play();
一旦我们有了来自摄像机的视频流,我们就可以通过将视频绘制到画布上下文,然后从其中获取ImageData来抓取帧。
函数getVideoFrame(video:HTMLVideoElement,Canvas:HTMLCanvasElement){const width=video。VideoWidth;常量高度=视频。VideoHeight;Const Context=Canvas。getContext(";2d";);//将视频绘制到画布上下文!drawImage(video,0,0,width,Height);//获取原始图像字节const ImageData=context!getImageData(0,0,width,Height);//转换为灰度常量字节=new Uint8Array(width*Height);for(设y=0;y<;Height;y++){for(设x=0;x<;width;x++){const r=ImageData。data[(y*width+x)*4];const g=ImageData。data[(y*width+x)*4+1];const b=ImageData。数据[(y*宽度+x)*4+2];//https://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale常量灰度=数学。MIN(255,0.299*r+0.587*g+0.114*b);字节[y*宽度+x]=灰色;}}返回字节;}。
现在我们可以抓取帧了,我们只需要抓取一个没有LED点亮的帧,点亮一个LED,抓取另一个帧,然后比较这两个帧。不同之处应该能告诉我们LED在哪里。为了避免噪声或相机的微小移动产生一点影响,我们在获取差异之前对捕获的帧应用高斯模糊。
这当然是一个非常幼稚和简单的算法,可以很容易地改进。
在ESP32的C++代码中,我们直接在代码中完成所有这些操作。在JavaScript版本中,我们在ESP32的Web接口上调用API函数来打开和关闭LED,一旦我们完成处理,就将计算出的LED位置发送到电路板上。
在我们的ESP32代码中,我们创建了一个帧缓冲区,并在其中绘制模式。然后,我们使用每个LED的位置来计算出它应该是什么颜色。
为了解决摄像头需要HTTPS访问,同时API调用也需要HTTPS的问题(现在不能混合内容!)。我们需要一种通过HTTPS从ESP32 Web服务器同时提供UI和API的方法。有一些Web服务器支持HTTPS和ESP32可用的自签名证书,但这会导致其他问题,需要重写设备代码。解决此问题的一个简单方法是使用诸如ngrok之类的服务来提供从云通过我们的计算机到ESP32设备的安全URL。有点费解,但很管用!
仅当您不使用ESP-CAM并且必须使用手机的摄像头来校准LED时才需要此功能。向ngrok注册免费帐户,然后找到您的ESP32主板的IP地址:
ping espcam.localPING espcam.local(10.0.1.17):56个数据字节10.0.1.17:icmp_seq=0ttl=255time=14.343 ms 10.0.1.17:icmp_seq=1ttl=255 time=6.493 ms。
你需要稳定的手-有相当长的等待时间,所以打开和关闭LED到抓取相框之间的空间可能相当大。当我拿着相框来显示位置时,我稍微移动了一下,所以位置稍微偏了一点。
查看这段视频,看看它有多好-对于如此简单的算法来说,这是令人惊讶的。