こんにちは。
コンピュータビジョン(『ロボットの眼』開発)が専門の”はやぶさ”先生@Cpp_Learningの一番弟子です!
はやぶさ先生は、画像処理や機械学習などの技術を分かりやすく説明してくれる”変な…優しいお兄さん”です!
本サイト:はやぶさの技術ノートで はやぶさ先生が書いた記事がタダで読めるよー
【深層学習入門】画像処理の基礎(画素操作)からCNN設計まで画像処理の基礎(画素操作)から深層学習のCNN設計までカバーした記事です。画像処理にはOpenCVとPythonを使用しました。画像処理入門、深層学習入門、どちらも取り組みたい人におすすめの記事です。...
MXNetで『カメラ・動画対応!物体検出ソフト』を作った -Yolo, SSD, Faster-RCNNモデル対応-こんにちは。
コンピュータビジョン(『ロボットの眼』開発)が専門の”はやぶさ”@Cpp_Learningです。
『深層学習に...
ONNX RuntimeとYoloV3でリアルタイム物体検出Microsoft社製OSS”ONNX Runtime”の入門から実践まで学べる記事です。ONNXおよびONNX Runtimeの概要から、YoloV3モデルによる物体検出(ソースコード付)まで説明します。深層学習や画像処理に興味のある人にオススメの内容です。...
など
くるる
多すぎて紹介しきれないけど、他にも沢山の記事を書いてるよ!
くるるは先生と一緒に勉強しながら、ゲームやオリジナルビデオを作ったことがあるよー
【Pyxel】Pythonでレトロゲームを作ろう! 総集編 -まるっと1週間でゲーム開発入門-Python向けのレトロゲームエンジン:pyxelを用いたゲーム開発入門チュートリアル(ソースコード付き)を書きました。画像処理・数学・物理・制御について学び、実践としてゲームプログラミングまで行います。...
【Processing入門】画像処理プログラミングでプロモーションビデオ作成教育用途やデジタルアートなど様々な用途があるプログラミング言語Processingの入門チュートリアルを作りました。オリジナル動画を作るためのサンプルコードも公開しています。...
【Pyxel】Pythonで物理シミュレーションをしよう! 総集編 -まるっと1週間チュートリアル-こんにちは!
本記事は『Pythonで物理シミュレーションをしよう!』シリーズの総集編です!
本シリーズは、...
最近、先生が遊んでるM5Stackってやつが楽しそうなので…
先生が留守の間に、こっそり画像処理で遊ぶことにした!本記事も勝手に書いちゃうよー
本記事は「静止画編」と「動画編」の二部構成で説明します。目次からジャンプできるので、好きなところから読み始めてくださな
M5Stackの始め方
M5Stack初心者のくるるでも以下の記事を読んだら、すぐにプログラミングを始められたよ!はやぶさ先生イイ記事書いてる~♪
【M5Stack入門】初心者におすすめしたい情報まとめこんにちは。
現役エンジニアの”はやぶさ”@Cpp_Learningです。
先日、Maker Faire Tokyoや趣味T...
M5StackちっちゃいBodyに画面まで付いてるから、つい画像処理とかしたくなっちゃうよね♪
M5Stackで画像処理 -静止画編-
M5StackのLCDにjpg画像を表示する場合、以下のソースコードのやり方が最も簡単です。
|
#include <M5Stack.h> void setup() { M5.begin(); } void loop() { M5.Lcd.drawJpgFile(SD, "/kururu.jpg"); } |
このコードでSDカード直下に保存した”kururu.jpg”という画像を表示できます。
もし、SDカード直下ではなく、imgフォルダなどに画像を保存している場合は、以下のように書きます。
|
void loop() { M5.Lcd.drawJpgFile(SD, "/img/kururu.jpg"); } |
M5StackのWindowサイズが320×240なので、画面いっぱいに表示させたいときは、同じ320×240pixelのjpg画像を使うのがオススメです。
座標を指定して画像表示
画像処理では画面左上を原点として扱うことが多く、M5Stackも左上が原点でした。
最初に紹介した画像表示のやり方は、M5Stack(Window)の原点とjpg画像の原点を揃えて表示する方法です。
以下のコードを使えば、座標指定で画像表示ができます。
|
void loop() { uint16_t x = 50; uint16_t y = 40; M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y); } |
以下のような画像表示になります。
画像の幅と高さを指定して表示
jpg画像の幅と高さを指定して表示することもできます。
|
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); } |
以下のような画像表示になります。
オフセットを指定して画像表示
オフセットも指定できるよー
|
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); } |
以下のような画像表示になります。
クリッピング(画像の指定範囲を表示)
今までの説明したやつを応用すれば、目の部分だけ表示(クリッピング)ができます。
|
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画像を表示させるなら、スケールを変更すると良いです。
|
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も省略せずに書く方が親切です。
補足 -良いソースコードとは?-
くるる
『読み手や使い手のことを想ってソースコードを書くのが正解』って、はやぶさ先生が教えてくれたよ♪
ケースバイケースだけど、変数を使わずに引数を書くと何の処理をしているか分かりにくいので…
|
M5.Lcd.drawJpgFile(SD, "/kururu.jpg", 50, 40, 100, 18, 30, 20); |
コメントで引数の定義を補足するか、直感的に理解しやすい名前の変数を使うと良いです。
|
M5.Lcd.drawJpgFile(SD, "/kururu.jpg", x, y, width, height, offset_x, offset_y, scale); |
また、「悪い例」・「良い例」で引数の数が異なります。これは、省略可能なスケールを書いたり・書かなかったりした差です。
エラーは出ませんが、統一感のないコードは読み手が混乱します。
『読み手や使い手のことを想ってソースコードを書くのが正解』
思想や好みもありますが、統一感のあるコードの方が「読み手を想ったコード」になると考えています。
(静止画編 完)
スポンサーリンク
M5Stackで画像処理 -動画編-
静止画だけじゃなくて、M5Stackで動画(アニメーション)も作成するよー!
簡単なアニメーションなら、パラパラ漫画…つまり、静止画を重ねるだけで実現できます。
単純に1枚の画像のx,y座標を少しずつ動かすだけでも面白い動画になります。
この図は『Processingでオリジナルビデオを作る』のブログ記事で使った図解です。なので、ソースコードの言語は異なりますが、画像処理の基礎は同じです!
Processingでオリジナルビデオを作る
【Processing入門】画像処理プログラミングでプロモーションビデオ作成教育用途やデジタルアートなど様々な用途があるプログラミング言語Processingの入門チュートリアルを作りました。オリジナル動画を作るためのサンプルコードも公開しています。...
オリジナルビデオ作成に興味のある人は、この記事も読んでほしいな~
くるる
今回はM5Stack(Arduino)でアニメーションを作成するよ♪
実践!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の小さな画面で動くのが可愛らしい♪
(動画編 完)
M5Stackで画像処理まとめ
M5Stackに画面が付いてたから、画像処理で遊んでみました。
画像表示の方法について説明し、最終的にはアニメーション作成まで実践しました。
みんなもオリジナルアニメーション作成に挑戦してみてね♪
おまけ -本ブログのサポートについて-
はやぶさ
画像処理の基礎がしっかり習得できてるから、言語が変わっても自分のやりたいことを実現できたね
くるる
言語も違ったし、PCじゃなくてマイコンモジュールだったけど、画像処理できたよー
くるるちゃんは着実にレベルアップしています。教える立場としては、とても誇らしいです!
はやぶさ
本記事は、子供も大人も楽しめる良い記事だと感じたよ!頑張ったご褒美に何かプレゼントしようか?
本ブログのサポート方法
本記事が参考になり、くるるちゃんに投げ銭(ごはん代をサポート)したいという人がいれば LINEスタンプや【くるるの野望ショップ】でフクロウグッズを購入して頂けると嬉しいです。
また、ブログ『はやぶさの技術ノート』では、本記事も含め多くのチュートリアル記事を無料で公開しています。SNSなどで友達にも教えてあげてほしいです!
くるる
最後まで読んでくれてありがとね!また一緒に勉強しようねー♪
【M5Stack入門】初心者におすすめしたい情報まとめこんにちは。
現役エンジニアの”はやぶさ”@Cpp_Learningです。
先日、Maker Faire Tokyoや趣味T...
【Processing入門】画像処理プログラミングでプロモーションビデオ作成教育用途やデジタルアートなど様々な用途があるプログラミング言語Processingの入門チュートリアルを作りました。オリジナル動画を作るためのサンプルコードも公開しています。...
【Pyxel】Pythonでレトロゲームを作ろう! 総集編 -まるっと1週間でゲーム開発入門-Python向けのレトロゲームエンジン:pyxelを用いたゲーム開発入門チュートリアル(ソースコード付き)を書きました。画像処理・数学・物理・制御について学び、実践としてゲームプログラミングまで行います。...