参考BiliBili 于仕琪老师 avoid-memory-copy-in-opencv

class CV_EXPORTS Mat
{
public:
// some members
int rows, cols;
//pointer to data
uchar* data;
//size_t step.p
MatStep step;
};

refcount* 起到智能指针的引用计数作用,Mat类中智能指针机制是OpenCV自行实现的,并没有用到C++的智能指针。

  • step的作用一:实现内存对齐便于加速

  • step的作用二:

注意,图像矩阵虽然可视化为二维的,但其在内存中是线性储存的一维数组。举个例子,



3行3列3通道的连续存储Mat, mat.data[9]为对应图像的第二行第一列的B通道的值,(&mat.data[9])[1]为第二行第一列的G通道的值。注意,不能使用mat.data[1][1]去索引该值,因为其不是多维数组,而是一维的。

对上图的c而言,其指针指向的不是Matrix Data的首地址,而是后面的某一个地址,且c图像矩阵的每一行不是连续存储的。换言之其每行的最后一个元素的下一个元素不是下一行的首元素。

通过存储step可以解决矩阵元素不连续存储的问题。

第二行的首元素相对于第一行的首元素,其偏移量为step,step为完整的大矩阵每行的字节数。

所以遍历该不连续的矩阵,可以写出如下代码:

for (int row = 0; row < mat.rows; row++)
{
for (int col = 0; col < mat.cols; col++)
{
(&mat.data[row*step])[col * channels * elemSize1] = ...
(&mat.data[row*step])[(col * channels + 1) * elemSize1] = ...
(&mat.data[row*step])[(col * channels + 2) * elemSize1] = ...
}
}
// mat.data[row*step] 数组索引相当于指针解引用
// 此处需要获取每一行的首地址, 所以需要&取值

也可以用mat.ptr<typename T>(row)

for (int row = 0; row < mat.rows; row++)
{
uchar* row_data = mat.ptr<uchar>(row) //获取第row行的首地址
for (int col = 0; col < mat.cols; col++)
{
row_data[col * channels * elemSize1] = ...
row_data[(col * channels + 1) * elemSize1] = ...
row_data[(col * channels + 2) * elemSize1] = ...
}
}
  • Mat的step和索引
void test()
{
Mat img(2, 2, CV_16UC4, Scalar_<uchar>(1, 2, 3, 4));
using namespace std;
cout << img << endl;
cout << "step:" << img.step << endl;
cout << "step[0]:" << img.step[0] << endl;
cout << "step[1]:" << img.step[1] << endl;
cout << "step1(0):" << img.step1(0) << endl;
cout << "step1(1):" << img.step1(1) << endl;
cout << "img.data[1 * step] = " << static_cast<int>(img.data[img.step]) << endl;
cout << "(&img.data[1 * step])[1] = " << static_cast<int>((&img.data[img.step])[1]) << endl;
cout << "(&img.data[1 * step])[2] = " << static_cast<int>((&img.data[img.step])[2]) << endl;
cout << "(&img.data[1 * step])[4] = " << static_cast<int>((&img.data[img.step])[4]) << endl;
cout << "(&img.data[1 * step])[6] = " << static_cast<int>((&img.data[img.step])[6]) << endl;
cout << "(&img.data[1 * step])[8] = " << static_cast<int>((&img.data[img.step])[8]) << endl;
cout << "(&img.data[1 * step])[10] = " << static_cast<int>((&img.data[img.step])[10]) << endl;
cout << "img.elemSize = " << img.elemSize() << endl;
cout << "img.elemSize1 = " << img.elemSize1() << endl;
cout << "img.channels = " << img.channels() << endl;
cout << "img.cols = " << img.cols << endl;
}
>>>
[1, 2, 3, 4, 1, 2, 3, 4;
1, 2, 3, 4, 1, 2, 3, 4]
step:16
step[0]:16
step[1]:8
step1(0):8
step1(1):4
img.data[1 * step] = 1
(&img.data[1 * step])[1] = 0
(&img.data[1 * step])[2] = 2
(&img.data[1 * step])[4] = 3
(&img.data[1 * step])[6] = 4
(&img.data[1 * step])[8] = 1
(&img.data[1 * step])[10] = 2
img.elemSize = 8
img.elemSize1 = 2
img.channels = 4
img.cols = 2

最新文章

  1. 【原创分享&#183;微信支付】C# MVC 微信支付之微信模板消息推送
  2. JavaBeans、EJB和POJO详解
  3. Git查看、删除、重命名远程分支和tag【转】
  4. 常用JS加密编码算法
  5. bzoj1601: [Usaco2008 Oct]灌水
  6. linux下获得块设备大小
  7. 构建jenkins
  8. WebSocket就是这么简单
  9. TabLayout下划线指示器自适应文字宽度
  10. 红米手机5 Plus完美刷成开发版获取root权限的教程
  11. 基于接口的 InvocationHandler 动态代理(换种写法)
  12. 如果merge分支出现问题,使用git方式查看日志
  13. Oracle&#160;11gR2_database在Linux下的安装
  14. NodeJs使用async让代码按顺序串行执行
  15. [Nginx]用Nginx实现与应用结合的訪问控制 - 防盗链
  16. python_程序模拟浏览器请求及会话保持
  17. [leetcode] 230. Kth Smallest Element in a BST 找出二叉搜索树中的第k小的元素
  18. 推荐的 MongoDB 安装文档
  19. VMware虚拟机安装Mac OS X
  20. Part2_lesson1---arm家族大检阅

热门文章

  1. 计网学习笔记二 Link Layer Service
  2. Ubuntu中用普通方法无法添加自启动
  3. centos7 部署 loonflow
  4. 如何设置QGraphicsItem线宽不随QGraphicsView缩放而变小或变大
  5. Python ( 高级 第一部)
  6. 信创要求下,FTP要不要替代?要怎么进行国产化替代?
  7. pypeeter 自动化
  8. el-table 处理表格数据中存在属性值为数组的情况
  9. 【个人笔记】CentOS 安装 Docker CE
  10. Rstudio 快捷键无法使用