Bhoke
Bhoke

Reputation: 521

Matrices become same after any operator

I have a class called BasePoint

BasePoint
{
public:
    BasePoint();
    //BasePoint(const BasePoint& bp);
    uint id;
    float avgVal;
    float varVal;
    float avgLas;
    float varLas;
    cv::Mat invariants;// Type : 32FC1
    int status;
};

and have 2 objects of this class:

BasePoint previousBasePoint;
BasePoint currentBasePoint;

In every iteration I perform

const float norm_factor = 1.0;
currentBasePoint.invariants = totalInvariants / norm_factor; // Problem is here
currentBasePoint.id = image_counter;

if(previousBasePoint.id == 0)
{
     previousBasePoint = currentBasePoint;
     currentPlace->members.push_back(currentBasePoint);
     wholebasepoints.push_back(currentBasePoint);
}
else
{
     //some code here
}

The problem with the code is that when I perform totalInvariants / norm_factor; instead of using totalInvariants, previousBasePoint become same with currentBasePoint. However, If I do not divide it everything works fine. What can be the problem here?

EDIT:

const float norm_factor = 1.0;
currentBasePoint.invariants = totalInvariants;
currentBasePoint.invariants = currenBasePoint.invariants / norm_factor

also works, but I am still wondering what is wrong with the division

Upvotes: 0

Views: 73

Answers (2)

Bhoke
Bhoke

Reputation: 521

I solved the problem by overloading = operator.

class A{
    public:
        cv::Mat matrix;
        A(){
            this->matrix = cv::Mat();
        }

        A(const A& otherA){
            std::cout << "Copy Called" << std::endl;
            this->matrix = otherA.matrix.clone();
        }

            void operator = (const A& otherA){
            std::cout << "Operator overlad called" << std::endl;
            this->matrix = otherA.matrix.clone();
        }
    };

    int main()
    {
        A a1,a2;
        cv::Mat anotherMat = cv::Mat::ones(3,3,CV_32FC1);
        a1.matrix = cv::Mat::zeros(3,3,CV_32FC1);
        //        a2 = a1;
        a2 = a1;
        std::cout << a2.matrix << std::endl;
        a1.matrix = anotherMat / 5; // Division, type MatExpr
        std::cout << a2.matrix << std::endl;

        return 0;
    }

Output without operator overloading[1]:

[0, 0, 0;   [0.2, 0.2, 0.2;
 0, 0, 0;    0.2, 0.2, 0.2;
 0, 0, 0]    0.2, 0.2, 0.2]

Output with operator overloading[2]:

[0, 0, 0;   [0, 0, 0;
 0, 0, 0;    0, 0, 0;
 0, 0, 0]    0, 0, 0]

Output without division[3]:

[0, 0, 0;   [0, 0, 0;
 0, 0, 0;    0, 0, 0;
 0, 0, 0]    0, 0, 0]

In OpenCV documentation:

C++: Mat& Mat::operator=(const Mat& m)

C++: Mat& Mat::operator=(const MatExpr& expr)

m – Assigned, right-hand-side matrix. Matrix assignment is an O(1) operation. This means that no data is copied but the data is shared and the reference counter, if any, is incremented. Before assigning new data, the old data is de-referenced via Mat::release() .

expr – Assigned matrix expression object. As opposite to the first form of the assignment operation, the second form can reuse already allocated matrix if it has the right size and type to fit the matrix expression result. It is automatically handled by the real function that the matrix expressions is expanded to. For example, C=A+B is expanded to add(A, B, C), and add() takes care of automatic C reallocation.

So this problem happens, since / operator returns MatExpr object and it causes that shared data can be reused by other matrix. But I expect that output[1] will be the same with output[3].

Upvotes: 1

Hakes
Hakes

Reputation: 621

You are using = opeartor on cv::Mat which uses a shallow copy operation. So all of them will have the same memory address, you need to use clone() operation of cv::Mat.

Also you need to overload = operator of BasePoint as default operator on previousBasePoint = currentBasePoint; will also do a shallow copy of the internal invariant.

Upvotes: 3

Related Questions