Problem with Hamming Matcher

asked 2014-08-08 17:07:44 -0600

NitinPrasad gravatar image

updated 2014-08-09 06:59:41 -0600

Guanta gravatar image

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;
}
edit retag flag offensive close merge delete

Comments

1

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 gravatar imageGuanta ( 2014-08-09 06:58:10 -0600 )edit

@Guanta, if you too believe that this is a bug, would there be some better place to file an official ticket?

NitinPrasad gravatar imageNitinPrasad ( 2014-08-10 22:21:27 -0600 )edit
2

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.

[  1,   0,   0; // Mat a
   0,   0,   0;
   0,   0,   1]
[  0,   1,   1; // Mat b
   0,   0,   0;
   0,   0,   0]
1 0 1 // distance, queryIdx, trainIdx
0 1 1
1 2 0

[  0,   1,   1; // Mat b
   0,   0,   0;
   0,   0,   0]
[  1,   0,   0; // Mat a
   0,   0,   0;
   0,   0,   1]
1 0 2
0 1 1
0 2 1
berak gravatar imageberak ( 2014-08-11 05:39:42 -0600 )edit
2

the nearest neighbour of my nearest neighbour might not be me.

berak gravatar imageberak ( 2014-08-11 05:44:31 -0600 )edit

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.

Guanta gravatar imageGuanta ( 2014-08-11 10:32:11 -0600 )edit