こんにちは。
コンピュータビジョン(『ロボットの眼』開発)が専門の”はやぶさ”先生@Cpp_Learningの一番弟子です!
はやぶさ先生は、画像処理や機械学習などの技術を分かりやすく説明してくれる”変な…優しいお兄さん”です!
本サイト:はやぶさの技術ノートで はやぶさ先生が書いた記事がタダで読めるよー
など
くるるは先生と一緒に勉強しながら、ゲームやオリジナルビデオを作ったことがあるよー
最近、先生が遊んでるM5Stackってやつが楽しそうなので…
先生が留守の間に、こっそり画像処理で遊ぶことにした!本記事も勝手に書いちゃうよー
本記事は「静止画編」と「動画編」の二部構成で説明します。目次からジャンプできるので、好きなところから読み始めてくださな
Contents
M5Stackの始め方
M5Stack初心者のくるるでも以下の記事を読んだら、すぐにプログラミングを始められたよ!はやぶさ先生イイ記事書いてる~♪
M5StackちっちゃいBodyに画面まで付いてるから、つい画像処理とかしたくなっちゃうよね♪
M5Stackで画像処理 -静止画編-
M5StackのLCDにjpg画像を表示する場合、以下のソースコードのやり方が最も簡単です。
1 2 3 4 5 6 7 8 9 |
#include <M5Stack.h> void setup() { M5.begin(); } void loop() { M5.Lcd.drawJpgFile(SD, "/kururu.jpg"); } |
このコードでSDカード直下に保存した”kururu.jpg”という画像を表示できます。
もし、SDカード直下ではなく、imgフォルダなどに画像を保存している場合は、以下のように書きます。
1 2 3 4 5 |
void loop() { M5.Lcd.drawJpgFile(SD, "/img/kururu.jpg"); } |
M5StackのWindowサイズが320×240なので、画面いっぱいに表示させたいときは、同じ320×240pixelのjpg画像を使うのがオススメです。
座標を指定して画像表示
画像処理では画面左上を原点として扱うことが多く、M5Stackも左上が原点でした。
最初に紹介した画像表示のやり方は、M5Stack(Window)の原点とjpg画像の原点を揃えて表示する方法です。
以下のコードを使えば、座標指定で画像表示ができます。
1 2 3 4 5 6 7 8 |
void loop() { uint16_t x = 50; uint16_t y = 40; M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y); } |
以下のような画像表示になります。
画像の幅と高さを指定して表示
jpg画像の幅と高さを指定して表示することもできます。
1 2 3 4 5 6 7 8 9 10 |
void loop() { uint16_t x = 50; uint16_t y = 40; uint16_t width = 160; uint16_t height = 80; M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y, width, height); } |
以下のような画像表示になります。
オフセットを指定して画像表示
オフセットも指定できるよー
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void loop() { uint16_t x = 50; uint16_t y = 40; uint16_t width = 0; uint16_t height = 0; uint16_t offset_x = 80; uint16_t offset_y = 20; M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y, width, height, offset_x, offset_y); } |
以下のような画像表示になります。
クリッピング(画像の指定範囲を表示)
今までの説明したやつを応用すれば、目の部分だけ表示(クリッピング)ができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void loop() { uint16_t x = 50; uint16_t y = 40; uint16_t width = 100; uint16_t height = 18; uint16_t offset_x = 80; uint16_t offset_y = 20; M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y, width, height, offset_x, offset_y); } |
以下のような画像表示になります。
スケールを指定して画像表示
サイズの大きいjpg画像を表示させるなら、スケールを変更すると良いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void loop() { uint16_t x = 0; uint16_t y = 0; uint16_t width = 0; uint16_t height = 0; uint16_t offset_x = 0; uint16_t offset_y = 0; jpeg_div_t scale = JPEG_DIV_2; // JPEG_DIV_NONE, JPEG_DIV_2, JPEG_DIV_4, JPEG_DIV_8 M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y, width, height, offset_x, offset_y, scale); } |
このコードで以下のような1/2スケールの表示ができます。
スケールは整数値でも指定できますが、用意してある列挙型を使う方が直感的にスケールを理解できるのでオススメです。
jpeg_div_tという列挙型が用意してあります。
- JPEG_DIV_NONE:スケール指定なし
- JPEG_DIV_2:1/2スケール
- JPEG_DIV_4:1/4スケール
- JPEG_DIV_8:1/8スケール
- JPEG_DIV_MAX:存在するけど使わない
列挙型なので、JPEG_DIV_NONE=0, JPEG_DIV_NONE2=1,… を表現しています。
そのため、scale=JPEG_DIV_NONE2ではなく、scale=1を指定してもスケールは1/2になります。
また、JPEG_DIV_NONEは省略してもOKです。
ただし、JPEG_DIV_〇を書いたり/書かなかったすると読み手が混乱するので…
一箇所でもJPEG_DIV_〇でスケール指定するなら、JPEG_DIV_NONEも省略せずに書く方が親切です。
補足 -良いソースコードとは?-
ケースバイケースだけど、変数を使わずに引数を書くと何の処理をしているか分かりにくいので…
1 2 3 |
M5.Lcd.drawJpgFile(SD, "/kururu.jpg", 50, 40, 100, 18, 30, 20); |
コメントで引数の定義を補足するか、直感的に理解しやすい名前の変数を使うと良いです。
1 2 3 4 5 6 |
M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y, width, height, offset_x, offset_y, scale); |
また、「悪い例」・「良い例」で引数の数が異なります。これは、省略可能なスケールを書いたり・書かなかったりした差です。
エラーは出ませんが、統一感のないコードは読み手が混乱します。
『読み手や使い手のことを想ってソースコードを書くのが正解』
思想や好みもありますが、統一感のあるコードの方が「読み手を想ったコード」になると考えています。
(静止画編 完)
M5Stackで画像処理 -動画編-
静止画だけじゃなくて、M5Stackで動画(アニメーション)も作成するよー!
簡単なアニメーションなら、パラパラ漫画…つまり、静止画を重ねるだけで実現できます。
単純に1枚の画像のx,y座標を少しずつ動かすだけでも面白い動画になります。
この図は『Processingでオリジナルビデオを作る』のブログ記事で使った図解です。なので、ソースコードの言語は異なりますが、画像処理の基礎は同じです!
オリジナルビデオ作成に興味のある人は、この記事も読んでほしいな~
実践!M5Stackでアニメーション表示
静止画編でjpg画像の一部を切り取ったり、スケールを変更する方法を説明しました。
静止画を表示させるだけなら、処理速度を気にする必要はありませんが、できるだけ実行する処理を減らした方が滑らかなアニメーションになります。
そのため、SDカードに保存した小さなjpg画像を読み込み、x,y座標を動かすソースコードを作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <M5Stack.h> uint16_t x = 0; uint16_t y = 40; void setup() { M5.begin(); } void loop() { int dx = 10, dy = 10; x = x + dx; y = y + dy; M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y); } |
このコードでjpg画像のx,y座標が10pixelずつ移動するアニメーションを生成できます。
あとは以下の仕様を検討すれば、オリジナルアニメーションが作成できます。
- 更新速度(画像を移動させる時間)を調整
- 移動量(dx=〇pixel移動させるか)を調整
- ある座標(画面の端など)に行ったときの処理
- ボタンが押されたらときの処理
- 移動軌跡(sin・cosを使って滑らかに移動など)の処理
など、自由な発想でオリジナルアニメーションを作ってみよう♪
実践!M5Stackでオリジナルアニメーション作成
最後に簡単なオリジナルアニメーションのソースコードを紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#include <M5Stack.h> // M5Stack window size #define WINDOW_W 320 #define WINDOW_H 240 // jpg image param uint16_t x = 0; uint16_t y = 0; uint16_t width = 120; uint16_t height = 120; // uint16_t offset_x = 30; // uint16_t offset_y = 50; // // JPEG_DIV_NONE, JPEG_DIV_2, JPEG_DIV_4, JPEG_DIV_8, JPEG_DIV_MAX // jpeg_div_t scale = JPEG_DIV_NONE; void setup() { M5.begin(); M5.Lcd.clear(BLACK); M5.Lcd.setTextColor(YELLOW); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(3, 10); M5.Lcd.println(""); M5.Lcd.println("Read image form SD."); } void loop() { M5.update(); int dx = 10, dy = 10; // move image if (M5.BtnA.wasReleased()) { M5.Lcd.clear(BLACK); if (x + width < WINDOW_W - dx){ x = x + dx; }else{ x = 0; y = 0; } if (y + height < WINDOW_H - dy){ y = y + dy; }else{ x = 0; y = 0; } M5.Lcd.drawJpgFile(SD, "/guruguru.jpg", x, y); } // display image if (M5.BtnB.wasReleased()) { M5.Lcd.drawJpgFile(SD, "/kururu.jpg"); } // animation if (M5.BtnC.wasReleased()) { y = 60; while (true){ M5.Lcd.clear(BLACK); if (x + width < WINDOW_W - dx){ x = x + dx; }else{ x = 0; y = 0; break; } M5.Lcd.drawJpgFile(SD, "/kururu_go.jpg", x, y); delay(100); } } } |
3つの画像を用意して、ボタン毎に処理を変えてみました。このコードを動かしたときの様子は以下の通りです。
#M5Stack で画像処理 pic.twitter.com/sp8dteWzrk
— はやぶさ (@Cpp_Learning) September 1, 2019
自分の好きな画像を使ってオリジナルアニメーションが動くの楽しい!M5Stackの小さな画面で動くのが可愛らしい♪
(動画編 完)
M5Stackで画像処理まとめ
M5Stackに画面が付いてたから、画像処理で遊んでみました。
画像表示の方法について説明し、最終的にはアニメーション作成まで実践しました。
みんなもオリジナルアニメーション作成に挑戦してみてね♪
おまけ -本ブログのサポートについて-
くるるちゃんは着実にレベルアップしています。教える立場としては、とても誇らしいです!
本ブログのサポート方法
本記事が参考になり、くるるちゃんに投げ銭(ごはん代をサポート)したいという人がいれば LINEスタンプや【くるるの野望ショップ】でフクロウグッズを購入して頂けると嬉しいです。
また、ブログ『はやぶさの技術ノート』では、本記事も含め多くのチュートリアル記事を無料で公開しています。SNSなどで友達にも教えてあげてほしいです!
【本ブログのサポート方法】
- LINEスタンプ を購入
- 【くるるの野望ショップ】でフクロウグッズを購入
- 本ブログの記事をSNS(Twitterやfacebookなど)でシェア