顔認識して強制的に人をアヘ顔にするアプリ「アヘ顔男」をリリースしました

「アヘ顔男」アプリとは

 某機動隊の「笑い男」にインスパイアされて、人をアヘ顔にする「アヘ顔男」というアプリを、何故かとち狂ってつくってしまったのでMac用のフリーソフトとして公開します。素材はインスパイアこそ受けているものの、一応全てオリジナルなのでそんなに問題は無いと思っています。
 ベースは、以前作った「Processingで顔認識を使って強制的にアヘ顔になるソフトを作ってみた」をベースに、某機動隊っぽいアレンジ(回転)を加えてみただけです。
 これでいつでもダブルピースできますね☆

ダウンロードと使い方

 以下のリンク先からダウンロードして下さい。

AhegaoMan_For_Mac_V0_1.zip 0.1

 そして1280x720のサイズの人の顔が入った動画を用意して下さい。サイズが合わなければiMovieとか適当な動画ソフトでサイズを変えてやって下さい。ピッタリ合わせなくても、比率があっていれば多分問題ないので面倒くさければサイズ変更しなくてもよいです。

 後は、AhegaoManというアヘ顔アイコンをダブルクリックして実行して下さい。フィアルダイアログが出るので、対象の動画を選択するだけです。後はアヘ顔動画が自動で生成されます。スペースボタンを押すと終了します。プログラムと同じフォルダに"ahegao.mov"というアヘ顔化した動画が生成されています。

完成アヘ顔動画

 とりあえず自分の顔で実験してみました。


アヘ顔ダブルピース

カスタマイズ方法

 プログラムと同じフォルダに、以下のような"ahegao.png"と"ahegao_back.png"というファイルがありますが、これの画像を差し替えると好きなアヘ顔を作ることができます。


ahegao.png


ahegao_back.png

 ahegao_back.pngの方は回転するエフェクトがかかりますので注意下さい。基本、Keynoteで作りました。透過pngはMacの標準ソフトの「プレビュー」で作成できますので、"プレビュー 透過png"とかでググって下さい。

顔認識に関して

 顔認識に関して、より理解が深まる記事を書きました。技術的に興味がある方はこちらも参考にしてみてください。

ChatGPTを使った顔検出

書籍の宣伝です

参考リンク

http://homepage2.nifty.com/tsugu/sotuken/rotation/
回転部分もの凄い参考にしました、というかほぼそのまま

関連記事

ソースコード

 ソースコード見たい奇特な方は続きをクリックしてください。。WindowsとかLinuxでもProcessingというフリーのプログラミング言語を落として下のソースコードをコピペすればアヘ顔ソフト使えます。根気かスキルのある方は、動かしてみたり改造にチャレンジしてみて下さい。

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

boolean rec = true;  // true: recording
int fps = 30;
int w = 1280;
int h = 720;
int angle = 0;

OpenCV opencv;
MovieMaker mm;

PImage img_back;
PImage img_ahegao;
PImage[] img_rotated = new PImage[360];

void setup() {
  size( w, h );

  String moviePath = selectInput();

  opencv = new OpenCV( this );
  opencv.movie( moviePath, width, height );
  opencv.cascade( OpenCV.CASCADE_FRONTALFACE_ALT );

  img_back = loadImage("ahegao_back.png");  
  MakeRotatedImage();

  img_ahegao = loadImage("ahegao.png");
  imageMode(CORNER);

  if(rec){
    mm = new MovieMaker(this, w, h, "ahegao.mov", fps, MovieMaker.VIDEO, MovieMaker.LOSSLESS); 
    frameRate(fps);
  }
}

void MakeRotatedImage(){
  float theta = 0;
  img_back.loadPixels();

  int cx = (int)(img_back.width/2);
  int cy = (int)(img_back.height/2);

  for(int i =0; i<360; i++){
    img_rotated[i] = createImage(img_back.width, img_back.height, ARGB);    
  }

  for(int i =0; i<360; i ++){
    theta = 2*PI*i/360;
    int tmp_sin = (int)(sin(theta)*1024);
    int tmp_cos = (int)(cos(theta)*1024);

    for(int y2 = 0; y2 < img_back.height; y2++){
      for(int x2 = 0; x2 < img_back.width; x2++){
        //          int x1 = (int)((x2-cx)*cos(theta) - (y2-cy)*sin(theta) +cx);
        //          int y1 = (int)((x2-cx)*sin(theta) + (y2-cy)*cos(theta) +cy);
        int x1 = (((x2-cx)*tmp_cos - (y2-cy)*tmp_sin) >> 10) +cx;
        int y1 = (((x2-cx)*tmp_sin + (y2-cy)*tmp_cos) >> 10) +cy;
        if(x1 >=0 && x1 < img_back.width && y1 >= 0 && y1 < img_back.height){
          img_rotated[i].pixels[x2+y2*img_back.width] = img_back.pixels[x1+y1*img_back.width];
        }
      }
    }
  }
}

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

  for( int i=0; i<faces.length; i++){
    image(img_rotated[angle], faces[i].x-faces[i].width*0.2, faces[i].y-faces[i].height*0.2, faces[i].width*1.4, faces[i].height*1.4);
    image(img_ahegao, faces[i].x+faces[i].width*0.1, faces[i].y+faces[i].height*0.1, faces[i].width*0.8, faces[i].height*0.8);
  }

  if(rec){
    mm.addFrame(); 
  }

  angle +=3;
  if(angle > 359){
    angle =0;
  }
}

void keyPressed() { 
  if (key == ' ') { 
    if(rec){
      mm.finish(); 
    }
  exit();
  }
}