« 顔認識プログラム | トップページ | 顔認識プログラム 3 »

2010.07.11

顔認識プログラム 2

前回の記事では肌色検出にて人間の顔を認識しようと考えていました。でも、はなっから肌色検出だけで顔認識ができると思っていなかったので、ある意味予想通りの結果を得ることができました。
それで、得られた結果から発展させるとして考えたのが、HSBの、「色相」、「彩度」、「明度」それぞれを別々に検査し、結果を平均してみるということです。
ここでは、厳密に顔認識する処理を後回しにすることで、“顔らしき場所”を特定することを目指しました。
細かな判断処理を重ね、やがて顔であると認識できるように段階を踏むプログラムを想定しています。

そして、今回のプログラムが下のものです。前述のとおり、色相、彩度、明度で判断をし、平均をとっています。円のポインタが顔のエリアに入っていれば今回はある程度合格点です。
また、ゴミとか、間違ったことしてますが、まぁ、気にしない。^^


package faceCatch;


//import processing
import processing.core.PApplet;
import processing.core.PImage;

import java.awt.Color;



public class FaceCatch extends PApplet{

        //これの意味は分からない
        private static final long serialVersionUID = 1L;

        //コンストラクタ
        public FaceCatch(){
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        //イメージの読み込みオブジェクト
        PImage mapImage;

        //イメージの縦横ピクセル
        int pixcelHieght, pixcelWidth;
        //イメージのピクセル値 HSB
        int celColorH, celColorS, celColorHB;
        //イメージのピクセル一つ分のRGB値
        int pixcelRGB;

        //肌色定数上位下位
        //色相
        final int HueHig = 30;
        final int HueRow = 5;
        //彩度
        final int SatHig = 255;
        final int SatRow = 150;
        //明るさ
        final int BriHig = 255;
        final int BriRow = 200;

        //肌色特定閾値
        final int THRASHOLD = Integer.decode("0x220000").intValue();

        //対象ピクセルのカラー値整数変換
        int colorInt = Integer.valueOf("FF7B2C", 16);

        //対象のピクセルがあるエリアの四隅の座標を代入する配列
        int rect[][] = new int [4][2];

        //HSBそれぞれのT、D、L、RのXYを代入する変数
        int rectH[][] = new int[4][2];
        int rectS[][] = new int[4][2];
        int rectB[][] = new int[4][2];


        //HSB判定用変数
        boolean judgHtoT = true, judgHtoD = true, judgHtoL = true, judgHtoR = true;
        boolean judgStoT = true, judgStoD = true, judgStoL = true, judgStoR = true;
        boolean judgBtoT = true, judgBtoD = true, judgBtoL = true, judgBtoR = true;


        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////


        public void setup(){

                //画面サイズ
                size(200, 200, JAVA2D);

                //colorモード、レンジを255に設定
                colorMode(HSB, 255);

                //イメージの読み込み放射状
                mapImage = loadImage("画像のある場所");

                //ピクセルの縦数
                pixcelHieght = mapImage.height;
                //ピクセルの横数
                pixcelWidth = mapImage.width;

                //背景画像指定
                image(mapImage, 0, 0);


                //イメージの中から肌色を探し出し、その中心を求める処理

                /*
                * 具体的内容
                *
                * イメージの中で対象のピクセルを4点
                * 最上端、最下端、最左端、最右端、で求める。
                * 求められた点の座標から四隅、(上左、上右、下左、下右)を求め、その中心を求める
                */


                escT:
                //最上端を求める処理(上から右へ順次調べていく)
                for(int i = 0; i < pixcelHieght; i++){
                        for(int j = 0; j < pixcelWidth; j++){

                                //イメージからピクセルのRGBを取得
                                pixcelRGB = mapImage.get(j, i);

                                //16進数に変換して先頭のffを取り去る
                                StringBuffer sb = new StringBuffer(Integer.toHexString(pixcelRGB));
                                sb.delete(0, 2);

                                //RGBをHSBに変換
                                float pixcelHSB[] = Color.RGBtoHSB(rgb(sb.toString(), 1), rgb(sb.toString(), 2), rgb(sb.toString(), 3), null);

                                //RGB、HSB変換の戻り値floatをレンジ255の整数にマッピング

                                //色相を255にマップ
                                int hsbH = (int) (255 * pixcelHSB[0]);
                                //彩度を255にマップ
                                int hsbS = (int) (255 * pixcelHSB[1]);
                                //明るさを255にマップ
                                int hsbB = (int) (255 * pixcelHSB[2]);


                                //HSBそれぞれを別々の処理に分ける。


                                //色相判定がまだ見つかっていなければ
                                if(judgHtoT){
                                        //色相を判定する
                                        if(judgmentH(hsbH)){

                                                //判定がtrueであれば、Hの配列にXY座標を代入
                                                rectH[0][0] = j;
                                                rectH[0][1] = i;

                                                //判定の結果が見つかった
                                                judgHtoT = false;
                                        }
                                }

                                //彩度判定がまだ見つかっていなければ
                                if(judgStoT){
                                        //彩度を判定する
                                        if(judgmentS(hsbS)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectS[0][0] = j;
                                                rectS[0][1] = i;

                                                //判定の結果が見つかったら
                                                judgStoT = false;
                                        }
                                }

                                //明るさ判定がまだ見つかっていなければ
                                if(judgBtoT){
                                        //彩度を判定する
                                        if(judgmentB(hsbB)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectB[0][0] = j;
                                                rectB[0][1] = i;

                                                //判定の結果が見つかったら
                                                judgBtoT = false;
                                        }
                                }

                                //全ての判定が出揃ったらループを抜ける
                                if(!judgHtoT & !judgStoT && !judgBtoT){

                                        break escT;

                                }
                        }
                } //end of for(TOP)

                ///////////////////////////////////////////////////////////////////////////////////////////

                escD:
                //最下端を求める処理(下から左に順に調べていく)
                for(int i = pixcelHieght - 1; i > 0; i--){
                        for(int j = pixcelWidth - 1; j > 0; j--){

                                //イメージからピクセルのRGBを取得
                                pixcelRGB = mapImage.get(j, i);

                                //16進数に変換して先頭のffを取り去る
                                StringBuffer sb = new StringBuffer(Integer.toHexString(pixcelRGB));
                                sb.delete(0, 2);

                                //RGBをHSBに変換
                                float pixcelHSB[] = Color.RGBtoHSB(rgb(sb.toString(), 1), rgb(sb.toString(), 2), rgb(sb.toString(), 3), null);

                                //RGB、HSB変換の戻り値floatをレンジ255の整数にマッピング

                                //色相を255にマップ
                                int hsbH = (int) (255 * pixcelHSB[0]);
                                //彩度を255にマップ
                                int hsbS = (int) (255 * pixcelHSB[1]);
                                //明るさを255にマップ
                                int hsbB = (int) (255 * pixcelHSB[2]);


                                //HSBそれぞれを別々の処理に分ける。


                                //色相判定がまだ見つかっていなければ
                                if(judgHtoD){
                                        //色相を判定する
                                        if(judgmentH(hsbH)){

                                                //判定がtrueであれば、Hの配列にXY座標を代入
                                                rectH[1][0] = j;
                                                rectH[1][1] = i;

                                                //判定の結果が見つかった
                                                judgHtoD = false;
                                        }
                                }

                                //彩度判定がまだ見つかっていなければ
                                if(judgStoD){
                                        //彩度を判定する
                                        if(judgmentS(hsbS)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectS[1][0] = j;
                                                rectS[1][1] = i;

                                                //判定の結果が見つかったら
                                                judgStoD = false;
                                        }
                                }

                                //明るさ判定がまだ見つかっていなければ
                                if(judgBtoD){
                                        //彩度を判定する
                                        if(judgmentB(hsbB)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectB[1][0] = j;
                                                rectB[1][1] = i;

                                                //判定の結果が見つかったら
                                                judgBtoD = false;
                                        }
                                }

                                //全ての判定が出揃ったらループを抜ける
                                if(!judgHtoD & !judgStoD && !judgBtoD){

                                        break escD;

                                }
                        }
                } //end of for(Down)

                ///////////////////////////////////////////////////////////////////////////////////////////

                escL:
                //最左端を求める処理(左から下へと順に調べていく)
                for(int j = 0; j < pixcelWidth; j++){
                        for(int i = 0; i < pixcelHieght; i++){

                                //イメージからピクセルのRGBを取得
                                pixcelRGB = mapImage.get(j, i);

                                //16進数に変換して先頭のffを取り去る
                                StringBuffer sb = new StringBuffer(Integer.toHexString(pixcelRGB));
                                sb.delete(0, 2);

                                //RGBをHSBに変換
                                float pixcelHSB[] = Color.RGBtoHSB(rgb(sb.toString(), 1), rgb(sb.toString(), 2), rgb(sb.toString(), 3), null);

                                //RGB、HSB変換の戻り値floatをレンジ255の整数にマッピング

                                //色相を255にマップ
                                int hsbH = (int) (255 * pixcelHSB[0]);
                                //彩度を255にマップ
                                int hsbS = (int) (255 * pixcelHSB[1]);
                                //明るさを255にマップ
                                int hsbB = (int) (255 * pixcelHSB[2]);


                                //HSBそれぞれを別々の処理に分ける。


                                //色相判定がまだ見つかっていなければ
                                if(judgHtoL){
                                        //色相を判定する
                                        if(judgmentH(hsbH)){

                                                //判定がtrueであれば、Hの配列にXY座標を代入
                                                rectH[2][0] = j;
                                                rectH[2][1] = i;

                                                //判定の結果が見つかった
                                                judgHtoL = false;
                                        }
                                }

                                //彩度判定がまだ見つかっていなければ
                                if(judgStoL){
                                        //彩度を判定する
                                        if(judgmentS(hsbS)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectS[2][0] = j;
                                                rectS[2][1] = i;

                                                //判定の結果が見つかったら
                                                judgStoL = false;
                                        }
                                }

                                //明るさ判定がまだ見つかっていなければ
                                if(judgBtoL){
                                        //彩度を判定する
                                        if(judgmentB(hsbB)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectB[2][0] = j;
                                                rectB[2][1] = i;

                                                //判定の結果が見つかったら
                                                judgBtoL = false;
                                        }
                                }

                                //全ての判定が出揃ったらループを抜ける
                                if(!judgHtoL & !judgStoL && !judgBtoL){

                                        break escL;

                                }
                        }
                } //end of for(Left)

                ///////////////////////////////////////////////////////////////////////////////////////////

                escR:
                //最右端を求める処理(左から下へと順に調べていく)
                for(int j = pixcelWidth - 1; j > 0; j--){
                        for(int i = pixcelHieght - 1; i > 0; i--){

                                //イメージからピクセルのRGBを取得
                                pixcelRGB = mapImage.get(j, i);

                                //16進数に変換して先頭のffを取り去る
                                StringBuffer sb = new StringBuffer(Integer.toHexString(pixcelRGB));
                                sb.delete(0, 2);

                                //RGBをHSBに変換
                                float pixcelHSB[] = Color.RGBtoHSB(rgb(sb.toString(), 1), rgb(sb.toString(), 2), rgb(sb.toString(), 3), null);

                                //RGB、HSB変換の戻り値floatをレンジ255の整数にマッピング

                                //色相を255にマップ
                                int hsbH = (int) (255 * pixcelHSB[0]);
                                //彩度を255にマップ
                                int hsbS = (int) (255 * pixcelHSB[1]);
                                //明るさを255にマップ
                                int hsbB = (int) (255 * pixcelHSB[2]);


                                //HSBそれぞれを別々の処理に分ける。


                                //色相判定がまだ見つかっていなければ
                                if(judgHtoR){
                                        //色相を判定する
                                        if(judgmentH(hsbH)){

                                                //判定がtrueであれば、Hの配列にXY座標を代入
                                                rectH[3][0] = j;
                                                rectH[3][1] = i;

                                                //判定の結果が見つかった
                                                judgHtoR = false;
                                        }
                                }

                                //彩度判定がまだ見つかっていなければ
                                if(judgStoR){
                                        //彩度を判定する
                                        if(judgmentS(hsbS)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectS[3][0] = j;
                                                rectS[3][1] = i;

                                                //判定の結果が見つかったら
                                                judgStoR = false;
                                        }
                                }

                                //明るさ判定がまだ見つかっていなければ
                                if(judgBtoR){
                                        //彩度を判定する
                                        if(judgmentB(hsbB)){

                                                //判定がtrueであれば、Sの配列にXY座標を代入
                                                rectB[3][0] = j;
                                                rectB[3][1] = i;

                                                //判定の結果が見つかったら
                                                judgBtoR = false;
                                        }
                                }

                                //全ての判定が出揃ったらループを抜ける
                                if(!judgHtoR & !judgStoR && !judgBtoR){

                                        break escR;

                                }
                        }
                } //end of for(Right)

                ///////////////////////////////////////////////////////////////////////////////////////////


                //四角
                noFill();

                stroke(204, 102, 255);
                quad(rectH[2][0], rectH[0][1], rectH[3][0], rectH[0][1], rectH[3][0], rectH[1][1], rectH[2][0], rectH[1][1]);

                stroke(150, 102, 255);
                quad(rectS[2][0], rectS[0][1], rectS[3][0], rectS[0][1], rectS[3][0], rectS[1][1], rectS[2][0], rectS[1][1]);

                stroke(50, 102, 255);
                quad(rectB[2][0], rectB[0][1], rectB[3][0], rectB[0][1], rectB[3][0], rectB[1][1], rectB[2][0], rectB[1][1]);


                //HSBそれぞれのエリアから平均を求める

                int x1 = (rectH[2][0] + rectS[2][0] + rectB[2][0]) / 3;
                int y1 = (rectH[0][1] + rectS[0][1] + rectB[0][1]) / 3;
                int x2 = (rectH[3][0] + rectS[3][0] + rectB[3][0]) / 3;
                int y2 = (rectH[1][1] + rectS[1][1] + rectB[1][1]) / 3;

                stroke(10, 200, 150);
                quad(x1, y1, x2, y1, x2, y2, x1, y2);



                //中心を求める
                int x = (x2 - x1) / 2 + x1;
                int y = (y2 - y1) / 2 + y1;

                stroke(5, 200, 255);
                ellipse(x, y, 30, 30);


                /*
                * 中心から特定のエリアのピクセル値を平均化し、その値の&#38334;値&#20869;に&#23646;するピクセルを中心から探し出し、ラベリング。一つのオブジェクトとして登&#37682;
                * 以後、そのオブジェクトをテンプレ&#12540;トとし、顔認&#35388;を行う
                *
                */



        } //end of setup

        public void draw(){


        }

        //色相を判断するメソッド
        public boolean judgmentH(int h){

                boolean judg = false;

                //色相判定領内だったらtrueを返す
                if(h > HueRow && h < HueHig){

                        judg = true;

                }
                return judg;
        }

        //彩度を判定するメソッド
        public boolean judgmentS(int s){

                boolean judg = false;

                //彩度判定領内だったらtrueを返す
                if(s > SatRow && s < SatHig){

                        judg = true;

                }
                return judg;
        }

        //明るさを判定するメソッド
        public boolean judgmentB(int b){

                boolean judg = false;

                //明るさが判定領内だったらtrueを返す
                if(b > BriRow && b < BriHig){

                        judg = true;

                }
                return judg;
        }

        //RGBを分解するメソッド
        public int rgb(String rgb, int num){
                int rgbNum = 0;
                StringBuffer s = new StringBuffer(rgb);

                switch(num){
                        case 1:
                        //赤の処理
                        s.delete(2, 6);
                        break;
                        case 2:
                        //緑の処理
                        s.delete(0, 2);
                        s.delete(2, 4);
                        break;
                        case 3:
                        //青の処理
                        s.delete(0, 4);
                        break;
                }

                //16進数を10進数に変換する
                rgbNum = Integer.decode("0x" + s.toString()).intValue();
                return rgbNum;
        }
}

Fc001_3

Fc002_3

Fc003_3




前回のプログラムでは反応しなかった画像にもプログラムを動作させることだ出来ました。
どうやら考え方は間違った方向に行ってなさそうですね。


完全独習 統計学入門完全独習 統計学入門
価格 : ¥1,890 (税込み)

「これ以上何かを削ったら、統計学にならない」という、最小限の道具立て(ツール)と簡単さで書かれた「超入門書」!! 確率の知識はほとんど使わない。微分積分もシグマも全く使わない。使う数学は、中学の数学(ルートと1次不等式)までだから、高校数学がわからなくても(忘れてしまっていても)大丈夫。毎講に穴埋め式の簡単な練習問題がついているので、独習に最適

|

« 顔認識プログラム | トップページ | 顔認識プログラム 3 »

processing」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/198455/48853012

この記事へのトラックバック一覧です: 顔認識プログラム 2:

« 顔認識プログラム | トップページ | 顔認識プログラム 3 »