图像处理(三) 检测障碍物

来源:互联网 发布:阿里云优惠码使用教程 编辑:程序博客网 时间:2024/04/30 23:47

前几天写了一个小的项目关于:当手机处于静止状态时,识别是否动或者前方有不同物体

MainActivity

public class MainActivity extends Activity implements SurfaceHolder.Callback,        PreviewCallback {    // 定义对象    private SurfaceView mSurfaceview = null; // SurfaceView对象:(视图组件)视频显示    private SurfaceHolder mSurfaceHolder = null; // SurfaceHolder对象:(抽象接口)SurfaceView支持类    private Camera mCamera;    private Camera.Parameters parameters = null;    private Bitmap bitmap;// 原图    private Bitmap tempBitmap;// temp bitmap    private Bitmap bitmap_;//处理后的bitmap    private Bitmap bgBitmap;//背景图    private Bitmap bgBitmap_;//处理后的背景图片    private ImageView img;    private SurfaceView view;    private long times = 0l;//连续多久不动时间    private long indexFrame = 0l;    private static final String TAG ="MainActivity";    private long times_ = 0l;//temp time        private int police_time = 25;//持续时间    private int police_time_ = 10;//持续时间    private long times_2 = 0l;//报警确认次数    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.camera_layout);        init();    }    // OpenCV库加载并初始化成功后的回调函数        private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {            @Override            public void onManagerConnected(int status) {                // TODO Auto-generated method stub                switch (status) {                case BaseLoaderCallback.SUCCESS:                    Log.i(TAG, "成功加载");                    break;                default:                    super.onManagerConnected(status);                    Log.i(TAG, "加载失败");                    break;                }            }        };        @Override        protected void onResume() {            // TODO Auto-generated method stub            super.onResume();            // load OpenCV engine and init OpenCV library            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_4,                    getApplicationContext(), mLoaderCallback);            Log.i(TAG, "onResume sucess load OpenCV...");        }    // 初始化控件    private void init() {        // SurfaceView        view = (SurfaceView) findViewById(R.id.surface_view);        // 照相机预览的空间        view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        view.getHolder().setFixedSize(1920, 1080); // 设置Surface分辨率        view.getHolder().setKeepScreenOn(true);// 屏幕常亮        view.getHolder().addCallback(this);// 为SurfaceView的句柄添加一个回调函数        // ImageView        img = (ImageView) findViewById(R.id.img_res);    }    // SurfaceHoder.Callback    // 当SurfaceView/预览界面的格式和大小发生改变时,该方法被调用    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width,            int height) {        // TODO Auto-generated method stub        parameters = mCamera.getParameters(); // 获取各项参数        mCamera.setParameters(parameters);        parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式        parameters.setPreviewSize(width, height); // 设置预览大小        parameters.setPreviewFrameRate(5); // 设置每秒显示4帧        parameters.setPictureSize(width, height); // 设置保存的图片尺寸        parameters.setJpegQuality(80); // 设置照片质量        mCamera.setPreviewCallback(this);        startFocus();    }    // SurfaceView启动时/初次实例化,预览界面被创建时,该方法被调用。    @Override    public void surfaceCreated(SurfaceHolder mSurfaceHolder) {        // TODO Auto-generated method stub        try {            mCamera = Camera.open(1); // 打开摄像头            mCamera.setPreviewDisplay(mSurfaceHolder); // 设置用于显示拍照影像的SurfaceHolder对象            mCamera.setDisplayOrientation(getPreviewDegree(MainActivity.this));            mCamera.startPreview(); // 开始预览        } catch (Exception e) {            e.printStackTrace();        }    }    // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度    public static int getPreviewDegree(Activity activity) {        // 获得手机的方向        int rotation = activity.getWindowManager().getDefaultDisplay()                .getRotation();        int degree = 0;        // 根据手机的方向计算相机预览画面应该选择的角度        switch (rotation) {        case Surface.ROTATION_0:            degree = 90;            break;        case Surface.ROTATION_90:            degree = 0;            break;        case Surface.ROTATION_180:            degree = 270;            break;        case Surface.ROTATION_270:            degree = 180;            break;        }          return degree;    }    // SurfaceView销毁时,该方法被调用    @Override    public void surfaceDestroyed(SurfaceHolder arg0) {        // TODO Auto-generated method stub        if (mCamera != null) {            mCamera.setPreviewCallback(null);            mCamera.release(); // 释放照相机            mCamera = null;        }    }    // PreviewCallback    @Override    public void onPreviewFrame(byte[] data, Camera camera) {        // TODO Auto-generated method stub        if (indexFrame++ % 6 != 0)            return;        Size size = camera.getParameters().getPreviewSize();        try {            YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width,                    size.height, null);            if (image != null) {                ByteArrayOutputStream stream = new ByteArrayOutputStream();                image.compressToJpeg(new Rect(0, 0, size.width, size.height),                        80, stream);                Bitmap bmp = BitmapFactory.decodeByteArray(                        stream.toByteArray(), 0, stream.size());                // **********************                // 因为图片会放生旋转,因此要对图片进行旋转到和手机在一个方向上                bmp = rotaingImageView(-90, bmp);                // 图片太大处理较慢,就把图片缩放裁剪                Matrix matrix = new Matrix();                matrix.postScale(0.125f, 0.125f); // 长和宽缩小的比例                bitmap = bmp.createBitmap(bmp, 0, 0, size.height, size.width,                        matrix, true);                bitmap_ = procSrc2Gray(bitmap);//灰度                bitmap_ = changeBitmap(bitmap);//二值                //报警                getPolice();                // **********************************                stream.close();            }        } catch (Exception ex) {            Log.e("Sys", "Error:" + ex.getMessage());        }    }    // 自动对焦    Timer timer = new Timer(true);    TimerTask task = new TimerTask() {        public void run() {            // 每次需要执行的代码放到这里面            // 实现自动对焦            mCamera.autoFocus(null);        }    };    public void startFocus() {        timer.schedule(task, 0, 3000);    }    // 旋转    public Bitmap rotaingImageView(int angle, Bitmap bitmap) {        // 旋转图片 动作        Matrix matrix = new Matrix();        matrix.postRotate(angle);        // 创建新的图片        Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),                bitmap.getHeight(), matrix, true);        return bm;    }    // 比较图片        public boolean isEquals(Bitmap b1, Bitmap b2) {            int xCount = b1.getWidth();            int yCount = b1.getHeight();            int number = 0;            for (int x = 0; x < xCount; x++) {                for (int y = 0; y < yCount; y++) {                    // 比较每个像素点颜色                    if (b1.getPixel(x, y) != b2.getPixel(x, y)) {                        number++;                    }                }            }            if(number < 500) return true;            return false;        }    //灰度化    public Bitmap procSrc2Gray(Bitmap bm){       Mat rgbMat = new Mat();         Mat grayMat = new Mat();         Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);         Utils.bitmapToMat(bm, rgbMat);//convert original bitmap to Mat, R G B.         Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);//rgbMat to gray grayMat       Utils.matToBitmap(grayMat, graybm);       return graybm;    }    //二值化    public Bitmap changeBitmap(Bitmap bm) {        Mat rgbMat = new Mat();          Mat grayMat = new Mat();          Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);          Utils.bitmapToMat(bm,rgbMat);        Imgproc.threshold(rgbMat,grayMat,100,255,Imgproc.THRESH_BINARY);        Utils.matToBitmap(grayMat,graybm);        return graybm;    } // 图像计算    public Bitmap getPicture(Bitmap bmp1, Bitmap bmp2) {        /*         * pixels 接收位图颜色值的数组 offset 写入到pixels[]中的第一个像素索引值 stride         * pixels[]中的行间距个数值(必须大于等于位图宽度)。可以为负数 x   从位图中读取的第一个像素的x坐标值。 y         * 从位图中读取的第一个像素的y坐标值 width   从每一行中读取的像素宽度 height    读取的行数         */        int m_ImageWidth, m_ImageHeigth;        m_ImageWidth = bmp1.getWidth();        m_ImageHeigth = bmp1.getHeight();        int m_Bmp1Pixel[], m_Bmp2Pixel[], m_Bmp3Pixel[];        m_Bmp1Pixel = new int[m_ImageWidth * m_ImageHeigth];        m_Bmp2Pixel = new int[m_ImageWidth * m_ImageHeigth];        m_Bmp3Pixel = new int[m_ImageWidth * m_ImageHeigth];        bmp1.getPixels(m_Bmp1Pixel, 0, m_ImageWidth, 0, 0, m_ImageWidth,                m_ImageHeigth);        bmp2.getPixels(m_Bmp2Pixel, 0, m_ImageWidth, 0, 0, m_ImageWidth,                m_ImageHeigth);        System.out.println("AAAAAAAAAAAA2");        for (int i = 0; i < m_ImageWidth * m_ImageHeigth; i++) {            if (m_Bmp1Pixel[i] != m_Bmp2Pixel[i]) {                m_Bmp3Pixel[i] = m_Bmp2Pixel[i];            }        }        System.out.println("AAAAAAAAAAAA3");        Bitmap pro = Bitmap.createBitmap(m_ImageWidth, m_ImageHeigth,                Bitmap.Config.ARGB_8888);        pro.setPixels(m_Bmp3Pixel, 0, m_ImageWidth, 0, 0, m_ImageWidth,                m_ImageHeigth);        System.out.println("AAAAAAAAAAAA4");        return pro;    }    //报警系统    public void getPolice(){        if(tempBitmap != null){            if (isEquals(tempBitmap, bitmap_) == true) {                times++;                times_2 = 0;                Log.e("MainActivity", "number:" + times + ";" );            }else{                times_ = 0;            }        }        if(tempBitmap != null && times < police_time){            if (isEquals(tempBitmap, bitmap_) == false){                times = times_;            }        }        //Toast.makeText(MainActivity.this, "number:" + times, Toast.LENGTH_LONG).show();        tempBitmap = bitmap_;        if(times == police_time){            bgBitmap = bitmap;//背景图            bgBitmap_ = procSrc2Gray(bgBitmap);//灰度            bgBitmap_ = changeBitmap(bgBitmap);//二值            //震动提醒//          Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);//          vibrator.vibrate(1000);            //声音提醒            NotificationManager manger = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);             Notification notification = new Notification();             //自定义声音   声音文件放在ram目录下,没有此目录自己创建一个            //notification.sound=Uri.parse("android.resource://" + getPackageName() + "/" +R.raw.mm);             notification.defaults=Notification.DEFAULT_SOUND;//手机系统提示音            manger.notify(1, notification);            Toast.makeText(MainActivity.this, "开始执行程序", Toast.LENGTH_LONG).show();        }        if(times >police_time){                Log.e(TAG, "action");                // 有结果,则终止线程                if(isEquals(bgBitmap_, bitmap_) == false){                    times_2++;                    if(times_2 > police_time_){                        // 有结果,则终止线程                        times = times_;                        Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:"                                + "1111"));                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                        startActivity(intent);                    }                }        }    }    //报警确认}

layout

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <SurfaceView        android:id="@+id/surface_view"        android:layout_width="fill_parent"        android:layout_height="fill_parent" />    <ImageView        android:id="@+id/img_res"        android:scaleType="centerInside"        android:layout_width="150dp"        android:layout_height="150dp"        android:layout_gravity="center_horizontal|bottom" /></FrameLayout>

这地方有几个难点:

1.  如何实现相机帧预览(即相机处于预览状态时,每帧图片多能得到);关键词 :PreviewCallback对应的方法:onPreviewFrame
// PreviewCallback    @Override    public void onPreviewFrame(byte[] data, Camera camera) {        // TODO Auto-generated method stub        if (indexFrame++ % 6 != 0)//一秒六帧。可以增加图片处理速度            return;        Size size = camera.getParameters().getPreviewSize();        try {            YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width,                    size.height, null);            if (image != null) {                ByteArrayOutputStream stream = new ByteArrayOutputStream();                image.compressToJpeg(new Rect(0, 0, size.width, size.height),                        80, stream);                Bitmap bmp = BitmapFactory.decodeByteArray(                        stream.toByteArray(), 0, stream.size());                // **********************                // 因为图片会放生旋转,因此要对图片进行旋转到和手机在一个方向上                bmp = rotaingImageView(-90, bmp);                // 图片太大处理较慢,就把图片缩放裁剪                Matrix matrix = new Matrix();                matrix.postScale(0.125f, 0.125f); // 长和宽缩小的比例                bitmap = bmp.createBitmap(bmp, 0, 0, size.height, size.width,                        matrix, true);                bitmap_ = procSrc2Gray(bitmap);//灰度                bitmap_ = changeBitmap(bitmap);//二值                //报警                getPolice();                // **********************************                stream.close();            }        } catch (Exception ex) {            Log.e("Sys", "Error:" + ex.getMessage());        }    }

其中,本身手机拍照图片会很大,图片对应显示就会很慢,人眼感觉就会一卡一卡的,除了处理每秒几帧,这里也图片裁切,缩小了

// 图片太大处理较慢,就把图片缩放裁剪                Matrix matrix = new Matrix();                matrix.postScale(0.125f, 0.125f); // 长和宽缩小的比例                bitmap = bmp.createBitmap(bmp, 0, 0, size.height, size.width,                        matrix, true);

两个方法:postScale();createBitmap()

2.  怎么去识别相机如何不动;思路:①将每帧处理的图片保存为tempbitmap ;②下一帧的图片与之比较;③相同times++,不同times = 0;④当times = x 时,即手机不动了。
//手机画面确认不动if(tempBitmap != null){            if (isEquals(tempBitmap, bitmap_) == true) {                times++;                times_2 = 0;                Log.e("MainActivity", "number:" + times + ";" );            }else{                times_ = 0;            }        }        if(tempBitmap != null && times < police_time){            if (isEquals(tempBitmap, bitmap_) == false){                times = times_;            }        }
3.  相机不动时,如何确认前方有障碍物或者手机在动;    思路相同,就不详细诉说了,代码多有

当时除了这些问题还有一些简单的问题卡了我好久,

1.相机如何自动对焦(要用时调用starFocus()):

// 自动对焦    Timer timer = new Timer(true);    TimerTask task = new TimerTask() {        public void run() {            // 每次需要执行的代码放到这里面            // 实现自动对焦            mCamera.autoFocus(null);        }    };    public void startFocus() {        timer.schedule(task, 0, 3000);    }

2.如何比较两组图片是否为相同(我能力有限不能让所有rgb值一样,所以就取了一个约值,2%-3%)

处理最重要的地方:将比较的两幅图片,灰度化并且二值化,不然你会很惨的

    // 比较图片        public boolean isEquals(Bitmap b1, Bitmap b2) {            int xCount = b1.getWidth();            int yCount = b1.getHeight();            int number = 0;            for (int x = 0; x < xCount; x++) {                for (int y = 0; y < yCount; y++) {                    // 比较每个像素点颜色                    if (b1.getPixel(x, y) != b2.getPixel(x, y)) {                        number++;                    }                }            }            if(number < 500) return true;            return false;        }

二值化,灰度化:

//灰度化    public Bitmap procSrc2Gray(Bitmap bm){       Mat rgbMat = new Mat();         Mat grayMat = new Mat();         Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);         Utils.bitmapToMat(bm, rgbMat);//convert original bitmap to Mat, R G B.         Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);//rgbMat to gray grayMat       Utils.matToBitmap(grayMat, graybm);       return graybm;    }    //二值化    public Bitmap changeBitmap(Bitmap bm) {        Mat rgbMat = new Mat();          Mat grayMat = new Mat();          Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);          Utils.bitmapToMat(bm,rgbMat);        Imgproc.threshold(rgbMat,grayMat,100,255,Imgproc.THRESH_BINARY);        Utils.matToBitmap(grayMat,graybm);        return graybm;    }

这里关于opencv的运用前面的博客有详细说明。

0 0
原创粉丝点击