顔認識してみるか・・・まずはモザイク、グレースケールに

 作成中の「ぞろぞろ」はマップに従いパーティクルで髭を生やすだけなのですが、何人かの顔を写して髭を生やしてみたところ、面長の方は髭が宙に浮いてしまうのです。枠に合わないのですね。
 丸顔専用のアプリにするか、横方向に拡縮させて位置を合わせようかとも思ったのですが、拡縮はタッチ位置のパーティクルをリセットするために座標変換が必要になってくるはずで厄介そう。
 
 そこで、顔認識に挑戦してみるかと、顔を撮影しているのは判っているのだから目鼻口輪郭を切り出そうかと、そう思い立ったわけです。
 こんなアプリに何故にそこまで、と思われるかも知れませんが、この挑戦が次のアプリにつながったりするのですね。
 
 手始めに写真をモザイク可してみました。
device-2015-01-31-203934
 ブロック内のRGB値をそれぞれ足し上げて、平均値を戻せばモザイクになります。

	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();
		int[] pixels = new int[width * height];
		int[] mosaic = new int[(width/dot)*(height/dot)];
		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 = Color.rgb(r/(dot*dot), g/(dot*dot), b/(dot*dot));
				mosaic[mx*(width/dot) + my] = color;
				for(int x = i ; x < i + dot ; x++){
					for(int y = j ; y < j + dot ; y++){
						pixels[x*width + y] = color;
					}
				}
			}
		}
		bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
		return bitmap;
	}

 今回は、モザイク画像を表示する必要もなく mosaic[] に色情報を格納しておけば足りるのですが、正しく動いているか確認するために Bitmap を返しています。
 
 そしてグレースケール化してみます。
device-2015-01-31-205058
 ピクセル毎にRGB値をNTSC系加重平均法で計算した値に置き換えています。

	private Bitmap grayScaleBitmap(Bitmap bm){
		Bitmap bitmap = bm.copy(Bitmap.Config.ARGB_8888, true);
		final int width = bitmap.getWidth();
		final int height = bitmap.getHeight();
		int[] pixels = new int[width * height];
		bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
		int r = 0;
		int g = 0;
		int b = 0;
		int color = 0;
		for(int i = 0 ; i < height ; i++){
			for(int j = 0 ; j < width ; j++){
		        r = Color.red(pixels[i*width + j]);
		        g = Color.green(pixels[i*width + j]);
		        b = Color.blue(pixels[i*width + j]);
				color = (int) (r * 0.298912 + g * 0.586611 + b * 0.114478);
				pixels[i*width + j] = Color.rgb(color, color, color);
			}
		}
		bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
		return bitmap;
	}

 mosaic[] をグレースケール化する肝心の処理は書いていなかったりします。画像表示は完全にいらん処理です。
 
 ちなみに AndEngine で Bitmap picture をグレーモザイクにするために、各メソッドから戻る Bitmap を予め作成してある BitmapTextureAtlas pictureTextureAtlas や ITextureRegion picture_region とする方法はこんなコードです。
 詳しいことは聞かないでください。

	public void test(int dot){
		final Bitmap bitmap = grayScaleBitmap(mosaicBitmap(picture, dot));
		if(pictureTextureAtlas != null){
			picture_region = null;
			pictureTextureAtlas.unload();
			pictureTextureAtlas = null;
		}
		this.pictureTextureAtlas = new BitmapTextureAtlas(activity.getTextureManager(), 1024, 1024, TextureOptions.BILINEAR);
		final IBitmapTextureAtlasSource baseTextureSource = new EmptyBitmapTextureAtlasSource(bitmap.getWidth(), bitmap.getHeight());
		final IBitmapTextureAtlasSource decoratedTextureAtlasSource = new BaseBitmapTextureAtlasSourceDecorator(baseTextureSource){
			@Override
			protected void onDecorateBitmap(Canvas pCanvas) throws Exception{
				pCanvas.drawBitmap(bitmap, 0, 0, this.mPaint);
			}
			@Override
			public BaseBitmapTextureAtlasSourceDecorator deepCopy(){
				return this;
			}
		};
		this.picture_region = BitmapTextureAtlasTextureRegionFactory.createFromSource(this.pictureTextureAtlas, decoratedTextureAtlasSource, 0, 0);
		this.pictureTextureAtlas.load();
	}

 
 さて、このグレーモザイク画像から目鼻口輪郭を認識することができるのか!?
 
 できない時には「ぞろぞろ」は丸顔専用アプリとなります。