Ask Your Question
1

How do I remove duplicate rows in cv::Mat?

asked 2013-10-14 13:02:58 -0600

Yamaneko gravatar image

updated 2013-10-14 13:06:58 -0600

berak gravatar image

I have four n x 2 matrices and I want to concatenate them, but removing the duplicate rows. I tried to use std::set

std::set<cv::Mat> nonDuplicatedPairs;
for (int i = 0; i < drPairs.rows; ++i) {
    nonDuplicatedPairs.insert( deltasMat.row(i) );
    nonDuplicatedPairs.insert( drPairs.row(i) );
    nonDuplicatedPairs.insert( dlPairs.row(i) );
    nonDuplicatedPairs.insert( ulPairs.row(i) );
}

but it gives the following compilation error:

error C2440: 'return' : cannot convert from 'cv::MatExpr' to 'bool'

These matrices are of type CV_32SC and have only one channel.

edit retag flag offensive close merge delete

Comments

i bet the culprit is the overloaded == operator, like Mat c = (a==b);

berak gravatar imageberak ( 2013-10-14 13:13:31 -0600 )edit

It's true, @berak! The operator== is returning to me a MatExpr. How can I get only the boolean value?

Yamaneko gravatar imageYamaneko ( 2013-10-14 13:18:39 -0600 )edit

2 answers

Sort by ยป oldest newest most voted
1

answered 2013-12-19 10:24:20 -0600

Yamaneko gravatar image

updated 2013-12-19 10:32:05 -0600

This is a solution without STL. It is very ugly, though.

// keep only unique rows
Mat allPairs;       // Mat with duplicate values
Mat uniqueStrides;  // Mat that will contain the unique values
uniqueStrides.push_back( allPairs.row(0) );
for (int i = 1; i < allPairs.rows; ++i) {
    int isInside = false;
    for (int j = 0; j < uniqueStrides.rows; ++j) {
        int count = 0;
        for (int k = 0; k < uniqueStrides.cols; ++k) // checks by element of 
            if(allPairs.at<int>(i,k) == uniqueStrides.at<int>(j,k)) 
                ++count;
        if (count == 2) {
            isInside = true;
            break;
        }   
    }
    if (isInside == false) uniqueStrides.push_back( allPairs.row(i) );
}

This algorithm checks for every uniqueStrides entry and for every value. As my matrices are n x 2, I check if the number of equal values is two:

...
if (count == 2)
    isInside = true;
...

If positive, then this row is already in my matrix.

edit flag offensive delete link more
4

answered 2013-10-14 13:20:10 -0600

berak gravatar image

updated 2013-10-14 13:41:57 -0600

maybe overloading the comparison like this works:

struct compareMats 
{
  bool operator()(const Mat & a,  const Mat & b) const
  {
    return sum(b-a)[0] > 0; 
  }
};

std::set<Mat, compareMats> nonDuplicatedPairs;
edit flag offensive delete link more

Comments

Thank you, berak! But the compiler is saying to me: Error: function "compareMats" is not a type name. Do you know what might be?

Yamaneko gravatar imageYamaneko ( 2013-10-14 13:34:16 -0600 )edit

sorry, sloppy here, i'll edit ;) so, it needed a 'function object', not a plain function

berak gravatar imageberak ( 2013-10-14 13:38:17 -0600 )edit

@berak it worked. Thank you!

Yamaneko gravatar imageYamaneko ( 2013-10-14 13:46:41 -0600 )edit
2

Just wanted to add that it also works with a function, but it looks ugly and confusing. You basically need a function pointer in the set and the object(constructor) needs the comparison function as input.

std::set < Mat, bool(*)(const Mat&,const Mat&) > nonDuplicatedPairs(compareMats)

Moster gravatar imageMoster ( 2013-10-14 14:09:31 -0600 )edit

Will this code work if I have negative values in Mat?

Yamaneko gravatar imageYamaneko ( 2013-10-14 20:34:18 -0600 )edit

Yes, it should.

Moster gravatar imageMoster ( 2013-10-15 02:16:55 -0600 )edit

I asked because my set didn't fill with the values I expected. I tried to reverse the logic, but it didn't work either. I think the Mats I'm passing are not the values I think they are. I'll debug and give you a feedback.

Yamaneko gravatar imageYamaneko ( 2013-10-15 10:39:35 -0600 )edit

berak and I came to a conclusion that this approach might not work for every input. Depending on the order of a and b, the result may return true or false for the same pair of Mats. We considered to take the absolute value of the sum, however this solution does not respect Strick Weak Ordering. I think it is not possible to remove duplicates using STL when your matrix has positive and negative values. But, this answer still very helpful because it can work for other input and explains how to implement comparators for STL.

Yamaneko gravatar imageYamaneko ( 2013-12-19 10:01:36 -0600 )edit

Question Tools

Stats

Asked: 2013-10-14 13:02:58 -0600

Seen: 2,534 times

Last updated: Dec 19 '13