Reputation: 6490
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
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
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