Android机器视觉实现框架

因为做竞赛要用到机器视觉,本来想用CM4开源平台但是由于需要很大的计算资源,手机更加合适方便,并且开发周期短,不需要操纵让人心烦的硬件逻辑
本Demo程序是基于安卓摄像头动态提取图像加工后输出到屏幕上的。
这个程序的逻辑很简单,找到图像中某一个颜色区域,比如,找到图像中的红色方块(环境颜色都是蓝色这种容易跟红色分开的色泽)
首先,在Manifest.xml文件中加入
    
    
上面这些是开启摄像头允许


然后我们在布局文件中定义两个SurfaceView
    
    

为什么是两个surfaceview呢,因为有一个surfaceview是用来预览摄像头的,但是我们需要预览的是经过处理后的图像,因此我们另一个surfaceview来覆盖掉原本用来预览摄像头的surfaceview


下面试MainActivity
public class MainActivity extends Activity implements SurfaceHolder.Callback,PreviewCallback{

    private Camera camera;
    private SurfaceView view=null;
    private SurfaceView surfaceDraw = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        view = (SurfaceView) findViewById(R.id.surface_view);
        view.getHolder().addCallback(this);
        surfaceDraw= (SurfaceView) findViewById(R.id.surface_view2);
        surfaceDraw.setVisibility(View.VISIBLE);
        surfaceDraw.setZOrderOnTop(true);//我们自己的预览窗口放到顶部,这个必须
    }

    public void surfaceCreated(SurfaceHolder holder) {
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        try
        {
            camera = Camera.open();//打开摄像头
            camera.setPreviewDisplay(holder);
            Camera.Parameters parameters = camera.getParameters();

            //支持照片格式,这里向调试器打印出所支持的所有照片格式
            List supPicFmtList = parameters.getSupportedPictureFormats();
            Log.d("LeoHDRTest", "Supported Picutre Format :" );
            for(int num = 0; num < supPicFmtList.size(); num++)
            {
                Integer ISupPicFmt = supPicFmtList.get(num);
                switch(ISupPicFmt)
                {
                    case ImageFormat.JPEG:
                        Log.d("lava", "Current Preview Format is JPEG");
                        break;
                    case ImageFormat.NV16:
                        Log.d("lava", "Current Preview Format is NV16");
                        break;
                    case ImageFormat.NV21:
                        Log.d("lava", "Current Preview Format is NV21");
                        break;
                    case ImageFormat.RGB_565:
                        Log.d("lava", "Current Preview Format is RGB_565");
                        break;
                    case ImageFormat.YUY2:
                        Log.d("lava", "Current Preview Format is YUY2");
                        break;
                    case ImageFormat.YV12:
                        Log.d("lava", "Current Preview Format is YV12");
                        break;
                    case ImageFormat.UNKNOWN:
                        Log.d("lava", "Current Preview Format is UNKNOWN");
                        break;
                    default:
                        Log.d("lava", "Current Preview Format is default : UNKNOWN");
                        break;
                }
            }

            //支持视频格式,这里向调试器打印出所支持的所有视频格式
            List supPreFmtList = parameters.getSupportedPreviewFormats();
            Log.d("LeoHDRTest", "Supported Preview Format :");
            for(int num = 0; num < supPreFmtList.size(); num++)
            {
                Integer ISupPreFmt = supPreFmtList.get(num);
                switch(ISupPreFmt)
                {
                    case ImageFormat.JPEG:
                        Log.d("lava", "Current Preview Format is JPEG");
                        break;
                    case ImageFormat.NV16:
                        Log.d("lava", "Current Preview Format is NV16");
                        break;
                    case ImageFormat.NV21:
                        Log.d("lava", "Current Preview Format is NV21");
                        break;
                    case ImageFormat.RGB_565:
                        Log.d("lava", "Current Preview Format is RGB_565");
                        break;
                    case ImageFormat.YUY2:
                        Log.d("lava", "Current Preview Format is YUY2");
                        break;
                    case ImageFormat.YV12:
                        Log.d("lava", "Current Preview Format is YV12");
                        break;
                    case ImageFormat.UNKNOWN:
                        Log.d("lava", "Current Preview Format is UNKNOWN");
                        break;
                    default:
                        Log.d("lava", "Current Preview Format is default : UNKNOWN");
                        break;
                }

            }

            //获取摄像头支持图片尺寸
            List PicSupSizeList = parameters.getSupportedPictureSizes();
            Log.d("LeoHDRTest", "Camera Supported Picture Size are :");
            for(int num = 0; num < PicSupSizeList.size(); num++)
            {
                Size PicSupSize = PicSupSizeList.get(num);
                Log.d("LeoHDRTest", "< " + num +" >" + PicSupSize.width + " x " + PicSupSize.height);
            }

            //获取摄像头支持视频尺寸
            List supPreviewList = parameters.getSupportedPreviewSizes();
            Log.d("LeoHDRTest", "Camera Supported Preview Size are :");
            for(int num = 0; num < supPreviewList.size(); num++)
            {
                Size PicPreSupSize = supPreviewList.get(num);
                Log.d("LeoHDRTest", "< " + num +" >" + PicPreSupSize.width + " x " + PicPreSupSize.height);
            }

            parameters.setPreviewFormat(ImageFormat.NV21);//设置视频的输出格式支持NV21/YV12两种
            parameters.setPreviewSize(640, 480);//在这里修改获取图片大小,一定是能支持的
            parameters.setPreviewFrameRate(30);//每秒30帧,一般支持5,8,12,15,30,50fps

            camera.setParameters(parameters);
            camera.setDisplayOrientation(90);//旋转角度,垂直手机用90度
            camera.startPreview();//开始预览
            camera.setPreviewCallback(this);
        }
        catch(Exception e){
            e.printStackTrace();
            Log.e("lava", "vedio print error");
        }
    }

    /*下面是每一帧到来后所进入的method,这里的data为图像原始数据,一般为yuv420(NV21)格式
    所以我们在应用机器视觉时一般先把它转化为rgb888*/
    public void onPreviewFrame(byte[] data, Camera camera) {
        camProcess(data, 640, 480);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        if(camera != null) {
            camera.release();//需要释放摄像头资源
        }
        camera = null ;
    }

    private void camProcess(byte[] data, int width, int height){
        int i,j,Y,U,V,r,g,b
        int frame_size=width*height;
        for(i=0;i> 1) * width + (j& ~1) + 0; //当前像素点v分量的位置
                int p_u=frame_size+(i >> 1) * width + (j& ~1) + 1; //当前像素点u分量的位置
                int Y=(data[p_y]&0xff);
                int V=(data[p_v]&0xff);
                int U=(data[p_u]&0xff);
                r=(int)((Y)+1.4075*((V)-128));
                g=(int)((Y)-0.3455*((U)-128) - 0.7169*((V)-128));
                b=(int)((Y)+1.779*((U)-128));
                r=r>255?255:r;
                r=r<0?0:r;
                g=g>255?255:g;
                g=g<0?0:g;
                b=b>255?255:b;
                b=b<0?0:b;
                /*此时rgb就是得到这个像素位置的rgb值,下面我没有写处理函数,自己添加*/
            }
        }
        DrawThread thread=new DrawThread(surfaceDraw.getHolder(),后面是自己添加的参数);
        thread.start();
    }
}


下面添加需要的DrawThread类,该类是我自己定义的,主要是在我们的预览层加入自己绘制的图像(覆盖掉相机原始图像),这里必须要另外开线程才能正常显示
thread.start()方法在需要开启线程的地方开启就行,因为我这里每来一帧画一次后线程结束,把它放在onPreviewFrame方法中

class DrawThread extends Thread{

    private SurfaceHolder holder;

    public DrawThread(SurfaceHolder holder,自己的其他参数) {
        this.holder = holder;
	/*其他参数初始化*/
    }
    @Override
    public void run() {
        super.run();
        Canvas canvas = null;
        int counter = 0,i,j;
        try {
            canvas = holder.lockCanvas();
            /*下面就可以实现绘图了*/
            canvas.drawColor(Color.BLACK);//这样就先覆盖掉了相机原始图像

            holder.unlockCanvasAndPost(canvas);//提交画布
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

需要用到的包

我这里就把我工程中的包全部贴上去了
import java.util.List;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;







你可能感兴趣的:(机器视觉)