【Android】开启前后相机用OpenCV进行实时人脸检测
2016-08-17 16:40
701 查看
android中Camera setDisplayOrientation使用
Camera.parames.setDisplayOrientation问题解决
Android学习七---Hello OpenCV samples
Android学习——在Android中使用OpenCV的第一个程序
使用OpenCV Android SDK从摄像头帧实时检测人脸
[android]摄像机 setDisplayOrientation() 在肖像模式打破纵横比
detectMultiScale(Mat image, //输入图像
MatOfRect objects, //检测到的Rect
double scaleFactor, //缩放比例,必须大于1
int minNeighbors, //合并窗口时最小neighbor,每个候选矩阵至少包含的附近元素个数
int flags, //检测标记,只对旧格式的分类器有效,与cvHaarDetectObjects的参数flags相同,默认为0,可能的取值为CV_HAAR_DO_CANNY_PRUNING(CANNY边缘检测)、CV_HAAR_SCALE_IMAGE(缩放图像)、CV_HAAR_FIND_BIGGEST_OBJECT(寻找最大的目标)、CV_HAAR_DO_ROUGH_SEARCH(做粗略搜索);如果寻找最大的目标就不能缩放图像,也不能CANNY边缘检测
Size minSize, //最小检测目标
Size maxSize //最大检测目标
)
package com.duanjiwei.faceapp; import android.app.Activity; //import android.support.v7.app.AppCompatActivity; //import android.content.Context; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.Surface; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.CameraBridgeViewBase; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.objdetect.CascadeClassifier; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; public class MainActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener2 { private CameraBridgeViewBase mOpenCvCameraView; private CascadeClassifier cascadeClassifier; private static final String TAG = "OCVSample::Activity"; private boolean mIsFrontCamera = false; //ImageView picture; Mat imageMat; Mat mRgba; private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(MainActivity.this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { Log.i(TAG, "OpenCV loaded successfully"); imageMat=new Mat(); //加载人脸检测xml try { // Copy the resource into a temp file so OpenCV can load it InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface); File cascadeDir = getDir("cascade", Context.MODE_PRIVATE); File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml"); FileOutputStream os = new FileOutputStream(mCascadeFile); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } is.close(); os.close(); // Load the cascade classifier cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath()); } catch (Exception e) { Log.e("OpenCVActivity", "Error loading cascade", e); } //enable camera mOpenCvCameraView.enableView(); } break; default: { super.onManagerConnected(status); } break; } } }; public MainActivity() { Log.i(TAG, "Instantiated new " + MainActivity.this.getClass()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //picture = (ImageView)findViewById(R.id.imageView); mOpenCvCameraView = (CameraBridgeViewBase)findViewById(R.id.java_surface_view); mOpenCvCameraView.setCvCameraViewListener(MainActivity.this); Button button1 = (Button)findViewById(R.id.button); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "开启前置相机!", Toast.LENGTH_SHORT).show(); mOpenCvCameraView.setVisibility(SurfaceView.GONE); //前置相机 mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.java_surface_view); mOpenCvCameraView.setCameraIndex(1); mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE); mOpenCvCameraView.setCvCameraViewListener(MainActivity.this); mOpenCvCameraView.enableView(); mIsFrontCamera = true; } }); Button button2 = (Button)findViewById(R.id.button2); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "开启后置相机!!", Toast.LENGTH_SHORT).show(); mOpenCvCameraView.setVisibility(SurfaceView.GONE); //后置相机 mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.java_surface_view); mOpenCvCameraView.setCameraIndex(-1); mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE); mOpenCvCameraView.setCvCameraViewListener(MainActivity.this); mOpenCvCameraView.enableView(); mIsFrontCamera = false; } }); } @Override public boolean onCreateOptionsMenu(Menu menu){ getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item){ switch(item.getItemId()){ case R.id.add_item: Toast.makeText(this, "You Clicked Add!!", Toast.LENGTH_SHORT).show(); break; case R.id.remove_item: Toast.makeText(this, "You Clicked Remove!", Toast.LENGTH_SHORT).show(); break; case R.id.delete_item: Toast.makeText(this, "You Clicked Delete!", Toast.LENGTH_SHORT).show(); break; default: break; } return true; } @Override public void onResume() { super.onResume(); if (!OpenCVLoader.initDebug()) { Log.d("OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization"); OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_10, this, mLoaderCallback); } else { Log.d("OpenCV", "OpenCV library found inside package. Using it!"); mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); } } @Override public void onCameraViewStarted(int width, int height) { mRgba = new Mat(height, width, CvType.CV_8UC4); } @Override public void onCameraViewStopped() { mRgba.release(); } @Override public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { Mat mGray = inputFrame.gray(); Mat mShow; mShow = inputFrame.rgba(); if ( !mIsFrontCamera) { Core.flip(mShow, mShow, 1); } //检测并显示 MatOfRect faces = new MatOfRect(); if (cascadeClassifier != null) { cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 2, 2, new Size(mGray.height()/5, mGray.height()/5), new Size()); } Rect[] facesArray = faces.toArray(); for (int i = 0; i <facesArray.length; i++) Core.rectangle(mShow, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3); return mShow; } @Override public void onPause() { super.onPause(); if (mOpenCvCameraView != null) mOpenCvCameraView.disableView(); } @Override public void onDestroy() { super.onDestroy(); if (mOpenCvCameraView != null) mOpenCvCameraView.disableView(); } }
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.duanjiwei.camcapture.MainActivity"> <org.opencv.android.JavaCameraView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/java_surface_view" android:layout_marginBottom="279dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id = "@+id/add_item" android:title = "Add"/> <item android:id = "@+id/remove_item" android:title = "Remove"/> <item android:id = "@+id/delete_item" android:title = "Delete"/> </menu>
相机权限:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.duanjiwei.camcapture"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.CAMERA"/> <uses-feature android:name="android.hardware.camera" android:required="false"/> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/> <uses-feature android:name="android.hardware.camera.front" android:required="false"/> <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/> </manifest>
[android]摄像机 setDisplayOrientation() 在肖像模式打破纵横比
我想拿相机预览,在纵向模式中正常工作允许活动本身通常改变方向的位置 (即,不被锁定为横向)。使用
setDisplayOrientation()严重打破的预告片的行为。
这可以表明对谷歌的 ApiDemos。第一幅图像基于
CameraPreview从
android-17版的
ApiDemos示例项目,哪里的唯一的更改是删除
android:orientation="landscape"从清单中的这一活动的项。下面的图像是纸的什么的结点
4,运行 Android 4.2,指着一个 8.5"正方形的相机显示屏上显示的截图:
不从,预览可以明显看出的是它是旋转 90 度。你看到在最右边的图像的袜子包脚实际上低于广场。
为此,解决方案至少为横向模式,是使用
setDisplayOrientation()。但是,如果您修改
Preview的内部类
CameraPreview有
mCamera.setDisplayOrientation(90);,你拿到这个:
值得注意的是,在广场不再是方形的。
这将使用相同
SurfaceView以前一样大小。我以外的再现了这种情况在一些其他的代码,
ApiDemos,和我获取相同的行为与
TextureView中的代码。
我简要地以为这个问题可能是,
getSupportedPreviewSizes()可能会返回不同的值,基于
setDisplayOrientation(),但快速的测试表明这不是个案。
任何人都不知道如何获得
setDisplayOrientation(),没有破坏图像的长宽比推到预览在纵向模式下工作吗?
谢谢 !
解决方法 1:
好的我想说搞这清楚。有几件谚语难题,并感谢 @kcoppock 帮我解决的这一些对洞察。首先,你需要考虑到方向时确定哪些预览的大小来选择。例如,
getOptimalPreviewSize()从
CameraPreview的
ApiDemos是漠视了他们的方向,只是因为他们的那个应用程序的版本已锁定为横向的方向。如果您想要让方向浮动,你必须扭转目标纵横比,以匹配。因此,凡
getOptimalPreviewSize()有:
double targetRatio=(double)width / height;
您还需要:
if (displayOrientation == 90 || displayOrientation == 270) { targetRatio=(double)height / width; }
其中
displayOrientation是一个从 0 到 360,我很确定从大约 100 行一些严重丑陋的代码,这就是为什么我将结束这一切在不久就会发布一个可重用组件的值。代码基于
setDisplayOrientation()JavaDocs和这个计算器答案。
(BTW,如果你读到这在 2013 年 7 月 1 日之后,你看不到这个答案在该组件中的链接,发表评论,提醒我,因为我忘了)
第二,你需要考虑到那显示方向控制的纵横比时
SurfaceView/
TextureView使用的。
CameraPreview活动从
ApiDemos有自己的
Preview
ViewGroup,处理纵横比,和你那里需要扭转在肖像使用纵横比:
if (displayOrientation == 90 || displayOrientation == 270) { previewWidth=mPreviewSize.height; previewHeight=mPreviewSize.width; } else { previewWidth=mPreviewSize.width; previewHeight=mPreviewSize.height; }
哪里
displayOrientation那是相同的值 (
90和
270分别被反向肖像和纵向和我还没试越来越反向纵向或反向景观要工作,所以可能会有更多的调整所需的注)。
第三 — — 和我发现令人愤怒 — — 你必须开始预览之前调用一个
setPictureSize()上
Camera.Parameters。否则,它是因为如果图片的纵横比应用到预览帧,事情搞砸。
所以我用了类似于以下内容的代码:
Camera.Parameters parameters=camera.getParameters(); Camera.Size pictureSize=getHost().getPictureSize(parameters); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); parameters.setPictureSize(pictureSize.width, pictureSize.height); parameters.setPictureFormat(ImageFormat.JPEG); camera.setParameters(parameters); camera.startPreview();
这是错误的。你真正需要的是:
Camera.Parameters parameters=camera.getParameters(); Camera.Size pictureSize=getHost().getPictureSize(parameters); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); camera.setParameters(parameters); camera.startPreview(); parameters=camera.getParameters(); parameters.setPictureSize(pictureSize.width, pictureSize.height); parameters.setPictureFormat(ImageFormat.JPEG); camera.setParameters(parameters);
没有这种变化,我舒展的纵横比,甚至在景观。这不是一个问题为
CameraPreview的
ApiDemos,因为他们都不在拍照和所以他们永远不会调用
setPictureSize()。
不过,到目前为止,Nexus 4、 我现在有方形长宽比为纵向和横向浮动的方向 (即,不锁定为横向)。
我会试着记住要修正这个问题,如果我跑进了其他黑客所需的其他设备,再加上要链接到我
CameraView/
CameraFragment组件时他们被释放。
更新 #1
嗯,当然,它不可能由近这个简单。:-)
问题的修复程序在
setPictureSize()螺丝了纵横比作品......直到你拍张照片。此时,预览切换到错的纵横比。
一种可能性就是限制图片对那些具有相同 (或非常接近) 纵横比为预览,所以呃逆并不存在。我不喜欢这个答案,用户应该能够拿相机的任何图片大小提供。
您可以限制所损害的范围:
只更新图片大小等的
Camera.Parameters只是在拍摄照片之前
恢复前 picture 考虑到
Camera.Parameters后拍摄照片
这在虽然图片正在采取期间时刻仍然构成了错的纵横比。长远的解决办法,这个--我想--将暂时用静止图像 (最后一个预览帧) 同时图片替换相机预览正在采取。我最终来试试这个。
相关文章推荐
- VLC for Android 基于 Opencv 对 RTSP视频 实时人脸检测
- opencv从摄像头读取视频并实时进行人脸检测代码
- OpenCV on Android 开发(2)实现实时人脸检测
- Opencv for Android 3.2 + Android Studio 3.0 + ndk-build 实时人脸检测
- IOS 中调用opencv进行人脸检测
- 使用python+OpenCV进行人脸检测
- 【android+opencv人脸检测】
- 利用opencv中的级联分类器进行人脸检测-opencv学习(1)
- OpenCV例子四:摄像头实时人脸检测
- OpenCV 实践程序12——用分类器对视频进行人脸检测
- 在Android平台上利用opencv进行图像处理之边缘检测、灰度变换、缩小
- OpenCV与Compressive Tracking实现人脸的实时检测与跟踪
- opencv-摄像头人脸人眼实时检测
- 用摄像头进行人脸和人眼实时检测的优化 算法
- android相机中的人脸检测注意
- 玩转Android Camera开发(五):基于Google自带算法实时检测人脸并绘制人脸框(网络首发,附完整demo)
- python中使用OpenCV进行人脸检测的例子
- android opencv 人脸检测实现
- Android平台上利用opencv进行图像的边沿检测
- python+OpenCV进行人脸检测