読者です 読者をやめる 読者になる 読者になる

Processingで顔認識を使って写真を自由自在にアヘ顔にするソフトを30分で作る方法

 前回「Processingで顔認識を使って強制的にアヘ顔になるソフトを作ってみた」でProcessingで色々動画を弄ってみたわけですけど、写真の処理とかにも普通に使えるんじゃ無いかなとふと思い作ってみました。
 ちなみに前回はあれだけ身体を張ったのにもかかわらず、全くといっていいほど反響ありませんでした。多分みんなドン引きしたのでしょう。よって今回でこのシリーズは最終回にしようと思います、みなさん短い間でしたがご清聴ありがとうございました。

アヘ顔画像生成ソフト

 それでは早速アヘ顔になるソフトのコードです。Processing、Open CVのインストールといった準備は前回の記事を参照して下さい。あとは下のコードをコピペして、同じフォルダにアヘ顔にしたい写真を「source.jpg」という名前で保存して実行すればOKです。

import hypermedia.video.*;
import java.awt.Rectangle;

int w = 1024;
int h = 768;

OpenCV opencv;

PImage source_img;
PImage ahegao_img;

void setup() {

  size( w, h );

  opencv = new OpenCV( this );
  opencv.loadImage("source.JPG", width, height);
  opencv.cascade( OpenCV.CASCADE_FRONTALFACE_ALT );

  ahegao_img = loadImage("ahegao.png");
  imageMode(CORNER);
}

void draw() {

  opencv.read();
  image( opencv.image() , 0, 0 );
  Rectangle[] faces = opencv.detect();

  for( int i=0; i<faces.length; i++){
  image(ahegao_img, faces[i].x, faces[i].y, faces[i].width, faces[i].height );
  }
}


void keyPressed() { 
  if(key == 'p' || key == 'P') {
    // save image
    save("screenshot.png"); 
    println("screen saved."); 
  }
  
  exit();
}

 int w = 1024; int h = 768; は写真の解像度に合わせて設定して下さい。あんまり大きいとオーバーフロ起こすので、その場合は2とか3で割った数を入力してやればよいです。
 実行してうまい具合にアヘ顔になったら「p」を押して下さい「screenshot.png」というアヘ顔ファイルを吐き出してくれます。

実施例

 実行例をいくつか公開します。

120301_hachimaru
 僕らのアイドルはち丸が・・・

120301_hachimaru_ahe
 あられもないアヘ顔に

120301_sento
 あのせんと君が

120301_sento_ahe
 でたー!アヘ顔せんと君!

120301_gian
 きれいなジャイアンが

120301_gian_ahe
 アヘ顔ジャイアンに!

 まあこんな感じにアヘ顔になります。 うまく顔認識しないときは、Rectangle faces = opencv.detect();の行のdetect関数に適当なパラメータを引数でわたしてやると認識してくれるときがあります。例えば、 Rectangle faces = opencv.detect(1.2, 0, 1, 10, 10); みたいな感じで。顔が大きいときは、1番目と4番目と5番目の引数を大きくしてやるとよいです。1番目の引数は1.1〜2くらいまでの間で設定するのがよさそうです。あんまり小さくすると時間がかかるのと誤認識多くなってきます。詳しくはリファレンスを調べてみて下さい。ちなみに僕はよく理解できませんでした(ダメダメ)。

モザイクフォト生成ソフト

 もひとつおまけに、フォトモザイク(モザイク状に並べた写真で写真を表現するやつ)もできそうだったのでやってみました。というかほとんどコピペです。まずはソースコード。

import hypermedia.video.*;
import java.awt.Rectangle;

PImage img;
int mosaicWidth = 20;
int mosaicHeight = 10;
int w = 1024;
int h = 768;

void setup() {
  size(w, h);
  noStroke();
  background(0);
  img = loadImage("source.JPG");
  image(img, 0, 0);
  loadPixels();
}
 
void draw() {
  println("h="+height);
  println("w="+width);

  for(int j = 0; j < height; j+=mosaicHeight) {  
    for(int i = 0; i < width; i+=mosaicWidth) {  
      color c = pixels[j * width + i];
      tint(red(c), green(c), blue(c));
      image(img, i, j, mosaicWidth, mosaicHeight);
    }
  }

  println("finished!!");
}


void keyPressed() { 
  if(key == 'p' || key == 'P') {
    // save image
    save("screenshot.png"); 
    println("screen saved."); 
  }
  
  exit();
}

 あんまり細かい写真だと面白くないので、シンプルなものがよいです。int mosaicWidth = 20;
int mosaicHeight = 10;はまずは大きめの値から徐々に小さくしていくのがよいかなと思います。設定値によってはモザイク状の絵が出てくるまで結構な時間がかかります。

実施例

120301_penguine
 かわいらしいペンギン画像が

120301_penguine_pixel
 あっという間にモザイク状に、でもその一つ一つがペンギン!

 こういう写真どうやってつくるのかなと思っていたのですが、意外と単純なアルゴリズムなんですね。

参考

Processingで画像データを扱う
 フォトモザイクのプログラムはほとんどここのコピペです

絵心がなくても簡単に絵が描ける Processing
 わかりやすい連載。スクリーンショットの保存の仕方とかはこれを参考にしました

OpenCV detect()関数のリファレンス
 よく読んでdetect関数の引数弄れば、顔認識精度を上げる事ができるかもしれません、僕は理解がイマイチでした。