7.3インチ7色カラー電子ペーパーを使った実用的なフォトフレーム


はじめに

以前5.65インチの7色カラー電子ペーパーを使用してフォトフレームを作成しましたが、7.3インチの7色カラー電子ペーパーを入手したので、改良したフォトフレームを作りました。

画像の変換

今回使用する電子ペーパーは7色(黒、白、緑、青、赤、黄、橙)しか表示できないため、表示したいフルカラーの画像を減色する必要があります。 前回7色電子ペーパーを使った際には何も考えずに、サンプルコードのとおりに原色のパレットを使って変換していました。 しかしながら実際にカラー電子ペーパーで表示できるのはややくすんだ色になります。 下記の画像は、原色を使ったオリジナルの画像データと、販売元の商品ページにあった表示サンプルです。

元の画像
実機での表示

この実際の表示例からRGBの値を調べると、下記のようなパレットになりました

原色のパレット 実機のパレット
( 0, 0, 0) ( 35, 30, 53)
(255, 255, 255) (233, 235, 234)
( 0, 255, 0) ( 53, 102, 78)
( 0, 0, 255) ( 51, 53, 118)
(255, 0, 0) (203, 85, 82)
(255, 255, 0) (235, 215, 100)
(255, 127, 0) (207, 120, 95)

画像を減色する際に原色のパレットではなく実機のパレットを使うことで、表示される画像が格段に良くなります。 以下に実際に変換した画像を示します。 左がオリジナルの画像、中央が原色のパレットで変換して実機で表示したもの、右が実機のパレットで変換して実機で表示したものです。

使用したパレットによる表示結果の違い

原色のパレットを使った場合は色がかなりくすんでいるのに対して、実機のパレットを使った場合は色の再現度が高くなっています。 色がくすむ問題が改善されるだけではなく、原色で表現できない中間調の色に対して誤差拡散法(ディザリング)が過剰に適用されてザラつきが多くなってしまうという問題が軽減されます。 人肌の表現などが改善しました。 なお下記の画像は、原色のパレットで変換した結果(左)と実機のパレットで変換した結果(右)を、両方とも原色のパレットを使って表示したものです。

原色のパレットで表示した結果

実機のパレットで変換したものを原色のパレットで表示すると、かなり誇張した色合いになります。

フルカラーの画像を実機のパレットを使って減色するには、Pythonで次のように変換できます。

from PIL import Image
pal_ideal  = [ 0,  0,  0, 255, 255, 255,  0, 255,  0,  0,  0, 255, 255,  0,   0, 255, 255,   0, 255, 127,   0]
pal_actual = [35, 30, 53, 233, 235, 234, 53, 102, 78, 51, 53, 118, 203, 85,  82, 235, 215, 100, 207, 120,  95]
palimg = Image.new('P', (1, 1))
palimg.putpalette(pal_actual + pal_actual[-3:] * 249)
img = Image.open('INPUT.jpg').quantize(palette=palimg)
img.putpalette(pal_ideal + pal_ideal[-3:] * 249)
img.save('OUTPUT.png')
#img.save('OUTPUT.gif', interlace=False, palette=pal_ideal, comment='')  # for GIF with the fixed palette.

このコードはPNGファイルを出力しますが、今回作成するフォトフレームはパレットを固定したGIFファイルのみを扱えるので、最後の行のコメントをはずして使います。

ところで、これまで「実機のパレット」としてきましたが、これは販売元の商品紹介ページの画像から得たパレットであり、実際の商品ではさらにややくすんだ色となります。 そこで、より実際に近いパレットを使って変換したところ、これまでの「実機のパレット」を使った場合よりも画質が悪くなりました。 できるだけ実機に忠実なパレットを使った方がきれいに表示できるというわけではなさそうです。 具体的には、全体的な色の再現度は向上したものの、パレット中に暗い色しかないため、誤差拡散法で中間色を表現するために白色が多用されてノイジーな画像になりました。 そこで、色の再現度は多少犠牲にしてでも、誤差拡散法により画像がノイジーになるのを防ぐようにパレットの最適化をできないか試してみました。 手法としては、k-means法を使って画像中の色を7つのクラスターに分けてそのクラスターの代表色をパレットとして減色処理を行いました。 使用したPythonのスクリプトはこちらです。 いくつかの画像で試しましたが、実機のパレットを使った場合よりも悪くなる場合が多かったので、どのような画像に対しても最適なパレットを得るにはまだ改良が必要なようです。

ハードウェア

今回使用した7色カラーの電子ペーパーは,Waveshare社の7.3inch e-Paper HAT (F)というもので解像度は800x480です。 SPI通信で制御します。

電子ペーパーの制御には、画像の格納に利用可能な大きめのフラッシュメモリを備えていることからESP32を使います。 前回は16MBのフラッシュメモリを搭載したESP32を使いましたが、今回は通常の4MBのタイプを使いました。 市販のシンプルなアダプターボードにハンダ付けして使いました。 このアダプターボードには、ファームウェア書き込みのためにGPIO0に接続されプルアップされたタクトスイッチがついていますが、このスイッチをフォトフレームの操作にも使用します。

電源は単三電池2本を使い、未使用時はESP32と電子ペーパーをディープスリープさせます。 全体の消費電流は、ディープスリープ時で10μA以下、画面書き換え時で160mA程度でした。 画面書き換えには35秒かかるので、アルカリ電池を使用した場合1日数回書き換えたとして1年程度もつと思います。 バッテリー電圧が2.3Vを下回ると、低電圧での動作による暴走を防ぐためハイバネーションモードに入りスリープからも復帰しなくなります。

今回の回路は非常に簡単なので、回路図は描かずに接続する端子同士を並べた下記の配線表を用意して配線していきました。 ESP、EPD、BAT、CONはそれぞれESP32、電子ペーパー、電池、ファームウェア書き込み用コネクタの端子を表します。

ESP:IO16 EPD:BUSY
ESP:IO17 EPD:RST
ESP:IO18(CLK) EPD:SCK
ESP:IO21 EPD:DC
ESP:IO22 EPD:CS
ESP:IO23(MOSI) EPD:DIN
ESP:3V3 EPD:VCC, BAT+
ESP:GND EPD:GND, BAT-
ESP:TXD CON:TXD
ESP:RXD CON:RXD

またこの配線表には書いてませんが、電池ボックスには1000μFの電解コンデンサを、ESP32の3V3とGND間には0.1μFのチップコンデンサを取り付けます。 ESP32のアダプターボードには2個のタクトスイッチと2個の10kΩプルアップ抵抗を取り付けます。

1.7mmの合板をレーザーカッターで切断したものを積み重ねてケースを作りました。

配線した状態
ケースに入れた状態(表)
ケースに入れた状態(裏)

ソフトウェア

動作モード

このフォトフレームは通常はディープスリープでマイコンを停止していますが、指定したスリープ時間が経過するかタクトスイッチが押されるとスリープから復帰して画像表示を行います。 また電源投入時にボタンを押すことにより各種設定や画像データの転送を行うことができます。 具体的には、下記の動作モードがあります。

設定モードでは,アクセスポイントモード(親機)でHTTPサーバーを動かします. スマホやタブレットで接続して(SSIDは"ESP32"、パスワードは"12345678"、接続先は"http://192.168.0.1/"),転送モードで使うアクセスポイントのSSID,そのパスワード,およびスリープ時間(単位は秒)を設定します。 任意のキーと値のペアを登録できるので,それぞれ"SSID","PASS","SLEEP"というキーに対する値として登録します. 設定した値はフラッシュメモリ上に保存されます.

画像転送モードでは,ステーションモード(子機)でアクセスポイントに接続してFTPサーバーを動かします. 適当なFTPクライアントソフトで接続して,画像ファイルのアップロードや削除を行います. WindowsであればファイルエクスプローラーをFTPクライアントとして使えます。 ESP32のデータ領域のフラッシュメモリは,LittleFSをファイルシステムに使いファイルを管理しました. フォトフレームで表示させる画像ファイルは全てルートディレクトリに置きます. ArduinoのSimpleFTPServerというライブラリを使用しました(SPIFFSではなくLittleFSを使うため、FtpServerKey.hのDEFAULT_STORAGE_TYPE_ESP32をSTORAGE_SPIFFSからSTORAGE_LITTLEFSに変更します)。

画像データと表示

表示する画像データはGIFフォーマットで格納します。 以前自作したGIFデコーダーを使いました。 前述の方法で変換したGIFファイルだけを入力として想定しているため、異なるパレットを使ったり画像サイズが異なったりコメント等の拡張情報が存在するファイルは表示できません。

今回フラッシュメモリが4MBのESP32を使いますが、Arduino IDEの"No OTA (1MB APP/3MB SPIFFS)"を選択することで、1MBをプログラム領域に、3MBをデータ領域(LittleFS)に使用します。 GIF形式で画像を格納した場合、画像にもよりますが1枚あたり90KBのサイズとすると34枚ほど格納できます。 なお、Arduinoでファームウェアをコンパイルするとフラッシュメモリ使用量が106%となりプログラム領域を越えてしまったので、Arduino Core for ESP32のバージョンを3.0.7から2.0.17に下げたところ、使用量が93%に減りました。

電池の交換時期が分かるように、電源電圧を画面上に表示するようにしました。 ESP32で測定した電圧を、画面右上(横置き時)の16x16ピクセルの領域に表示します。 3.00V以上の場合は小数点以下1桁だけを、3.00V未満の場合は2桁を表示します。 4x8ピクセルの数字フォントを用意して描画しています。

使用した感想

これまで、6インチのグレースケール電子ペーパーを使ったフォトフレームと、5.65インチの7色カラー電子ペーパーを使ったフォトフレームを作りました。 グレースケールだと表現力に限界があり、5.65インチのカラーでも解像度がいまいちだと感じました。 今回、画像の変換方法を改良して、さらに7.3インチのデバイスを使うことで、フォトフレームとしてある程度の実用性が得られたと思います。 なおこの7.3インチの電子ペーパーにマイコンとリチウムイオン電池を取り付けて木製フレームに入れたものがPhotoPainterとして販売されています。 これまでACePの7色カラー電子ペーパーを使用してきましたが、最近になってWaveshare社やGood Display社からSpectra 6の6色カラー電子ペーパーが販売されました。 こちらの方がACePよりも発色が良いようなので、フォトフレームに向いているかもしれません。

昔、デジタルフォトフレームが出回ってきたころに初めて買った商品が、7インチで800x600ピクセルの液晶を使用したものでした。 液晶はフルカラー表示が可能で、電子ペーパーは電源なしで使えるといった違いはありますが、解像度的には一般的なデジタルフォトフレームと変わらないレベルにまでなったのかなと思います。

ダウンロード


[Back]
2024-12 製作
2024-12-23 ページ作成
T. Nakagawa