Samuel
Samuel

Reputation: 6490

Can I change a mat interpretation without changing the data? (Say mirror it)

I have a mat that forms an n x n matrix on which I need to perform one algorithm from several directions.

Say I want to loop the mat classically y = [0..n] and x = [0..n] and apply some function on it.

Then I need to loop the mat y = [n..0] and x = [n..0] this is basically the "other way" round. I basically need to approach the mat from all 4 directions, (eg the last one y = [0..n]/x = [n..0] and y = [n..0]/x = [0..n])

Now I don't want to replicate the code four times but the operation I need to apply is more complex than simply passing min, max and direction values to one function like

void apply(cv::Mat & mat, uint xStart, uint xEnd, uint xDirection, uint yStart, uint yEnd, uint yDirection);

because the algorithm does look ahead, etc.

Now I was thinking about if it is possible to transform a given matrix without changing it's data by changing the header interpretation of the data. Then I would be able to call apply always with the same parameters.

There are some operations like cv::transform, cv::transpose etc but they create copy of the data too, which I don't want.

Upvotes: 1

Views: 71

Answers (2)

Samuel
Samuel

Reputation: 6490

I've created a MatView class that does the abstraction for all directions:

/**
* Allows to create different views of mat with direct access.
* Supports inversion of axis so that iteration of a row is a col indeed a switch
* Possible optimization: Remove switches, introduce compile time constants
*/
template<typename T>
class MatView
{
public:

    MatView(cv::Mat & mat, int rowStart, int rowEnd, int colStart, int colEnd, bool switchAxes = false) : 
        m_mat(mat), m_rowStart(rowStart), m_rowEnd(rowEnd), m_colStart(colStart), m_colEnd(colEnd), m_switchedAxes(switchAxes)
    {
        m_rowDirection = rowStart < rowEnd? 1: -1;
        m_colDirection = colStart < colEnd? 1: -1;
    }

    T & at(int rowY, int colX) 
    {
        // Project the data

        auto finalRow = m_rowStart + rowY * m_rowDirection;
        auto finalCol = m_colStart + colX * m_colDirection;

        if(m_switchedAxes == false)
        {
            return m_mat.at<T>(finalRow,finalCol);
        }
        else
        {
            return m_mat.at<T>(finalCol,finalRow);
        }
    }

    const T & at(int rowY, int colX)  const
    {
        auto finalRow = m_rowStart + rowY * m_rowDirection;
        auto finalCol = m_colStart + colX * m_colDirection;

        if(m_switchedAxes == false)
        {
            return m_mat.at<T>(finalRow,finalCol);
        }
        else
        {
            return m_mat.at<T>(finalCol,finalRow);
        }
    }

protected:

    cv::Mat m_mat;

    int m_rowStart;
    int m_rowEnd;

    int m_colStart;
    int m_colEnd;

    int m_rowDirection;
    int m_colDirection;

    bool m_switchedAxes;
};

How ever I think this is a major impact on memory complexity, furthermore the condition may have a vast impact on branch prediction.

While sizeof(cv::Mat) equals to 96 and sizeof(MatView) equals to 128. My current Mat data is actually only a 4*4* sizeof(int) (while my int size is 4 when compiling as 64 bit).

It breaks of course the linear memory access of the cv::Mat anyway but the original Mat is accessed in a random way anyway (not iterating continuous data).

Well, I am not content with this solution but I really won't duplicate the algorithm code.

Upvotes: 1

Vlad
Vlad

Reputation: 4525

No, you cannot. It is quite simple actually if you think about the memory storage. Memory storage is linear (row-wise) and without changing the data you can only change a step for moving along your linear memory. This means you can reshape and change type only.

Transpose and reflection operations will change data. This still can be cleaner and faster than writing and running separate algorithms for 4 search directions. Of course, storing the results of the search can be a hassle then since their interpretations will depend on the Mat configuration. So, to avoid further complications, my advice is to write 4 separate algorithms.

Upvotes: 1

Related Questions