4.crop機能で、画像を縮小せずに周囲をカットして表示してみた
JPEGDECデコーダが持っている画像の縮小は 1/2, 1/4, 1/8 なので、picocalcの320x320をちょっとはみ出る画像を縮小表示すると画像がやたらと小さい。
なので、少々大きい程度の画像なら周囲をカットする表示モードも欲しいな。せっかく機能があることだし。
ということで、crop 機能を使うように改造を始めた。
JPEGDECのAPI仕様は、画像の左上の始点を x, y で指定し、有効なサイズを w, h で指定するというもの。元画像の width, height を取得して、320x320 に収まらない場合は、x = (320 - w)//2 , w = 320 という感じではみ出るpixel数/2 を始点にするだけの簡単なお仕事。
そして縮小比率を 1/2, 1/4 と順次確認しようとしたら、表示が半分しかないとか、全くないとか、ハングアップするとかで、使い物にならない。なんで誰も困ってないの?(二度目)
挙動を確認するためのサンプル画像を作る。excelでセル方眼を作って、11-18, 21-28, ..., 81-88までのxyを示す数字を入力。罫線を付ける。その画面をキャプチャして、ペイントへ貼り付け、サイズを640x640, 1280x1280 のjpeg画像として保存。
これで1/2, 1/4 にしたときに画面にフィットして表示できるし、crop で一部分だけ表示したときの挙動確認が簡単。
さて、画像を縦に4分割(縦長)、横に4分割(横長)という感じで表示させていったところ、驚きの結果に!
動画プレイヤー用の320x180の画像で等倍表示:問題なし!と思ったら横長の4番目(最下段)表示をした時にゴミ(画像の一部)が表示される。でかい画像をcropしたときや、何も指定しないときは問題ないのにcrop 指定すると問題あり??
640x640の倍率1/2表示:縦長の最初でいきなり異常。11-12, 21-22,... と左の1/4が表示されるべきが、11-14, 21-24 と左の1/2が表示される。左の2/4 部分の表示だと右の1/2 が表示され、3/4, 4/4は無表示。
挙動としては、画像サイズのx,w を指定するとダメで、画面サイズのx,w を指定すればいい感じ。つまりcrop座標の計算は画面サイズ基準ってことか。
と思いながら横長分割表示を見ると、今度はちゃんと1/4部分が表示された。あれ?Y方向は正常?と思ったら残りの2/4以降は無表示。
う~ん、これは困った。と思い、手で地道に数値を打ち込んで延々と挙動確認をして、なんとか計算式を導き出した。
x, w :画面サイズ基準で指定
y :画面サイズ基準で指定
h :画像サイズ基準 - y で指定
なんだよ h の計算式って。画像サイズと画面サイズが混在してるし。。。
ともあれ、計算式さえ出れば、後は色んなパターンで表示して試してみよう。1/3 サイズとかな。
と思ったら、最下段の表示でハングアップする。そ~いや、320x180でテストしたときもゴミが出てたな。画像の最下段の処理に問題があるのか?
JPEGDECのソースのcrop処理のソースを見るとmcu 単位(16pixel)でx, y, w, hを丸めてる。ただ、w, hの丸めでは16で切り上げてる。ということは16の倍数になってないとメモリ破壊のパターン??
縦180を4分割すると45pixelになるからアウトな感じ。
ここも手作業のトライアンドエラーで安全な範囲を探してみると画像サイズ-32でなんとかなる感じ。-16じゃダメなだよな。なんで?
ともあれ、これでかなりのJPEG画像を表示できるようになった。スライドショー機能完成。満足。でもなんで誰も困ってないんだろう??
と思っていたが気が付いた。いまさら気が付いてしまったんだよ。
表示する画像を事前に320x320に収まるように加工すればいいだけじゃん pythonのcv2.resize で一発じゃん。
そりゃそうだよ。遅いマイコンに大きいデータをSDやWiFiで読み込ませて、時間をかけてデコードさせて、何がうれしいんだよ。
実際のところ、CYD(Cheap Yellow Display) のESP32 を使って監視カメラ画像を表示させてるんだが、メモリの制約が厳しいからサーバ側で320x240に縮小して160x240に分割して転送してるんだよな。
画像作成側で工夫するから、表示側で頑張る人はほとんどいないってことなんだろう。(動きがおかしいからあきらめたって可能性もあるが)
なんか、すんげー、疲れた。
「できる」と「簡単にできる」は大きく違うし、「できる」と「使い物になる」も大きく違うんだよね。
でもまぁやりかけだから、SDの読み込み速度の改善ぐらいはやっておこう。
今の処理では、デコーダが必要なデータをcore0へ要求してからSDを読み込んでるけど、core0が遊んでる時間がもったいない。その間に先読みさせておきたいし。




