ESP32でビットマップ画像ファイルを生成し、ブラウザに連続送信してMotion JPEGならぬMotion BMP動画ストリーミングする実験

ESP32,でビットマップ画像を生成し、Motion,JPEG,でブラウザに動画ストリーミングさせてみた。 ESP32 ( ESP-WROOM-32 )

ビットマップ(BMP)ファイル(拡張子 .bmp)の作り方

では、Motion JPEG をやる前に、ビットマップ画像の作り方を紹介します。
以下、Windows 10環境で説明します。

Motion JPEG (MJPEG)では、一般的にJPEG画像を扱いますが、JPEG画像というのは圧縮されていて、構成がとても複雑です。
私の様なアマチュアプログラマではまだまだ勉強不足で、敷居が高いのです。
というわけで、まずはビットマップ(BMP)画像から扱います。

ビットマップファイルのフォーマットはネット上で多くの情報があります。
私は碧色工房さんの以下の記事を参考にさせていただきました。

BMPファイルフォーマット(Windows)

まず、ビットマップファイルのフォーマットを理解するために、パソコンでピットマップファイルを一から作ってみます。
ここでは、RGB565方式を使い、4 x 1 pixel で、赤、緑、青、白という並びの、ごく小さい画角のビットマップファイルを作成してみます。

RGB565は当ブログで過去何度も紹介してきたとおり、1pixel当たり2byteのデータ量だけで済むので、できるだけ高速通信を目指せます。
解像度設定やカラーパレット設定はしません。
よって、画像の実データ直前までのヘッダは合計66byteです。

作成にはバイナリエディタを使います。
私はフリーのStirlingを使いました。
Vector等のサイトで入手できます。
一応、Windows 10 でも問題無く使えています。

バイナリエディタを起動したら、下図を参考にして16進数で数値を入力していきます。
ファイルサイズは
0x4A = 74 byte
あります。

注意していただきたいのは、このバイナリデータの末尾のアドレスが0x49なので、それがファイルサイズかと勘違いし易いのですが、0x49 + 1 = 0x4A が正しいです。
なぜなら、最初のバイトのアドレスがゼロから始まっているからです。

頭の66byte分がヘッダ情報で、上図のピンク色のところが実際の画像ピクセルデータです。
ヘッダ情報についてのザッとした解説は以下です。

  1. 英大文字”BM” 2byte表記
  2. ファイルサイズ 4byte表記
  3. 予約領域1(常にゼロ) 2byte表記
  4. 予約領域2(常にゼロ) 2byte表記
  5. 画像実データまでのオフセットバイト数(常に66 byte = 0x42) 4byte表記
    ————————————-
  6. 情報ヘッダサイズ(常に40 byte = 0x28) 4byte表記
  7. 画像幅(pixel数) 4byte表記
  8. 画像高さ(pixel数) 4byte表記
  9. 画像プレーン数(常に1) 2byte表記
  10. 色bit数(ここでは16 bit = 0x10) 2byte表記
  11. 圧縮形式(RGB565 16 bitの場合、3にする) 4byte表記
  12. 画像データサイズ 4byte表記
  13. X Pixels Per Meter(水平方向の解像度。使わない場合ゼロ) 4byte表記
  14. Y Pixels Per Meter(垂直方向の解像度。使わない場合ゼロ) 4byte表記
  15. Color Used(カラーパレット方式を使わない場合ゼロ) 4byte表記
  16. 重要色数(使わない場合ゼロ) 4byte表記
    ——————————————-
  17. カラーマスク(RGB565の場合、ここでは赤色マスク) 4byte表記
  18. カラーマスク(RGB565の場合、ここでは緑色マスク) 4byte表記
  19. カラーマスク(RGB565の場合、ここでは青色マスク) 4byte表記
  20. 実データ(※リトルエンディアン、つまり、下位バイトから先に書き込む)

冒頭の2バイトは、
「このファイルはビットマップ画像だよ!」
ということ表す “BM” という半角大文字をASCIIコード16進数で表したものです。
‘B’ = 0x42
‘M’ = 0x4D
となるので、書き込む順番はそのままですね。

次のファイルサイズから概ね4byte毎の区切りになります。
そして、リトルエンディアンで入力していくことになります。
リトルエンディアンという用語は、アマチュアには意味不明な用語だと思います。
私も最初は分らず、専門用語大嫌いだったので、読み飛ばしていました。

要するに、下図の様にただ単に下位バイトから先に入力していくことをリトルエンディアンというようです。

例えばファイルサイズが73byteだとすると、
73 = 0x49
となり、これは4byte(32bit)表記にすると、
0x00 00 00 49
という並びになりますが、これをリトルエンディアンにすると、下位バイトから先に入力していくので、
0x49, 0x00, 0x00, 0x00
という並びになります。
分かってしまえばそれほど難しくないですね。
もうかれこれ1か月以上もこの用語に触れていたので、今はもう慣れてしまいました。
こうやってド素人だった自分でも専門用語だらけになってしまうんだろなぁ。。。

次に、情報ヘッダサイズは、上記の6~16番までの合計バイト数で、40 = 0x28 となります。

13番~16番は、今回設定しないのでゼロとします。

カラーマスクについては、ちょっと難しいです。
今回扱うRGB565フォーマットの場合、1pixel が2byteデータです。
(RGB565については、こちらの記事でも少し述べていますので、参照してみてください。)
この2byteのカラーデータをカラーマスクによって、RGBの各値に分離する役目があります。

カラーマスクは4byteデータですが、RGB565の場合は下位の2バイト分だけ使います。
下図の様に赤色マスクの場合、RGB565データの赤色の部分の5bitだけ1になっています。
そのマスクと実際の色データをAND演算すると赤色部分だけ抽出されるというわけです。

このマスクの構成を変えるだけで、RGB888 やRGB444データも扱えるわけです。
それに、色の順番を入れ替えれば、RGB順をBGR順に色反転することもできるわけです。

それぞれのカラーマスクをリトルエンディアン並びにすると、下図の様になります。

そして、このリトルエンディアンにした値をバイナリエディタに入力していきます。

では、次に画像の実データ領域を説明します。

座標(0, 0) 位置のpixel が赤色ならば、
11111000, 00000000
というデータになります。
16進表記では、
0xF8, 0x00
となります。
それをリトルエンディアン並びにすると、
0x00, 0xF8
という順番で入力していきます。

同じく続けて座標(0, 1)位置のpixelが緑色ならば、
00000111, 11100000
となり、16進表記では、
0x07, 0xE0
となります。
リトルエンディアンにして、
0xE0, 0x07
とバイナリエディタに入力していきます。
これを続けて順番に入力行けば、画像データが出来上がります。
座標位置情報は入力する必要無く、ただ単にpixel色を順番に並べていくだけです。

ただ、注意してほしいのは、ビットマップ画像は通常の液晶ディスプレイの座標位置と異なり、下図の様に上下逆になっていて、左下から描画されていきます。
それを考えながら入力していく必要があります。

ということは、自分のように過去に何度も液晶ディスプレイを駆動してきた者としては、上下を反転させたくなりますね。
その場合、HTMLのスタイルシートで上下反転させてやればOKです。
その方法は後で述べます。

そして、もう一つ注意して欲しいのは、実データのデータサイズやファイルサイズ、画像幅などが矛盾していないか確認することです。
どれかを間違えると、画像は表示されません。
特に、バイナリファイルを直入力して、pixelを増やす時に、画像幅やファイルサイズ、データサイズの変更を忘れないように注意してください。
私は何度もやらかしました、、。

では、バイナリエディタで入力し終わったら、拡張子を.bmpにして名前を付けて保存します。
たとえば、
RGB.bmp
みたいな感じです。

そうしたらブラウザを起動して、ビットマップファイルをドラッグ&ドロップしてみます。
あるいは、URL入力欄にファイルのパスを入力しても良いです。
その場合は、¥マークは使わずにスラッシュ’/’にしてください。

(例)
file:///C:/Users/自分のユーザー名/Desktop/test/RGB.bmp

表示させたら、あまりにも画素が小さいので、500%に拡大して見てみます。
下図の様に小さいpixelが左から赤、緑、青、白の順で並んでいればビットマップファイルの作成成功です。

ちゃんと自分の意図した位置にカラーが表示されていればOKです。

ここまでできて、ビットマップファイルの作り方が理解できれば、Arduinoプログラミングは出来たも同然です。
ESP32やM5Stackを使ってビットマップファイルを自在に作ることができます。

ビットマップファイルのヘッダは様々な圧縮モードがあったり、カラーパレットを使う場合があったりして、いろいろ設定可能です。

では、次はArduino core for the ESP32でWiFiでブラウザにビットマップファイルを連続送信して動画ストリーミングする方法を説明します。

コメント

タイトルとURLをコピーしました