mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 04:43:22 -05:00
Merge pull request #29804 from MahathirMohammadShuvo:fix/facerecognizersf-match-const-input
objdetect: do not modify the input features in FaceRecognizerSF::match - #29804 `FaceRecognizerSF::match()` normalizes its two `InputArray` features in place, writing through to the caller's buffers, and returns a wrong score when the two overlap. ### Fix Normalize both features into their own destinations. This yields bit-exact the same values as the in-place form, checked across a range of shapes and depths including a non-continuous ROI, so scores for non-overlapping inputs do not move. ### Pull Request Readiness Checklist - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work (no issue reports this; #7298 is the related RFC) - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable (accuracy test added in-repo; it reuses the existing model, so there is no opencv_extra patch) - [ ] The feature is well documented and sample code can be built with the project CMake (n/a — bug fix, no API, sample or documentation change)
This commit is contained in:
committed by
GitHub
parent
6dc8e40903
commit
13c571a801
@@ -61,9 +61,10 @@ public:
|
||||
}
|
||||
double match(InputArray _face_feature1, InputArray _face_feature2, int dis_type) const override
|
||||
{
|
||||
Mat face_feature1 = _face_feature1.getMat(), face_feature2 = _face_feature2.getMat();
|
||||
normalize(face_feature1, face_feature1);
|
||||
normalize(face_feature2, face_feature2);
|
||||
// match() is const and takes InputArray: never write through to the caller's buffers.
|
||||
Mat face_feature1, face_feature2;
|
||||
normalize(_face_feature1, face_feature1);
|
||||
normalize(_face_feature2, face_feature2);
|
||||
|
||||
if(dis_type == DisType::FR_COSINE){
|
||||
return sum(face_feature1.mul(face_feature2))[0];
|
||||
|
||||
@@ -213,4 +213,25 @@ TEST(Objdetect_face_recognition, regression)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Objdetect_face_recognition, match_does_not_modify_input)
|
||||
{
|
||||
std::string recog_model = findDataFile("dnn/onnx/models/face_recognizer_fast.onnx", false);
|
||||
Ptr<FaceRecognizerSF> faceRecognizer = FaceRecognizerSF::create(recog_model, "");
|
||||
|
||||
// match() is declared const and takes both features as InputArray, so it must leave
|
||||
// the caller's data untouched.
|
||||
Mat feature1(1, 128, CV_32F), feature2(1, 128, CV_32F);
|
||||
randu(feature1, Scalar::all(-10), Scalar::all(10));
|
||||
randu(feature2, Scalar::all(-10), Scalar::all(10));
|
||||
Mat expected1 = feature1.clone(), expected2 = feature2.clone();
|
||||
|
||||
faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_COSINE);
|
||||
EXPECT_EQ(0, cvtest::norm(expected1, feature1, NORM_INF)) << "FR_COSINE changed input 1";
|
||||
EXPECT_EQ(0, cvtest::norm(expected2, feature2, NORM_INF)) << "FR_COSINE changed input 2";
|
||||
|
||||
faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_NORM_L2);
|
||||
EXPECT_EQ(0, cvtest::norm(expected1, feature1, NORM_INF)) << "FR_NORM_L2 changed input 1";
|
||||
EXPECT_EQ(0, cvtest::norm(expected2, feature2, NORM_INF)) << "FR_NORM_L2 changed input 2";
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
Reference in New Issue
Block a user