Problem with Hamming Matcher
I'm running into issues that lead me to believe that Hamming matcher is not working as expected (or at least, not as I expect). Consider the following code (please run it if you have the appropriate packages installed):
int main( int argc, char** argv ) {
const int rows = 2;
const int cols = 3;
const int bitl = cols * 8;
BruteForceMatcher<Hamming> matcher;
std::vector<DMatch> matches;
Mat mat1 = cv::Mat::zeros(rows, cols, CV_8U);
std::bitset<bitl>* ptr1 = (std::bitset<bitl>*) (mat1.data + (rows - 1) * mat1.step[0]);
Mat mat2 = cv::Mat::zeros(rows, cols, CV_8U);
std::bitset<bitl>* ptr2 = (std::bitset<bitl>*) (mat2.data + (rows - 1) * mat2.step[0]);
ptr1->set(0, 0);
ptr2->set(0, 1);
std::cout << mat1 << std::endl << std::endl;
std::cout << mat2 << std::endl << std::endl;
matcher.match(mat1, mat2, matches);
for (int i = 0; i < (int) matches.size(); i++ ) {
std::cout << matches[i].distance << std::endl;
}
std::cout << std::endl << std::endl;
ptr1->set(0, 1);
ptr2->set(0, 0);
std::cout << mat1 << std::endl << std::endl;
std::cout << mat2 << std::endl << std::endl;
matcher.match(mat1, mat2, matches);
for (int i = 0; i < (int) matches.size(); i++ ) {
std::cout << matches[i].distance << std::endl;
}
}
This gives the following output:
[0, 0, 0;
0, 0, 0]
[0, 0, 0;
1, 0, 0]
0
0
[0, 0, 0;
1, 0, 0]
[0, 0, 0;
0, 0, 0]
0
1
which is, of course, nonsensical because the Hamming distance should be symmetric. Is there some subtlety in the way the Hamming matcher works that I am missing? Thank you all
EDIT: The example transferred to current OpenCV 2.4.9-version gives same output
const int rows = 2;
const int cols = 3;
cv::BFMatcher matcher(cv::NORM_HAMMING);
std::vector<cv::DMatch> matches;
cv::Mat mat1 = cv::Mat::zeros(rows, cols, CV_8U);
cv::Mat mat2 = cv::Mat::zeros(rows, cols, CV_8U);
mat2.at<uchar>(1,0) = 1;
std::cout << mat1 << "\n\n" << mat2 << "\n\n";
matcher.match(mat1, mat2, matches);
for (size_t i = 0; i < matches.size(); i++ ) {
std::cout << matches[i].distance << std::endl;
}
std::cout << std::endl << std::endl;
mat2.at<uchar>(1,0) = 0;
mat1.at<uchar>(1,0) = 1;
std::cout << mat1 << "\n\n" << mat2 << "\n\n";
matcher.match(mat1, mat2, matches);
for (size_t i = 0; i < matches.size(); i++ ) {
std::cout << matches[i].distance << std::endl;
}
I was so free to transfer the example to OpenCV 2.4.9, since I was curious if the problem there still exists, unfortunately it does. For me this is a clear bug. @berak what's your opinion on that?
@Guanta, if you too believe that this is a bug, would there be some better place to file an official ticket?
i don't really think it's a bug.
the matcher tries to find the closest item from the trainset to a given query.
if you reverse the roles of train and query set, you get different results, no matter what distance function used.
the nearest neighbour of my nearest neighbour might not be me.
Ah yes, stupid me, since for each row of the query the best matching row of the train is searched, the results are totally correct.