人脸识别app源码
package com.e.opencv;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import static android.Manifest.permission.CAMERA;
import static org.opencv.android.Utils.bitmapToMat;
public class CameraMain extends AppCompatActivity {
private static final String TAG = "OCVSample::Activity";
private Mat mRgba;
private Mat mGray;
private File mCascadeFile;
private CascadeClassifier mJavaDetector;
private float mRelativeFaceSize = 0.2f;
private int mAbsoluteFaceSize = 0;
private Camera camera;
private boolean isPreview = false;
private View mView;
private Mat locface;
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
// Load native library after(!) OpenCV initialization
System.loadLibrary("detection_based_tracker");
try {
// load cascade file from application resources
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
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();
mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
if (mJavaDetector.empty()) {
Log.e(TAG, "Failed to load cascade classifier");
mJavaDetector = null;
} else {
Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());
}
cascadeDir.delete();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
}
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.cameramain);
requestPermissions(new String[]{CAMERA}, 200);
SurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
mView=findViewById(R.id.myview);
// 获得 SurfaceHolder 对象
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
// 设置 Surface 格式
// 参数: PixelFormat中定义的 int 值 ,详细参见 PixelFormat.java
mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
// 如果需要,保持屏幕常亮
mSurfaceHolder.setKeepScreenOn(true);
// 设置 Surface 的分辨率
// mSurfaceHolder.setFixedSize(width,height);
// 设置 Surface 类型
// 参数:
// SURFACE_TYPE_NORMAL : 用 RAM 缓存原生数据的普通 Surface
// SURFACE_TYPE_HARDWARE : 适用于 DMA(Direct memory access )引擎和硬件加速的Surface
// SURFACE_TYPE_GPU : 适用于 GPU 加速的 Surface
// SURFACE_TYPE_PUSH_BUFFERS :表明该 Surface 不包含原生数据,Surface用到的数据由其他对象提供
// 在 Camera 图像预览中就使用 SURFACE_TYPE_PUSH_BUFFERS 类型的 Surface,有 Camera 负责提供给预览 Surface 数据,这样图像预览会比较流
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// 添加 Surface 的 callback 接口
mSurfaceHolder.addCallback(mSurfaceCallback);
}
private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
/**
* 在 Surface 首次创建时被立即调用:获得焦点时。一般在这里开启画图的线程
* @param surfaceHolder 持有当前 Surface 的 SurfaceHolder 对象
*/
@Override
public void surfaceCreated(final SurfaceHolder surfaceHolder) {
try {
// Camera,open() 默认返回的后置摄像头信息
camera = Camera.open();//打开硬件摄像头,这里导包得时候一定要注意是android.hardware.Camera
//此处也可以设置摄像头参数
/**
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);//得到窗口管理器
Display display = wm.getDefaultDisplay();//得到当前屏幕
Camera.Parameters parameters = camera.getParameters();//得到摄像头的参数
parameters.setPictureFormat(PixelFormat.RGB_888);//设置照片的格式
parameters.setJpegQuality(85);//设置照片的质量
parameters.setPictureSize(display.getHeight(), display.getWidth());//设置照片的大小,默认是和 屏幕一样大
camera.setParameters(parameters);
**/
//设置角度,此处 CameraId 我默认 为 0 (后置)
// CameraId 也可以 通过 参考 Camera.open() 源码 方法获取
Camera.Parameters parameters=camera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
camera.setParameters(parameters);
//自动聚焦:参考blog https://blog.csdn.net/yanzi1225627/article/details/8577682方法5
setCameraDisplayOrientation(CameraMain.this,0,camera);
camera.setPreviewDisplay(surfaceHolder);//通过SurfaceView显示取景画面
camera.startPreview();//开始预览
isPreview = true;//设置是否预览参数为真
mRgba=new Mat();
mGray=new Mat();
if (mAbsoluteFaceSize == 0) {
int height = mGray.rows();
if (Math.round(height * mRelativeFaceSize) > 0) {
mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
}
}
locface=new Mat();
Bitmap locbit=BitmapFactory.decodeResource(getApplicationContext().getResources(),R.raw.timg);
bitmapToMat(locbit,locface,true);
MatOfRect facestemp = new MatOfRect();
mJavaDetector.detectMultiScale(locface, facestemp, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
org.opencv.core.Rect[] facesArraytemp = facestemp.toArray();
if(facesArraytemp.length!=0) {
locface=onFace(locface, facesArraytemp[0]);
Imgproc.cvtColor(locface,locface,Imgproc.COLOR_BGR2GRAY);
locface.convertTo(locface, CvType.CV_32F);
}
camera.setPreviewCallback(new Camera.PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.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());
//facedect
//mNativeDetector.detect(mGray, faces);参考opencv
stream.close();
bitmapToMat(bmp,mRgba,true);
Log.d("mrgba",mRgba.toString());
MatOfRect faces = new MatOfRect();
mJavaDetector.detectMultiScale(mRgba, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
//t
org.opencv.core.Rect[] facesArray = faces.toArray();
//保存人脸位置的数组
if(facesArray.length!=0) {
Log.d("facepos","x:"+facesArray[0].x+"y:"+facesArray[0].y);
FrameLayout.LayoutParams focusItemParams = new FrameLayout.LayoutParams(mView.getLayoutParams());
focusItemParams.leftMargin = facesArray[0].x * ((int) getApplicationContext().getResources().getDisplayMetrics().density);
focusItemParams.topMargin = (facesArray[0].y - 65) * ((int) getApplicationContext().getResources().getDisplayMetrics().density);
focusItemParams.width = facesArray[0].width * ((int) getApplicationContext().getResources().getDisplayMetrics().density);
focusItemParams.height = (facesArray[0].height) * ((int) getApplicationContext().getResources().getDisplayMetrics().density);
//减去65的理由:返回的位置是眼睛所以看上去框框有点偏下,所以往上移动一点距离框住人脸。
//*后面参数的理由:opencv返回的单位是用的dp,如果用来设置view要用px,如果不转换会导致误差有点大。
//如果用到数组的话:
mView.setLayoutParams(focusItemParams);//focusView为你需要设置位置的VIEW
}
if(facesArray.length!=0) {
Mat imgface = new Mat();
imgface = onFace(mRgba, facesArray[0]);
Imgproc.cvtColor(imgface,imgface,Imgproc.COLOR_BGR2GRAY);
imgface.convertTo(imgface, CvType.CV_32F);
double target = Imgproc.compareHist(locface, imgface, Imgproc.CV_COMP_CORREL);
if(target<0){
target=-target;
}
//有可能到catch去了
System.out.println(target);
} // Log.d("comaa","xiangsidu:"+percent);
//把现在的读取拿到create里面去。
}
Log.d("image","get image success");
}catch(Exception ex){
Log.e("Sys","Error:"+ex.getMessage());
}
}
});
/**
@param format ss
* @author ldz
*/
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
/**
* 在 Surface 格式 和 大小发生变化时会立即调用,可以在这个方法中更新 Surface
* @param surfaceHolder 持有当前 Surface 的 SurfaceHolder 对象
* @param format surface 的新格式
* @param width surface 的新宽度
* @param height surface 的新高度
*/
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
}
/**
* 在 Surface 被销毁时立即调用:失去焦点时。一般在这里将画图的线程停止销毁
* @param surfaceHolder 持有当前 Surface 的 SurfaceHolder 对象
*/
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if(camera != null){
if(isPreview){//正在预览
mGray.release();
mRgba.release();
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
}
}
}
};
/**
* 设置 摄像头的角度
*
* @param activity 上下文
* @param cameraId 摄像头ID(假如手机有N个摄像头,cameraId 的值 就是 0 ~ N-1)
* @param camera 摄像头对象
*/
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
//获取摄像头信息
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
//获取摄像头当前的角度
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
//前置摄像头
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else {
// back-facing 后置摄像头
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
@Override
protected void onResume() {
super.onResume();
if (!OpenCVLoader.initDebug()) {
Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else {
Log.d(TAG, "OpenCV library found inside package. Using it!");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
//openCV4Android 需要加载用到
public Mat onFace(Mat mat, org.opencv.core.Rect rect) {
Mat imgface=null;
Mat mat1= new Mat();
//todo:传入一个mat和位置得到一个固定大小的mat图像。
imgface=mat.submat(rect);
Size commonsize=new Size(100,100);
Imgproc.resize(imgface,mat1,commonsize);
return mat1;
}}
查看19道真题和解析