[Go to “teaching” in Morimoto Lab]
videoと OpenCVのライブラリを使います。
この講義ではウェブカメラが必要です。
※カメラのない人は早めにお知らせください。
サンプルコードの”GettingStartedCapture”を見てみましょう
Video library
をインポートし、以下のサンプルコードを選択します。
File > Sample > Library > Video > Capture > GettingStartedCapture
Note: video(やopencv)ライブラリ周辺トラブルの対処法
videoライブラリは毎年のようにトラブルがあります。以下に該当する人はそれぞれリンク先より対処をお願いします。
processing3でvideo 2.0を使用する場合の対処はこちら:
Winでカメラ取得がなかなかできない問題や、MacでProcessingがカメラにアクセスを許可されていない場合の対応が書かれています。MacでProcessing 4.2bが動かない場合はProcessing3を使いましょう:[ダウンロードページ]
基本的にProcessing3が推奨です。
上記のサンプルプログラムを実行してみましょう。以下は私のPCでのprintArray()の結果です。
String[] camera = Capture.list();
のlistの中身はそのPCで使えるカメラのリストです。
文字を扱うデータ型Stringの配列cameraに中身を代入しています。
printArray()は名前の通り、その配列をprintします。
Available cameras:
[0] “name=Rear Camera,size=640x480,fps=30”
[1] “name=Rear Camera,size=640x360,fps=30”
[2] “name=Rear Camera,size=3264x2448,fps=15”
[3] “name=Rear Camera,size=2592x1944,fps=15”
[4] “name=Rear Camera,size=1920x1080,fps=24”
[5] “name=Rear Camera,size=1600x1200,fps=30”
[6] “name=Rear Camera,size=1280x720,fps=60”
[7] “name=Front Camera,size=640x480,fps=30”
[8] “name=Front Camera,size=160x120,fps=30”
[9] “name=Front Camera,size=176x144,fps=30”
...
キャプチャーリストの番号は使うカメラを切り替えるために使います。
サンプルコードの下記の部分では、cameras[0]なので0番目のカメラを使っています。
cam = new Capture(this, cameras[0]);
キャプチャを行うカメラの変更も行ってみてください。
更に、saveFrame()を使ってキャプチャした連番静止画を保存し、movファイルに変換をしてください。
参照:movファイルへの変換など。
参照:saveFrame()は実行画面を連番静止画にして保存することができます。
saveFrame("frames2/line-######.png");
↑シャープ記号の数の桁の連番になります。
/で区切れば、それ以前の部分の名前のフォルダを自動で作成してくれます。
画像(フォルダを作成する場合はフォルダ)はプログラムのファイルと同じフォルダ内に作成されます。
画像ができたら、Processingのメニューのツールより、「ムービーメーカー」を選び、連番静止画のあるフォルダを選択して、「動画を作成」ボタンを押すと動画が作成されます。
PC付属のカメラなどを持っていない人は、早めに担当教員までお知らせください。
↑ムービーメーカーでトラブルが起こる場合は、圧縮をJPEGにするとうまく書き出せるかもしれません。
OpenCVはリアルタイムでのcomputer visionを主な目的としたプログラムのライブラリです。OpenCV は C, C++, C#, Java, その他で使えてとても広く使われています。
OpenCV for Processing
で何ができるのでしょう?
以下の場所にあるサンプル名を見ると大体わかります。
Contributed Libraries > OpenCV for Processing.
サンプルの内、FaceDetection
をダブルクリックして実行しましょう
男性の顔の部分が四角で囲まれた画面が表示されると思います。
下記はそのサンプルコードに追記をしたものですが、
顔写真データがないと同じ挙動にならない
ので、
「サンプル」から実行し、
「名前を付けて保存」をして複製を作成して編集するとよいでしょう。
import gab.opencv.*; //openCVのライブラリ
import java.awt.Rectangle; //javaのRectangleクラス
OpenCV opencv; //OpenCVクラスの変数を定義
Rectangle[] faces;//1. Rectangleクラスの配列を定義(顔を複数検出できるため)
void setup() {
//静止画の読込
opencv = new OpenCV(this, "test.jpg");
size(1080, 720);
//2.
//顔のデータをロード→顔を検出
opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
//目のデータをロード→目を検出
//opencv.loadCascade(OpenCV.CASCADE_EYE);
//口のデータをロード→口を検出
//opencv.loadCascade(OpenCV.CASCADE_MOUTH);
//顔を検出
faces = opencv.detect();
}
void draw() {
//入力画像の描画
image(opencv.getInput(), 0, 0);
noFill();
stroke(0, 255, 0);
strokeWeight(3);
//顔は複数検出可能なので、for文を使っているがここでは一つの顔のみ
for (int i = 0; i < faces.length; i++) {
rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
}
}
Rectangleクラスには、x, y, width, height (左上のx,y座標、横・縦幅)がある。詳細はこちら。
setup内のloadCascadeのところに目や口を検出するコードを記載しています。
このように、顔以外にも検出が可能ですので色々試してみましょう。
更に他の部分を検出したい場合は、 こちらを参考にしてください。
自分のPCのカメラで撮った動画に対してリアルタイムに顔検出をするプログラムを書いてください(下にある動画のように)。
更に、何かしらの画像を読込み、キャプチャした動画の顔や目などの上に表示するようにしてください。
Hint:
OpenCVを動画やリアルタイムキャプチャ画面に使う場合、次のサンプルコードを参考にしてください。
特に毎フレーム、キャプチャした画面をopencvにloadしないといけないあたり、気を付けましょう。マスクなどをしていると顔が検出されません!
Optical flowは2つの画像間で各点がどう動いたのかを表します。
動画なら、一つ前のフレームのある位置が次のフレームでどこに行ったのかをベクトルで表します。
以下はOpenCV for ProcessingのOptical Flowの実行結果です。
まずこのサンプルを実行しましょう。
OpenCV for processingのサンプルからOpticalFlowを開いて下さい。
サンプルからの実行がうまくいかない場合は、下記のコードを使ってもらってもOK
ただし、動画が必要(こちらからDLできます)
MOVファイル読込のトラブル防止
1.プログラムのコピーと動画ファイルのコピーをしましょう:
サンプルプログラムをそのまま上書きして編集してしまうと、元の内容が失われてしまうので、「名前を付けて保存」などで同じプログラムのコピーを別の場所に作りましょう。
↑このとき、プログラムファイルはコピーされますが、参照ファイル(MOVファイルなど)はコピーされないので、手動でコピーします。
↑このとき、プログラムファイルのあるフォルダにdataと言う名前のフォルダを作り、その中にファイルを置きましょう
↑このとき、ファイル名の前に”data/”などと入れる必要はありません。dataはProcessingでは参照ファイルのデフォルトのフォルダになっているみたいで、特別な扱いになっています。
2.ライブラリインポート後にProcessingを再起動しましょう:
不要な人もいますが、これで解決する場合もあります
3.Win11でProcessing関連のファイルがOneDriveにデフォルトで保存されている場合、不具合が起こる:
その場合はOneDrive以外の場所にプログラムの保存・管理場所を変更しましょう。
OneDriveではなく、C直下のドキュメントフォルダなどに変更するとよいです。
Processingの「ファイル>設定>スケッチブックの場所」のパスをC直下のドキュメントフォルダ内に変更する必要もあります。
4.PC室のPCでMOVが読みこめない:
3と同じ対処でもいいのですが、次回PCログイン時にファイルが削除されているかもしれませんので、別の場所に保存しないといけません。
他の対処として、MOVファイルだけC直下などに置いて、絶対パス(例
"C:\\sample1.mov"
)で読みこみをしてもいいです。ただ、やはりC直下のファイルは消される可能性があります。※Processingのエディタではバックスラッシュは円マークで表示されるかもしれません。
下記のプログラムは少しサンプルに改変を加えています。
import gab.opencv.*;
import processing.video.*;
OpenCV opencv;
Movie video;
void setup() {
size(1136, 320);
video = new Movie(this, "sample1.mov");
opencv = new OpenCV(this, 568, 320);
video.loop();
video.play();
}
void draw() {
background(0);
if (video.width>0) {
//if (video.available()){
video.read();
opencv.loadImage(video);
opencv.calculateOpticalFlow();
image(video, 0, 0);
translate(video.width, 0);
stroke(255, 0, 0);
opencv.drawOpticalFlow();
PVector aveFlow = opencv.getAverageFlow();
int flowScale = 50;
stroke(255);
strokeWeight(2);
line(video.width/2, video.height/2, video.width/2 + aveFlow.x * flowScale, video.height / 2 + aveFlow.y * flowScale);
}
}
available()はビデオの新しいフレームが読込可能になっているかどうかをboolean (true or false)で返しています。
※ifの中が式になっていない場合、中身がtrueなら{}内の処理をします。
ここがうまくいかない場合もあり、代わりにvideo.widthが0より大きくなっているかどうかに置き換えるとうまくいくことがあります。
getAverageFlow()は画面全体のoptical flowの平均を求める関数です。
以下のような、optical flowを扱う他の関数を試してみてください
getAverageFlowInRegion(x,y,width,height)
指定した領域の平均のflowベクトルを取得します。getFlowAt(x,y)
指定された位置のflowベクトルを取得します。
ボールにoptical flowで取得したベクトルで力を与えてください。
Hint: やり方は色々ありますが、ボールとインタラクションするために、 ボールの位置で
getFlowInRegion()
を使うとよいでしょう。
2人以上で楽しむインタラクティブなアプリケーションなど実装してみてもよいと思います。
動画を左右反転すると直感的なインタラクションに
キャプチャした動画は鏡写しのような形ではなく、その左右が反対の状態で表示されます。
直感的なインタラクションをする場合、左右反転をするとよいです。
scaleとtranslateのアフィン変換の関数を使います。
scale(-1,1)
を使うと画像を左右反転することができます。
scaleは拡大縮小の関数ですが、マイナスを使うと反転ができます。
更に単純にscale(-1,1)をすると、x=0を軸に左右反転するので画像が見えなくなると思います。
その分
translate(画像の幅,0)
とすると原点の位置まで反転した画像を移動できるはずです。このとき注意として、アフィン変換はコードの下から順に変換が行われる結果となります。
scaleしてtranslateするという順なら、コードの順は逆にします。
これらの関数のあとに、変換をしたい描画のプログラムを書きます。上記のアフィン変換の関数はそれ以降のブロック内の全ての描画に適用されます。
もし描画対象を限定したい場合は、pushMatrixとpopMatrixの関数で範囲を囲みましょう。
背景差分法といって、背景と現在のカメラで取得した画像の差分をとることで、動いている部分を取り出す方法があります。
sampleにはこの使用例があります。
たとえば、人のシルエットを使った処理とか、これを使ってもいいと思います。
Footfalls 2006 | Tmema (Golan Levin & Zachary Lieberman)
Golan Levin and Collaborators Projects
Messa di Voceなどがおすすめ。
うまく実装できれば、このような感じになると思います。期待するほど反応は顕著ではないかもしれません。
こちらもoptical flowを用いたよい例 で参考になりそうです。
OpticalFlow meets FlipFluidsこちらも同様の例で、流体と組み合わせたものになります。
コメント:
OpticalFlowはよく特定した物体の追従などに使われることが多いです。
それ以外の応用としては、ボールや流体など、何かに影響を与えるものが多いかなと思います。
他に軌跡を楽しむものもありますね。
アトラクターなどと組み合わせるときれいかもしれません。
講義で使っているProcessingはJavaベースのものですが、js (javascript)ベースのp5.jsというものもあります。
それぞれで、使えるライブラリなどが異なります。
clmtrackrはjs用のもので、顔の輪郭や感情認識などが手軽に行えます。
また、p5.jsはいくつか開発環境が考えられますが、webエディターもあります。
webエディターで公開されているclmtrackrを使ったプログラムを更に自分で編集して、色々な表現に使うこともできますね。
javaベースのものと変数の定義の仕方など少し違いますが、共通する部分も多いので、習得も難しくないかもしれません。