##はじめに
qiita adavent calender 2020 12/24の記事です
始めての投稿なのでご容赦ください
ESP32のSPIFFSから画像データ(bitmap)を送りたかったので簡単な画像転送用のプログラムを作った話です
環境
送信側
・ESP32(Arduino)
受信側
・python
コード
まず、ESP32側で必要なライブラリを読み込み、シリアルbluettohを始めます
#include <SPIFFS.h>
#include <FS.h>
#include <BITMAPDecoder.h>
#include "BluetoothSerial.h"
BITMAPDecoder bitmap = BITMAPDecoder();
BluetoothSerial SerialBT;
void setup(){
SerialBT.begin("ESP32");
}
次にESP32側でループ処理に入り信号(f)を待たせます
void loop() {
if(SerialBT.available() > 0){
int i = SerialBT.read();
if(i == 'f')
その間python側を起動させます
python側で、ライブラリをインポートし、新しくイメージオブジェクトを生成します
import serial
from io import BytesIO
from PIL import Image
import time
img = Image.new('RGB',(32,32))
今回はサイズを決めています
次に、python側からシリアルbluetoothを開き、信号(f)を送信します
ser = serial.Serial('/dev/cu.ESP32-ESP32SPP',115200,timeout=None)
time.sleep(2)
ser.write(b"f")
ここで少し間を入れておかないと、処理が追いつかなくなるようです
送信に関して
bitmapの左上から右上、戻って、1pixel下げて左から右を繰り返す形になります。
信号(f)を受信したESP32はSPFFSから画像ファイルを呼び出し、各pixelのRGBを読み込みます
ここで@DeepSpawnさんのライブラリを使用させていただきました
{
SPIFFS.begin();
File fp;
fp = SPIFFS.open( "/sample.bmp","r" );
bitmap.checkFile( fp );
for( int Y=0 ; Y<bitmap.height() ; Y++ ){
for( int X=0 ; X<bitmap.width() ; X++ ){
PIXEL p = bitmap.readPixel( fp, X, Y );
ただ、RGBの配列のままだと一度に送ることができないので、16進数に変換して送信します
int hex = p.r * 65536 + p.g * 256 + p.b;
SerialBT.println(hex,HEX);
そして送信に成功することを確認する信号(r)を待ちます
for(char i;i != 'r';){
i = SerialBT.read();
}
}
その間、python側で各pixelのカラーコードを受信し、信号(r)を送信、各pixelに色を当てはめます
while True:
color = ()
for h in range(32):
for w in range(32):
date = ser.readline()
date_str = date.decode('utf-8')
date_fix = date_str.strip("\r\n")
ten = int(date_fix,16)
color = (int(ten/65536),int(ten%65536/256),int(ten%256))
ser.write(b"r")
img.putpixel((w+1,h+1),color)
これらの処理を何度か繰り返したのち、ESP32側でファイルを閉じます
fp.close();
}
Python 側ではImageオブジェ9tをファイルとして保存します
img.save('deta.jpg')
コード全体としては以下の通りです
#include <SPIFFS.h>
#include <FS.h>
#include <BITMAPDecoder.h>
#include "BluetoothSerial.h"
BITMAPDecoder bitmap = BITMAPDecoder();
BluetoothSerial SerialBT;
void setup(){
SerialBT.begin("ESP32");
}
void loop() {
if(SerialBT.available() > 0){
int i = SerialBT.read();
if(i == 'f'){
SPIFFS.begin();
File fp;
fp = SPIFFS.open( "/sample.bmp","r" );
bitmap.checkFile( fp );
for( int Y=0 ; Y<bitmap.height() ; Y++ ){
for( int X=0 ; X<bitmap.width() ; X++ ){
PIXEL p = bitmap.readPixel( fp, X, Y );
int hex = p.r * 65536 + p.g * 256 + p.b;
SerialBT.println(hex,HEX);
for(char i;i != 'r';){
i = SerialBT.read();
}
}
}
fp.close();
}
}
}
import serial
from io import BytesIO
from PIL import Image
import time
img = Image.new('RGB',(32,32))
ser = serial.Serial('/dev/cu.ESP32-ESP32SPP',115200,timeout=None)
time.sleep(2)
ser.write(b"f")
while True:
color = ()
for h in range(32):
for w in range(32):
date = ser.readline()
date_str = date.decode('utf-8')
date_fix = date_str.strip("\r\n")
ten = int(date_fix,16)
color = (int(ten/65536),int(ten%65536/256),int(ten%256))
ser.write(b"r")
img.putpixel((w,h),color)
print(w)
print(h)
else:
img.save('deta.jpg')
問題点
1.この方式では画像形式でしか対応していないこと(bitmap)
2.容量に制限がかかるSPIFFSからしかファイル呼び出せないこと
3.どうしても、速度が遅くなること
古典的な方法を使っているためどうしてもこのような問題点が出てきてしまいます
そこで
1.読み出し方法をpixel単位から、buffaを分割する方法を取る
2.SDカード等への対応
3.Bluetoothサーバーへの書き換えや、変数のデータを圧縮する方法が取れる
などの問題解決をGithub上でやろうと感じています。
最後に
bitmap読み込みライブラリを作ってくださった@DeepSpawnさま、藪からに質問をさせていただいた学校の知人の皆様、ありがとうございました!!