android UvcCamera中使用OpenCV人脸识别
UvcCamera:
https://xie.infoq.cn/article/7e6a906f7096bb8e743ec2fc1
OpenCV
https://blog.csdn.net/switch_love_case/article/details/104137311
public class UserFaceActivity extends BaseActivity implements CameraDialog.CameraDialogParent {
private static final String TAG = "UserFaceActivity";
private final Object mSync = new Object();
// for accessing USB and USB camera
private USBMonitor mUSBMonitor;
private UVCCamera mUVCCamera;
private SurfaceView surfaceView;
private Surface mPreviewSurface;
private boolean isActive, isPreview, isTakePhoto;
View photoView;
private CascadeClassifier classifier;
Mat mFrameChain = new Mat(UVCCamera.DEFAULT_PREVIEW_HEIGHT + UVCCamera.DEFAULT_PREVIEW_HEIGHT/2 , UVCCamera.DEFAULT_PREVIEW_WIDTH, CvType.CV_8UC1);
private int mAbsoluteFaceSize = 200;
String code;
String cur;
// 手动装载openCV库文件,以保证手机无需安装OpenCV Manager 不加这里将导致无法初始化 级联分类器(开机闪退)
static {
System.loadLibrary("opencv_java3");
}
boolean isFinish;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_face);
surfaceView = findViewById(R.id.user_face_surface_view);
mPreviewSurface = surfaceView.getHolder().getSurface();
code = getIntent().getStringExtra("code");
((TextView)findViewById(R.id.face_code)).setText(code);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(final SurfaceHolder holder) {
Log.v(TAG, "surfaceCreated:");
}
@Override
public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
if ((width == 0) || (height == 0)) return;
Log.v(TAG, "surfaceChanged:");
mPreviewSurface = holder.getSurface();
synchronized (mSync) {
if (isActive && !isPreview && (mUVCCamera != null)) {
mUVCCamera.setPreviewDisplay(mPreviewSurface);
mUVCCamera.startPreview();
isPreview = true;
}
}
}
@Override
public void surfaceDestroyed(final SurfaceHolder holder) {
Log.v(TAG, "surfaceDestroyed:");
synchronized (mSync) {
if (mUVCCamera != null) {
mUVCCamera.stopPreview();
}
isPreview = false;
if(mPreviewSurface!=null) {
mPreviewSurface.release();
mPreviewSurface = null;
}
}
}
});
mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
initClassifier();
findViewById(R.id.back).setOnClickListener(v -> {
synchronized (mSync){
if(isFinish) return;
isFinish = true;
isActive = isPreview = false;
}
new Thread(() -> {
try {
Thread.sleep(1000);
finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
});
findViewById(R.id.take_photo).setOnClickListener(v -> {
isTakePhoto = true;
});
photoView = findViewById(R.id.face_photo);
initFaceList();
findViewById(R.id.delete_photo).setOnClickListener(v -> deletePhoto());
}
// 初始化人脸级联分类器,必须先初始化
private void initClassifier() {
try {
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
FileOutputStream os = new FileOutputStream(cascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
is.close();
os.close();
classifier = new CascadeClassifier(cascadeFile.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onStart() {
super.onStart();
Log.v(TAG, "onStart:");
synchronized (mSync) {
if (mUSBMonitor != null) {
mUSBMonitor.register();
}
}
}
@Override
protected void onStop() {
Log.v(TAG, "onStop:");
synchronized (mSync) {
if (mUSBMonitor != null) {
mUSBMonitor.unregister();
}
}
super.onStop();
}
@Override
protected void onDestroy() {
Log.v(TAG, "onDestroy:");
clear();
super.onDestroy();
}
void clear(){
synchronized (mSync) {
isActive = isPreview = false;
if (mUVCCamera != null) {
mUVCCamera.stopCapture();
mUVCCamera.destroy();
mUVCCamera = null;
}
if (mUSBMonitor != null) {
mUSBMonitor.destroy();
mUSBMonitor = null;
}
if (mPreviewSurface != null) {
mPreviewSurface.release();
mPreviewSurface = null;
}
if(classifier!=null){
classifier.empty();
classifier = null;
}
}
}
private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {
@Override
public void onAttach(final UsbDevice device) {
Log.v(TAG, "onAttach:"+device.toString());
//自动连接
try {
if(device.getProductId() == getCameraId(UserFaceActivity.this, mUSBMonitor)){
mUSBMonitor.requestPermission(device);
}
}catch (Exception e){
e.printStackTrace();
}
//Toast.makeText(FaceActivity.this, "USB_DEVICE_ATTACHED", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
Log.v(TAG, "onConnect:"+device.toString());
//Toast.makeText(FaceActivity.this, "USB_DEVICE_Connect", Toast.LENGTH_SHORT).show();
synchronized (mSync) {
if (mUVCCamera != null) {
mUVCCamera.destroy();
mUVCCamera = null;
}
isActive = isPreview = false;
}
queueEvent(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
synchronized (mSync) {
final UVCCamera camera = new UVCCamera();
camera.open(ctrlBlock);
Log.i(TAG, "supportedSize:" + camera.getSupportedSize());
try {
camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG);
} catch (final IllegalArgumentException e) {
try {
// fallback to YUV mode
camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE);
} catch (final IllegalArgumentException e1) {
camera.destroy();
return;
}
}
Log.d(TAG, "Starting processing thread");
//new Thread(new CameraWorker()).start();
if (mPreviewSurface != null) {
isActive = true;
camera.setPreviewDisplay(mPreviewSurface);
camera.startPreview();
camera.setFrameCallback(frame -> {
if(!isActive || !isPreview) return;
//System.out.println("FrameCallback");
byte[] bytes = new byte[frame.capacity()];
frame.get(bytes);
//System.out.println("相机数据长度: " +bytes.length);
mFrameChain.put(0, 0, bytes);
if (isTakePhoto) {
takeFacePhoto(mFrameChain.submat(0, UVCCamera.DEFAULT_PREVIEW_HEIGHT, 0, UVCCamera.DEFAULT_PREVIEW_WIDTH));
}
}, UVCCamera.PIXEL_FORMAT_YUV420SP);
isPreview = true;
}
synchronized (mSync) {
mUVCCamera = camera;
}
}
}
}, 0);
}
@Override
public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
Log.v(TAG, "onDisconnect:");
// XXX you should check whether the comming device equal to camera device that currently using
queueEvent(new Runnable() {
@Override
public void run() {
synchronized (mSync) {
if (mUVCCamera != null) {
isActive = isPreview = false;
mUVCCamera.destroy();
mUVCCamera = null;
Log.d(TAG, "queueEvent: mUVCCamera.onDisconnect");
}
}
}
}, 0);
}
@Override
public void onDettach(final UsbDevice device) {
Log.v(TAG, "onDettach:");
//Toast.makeText(FaceActivity.this, "USB_DEVICE_DETACHED", Toast.LENGTH_SHORT).show();
}
@Override
public void onCancel(final UsbDevice device) {
}
};
/**
* to access from CameraDialog
* @return
*/
@Override
public USBMonitor getUSBMonitor() {
return mUSBMonitor;
}
@Override
public void onDialogResult(boolean canceled) {
if (canceled) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// FIXME
}
}, 0);
}
}
public void showPhoto(String path){
cur = path;
showPhoto(Imgcodecs.imread(getFile(code,path),0));
}
private void showPhoto(Mat mat){
if(mat==null){
runOnUiThread(() -> photoView.setBackgroundColor(Color.parseColor("#FF0000")));
}else {
try {
Bitmap bitmap = Bitmap.createBitmap((int) mat.size().width, (int) mat.size().height, Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mat, bitmap);
runOnUiThread(() -> photoView.setBackground(new BitmapDrawable(getResources(), bitmap)));
//todo bitmap回收
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void showFilePhoto(File file){
try {
FileInputStream fis = new FileInputStream(file);
Bitmap bitmap = BitmapFactory.decodeStream(fis);
//System.out.println("图片数据: "+bitmap.getByteCount());
runOnUiThread(()->photoView.setBackground(new BitmapDrawable(getResources(),bitmap)));
} catch (Exception e) {
e.printStackTrace();
}
}
private void deletePhoto(){
File file = new File(getFile(code,cur));
file.delete();
faceArr.remove(cur);
faceNameAdapter.notifyDataSetChanged();
photoView.setBackgroundColor(Color.parseColor("#FF0000"));
}
private void takeFacePhoto(Mat mGray){
Log.d(TAG, "takeFacePhoto: try");
try {
MatOfRect faces = new MatOfRect();
if (classifier != null)
classifier.detectMultiScale(mGray, faces, 1.1, 2, 2, new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
Rect[] rectArr = faces.toArray();
if(rectArr.length<=0) return;
Rect rect = rectArr[0] ;
double area = rect.area();
for(int i=1;i<rectArr.length;i++){
double a = rectArr[i].area();
if(a>area){
area = a;
rect = rectArr[i];//选取最大的
}
}
Log.d(TAG, "takeFacePhoto: do");
Mat mat = new Mat(mGray,rect);
String fileName = System.currentTimeMillis()+".png";
Imgcodecs.imwrite(getFile(code,fileName),mat);
isTakePhoto = false;
showPhoto(mat);
faceArr.add(fileName);
cur = fileName;
faceNameAdapter.notifyDataSetChanged();
}catch (Exception e){
e.printStackTrace();
}
}
FaceNameAdapter faceNameAdapter;
ArrayList<String> faceArr = new ArrayList<>();
private void initFaceList(){
File folder = new File(getFolder(code));
for (String name : folder.list()) {
if (name.endsWith(".png"))
faceArr.add(name);
}
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
RecyclerView rv = findViewById(R.id.face_rv);
rv.setLayoutManager(llm);
faceNameAdapter = new FaceNameAdapter(this,faceArr);
rv.setAdapter(faceNameAdapter);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ffffff"
tools:ignore="HardcodedText" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView style="@style/style" android:layout_alignParentStart="true" android:id="@+id/face_code" android:hint="条码"/>
<TextView style="@style/style" android:layout_centerInParent="true" android:text="人脸录入" />
<Button style="@style/button" android:layout_alignParentEnd="true" android:id="@+id/back" android:text="返回" />
</RelativeLayout>
<TextView
android:text="请正对摄像头拍摄脸部"
android:textColor="#FF0000"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<LinearLayout
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
>
<SurfaceView
android:id="@+id/user_face_surface_view"
android:layout_width="480dp"
android:layout_height="400dp" />
<LinearLayout
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:background="#aaaaaa"
android:layout_gravity="center_horizontal"
android:id="@+id/take_photo"
android:layout_margin="5dp"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:contentDescription="@string/camera"
android:text="拍"
/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="310dp"
android:id="@+id/face_rv"/>
<Button
android:background="#aaaaaa"
android:layout_gravity="center_horizontal"
android:id="@+id/delete_photo"
android:layout_margin="5dp"
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:contentDescription="@string/camera"
android:text="删"
/>
</LinearLayout>
<View
android:id="@+id/face_photo"
android:layout_width="400dp"
android:layout_height="400dp"
android:background="#FF0000" />
</LinearLayout>
</LinearLayout>
原文地址:https://blog.csdn.net/huangmingcsdn/article/details/143588764
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!