The discretion of a man deferreth his anger

; and it is his glory to pass over a transgression (Prov. 19:11 KJV) - このブログは基本的に画像処理やRTMなど技術に関することを書き連ねていきます。

Androidのカメラプレビューをそのまま使って動画処理とか。

をやろうとしたら本当に大変だったorz
Androidのカメラプレビューを取ろうと思ったら、なんか、

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
    dw = width;
    dh = height;
    
    Camera.Parameters parameters = mCamera.getParameters();
    parameters.setPreviewSize(width, height);
    mCamera.setParameters(parameters);
    mCamera.startPreview();
    mCamera.setPreviewCallback(new Camera.PreviewCallback() {
	public void onPreviewFrame(byte[] data, Camera camera) {
             // Write in process
	}
    });
}

な事をしなきゃいけないらしく、とりあえずそれを差し込んでみて、適当にいつも通りピクセル弄りの画像処理をしようとしたら、メモリエラーで落ちまくり…。
何でだろう?と思うと、どうやらonPreviewFrameでプロセスしている間、Threadが立っていて他のViewを破棄している訳ではなく、たんまりとバッファに入れまくってるためすぐ落ちるそうで…。そんなん手前でやっとけよと突っ込みを入れたくなりつつ、仕方ないのでThreadを立てて外部のクラスにプロセスを飛ばすことに

try {
    if (!camproc.isProcess()) {
        // 処理時間を設定
        debugtext = " " + ((System.nanoTime() - t) / 1000000000D) + " sec";
	t = System.nanoTime();
        // スレッド実行
        camproc.initProcess(data, dw, dh);
        Thread thread = new Thread(camproc);
        thread.start();
    }
} catch (Exception e) {
        e.printStackTrace();
}

中に入れたのはこんな感じ。(参考: ももいろあたまさいと Thx!)

で、Thread用のクラスを作って、やっとこさバイナリ弄りを…としたところ、

class CamCoding implements Runnable{
    private boolean flag;
    byte[] buf;
    int[] bmpbuf;
    int w, h;
    int tw, th;

    public CamCoding(){
    	flag = false;
    	w = 0;
    	h = 0;
    	bmpbuf = null;
    	buf = null;
    }

    public boolean isProcess(){
 	return flag;
    }

    public void initProcess(byte[] code,int width, int height){
    	w = (int)width/4;
    	h = (int)height/4;
    	tw = width;
    	th = height;
    	bmpbuf = new int[h*w];
    	buf = code;
    }

    public void run() {
	flag = true;
	for (int j =0; j < h; j++){
	    for(int i = 0; i < w; i++){
		int ii = i*4;
		int jj = j*4;
		int pixel =  0xFF000000;
		int val = 0;
		if(i!=0 && j!=0 && i != w-1 && j != h-1){
		    for(int k = 0; k < 3; k++){
		        for(int l = 0; l<3; l++){
			    val = (int)buf[(jj-l-1)*(tw+10) + (ii-k-1)]*lap[l*3 + k];
			}
		    }
		val = Math.abs(val) / 4;
		if(val > 0xFF) val = 0xFFFFFF;
		else val = (val << 16) + (val << 8) + val;
		}
	        bmpbuf[j*w + i] = pixel + val;
	    }
	}
	bmp = Bitmap.createBitmap(bmpbuf, w, h, Bitmap.Config.ARGB_8888);
	bmpable = true;
	flag = false;
    }
}

なげぇよ。
まぁ、やりたいのは、3x3のフィルタを掛けたいだけなんですけど。
掛けるための時間を節約するために、キャプチャで取ったサイズを縦横1/4(面積的に1/16)まで落としてやったにも関わらず、これで1フレーム辺り0.5秒。長い…。
そして、これで2時間くらい格闘した。

val = (int)buf[(jj-l-1)*(tw+10) + (ii-k-1)]*lap[l*3 + k];

twって言うのは画像の横幅。buf[]がonPreviewFrameの時に取ってきたバイト列。こいつがYUV420なのは別に良いんだけど、普通、buf[j * tw + i] 見たいな感じで流せるはずなのに…なんで(tw+10)なんて10pxのOffsetがついてるんだ?IS01…。
とりあえず何とか画像処理は遅いけれども出来るようで…RGB変換とかはしないデス。メンドイ。別にYUVそのままで画像処理してもかまわんだろう?(何