カメラのプレビューを自分で描画するプログラムを作った。使ってるうクラスの関係でAndroid 2.1以降で動くと思われる。必要なPermissionは
android.permission.CAMERA
となっている。あとandroid:screenOrientation="landscape"を忘れずに。今回はプレビューで取得した画像をモノクロ画像に変換して描画してみた
package camera.test; import java.util.List; import android.hardware.Camera; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.view.SurfaceHolder; import android.view.SurfaceView; public class CameraView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback{ private Camera camera; private int width; private int height; private Bitmap bitmap; private int[] src; private int[] monoRGBs; public CameraView(Context context) { super(context); SurfaceHolder holder = getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL); } public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); try{ camera.setPreviewCallback(this); }catch(Exception e){ android.util.Log.e("", e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { camera.stopPreview(); Camera.Parameters parameters = camera.getParameters(); List<Camera.Size> sizes = parameters.getSupportedPreviewSizes(); Camera.Size optimalSize = CameraView.getOptimalPreviewSize(sizes, w, h); width = optimalSize.width; height = optimalSize.height; parameters.setPreviewSize(width, height); //効果が無い? //parameters.setColorEffect(Camera.Parameters.EFFECT_MONO); bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); src = new int[width * height]; monoRGBs = new int[width * height]; camera.setParameters(parameters); camera.startPreview(); } public void surfaceDestroyed(SurfaceHolder holder) { camera.setPreviewCallback(null); camera.stopPreview(); camera.release(); } public void onPreviewFrame(final byte[] data, Camera camera){ byte[] dataE = new byte[(int)(width * height * 1.5)]; for(int i = 0; i < data.length; i++){ dataE[i] = data[i]; } CameraView.decodeYUV420SP(src, dataE, width, height); CameraView.monoFilter(monoRGBs, src, width, height); bitmap.setPixels(monoRGBs, 0, width, 0, 0, width, height); SurfaceHolder holder = getHolder(); Canvas canvas = holder.lockCanvas(); canvas.drawBitmap(bitmap, 0, 0, new Paint()); holder.unlockCanvasAndPost(canvas); } private static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { int min = Integer.MAX_VALUE; Camera.Size optimalSize = sizes.get(0); for(Camera.Size size : sizes){ if(size .width < w || size.height < h){ continue; } int dw = Math.abs(w - size.width); int dh = Math.abs(h - size.height); if(min > dw + dh){ min = dw + dh; optimalSize = size; } } return optimalSize; } private static void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) { final int frameSize = width * height; for (int j = 0, yp = 0; j < height; j++) { int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; for (int i = 0; i < width; i++, yp++) { int y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } int y1192 = 1192 * y; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); if (r < 0) r = 0; else if (r > 262143) r = 262143; if (g < 0) g = 0; else if (g > 262143) g = 262143; if (b < 0) b = 0; else if (b > 262143) b = 262143; rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); } } } private static void monoFilter(int[] to, int[] from, int width, int height){ int index, rgb, red, green, blue, mono, newRGB; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ index = y * width + x; rgb = from[index]; red = (rgb >> 16) & 0xFF; green = (rgb >> 8) & 0xFF; blue = rgb & 0xFF; mono = (red + green + blue) / 3; newRGB = 0xFF << 24 | mono << 16 | mono << 8 | mono; to[index] = newRGB; } } } }