图像处理(三) 检测障碍物
来源:互联网 发布:阿里云优惠码使用教程 编辑:程序博客网 时间: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
- 图像处理(三) 检测障碍物
- 检测图像边缘(包括障碍物的边缘,道路边缘)算法
- 数字图像处理实验三 图像轮廓提取与边缘检测
- 三种图像处理的基本边缘检测法
- 计算机视觉笔记(三)图像处理(2)霍夫变换、角点检测、图像匹配SIFT
- 基于深度摄像头的障碍物检测(realsense+opencv)
- 基于深度摄像头的障碍物检测(realsense+opencv)
- 【图像处理】图像边缘检测
- Python图像处理(8):边缘检测
- 图像处理算法(四)---边缘检测
- 图像处理(四):边缘检测(一):
- 图像处理 倾斜检测
- 【OpenCV图像处理】二十二、图像边缘检测(上)
- 【OpenCV图像处理】二十三、图像边缘检测(下)
- c#图像处理-边缘检测
- 图像处理-纹理检测-lbp
- 图像处理与边缘检测
- 图像处理------Canny边缘检测
- Android移动终端设计实验三+Intent与Activity实验
- MapReduce算法一、简单求和计数(类似WordCount)
- 上拉面板, 向上滑动的时候往上飞出一个显示面板的 Android 开源控件
- Java日志系统
- 数组的方法
- 图像处理(三) 检测障碍物
- 熊迈模块rootfs及启动脚本剖析
- 目录
- 基于@Transactional注解方式的spring声明式事务管理
- 字符串方法
- apache安全配置参考
- python-multiprocessing
- 最全Android webview使用详解
- IOS 原生二维码