( 灬 ) を付ける

 瞳検出と口元検出の後に鼻筋検出して、その結果から瞳位置を補正し、再度口元検出したところ、総理の目や口も正しく捉えることができたので、鼻検出も加えて円眼鏡とちょび髭を付けてみました。
device-2015-02-23-003908
 サザンのアルバム発売を前に大晦日の話題を蒸し返すつもりはございません。
 
 眼鏡の傾きも計算して考慮しています。
 髭は、AndEngine の Particle システムを使っていますが、思い通りに生えてくれない・・。
 第一、ズレてるしなぁ。

(●ー●) を付ける 後編

 前編に続き「サングラスを付ける」ランキング発表です。
 
 早速、第5位
05
 沖縄及び北方対策 消費者及び食品安全 科学技術政策 宇宙政策特命大臣:判定の精度の割にはお似合いです。それにしても、仕事多そうだな。
 
 第4位
04
 コワい大統領:さすが元KGBだけあって、多少のズレは貫禄で押し切っています。コワいなぁ。
 
 第3位
03
 規制改革、少子化対策、男女共同参画特命大臣:コワい大統領をかわして3位入賞です。判定もドンピシャ、正面顔でフィット感もバッチリです。
 
 第2位
02
 コワくない大統領:判定の精度もさることながら、このフィット感!似合いすぎです。サングラスを付けること自体が東洋の人には不利だったか・・と思いきや。
 
 第1位
01
 経済産業大臣:両大統領をおさえ堂々の第1位です。眼鏡オン眼鏡でありながらジャストフィット、元々の眼鏡の弦も一体となり、最早画像を重ねたとは思えません。貫禄も十分で文句なしの第1位です。
 
 あぁ楽しかった。角度を調整して実装しようかしらん。
 さて、アプリ作成に戻るとするか。

(●ー●) を付ける 前編

 今回は「ベイマックスを付ける」ではなく「サングラスを付ける」です。
 
 瞳の検出がそこそこ動作しているので、閣僚各位と大統領にサングラスをかけてみました。
 多くの方々が FaceDetector クラスを使って作られているアプリと同じですね。
 
 サングラスの似合う(=検出器にフィットした)方をランキング形式でお届けします。
00
 モデルさんはこうなりました。
 サングラスの大きさは調整していますが、傾きは考慮していないので斜に写っている方はフィットしません。
 
 では、同率で第10位の方が2名いらっしゃいます。
10-2
 国家戦略特別区域特命大臣:若干斜めになっているので惜しくも10位です。瞳が水平位置だったら渡哲也さんに見紛う渋さとなっていたでしょう。
10-1
 防災特命大臣:やはり若干斜めとなってしまったことと上品さ故に10位止まりでした。
 
 第9位
09
 内閣官房長官:検出時にはダントツ相性が良かったのですが、サングラスのフィット感で順位を落としました。

 第8位
08
 復興大臣:赤ら顔の写真にマッチし怒り爆発感が出ています。
 
 第7位
07
 経済財政政策特命大臣:サングラスの位置なんでしょうか。なんかイヤラしい感じとなってしまいました。
 
 第6位
06
 総務大臣:嫌味なくかけていらっしゃいますが、フィット感がいまひとつ足りなかったか。
 
 第5位から次回「後編」に続く。

( 口 ) を見つける

 瞳の位置や間隔を参考に( 口 )を見つけてみました。
 瞳の判定が違っている方は、当然今回の判定も違ってきます。

 判定は「瞳の間隔よりチョイ長め × 高さ3モザイク分の範囲」を「瞳からチョイ下の位置から口がありそうな位置まで」探索し、一番暗くなった範囲を口としただけです。
 思った以上に上手くいったみたい。
 
 でも、副総理、外務大臣、農林水産大臣、防衛大臣は、もう手の施しようがないですね。
device-2015-02-15-203941 device-2015-02-15-204006 device-2015-02-15-204024
device-2015-02-15-204051 device-2015-02-15-204112 device-2015-02-15-204133
device-2015-02-15-204201 device-2015-02-15-204227 device-2015-02-15-204251
device-2015-02-15-204346 device-2015-02-15-204410 device-2015-02-15-204437
device-2015-02-15-204502 device-2015-02-15-204526 device-2015-02-15-204550
device-2015-02-15-204722 device-2015-02-15-204747 device-2015-02-15-204819
device-2015-02-15-204845 device-2015-02-15-204915 device-2015-02-15-204941
device-2015-02-15-205015 device-2015-02-15-205040
 
 鼻筋から顔の中心を見つければ、目も口も補正できるかな。
「( 鼻 ) を見つける」に期待。

(Θ Θ) を見つける

 相変わらず Android の FaceDetector クラスで出来ることを独自に実装しています。
 機能は本家には遠く及ばないけれど、作っていて楽しいからね。
 
 今回は(Θ Θ)を、(瞳 瞳)をピンポイントで見つけることに挑戦です。
 
 前回は、目の周囲を赤く染め上げることには成功しましたが、眉も判定してしまうので、恥らう乙女ではなく熱病患者のような染まり具合でした。
 
 瞳を見つける今回は、条件を更に付け加え
 ・ 画面には顔が写っている。
 ・ 目は画面上半分にある。
 ・ 右目は画面左半分、左目は画面右半分にある。
 ・ 判定範囲の上半分は眉のエリアである。眉毛を剃ったり抜いたりしていない。
と決め打ちし、目の範囲を決めた上で高得点かつ暗い点を「瞳」とすることにしました。
 
 画像を指定ドット数単位でモザイク・16階調グレースケール化するコードは、こんな感じです。全部盛りメソッド。

	private Bitmap mosaicBitmap(Bitmap bm, int dot){
		Bitmap bitmap = bm.copy(Bitmap.Config.ARGB_8888, true);
		final int width = bitmap.getWidth();
		final int height = bitmap.getHeight();
		final int mosaicWidth = width/dot;
		final int mosaicHeight = height/dot;
		int[] pixels = new int[width * height];
		int[] mosaic = new int[mosaicWidth*mosaicHeight];
		bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
		int r, g, b;
		int color;
		for(int i = 0 , mx = 0 ; i < height ; i += dot , mx++){
			for(int j = 0 , my = 0 ; j < width ; j += dot , my++){
				r = 0;
				g = 0;
				b = 0;
				for(int x = i ; x < i + dot ; x++){
					for(int y = j ; y < j + dot ; y++){
				        r += Color.red(pixels[x*width + y]);
				        g += Color.green(pixels[x*width + y]);
				        b += Color.blue(pixels[x*width + y]);
					}
				}
				color = ((int)((r/(dot*dot) * 0.298912 + g/(dot*dot) * 0.586611 + b/(dot*dot) * 0.114478) / 16)) * 16;
				mosaic[mx*mosaicWidth + my] = Color.rgb(color, color, color);
				for(int x = i ; x < i + dot ; x++){
					for(int y = j ; y < j + dot ; y++){
				        pixels[x*width + y] = Color.rgb(color, color, color);
					}
				}
			}
		}

		int[][] eyes = searchEyes(mosaic, mosaicWidth, mosaicHeight);
		for(int x = eyes[0][0]*dot ; x < eyes[0][0]*dot + dot ; x++){
			for(int y = eyes[0][1]*dot ; y < eyes[0][1]*dot + dot ; y++){
		        pixels[x*width + y] = Color.rgb(255, 0, 0);
			}
		}
		for(int x = eyes[1][0]*dot ; x < eyes[1][0]*dot + dot ; x++){
			for(int y = eyes[1][1]*dot ; y < eyes[1][1]*dot + dot ; y++){
		        pixels[x*width + y] = Color.rgb(255, 0, 0);
			}
		}

		bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
		return bitmap;
	}

 この中の searchEyes(int[], int. int) が瞳検出器です。
 こんなコード(2/15 に x,y なのか width,height なのか判りにくかったので修正)。

	private int[][] searchEyes(int[] target, final int width, final int height){
		int[][] eyes = new int[2][2];
		for(int i = 0 ; i < 2 ; i++){
			for(int j = 0 ; j < 2 ; j++){
				eyes[i][j] = 0;
			}
		}
		int[] result = new int[width*height];
		for(int i = 0 ; i < height ; i++){
			for(int j = 0 ; j < width ; j++){
				result[i*width + j] = 0;
			}
		}

		final int areaH = 2;
		final int areaW = 3;
		int[][] area = new int[areaH][areaW];
		int[][] areaCount = new int[areaH][areaW];
		final int areaH1 = 1;
		final int areaH2 = 2;
		final int areaHTotal = areaH1 + areaH2;
		final int areaW1 = 2;
		final int areaW2 = 1;
		final int areaW3 = 2;
		final int areaWTotal = areaW1 + areaW2 + areaW3;
		final int searchWidth = width/2;
		final int searchHeight = height/6;
		final int searchStartX = width/2 - searchWidth/areaWTotal*(areaW2+areaW3);
		final int searchEndX = width/2 - searchWidth/areaWTotal*areaW1;
		final int searchStartY = height/4;
		final int searchEndY = height/2;
		int positionX;
		int positionY;

		int eraseStart = 0;
		int eraseEnd = 0;

		for(int i = searchStartY ; i < searchEndY ; i++){
			for(int j = searchStartX ; j < searchEndX ; j++){
				for(int m = 0 ; m < areaH ; m++){
					for(int n = 0 ; n < areaW ; n++){
						area[m][n] = 0;
						areaCount[m][n] = 0;
					}
				}
				for(int x = i, h = 0 ; x < i + searchHeight ; x++, h++){
					for(int y = j, w = 0 ; y < j + searchWidth ; y++, w++){
						if(h < searchHeight/areaHTotal*areaH1) positionY = 0;
						else positionY = 1;
						if(w < searchWidth/areaWTotal*areaW1) positionX = 0;
						else if(w < searchWidth/areaWTotal*(areaW1+areaW2)) positionX = 1;
						else positionX = 2;
				        area[positionY][positionX] += target[x*width + y];
				        areaCount[positionY][positionX]++;
					}
				}
				for(int m = 0 ; m < areaH ; m++){
					for(int n = 0 ; n < areaW ; n++){
						area[m][n] /= areaCount[m][n];
					}
				}
				if(area[0][0] < area[0][1] && area[0][2] < area[0][1] && area[0][0] < area[1][0] && area[0][2] < area[1][2]){
					for(int x = i ; x < i + searchHeight/areaHTotal*areaH1 ; x++){
						for(int y = j ; y < j + searchWidth/areaWTotal*areaW1 ; y++){
					        result[x*width + y]++;
						}
					}
					for(int x = i ; x < i + searchHeight/areaHTotal*areaH1 ; x++){
						for(int y = j + searchWidth/areaWTotal*(areaW1+areaW2) ; y < j + searchWidth ; y++){
					        result[x*width + y]++;
						}
					}

					if(eraseStart == 0 && eraseEnd == 0){
						eraseStart = i;
						eraseEnd = i + searchHeight/areaHTotal*areaH1;
					}
					else if(eraseEnd + 1 == i + searchHeight/areaHTotal*areaH1){
						eraseEnd = i + searchHeight/areaHTotal*areaH1;
					}

				}
			}
		}

		int plus = 0;
		int color = 0;
		int maxRight = 0;
		int maxLeft = 0;
		for(int i = eraseStart + (eraseEnd - eraseStart)/2 ; i < searchEndY + searchHeight ; i++){
			for(int j = searchStartX ; j < searchEndX + searchWidth ; j++){
				plus = result[i*width + j];
				if(plus > 0){
			        color = Color.red(target[i*width + j]);
					if(j < width/2){
						if(maxRight < plus*(255 - color)){
							maxRight = plus*(255 - color);
							eyes[0][0] = i;
							eyes[0][1] = j;
						}
					}
					else{
						if(maxLeft < plus*(255 - color)){
							maxLeft = plus*(255 - color);
							eyes[1][0] = i;
							eyes[1][1] = j;
						}
					}
				}
			}
		}
		return eyes;
	}

 判定ポイントを赤目にします。

 では、結果発表です。
device-2015-02-14-121645 device-2015-02-14-121713 device-2015-02-14-121735
 総理と副総理は、前回から相性よくありません。
device-2015-02-14-121800 device-2015-02-14-121840 device-2015-02-14-121859
 官房長官、好きです。
device-2015-02-14-121928 device-2015-02-14-122012 device-2015-02-14-122038
 大統領はバッチリですね。
 彼らにフィッティングしてしまっている可能性もあるので、他の閣僚の方々にも登場願いました。
device-2015-02-14-122159 device-2015-02-14-122230 device-2015-02-14-122704
 外務大臣大ハズレ・・。
device-2015-02-14-122734 device-2015-02-14-122603 device-2015-02-14-122422
 厚生労働大臣惜しい。
 農林水産大臣は角度が悪いのか、献金疑惑が悪いのか。
device-2015-02-14-122630 device-2015-02-14-122506 device-2015-02-14-122532
 防衛大臣は大きさが足らんのだよ。
device-2015-02-14-122804 device-2015-02-14-122858 device-2015-02-14-122830
device-2015-02-14-122106 device-2015-02-14-122133
 特命大臣は、全般に成績がよいようです。
 
 認識率 74%、ジョージョーだね。((c)ポニョ)
 
 まだまだ、続く。