バーサライタに映像を無線転送
前回、ESP32で割り込みやマルチタスクを駆使してバーザライタの高分解能化に成功いたしました。
今回は画像や動画をWiFiで転送して表示に成功いたしましたのでご報告します。
目次
UDPで静止画送信
UDP通信でWiFi介して静止画をバーサライタ装置に転送します。
Node-REDのDashboardノードで画像選択のボタンをこしらえて、Pythonで選択された画像の縮小とバーサライタ用にデータ変換を実施してUDP送信しています。
Node-RED設定
Node-REDでボタンなどのUI表示と選択した画像の名前をPythonに送ります。
①ダッシュボード ボタン表示
node-red-dashboardのbutton nodeでボタンUIを表示します。
3画像用意してバーサライタに表示させます。
Group:ダッシュボードノードを表示させるグループ名を決めて選択します。
Icon:ボタンに表示させる画像を選択します。
Label:ボタンの表記
Payload:ここでは画像名を次段に送ります。
②ファンクションノード
3つのボタンのノードをまとめるためにファンクションノードを配置
③ダッシュボード テキスト表示
node-red-dashboardのtext nodeで選択されたボタンのPayloadをダッシュボードに表示させます。
Group:ダッシュボードノードを表示させるグループ名を決めて選択します。
Label:テキスト欄に表示させる画像を選択します。
Value format:表示させるテキストを選択。ここではボタンノードからのPayloadを指定。
Dashboardタグを選択して表示ボタンでダッシュボード画面が表示されます。
ダッシュボード
④Python実行
exec nodeでPythonコードを起動させます。
Command:Pythonコード実行させるバッチファイルを指定。(Windows PC使用)
Append:引数にPayloadをチェック入れて画像名を送っています。
以下がバッチファイルの内容です。引数1個をもってpythonコードを起動します。
1 |
python C:\Users\hirot\workspace\0_python\povUdp02.py %1 |
Pythonコード
ダッシュボードボタンで選択された画像ファイル名を受けて、その画像を変換してUDPでバーサライタに映像情報を送信します。
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 |
# -*- coding: utf-8 -*- import socket import cv2 import os import sys import math from PIL import Image args = sys.argv #配列設定 NUMPIXELS = 57 #LEDの数 Div = 200 #1周の分割数 Bright = 30 #輝度 Led0Bright = 1 #中心LEDの輝度 [%] #UDP設定 sendAddr = ('192.168.255.255', 1234) #ブロードキャスト udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #画像データ pic = 'C:/Users/xxxx/0_python/' + args[1] #画像変換関数 def polarConv(pic): imgOrgin = cv2.imread(pic) #画像データ読み込み h, w, _ = imgOrgin.shape #画像サイズ取得 #画像縮小 imgRedu = cv2.resize(imgOrgin,(math.floor((NUMPIXELS * 2 -1)/h *w), NUMPIXELS * 2 -1)) #縮小画像中心座標 h2, w2, _ = imgRedu.shape wC = math.floor(w2 / 2) hC = math.floor(h2 / 2) #極座標変換 for j in range(0, Div): data = '%02X' % j for i in range(0, hC+1): #座標色取得 #参考:http://peaceandhilightandpython.hatenablog.com/entry/2016/01/03/151320 rP = int(imgRedu[hC + math.ceil(i * math.cos(2*math.pi/Div*j)), wC - math.ceil(i * math.sin(2*math.pi/Div*j)), 2] * ((100 - Led0Bright) / NUMPIXELS * i + Led0Bright) / 100 * Bright /100) gP = int(imgRedu[hC + math.ceil(i * math.cos(2*math.pi/Div*j)), wC - math.ceil(i * math.sin(2*math.pi/Div*j)), 1] * ((100 - Led0Bright) / NUMPIXELS * i + Led0Bright) / 100 * Bright /100) bP = int(imgRedu[hC + math.ceil(i * math.cos(2*math.pi/Div*j)), wC - math.ceil(i * math.sin(2*math.pi/Div*j)), 0] * ((100 - Led0Bright) / NUMPIXELS * i + Led0Bright) / 100 * Bright /100) #送信データ配列に格納 data += '%02X%02X%02X' % (rP,gP,bP) if i == hC: #udp.sendto(data[0].encode('utf-8'), sendAddr) udp.sendto(data.encode('utf-8'), sendAddr) #変換 polarConv(pic) #UDPクローズ udp.close() |
Arduinoコード
pythonから送られた画像データを受けてバーサライタに表示させます。
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 133 134 135 136 137 138 139 140 141 142 |
#include <SPI.h> #include "Adafruit_DotStar_VSPI.h" #include "Adafruit_DotStar_HSPI.h" #include "WiFi.h" #include "AsyncUDP.h" const char * ssid = "WiFi SSID"; const char * password = "Pass"; AsyncUDP udp; #define NUMPIXELS 57 #define NUMPIXELS2 29 // Number of LEDs in strip #define Div 200 #define itrPin 34 uint32_t pic[Div][NUMPIXELS] = {0, }; int num = 0; int num2 = 0; int numDiv = 0, numDiv2 = 0; int stateRot = 0; int stateDiv = 0; int stateDiv2 = 0; unsigned long rotTime, timeOld, timeNow; Adafruit_DotStar_VSPI stripV = Adafruit_DotStar_VSPI(NUMPIXELS2, DOTSTAR_BGR); Adafruit_DotStar_HSPI stripH = Adafruit_DotStar_HSPI(NUMPIXELS2, DOTSTAR_BGR); char chararrayDiv[] = "0x00"; char chararrayColor[] = "0xffffff"; //LED2点灯 void LED2(void *pvParameters) { for (;;){ disableCore0WDT(); if(stateDiv2 == 1){ stripH.clear(); for(int i=0;i<NUMPIXELS2; i++){ stripH.setPixelColor(i, pic[numDiv][i*2+1]); } stripH.show(); stateDiv2 = 0; } } } void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); if (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("WiFi Failed"); while(1) { delay(1000); } } //UDP受信 if(udp.listen(1234)) { udp.onPacket([](AsyncUDPPacket packet) { chararrayDiv[2] = packet.data()[0]; chararrayDiv[3] = packet.data()[1]; Serial.println(int(strtoul(chararrayDiv, NULL, 16))); for(int i = 0; i <NUMPIXELS ; i++){ for(int j = 0; j < 6 ; j++){ chararrayColor[j+2] = packet.data()[2 + i*6 + j]; } pic[int(strtoul(chararrayDiv, NULL, 16))][i] = strtoul(chararrayColor, NULL, 16); } }); } stripV.begin(); stripV.clear(); stripV.show(); stripH.begin(); stripH.clear(); stripH.show(); pinMode(itrPin, INPUT); delay(500); attachInterrupt(digitalPinToInterrupt(itrPin), RotCount, RISING ); //LED2点灯 タスク xTaskCreatePinnedToCore( LED2 , "LED2" // A name just for humans , 4096 // This stack size can be checked & adjusted by reading the Stack Highwater , NULL , 1 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. , NULL , 0); } void loop() { if(stateDiv == 1 &µs() - timeOld > rotTime / Div * (numDiv)){ stateDiv = 0; } if(stateDiv == 0 && micros() - timeOld < rotTime / Div * (numDiv + 1)){ stateDiv = 1; stateDiv2 = 1; stripV.clear(); for(int i=0;i<NUMPIXELS2; i++){ numDiv2 = numDiv+2; if(numDiv2 >= Div) numDiv2 -= Div; stripV.setPixelColor(i, pic[numDiv2][i*2]); } stripV.show(); numDiv++; if(numDiv >= Div ) numDiv = 0; num++; if(num > 3 ) num = 0; } } void RotCount() { timeNow = micros(); rotTime = timeNow - timeOld; timeOld = timeNow; } |
動作
静止画転送できた! pythonで画像縮小、座標変換してUDP送信。パソコンのUIはNode-REDで作成。画像選択ボタンクリックでUDP送信開始。転送漏れがたまにある。目標の動画転送の実現は近い 気がする。#ESP32 #バーサライタ #python #nodeRED pic.twitter.com/eIKM40FbSp
— HomeMadeGarbage (@H0meMadeGarbage) 2019年3月10日
たまに取りこぼしあるけど画像伝送実現できました!わーい 😛
ダッシュボードノードのボタンで画像が切り替わります。
動画転送
動画転送も試してみました。PythonでGIFファイルをフレームごとに変換してバーサライタに転送します。
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 |
# -*- coding: utf-8 -*- import socket import time import cv2 import os import sys import math from PIL import Image args = sys.argv #配列設定 NUMPIXELS = 57 #LEDの数 Div = 100 #1周の分割数 unit = 1 #送信列数 Bright = 30 #輝度 Led0Bright = 1 #中心LEDの輝度 [%] #UDP設定 sendAddr = ('192.168.0.255', 1234) udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #画像データ #gif_file_name = 'C:/Users/hirot/workspace/0_python/' + args[1] #gif_file_name = 'C:/Users/hirot/workspace/0_python/03-Baby-giphy-3.gif' gif_file_name = 'C:/Users/hirot/workspace/0_python/gifmagazine.gif' #画像変換関数 def polarConv(imgOrgin): #imgOrgin = cv2.imread(pic) #画像データ読み込み h, w, _ = imgOrgin.shape #画像サイズ取得 #画像縮小 imgRedu = cv2.resize(imgOrgin,(math.floor((NUMPIXELS * 2 -1)/h *w), NUMPIXELS * 2 -1)) #縮小画像中心座標 h2, w2, _ = imgRedu.shape wC = math.floor(w2 / 2) hC = math.floor(h2 / 2) #極座標変換 k = 0 for j in range(0, Div): if (j % unit) == 0: data = '%02X' % j for i in range(0, hC+1): #座標色取得 #参考:http://peaceandhilightandpython.hatenablog.com/entry/2016/01/03/151320 rP = int(imgRedu[hC + math.ceil(i * math.cos(2*math.pi/Div*j)), wC - math.ceil(i * math.sin(2*math.pi/Div*j)), 2] * ((100 - Led0Bright) / NUMPIXELS * i + Led0Bright) / 100 * Bright /100) gP = int(imgRedu[hC + math.ceil(i * math.cos(2*math.pi/Div*j)), wC - math.ceil(i * math.sin(2*math.pi/Div*j)), 1] * ((100 - Led0Bright) / NUMPIXELS * i + Led0Bright) / 100 * Bright /100) bP = int(imgRedu[hC + math.ceil(i * math.cos(2*math.pi/Div*j)), wC - math.ceil(i * math.sin(2*math.pi/Div*j)), 0] * ((100 - Led0Bright) / NUMPIXELS * i + Led0Bright) / 100 * Bright /100) #送信データ配列に格納 data += '%02X%02X%02X' % (rP,gP,bP) k+=1 if k == unit: k = 0 udp.sendto(data.encode('utf-8'), sendAddr) #GIF変換 while True: gif = cv2.VideoCapture(gif_file_name) while True: is_success, frame = gif.read() # ファイルが読み込めなくなったら終了 if not is_success: break #変換 polarConv(frame) #time.sleep(0.01) #UDPクローズ udp.close() |
動作
バーサライタにUDPでGIF転送実験。1周の分解能200→100にしたけどスロー。なかなか難しいな#ESP32 #ザコシGIF #バーサライタ pic.twitter.com/4gobxeobWy
— HomeMadeGarbage (@H0meMadeGarbage) 2019年3月11日
バーサライタの1周の分解能を200から100に減らして転送しているのですが、遅い。。。
転送量をギリギリまで増やして送信漏れもないようにうまいことできるように引き続き勉強します! 😆