(Θ Θ) を見つける

 相変わらず 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)ポニョ)
 
 まだまだ、続く。