Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FaceRecognizer demo for Java #195

Closed
12341234-yangboran opened this issue Jul 12, 2023 · 14 comments
Closed

FaceRecognizer demo for Java #195

12341234-yangboran opened this issue Jul 12, 2023 · 14 comments
Assignees
Labels
demo anything related to demo in Python / C++

Comments

@12341234-yangboran
Copy link

12341234-yangboran commented Jul 12, 2023

package com.test;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.FaceDetectorYN;
import org.opencv.objdetect.FaceRecognizerSF;

/**
 * the java demo of FaceDetectorYN and FaceRecognizerSF
 */
public class FaceRecognizer {

    private static double cosine_similar_threshold = 0.363;

    private static double l2norm_similar_threshold = 1.128;

    // your path of yunet model
    private static String faceDetectModelPath = "lib/opencv/model/face/face_detection_yunet_2022mar.onnx";
    // declare faceDetector
    private static FaceDetectorYN faceDetector = null;

    // your path of sface model
    private static String faceRecognizModelPath = "lib/opencv/model/face/face_recognition_sface_2021dec.onnx";
    // declare faceRecognizer
    private static FaceRecognizerSF faceRecognizer = null;

    public static boolean faceRecognizer(String imgPathA, String imgPathB) {
        // load for opencv
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        // load for faceDetector
        loadFaceDetector();
        // load for faceRecognizer
        loadFaceRecognizer();

        return faceRecognizerUtil(imgPathA, imgPathA);
    }

    /**
     * load of faceDetector
     */
    private static void loadFaceDetector() {
        if (faceDetector != null) {
            return;
        }
        // You could use the full path for faceDetect model instead to get the resource
        String path = Thread.currentThread().getContextClassLoader().getResource("").getPath().substring(1);
        faceDetector = FaceDetectorYN.create(path + faceDetectModelPath, "", new Size());
    }

    /**
     * load for faceRecognizer
     */
    private static void loadFaceRecognizer() {
        if (faceRecognizer != null) {
            return;
        }
        // You could use the full path for faceRecogniz model instead to get the resource
        String path = Thread.currentThread().getContextClassLoader().getResource("").getPath().substring(1);
        faceRecognizer = FaceRecognizerSF.create(path + faceRecognizModelPath, "");
    }

    /**
     * faceRecogniz. Calculating the distance between two face features
     *
     * @param imgPathA the path of imgA
     * @param imgPathB the path of imgB
     * @return
     */
    private static boolean faceRecognizerUtil(String imgPathA, String imgPathB) {
        // 1.get mats of imgA and imgB
        Mat imgA = Imgcodecs.imread(imgPathA);
        Mat imgB = Imgcodecs.imread(imgPathB);

        // 2.detect face from given image
        Mat faceA = new Mat();
        faceDetector.setInputSize(imgA.size());
        faceDetector.detect(imgA, faceA);
        Mat faceB = new Mat();
        faceDetector.setInputSize(imgB.size());
        faceDetector.detect(imgB, faceB);

        /*// 3.Draw face info in img
        // Draw a face frame in imgA
        Imgproc.rectangle(imgA, new Rect((int) (faceA.get(0, 0)[0]), (int) (faceA.get(0, 1)[0]), (int) (faceA.get(0, 2)[0]), (int) (faceA.get(0, 3)[0])), new Scalar(0, 255, 0), 2);
        // Draw eyes/nose/mouth points on imgB
        Imgproc.circle(imgA, new Point(faceA.get(0, 4)[0], faceA.get(0, 5)[0]), 2, new Scalar(255, 0, 0), 2);
        Imgproc.circle(imgA, new Point(faceA.get(0, 6)[0], faceA.get(0, 7)[0]), 2, new Scalar(0, 0, 255), 2);
        Imgproc.circle(imgA, new Point(faceA.get(0, 8)[0], faceA.get(0, 9)[0]), 2, new Scalar(0, 255, 0), 2);
        Imgproc.circle(imgA, new Point(faceA.get(0, 10)[0], faceA.get(0, 11)[0]), 2, new Scalar(255, 0, 255), 2);
        Imgproc.circle(imgA, new Point(faceA.get(0, 12)[0], faceA.get(0, 13)[0]), 2, new Scalar(0, 255, 255), 2);
        // Imgcodecs.imwrite("", imgA);

        // Draw a face frame in imgB
        Imgproc.rectangle(imgB, new Rect((int) (faceB.get(0, 0)[0]), (int) (faceB.get(0, 1)[0]), (int) (faceB.get(0, 2)[0]), (int) (faceB.get(0, 3)[0])), new Scalar(0, 255, 0), 2);
        // Draw eyes/nose/mouth in imgB
        Imgproc.circle(imgB, new Point(faceB.get(0, 4)[0], faceB.get(0, 5)[0]), 2, new Scalar(255, 0, 0), 2);
        Imgproc.circle(imgB, new Point(faceB.get(0, 6)[0], faceB.get(0, 7)[0]), 2, new Scalar(0, 0, 255), 2);
        Imgproc.circle(imgB, new Point(faceB.get(0, 8)[0], faceB.get(0, 9)[0]), 2, new Scalar(0, 255, 0), 2);
        Imgproc.circle(imgB, new Point(faceB.get(0, 10)[0], faceB.get(0, 11)[0]), 2, new Scalar(255, 0, 255), 2);
        Imgproc.circle(imgB, new Point(faceB.get(0, 12)[0], faceB.get(0, 13)[0]), 2, new Scalar(0, 255, 255), 2);
        // Imgcodecs.imwrite("", imgB);*/

        // 4.Aligning image to put face on the standard position
        Mat alignFaceA = new Mat();
        faceRecognizer.alignCrop(imgA, faceA.row(0), alignFaceA);
        Mat alignFaceB = new Mat();
        faceRecognizer.alignCrop(imgB, faceB.row(0), alignFaceB);

        // 5.Extracting face feature from aligned image
        Mat featureA = new Mat();
        faceRecognizer.feature(alignFaceA, featureA);
        featureA = featureA.clone();
        Mat featureB = new Mat();
        faceRecognizer.feature(alignFaceB, featureB);
        featureB = featureB.clone();

        // 6.faceRecogniz. Calculating the distance between two face features
        // get cosine similar
        double match1 = faceRecognizer.match(featureA, featureB, FaceRecognizerSF.FR_COSINE);
        // get l2norm similar
        double match2 = faceRecognizer.match(featureA, featureB, FaceRecognizerSF.FR_NORM_L2);
        if (match1 >= cosine_similar_threshold && match2 <= l2norm_similar_threshold) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) {
        faceRecognizer("imgPathA", "imgPathB");
    }
}
@fengyuentau
Copy link
Member

What is your problem?

1 similar comment
@fengyuentau
Copy link
Member

What is your problem?

@fengyuentau fengyuentau self-assigned this Jul 12, 2023
@fengyuentau fengyuentau added the invalid This doesn't seem right label Jul 12, 2023
@12341234-yangboran
Copy link
Author

No problem.
There are no Java demo, I have a lot of bugs when using it. So I wrote this demo.

@fengyuentau
Copy link
Member

Is this demo working well?

1 similar comment
@fengyuentau
Copy link
Member

Is this demo working well?

@fengyuentau fengyuentau added demo anything related to demo in Python / C++ and removed invalid This doesn't seem right labels Jul 13, 2023
@12341234-yangboran
Copy link
Author

Is this demo working well?

very good

@fengyuentau
Copy link
Member

You are welcome to submit this java demo to our repo. If you plan to do so, please, use English for comments.

1 similar comment
@fengyuentau
Copy link
Member

You are welcome to submit this java demo to our repo. If you plan to do so, please, use English for comments.

@12341234-yangboran
Copy link
Author

You are welcome to submit this java demo to our repo. If you plan to do so, please, use English for comments.

ok

@liliangzisweet
Copy link

Is this demo working well?

very good

Hello, I've tried this demo. The faceRecognizer works well, but the faceDetector is not working for me. When I run 'faceDetector.detect(imgA, faceA)', I'cant get the face.(The result is a (-1,-1)). I promise my image contains face. I use the same image and change another face detect method, i.e.,cascadeClassifier. I get the right face. The faceDetector is loaded successfully. The model for faceDetector is downloaded from the original repository.

@fengyuentau
Copy link
Member

Is this demo working well?

very good

Hello, I've tried this demo. The faceRecognizer works well, but the faceDetector is not working for me. When I run 'faceDetector.detect(imgA, faceA)', I'cant get the face.(The result is a (-1,-1)). I promise my image contains face. I use the same image and change another face detect method, i.e.,cascadeClassifier. I get the right face. The faceDetector is loaded successfully. The model for faceDetector is downloaded from the original repository.

Please ensure:

  1. the model is downloaded correctly. SHA: acbe4b5976ade60c4b866a30d0720d71589c8bbc.
  2. the size of the face to be detected needs to be in range of 10x10 to 300x300.

@weeleng
Copy link

weeleng commented Jun 21, 2024

hello ,I use your code in my android project.
The face has been detected.
It reports 'opencv\modules\dnn\src\layers\nary_eltwise_layers.cpp:321: error: (-215:Assertion failed) shape[i] == 1 || outShape[i] == 1 in function 'findCommonShape'' when it runs faceRecognizerSF.feature(alignFaceA, featureA).
My opencv version is 4.10.0 . I build it from the opencv source code. Thank you .
This is my code.

try {
  Size newSize = new Size(240, 240);
  Mat imgTmpa = Imgcodecs.imread(modelFile1.getAbsolutePath());
  Mat imgA = new Mat();
  Imgproc.resize(imgTmpa, imgA, newSize);
  Mat imgTmpB = Imgcodecs.imread(modelFile2.getAbsolutePath());
  Mat imgB = new Mat();
  Imgproc.resize(imgTmpB, imgB, newSize);
  Mat faceA = new Mat();
  faceDetector.setInputSize(imgA.size());
  faceDetector.detect(imgA, faceA);
  Mat faceB = new Mat();
  faceDetector.setInputSize(imgB.size());
  faceDetector.detect(imgB, faceB);
  Mat alignFaceA = new Mat();
  faceRecognizerSF.alignCrop(imgA, faceA.row(0), alignFaceA);
  Mat alignFaceB = new Mat();
  faceRecognizerSF.alignCrop(imgB, faceB.row(0), alignFaceB);
  // 5.Extracting face feature from aligned image
  Mat featureA = new Mat();
  faceRecognizerSF.feature(alignFaceA, featureA);
  featureA = featureA.clone();
  Mat featureB = new Mat();
  faceRecognizerSF.feature(alignFaceB, featureB);
  featureB = featureB.clone();
  double match1 = faceRecognizerSF.match(featureA, featureB, FaceRecognizerSF.FR_COSINE);
  // get l2norm similar
  double match2 = faceRecognizerSF.match(featureA, featureB, FaceRecognizerSF.FR_NORM_L2);
  if (match1 >= 0.363 && match2 <= 1.128) {
  Log.i(TAG,"face same");
} else {
Log.e(TAG,"face  not same");
}
}catch (Exception e){
Log.e(TAG,e.toString());
}

@fengyuentau
Copy link
Member

hello ,I use your code in my android project. The face has been detected. It reports 'opencv\modules\dnn\src\layers\nary_eltwise_layers.cpp:321: error: (-215:Assertion failed) shape[i] == 1 || outShape[i] == 1 in function 'findCommonShape'' when it runs faceRecognizerSF.feature(alignFaceA, featureA). My opencv version is 4.10.0 . I build it from the opencv source code. Thank you . This is my code.

try {
  Size newSize = new Size(240, 240);
  Mat imgTmpa = Imgcodecs.imread(modelFile1.getAbsolutePath());
  Mat imgA = new Mat();
  Imgproc.resize(imgTmpa, imgA, newSize);
  Mat imgTmpB = Imgcodecs.imread(modelFile2.getAbsolutePath());
  Mat imgB = new Mat();
  Imgproc.resize(imgTmpB, imgB, newSize);
  Mat faceA = new Mat();
  faceDetector.setInputSize(imgA.size());
  faceDetector.detect(imgA, faceA);
  Mat faceB = new Mat();
  faceDetector.setInputSize(imgB.size());
  faceDetector.detect(imgB, faceB);
  Mat alignFaceA = new Mat();
  faceRecognizerSF.alignCrop(imgA, faceA.row(0), alignFaceA);
  Mat alignFaceB = new Mat();
  faceRecognizerSF.alignCrop(imgB, faceB.row(0), alignFaceB);
  // 5.Extracting face feature from aligned image
  Mat featureA = new Mat();
  faceRecognizerSF.feature(alignFaceA, featureA);
  featureA = featureA.clone();
  Mat featureB = new Mat();
  faceRecognizerSF.feature(alignFaceB, featureB);
  featureB = featureB.clone();
  double match1 = faceRecognizerSF.match(featureA, featureB, FaceRecognizerSF.FR_COSINE);
  // get l2norm similar
  double match2 = faceRecognizerSF.match(featureA, featureB, FaceRecognizerSF.FR_NORM_L2);
  if (match1 >= 0.363 && match2 <= 1.128) {
  Log.i(TAG,"face same");
} else {
Log.e(TAG,"face  not same");
}
}catch (Exception e){
Log.e(TAG,e.toString());
}

@weeleng Try a different size but larger than 240x240.

@papito
Copy link

papito commented Jul 18, 2024

@12341234-yangboran Excellent work! It works. I find that this model identifies body parts, such as ears and hands of all things, for some reason, even if you set the threshold to 0.9f. In that sense the "regular" DNN detectors are still very good.

I found another goldmine of examples for this here.

Update: Much better results with reasonably-sized images, somewhere around 600 - which probably makes sense as that's a common training set image dimension. With LARGE portraits, the model goes off the rails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
demo anything related to demo in Python / C++
Projects
None yet
Development

No branches or pull requests

5 participants