#はじめに 「__LovyanGFXグラフィックライブラリ__は描画がめちゃ早い」 といううわさを聞いたので、M5StickC PLUSで使ってみました。 M5Cameraの画像を動画で表示しています。 #コード 上の動画では画面のサイズが合ってませんが、以下のコードではM5StickC PLUSを横にした画面にちょうど良くなるよう変更してあります。M5camera の画像を、Lovyangfx 使ってM5stickC PLUSに表示。
— sull (@sullblue) December 15, 2020
すごい早い#M5stickC #M5Camera pic.twitter.com/whDOTgj0ae
#include <WiFi.h>
#include <HTTPClient.h>
#define LGFX_AUTODETECT // (1)
#include <LovyanGFX.hpp>
#include <M5StickCPlus.h>
// 接続先のSSIDとパスワード
const char ssid[] = "YOURM5CAMERASSID";
const char passwd[] = "YOURCAMERAPASSWORD";
HTTPClient http;
int httpCode;
String response;
uint8_t buff[64 * 1024] = { 0 };// カメラの画像を受け取る用のバッファ。十分な大きさが必要
static LGFX lcd;
void setup() {
Serial.begin(115200);
lcd.init();
lcd.setRotation(1);
lcd.setBrightness(128);
lcd.fillScreen(TFT_BLACK);
// WiFi つなぐ
connectWiFi();
// カメラのフレームサイズを設定する
cameraInit(); // (2)
// カメラの準備ができるのを待つ。数字は適当です
delay(1000);
}
// メインループ
void loop() {
if ( WiFi.status() != WL_CONNECTED ) {
// WiFi切れたらつなぎなおす
connectWiFi();
cameraInit();
delay(1000);
} else {
// 画像を受け取って表示する
draw_captureimage();
}
// このdelay(1)は必要
delay(1);
}
// WiFiに繋ぐ処理
void connectWiFi()
{
WiFi.begin(ssid, passwd);
Serial.print("WiFi connecting..");
while(WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.print(" connected. ");
Serial.println(WiFi.localIP());
}
// M5Cameraからの画像を受け取って表示する処理
void draw_captureimage(){
http.begin("http://192.168.4.1/capture"); // GET
httpCode = http.GET();
if (httpCode > 0) {
int len = http.getSize();
Serial.printf("[HTTP] size: %d\n", len);
if (len <= 0) {
Serial.printf("[HTTP] Unknow content size: %d\n", len);
} else {
// create buffer for read
//uint8_t buff[len] = { 0 };
// get tcp stream
WiFiClient * stream = http.getStreamPtr();
Serial.printf("[HTTP] strm ptr: %x\n", stream);
// read all data from server
uint8_t* p = buff;
int l = len;
while (http.connected() && (l > 0 || len == -1)) {
// get available data size
size_t size = stream->available();
if (size) {
int s = ((size > sizeof(buff)) ? sizeof(buff) : size);
int c = stream->readBytes(p, s);
p += c;
Serial.printf("[HTTP] read: %d\n", c);
if (l > 0) {
l -= c;
}
}
}
}
lcd.drawJpg(buff,sizeof(buff)); // 画像の描画 (3)
} else {
Serial.println("Error on HTTP request");
Serial.println(httpCode);
}
http.end();
Serial.println();
Serial.print("[HTTP] connection closed.\n");
}
// カメラのフレームサイズを設定 (2)
void cameraInit(){
// 画像サイズをQVGAに設定
// これがM5StickC PLUSの画面にちょうどいいサイズ感
http.begin("http://192.168.4.1/control?var=framesize&val=3");
httpCode = http.GET();
if (httpCode > 0) {
Serial.println("status");
response = http.getString();
Serial.println(httpCode);
Serial.println(response);
} else {
Serial.println("Error on HTTP request");
Serial.println(httpCode);
}
http.end();
}
#ちょっとだけ説明
(1)#define LGFX_AUTODETECT
LovyanGFXがLCDのサイズを自動的に判別するという定義。
現在は次の定義でもいけるそうです。(LovyanGFX 0.3.4情報)
#define LGFX_M5STICK_C
(2)カメラのフレームサイズをQVGAに設定
もっと大きなサイズでも取得はできますが、LCDに収まらないので一部しか見れません。
大きな画像を受け取りたいときはバッファサイズも変更したほうがいいと思います。
(3)lcd.drawJpg(buff,sizeof(buff));
これを使うためにLovyanGFXを導入したのだ
#実行結果
#おわりに 上にも書きましたが、LovyanGFXを使うと決めたのは__drawJpg()__が使えるようになるからです。 M5StickCのライブラリにはdrawJpg()がないんです! M5Stackにはあるのに! >(追記) GitHubのソースを追ってみたのですが、どうもM5StickC PLUSはソースにはdrawJpg()あるけど使うことはできないという状況みたいです。謎。設定変えてみた。こっちのほうがいいっぽいな pic.twitter.com/9nfvs4HIFC
— sull (@sullblue) December 15, 2020
M5Cameraの画像はjpeg形式で送られてくるわけで、それが描画できないというのはけっこう問題でした。
それと、先人のブログなどを拝見していると皆さん__画像表示の遅さ__には苦労しておられるようで...
それがLovyanGFXの登場で圧倒的に早くなったわけですから、これは是非やってみたいと思った次第でした。
先人の皆様と、ライブラリ作者の@lovyan03さんに深く感謝です。
###参考文献
github - LovyanGFX
Androidのカメラ映像をMotionJPEGで配信する
ESP32でビットマップ画像ファイルを生成し、ブラウザに連続送信してMotion JPEGならぬMotion BMP動画ストリーミングする実験
#おまけ
IMU × LovyanGFX
理解が深まってきた#M5stickC pic.twitter.com/nKXoYCkwcC
— sull (@sullblue) December 13, 2020