我有一个mat
,它形成一个n x n
矩阵,我需要从几个方向执行一个算法。
假设我想循环mat
经典y = [0..]N]和x = [0..]N]并在其上应用一些函数
然后我需要循环mat
y = [n..]0]和x = [n..][0]这基本上是反过来的。我基本上需要从所有4个方向接近mat
,例如最后一个y = [0..]/x = [N ..]0]和y = [n..]/x = [0..n])
现在我不想重复四次代码,但是我需要应用的操作比简单地将最小,最大和方向值传递给一个函数要复杂得多,比如
void apply(cv::Mat & mat, uint xStart, uint xEnd, uint xDirection, uint yStart, uint yEnd, uint yDirection);
因为算法确实向前看,等等
现在我在想是否有可能通过改变数据的头解释来变换给定矩阵而不改变它的数据。然后我就可以用相同的参数调用apply
。
有一些操作,如cv::变换,cv::转置等,但他们也创建数据的副本,这是我不想要的
不行。如果你考虑一下内存存储,其实很简单。内存存储是线性的(按行),在不改变数据的情况下,您只能改变沿着线性内存移动的一个步骤。这意味着您只能重塑和更改类型。
转置和反射操作将改变数据。这仍然比为4个搜索方向编写和运行单独的算法更干净、更快。当然,存储搜索结果可能会很麻烦,因为它们的解释将取决于Mat配置。因此,为了避免进一步复杂化,我的建议是编写4个单独的算法。
我已经创建了一个MatView
类,做所有方向的抽象:
/**
* 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;
};
尽管我认为这是对内存复杂性的主要影响,而且这个条件可能对分支预测有很大的影响。
sizeof(cv::Mat)
= 96, sizeof(MatView)
= 128。我当前的Mat
数据实际上只是4*4* sizeof(int)
(当编译为64位时,我的int大小为4)。
它当然打破了cv::Mat
的线性内存访问,但原始Mat
无论如何都是以随机方式访问的(不迭代连续数据)。
好吧,我不满足于这个解决方案,但我真的不会复制算法代码