自学内容网 自学内容网

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)!