【秣厉科技】LabVIEW工具包——OpenCV 教程(1):Mat 类的基本用法 📅 发布时间:2026/8/20 16:04:40 👁 浏览次数: 文章目录前言Mat类的基本用法1. Mat初始化从 LV 到 Mat2. Mat可视化从 Mat 到 LV3. 矩阵运算3.1 操作符3.2 内置函数3.3 外部函数4. 图像容器4.1 读取图片4.2 读取视频流不要忘记LabVIEW本身也很强大拓展IMAQ 转 Mat 方法总结前言需要下载安装OpenCV工具包的朋友请前往 此处 系统要求Windows系统LabVIEW2018兼容32位和64位。Mat类的基本用法Mat即矩阵Matrix是OpenCV最重要的核心类通常作为图像数据的容器。本文将介绍如何在LabVIEW下使用Mat类进行矩阵运算和图像处理。1. Mat初始化从 LV 到 Mat在LabVIEW中初始化一个Mat类可以使用函数选板AddonsMolitecOpenCVcoreMatnew.vi 位置如下图。放置一个new到程序框图中可以发现它是一个多态VI通过下拉列表查看到一共有14种初始化模式。其中最后两种模式是 1.1.0.6 版本新增。Mat()创建一个空矩阵Mat(mat,roi)创建子矩阵指向另一个已知Mat的矩形ROI区域 适用于二维Mat。Mat(mat,ranges)创建子矩阵ranges代表每一维度的截取范围 适用于多维Mat。Mat(rows,cols,type,scalar)通过行数、列数、类型、初始值来创建Mat适用于二维Mat。type包含数据类型通道数Mat中的每一个元素都等于scalar。下同Mat(rows,cols,type,data,step0)通过行数、列数、类型、数组来创建Mat适用于二维Mat。Mat将依次填入data数组的每一个值不足时末尾补0。下同目前限定数组内存连续所以step永远等于0直接忽略。下同Mat(ndims,sizes,type,scalar)通过维数、尺寸、类型、初始值来创建Mat适用于多维Mat。sizes数组长度应等于ndims代表每一维度的尺寸。下同Mat(ndims,sizes,type,data,step0)通过维数、尺寸、类型、数组来创建Mat适用于多维Mat。zeros(rows,cols,type)创建全0矩阵参数为行数、列数、类型适用于二维Mat。zeros(ndims,sizes,type)创建全0矩阵参数为维数、尺寸、类型适用于多维Mat。ones(rows,cols,type)创建全1矩阵参数为行数、列数、类型适用于二维Mat。ones(ndims,sizes,type)创建全1矩阵参数为维数、尺寸、类型适用于多维Mat。eye(rows,cols,type)创建单位矩阵全1对角参数为行数、列数、类型只能是二维Mat。Mat(rows,cols,type,data_ptr,step0)v1.1.0.6 新增通过行数、列数、类型、数据指针来初始化Mat。Mat(ndims,sizes,type,data_ptr,step0)v1.1.0.6 新增通过维数、尺寸、类型、数据指针来初始化Mat。例1-1创建一个2行3列的1通道矩阵元素类型为8U8位无符号整数初始值均为255。使用 Mat(rows,cols,type,scalar) 模式【左图】与 使用 Mat(ndims,sizes,type,scalar) 模式【右图】scalar作为所有元素的公共初始值其长度等于通道数。为了能涵盖所有数据类型LabVIEW参数中的scalar采用最宽泛的double类型但传入Mat对象时将自动转换成type指定的数据类型。例1-2创建一个100行150列3通道矩阵元素类型为8U初始值均为[0,128,255] 。使用 Mat(rows,cols,type,scalar) 模式【左图】与 使用 Mat(ndims,sizes,type,scalar) 模式【右图】因为是3通道Mat所以scalar长度也为3当表示颜色时通道顺序为 [B, G, R]例1-3创建一个2行3列1通道矩阵元素类型为32F单精度浮点数float初始值为{{1.1, 2.2, 3.3}, {4.4, 5.5, 6.6}}。使用 Mat(rows,cols,type,data,step0) 模式【左图】与 使用 Mat(ndims,sizes,type,data,step0) 模式【右图】data数组作为整体的初始值依次填入Mat对象。填入顺序是先通道再满行后满列。同样data也采用最宽泛的double类型传入Mat对象时将自动转换成type指定的数据类型。例1-4创建一个2行3列3通道矩阵元素类型8U初始值{{[11,12,13], [21,22,23], [31,32,33]}, {[111,112,113], [121,122,123], [131,132,133]}}使用 Mat(rows,cols,type,data,step0) 模式实现如下。此例Mat是3通道data顺序正如上文提到先通道再满行后满列。同一元素的3通道数据要彼此相邻当作一个整体。当你不想手动输入data时就可以如下图那样通过LabVIEW “捆绑簇” 的方式将data单独列出然后用其他算法产生数据连接到data上作为变量输入。使用 2D_to_Mat.vi 实现如下。由于二维矩阵最常用所以Mat选板中额外提供一个VI可以更加直观地将LabVIEW的2D数组转化成二维Mat对象。2D数组的行即是Mat的行2D数组的列即是Mat的列。多通道数据在2D数组中同行相邻展开。例1-5创建一个三维1通道矩阵尺寸4x3x2元素类型32S32位有符号整数初始值{ { {1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24} } }使用 Mat(ndims,sizes,type,data,step0) 模式实现如下。在多维矩阵的情况下data的排列规律要更广义地理解最低维度相邻排列然后向次低纬度延申再向更高维度延申依此类推。这是因为矩阵遍历时是从高纬度向低纬度层层For循环剥开最低维度在最后一层For循环。设元素的索引为i,j,k定义其“索引权重”为 (i * dim1 j * dim2 k)即在读取它之前已经历的For循环次数。从而data的排列规律为按照“索引权重”从低到高排列。多通道时依然是通道最先相邻排列例1-6先创建一个矩阵然后获取其数据区指针传递给另一个矩阵。相当于浅拷贝须将 OpenCV 工具包升级到 1.1.0.6 或以上版本。采用指针传参的方式让两个 Mat 共享数据区的内存空间从而在避免大量读写的前提下快速实现数据同步。该方法也可用于第三方模块的指针操作让非 OpenCV 封装的DLL函数可以通过指针访问 Mat 对象的数据。须妥善管理指针的内存空间确保大小一致生命周期同步。另外只有内存连续的 Mat 对象才适合指针传参通过 isContinuous 属性查看是否连续。2. Mat可视化从 Mat 到 LV将一个Mat对象的数据取出并在LabVIEW中可视化地显示出来可以使用相同选板下的 to_LV.vi 位置如下图。放置一个to_LV到程序框图中可以发现它是一个多态VI通过下拉列表查看到一共有4种主模式其中array模式又根据数据类型和维度的不同细分为21种子模式。raw读取原始buffer数据返回数据类型为bytes数组小端模式不必考虑Mat内存的不连续性to_LV 已做处理下同common根据Mat数据类型对raw模式的buffer按照小端模式进行元素切割排列成一维数组。同样为了涵盖所有类型该一维数组统一转化成double类型相当于Mat初始化时的data数组。image将Mat数据转化为LabVIEW的图像仅适用于单通道和3通道且数据类型为8Uarray根据Mat的通道、维数、尺寸对common模式返回的一维数组进行再切割转化成LabVIEW中相应的多维数组。目前每种数据类型下只提供3种维度2D、3D、4D其他维度请选common模式然后自写算法来切割。多通道数据依然是同行相邻展开沿最低维度展开例2-1把一个二维8U的Mat读取成LabVIEW的2D数组如下图上方是1通道下方是3通道。注意data数组长度小于Mat容量时末尾自动补零。最后调用release.vi 释放Mat的内存该VI位于Mat选板最末。例2-2把一个未知数据类型的二维Mat读取成LabVIEW的2D数组使用common模式读取然后根据返回的 properties 确定Mat的通道和尺寸对 double_1d 进行reshape。上例中出现了Mat属性properties这个变量是伴随 to_LV 一起返回的。除此之外我们还可以单独获取Mat的某些属性作为后续算法处理的前提条件。方法是使用“属性节点”如下图。属性节点是LabVIEW自带的位于Application Control选板。其中 data_ptr 属性是 1.1.0.6 版本新增。例2-3创建一张纯色图片并用LabVIEW的2D图片控件显示。然后修改ROI区域变成另一种颜色再显示。注意通过ROI创建的子矩阵其内存直接指向父矩阵的某一块区域而不是拷贝到新的内存空间除非经过深拷贝如clone。所以当子矩阵被修改时父矩阵也同样被修改。父矩阵和子矩阵必须全部release之后内存才会真正被释放。只release其中一个另一个依然在使用中。setTo.vi 同样位于Mat选板作用是将矩阵的元素统一重置为输入的scalar数值。3. 矩阵运算3.1 操作符在Mat选板中第一项是一个叫operator的子目录里面包含多种运算符号包括加、减、乘、除逻辑与、或、非、异或以及各种比较运算符。利用这些VI可以实现矩阵的基础运算。其逻辑相当于在C编程中直接用运算符号连接两个对象。连接的两个对象可以都是Mat也可以一个是Mat另一个是元素scalar通过多态VI来切换模式。3.2 内置函数Mat选板下的所有VI其图标设计与配色风格一致都属于Mat类的内置函数。这些函数功能包括函数功能create对已有Mat重新定义类型、尺寸并分配存储空间convertTo转换Mat数据类型并可自定义线性变换copyTo深拷贝clone深拷贝col取源Mat的某一列作为子矩阵输出该子矩阵仍是二维下同colRange按照range范围截取源Mat的某些列作为子矩阵输出row取源Mat的某一行作为子矩阵输出rowRange按照range范围截取源Mat的某些行作为子矩阵输出diag创建对角矩阵或获取矩阵对角向量at按照坐标索引读取或写入Mat中的某一元素checkVector检查输入的Mat是否为向量行数、列数至少有一个等于1dot计算两个向量的内积数量积cross计算两个向量的外积向量积、叉积mul两个尺寸相同的Mat对应元素相乘得到同样尺寸的乘积矩阵。并非“矩阵乘法”operator(*)顺便一提上文提到的operator目录下的 * 符号用于连接两个Mat时才是真正的“矩阵乘法”然而下文中core目录下的multiply函数其功能与内置函数mul一样也不是“矩阵乘法”adjustROI调整ROI区域适用于子矩阵locateROI获取当前ROI位置适用于子矩阵push_back在向量末尾追加元素或在Mat的末尾追加另一个列数相同的Mat作为拓展的行pop_back删除向量末尾的n个元素或删除Mat末尾的n个行resize修改Mat行数。行数减少时元素被释放行数增加时新元素被写入指定的初始值reshape在数据不变的前提下重新切割Mat的通道、尺寸reserve保留一定数量的行空间确保不会在resize等操作时被删除下同reserveBuffer保留一定数量的buffer空间inv求逆矩阵t求转置矩阵setTo重置Mat元素为统一初始值具体用法不一一列举了。下图是一个范例从创建的Mat中取出2列求内积。然后用其中一列作为对角元素生成对角阵再求该对角阵的逆矩阵。更多用法请查找工具包附带的范例examples\Molitec\OpenCV\core\Mat…3.3 外部函数由于Mat是OpenCV最重要的核心类型所以几乎所有模块下的函数都需要Mat类型的变量作为输入输出。其中对矩阵计算支持最多数量最庞大的要数 core 模块。其函数选板如下图节选注意虽然core选板下也有加、减、乘、除、逻辑、比较运算符但与上文operator目录下的运算符用法不尽相同。最主要的区别是core下的运算函数多了一个Mask输入量用以定义掩膜区域。另外multiply函数的功能与Mat内置的mul一样与 operator(*) 不一样。下面是一个范例计算一个输入Mat的平方、开方、自然底数幂、自然对数。更多范例请查找examples\Molitec\OpenCV\core…4. 图像容器4.1 读取图片在OpenCV中对图像的处理都是基于对矩阵的运算来实现的。因此Mat类经常作为承载图像的容器。下图中展示的是读取彩色图片文件到Mat对象并转为灰度图。imread.vi 位于imgcodes模块cvtColor.vi 位于imgproc模块。4.2 读取视频流从摄像头、视频文件、URL等读取一帧图像也是存放在Mat对象中。下图中展示的是连续读取摄像头画面并连续显示。VideoCapture类位于videoio模块。作为容器的Mat只需初始化一次空矩阵进入read.vi后将自动分配空间。每次循环读取的图像都会写入同一个Mat对象中避免占用过多内存。不要忘记LabVIEW本身也很强大通过上文的 “Mat初始化” 和 “Mat可视化” 我们已经打通了LabVIEW的数组与OpenCV的Mat之间互相转化的渠道。既然如此很多关于矩阵的计算我们就不必拘泥于非要用OpenCV的接口来实现。毕竟LabVIEW在矩阵数组计算方面也足够强大。比如通过 to_LV.vi 从Mat中获取到数组之后接下来完全用LabVIEW来完成对该数组的自定义处理。如果有需要再将LabVIEW计算之后的结果重新转化成Mat对象。下图中展示的是读取一个二维Mat到2D数组然后用LabVIEW做QR分解得到一个正交矩阵Q和一个上三角矩阵R最后再分别用Q、R 新建Mat对象。拓展IMAQ 转 Mat 方法IMAQ 是 LabVIEW 官方拓展包——NI Vision 的图像格式。创建 IMAQ 并载入一张彩色图片的方法如下转换方法一数据拷贝获取 IMAQ 的 U32 数据转换成 RGB 字节数组传递给 Mat 初始化时的 data 参数。再获取 IMAQ 的图像分辨率分别传递给 Mat 的行数和列数。最后使用 cvtColor 将颜色空间从 RGB 转换成 BGR。如下图转换方法二指针传递当图片分辨率非常大时由于数据拷贝耗时太长上述方法一就显得效率低下。为解决这个问题可以采用指针传递的方案。1首先获取 IMAQ 的内存指针、LineWidth、XY分辨率。2然后初始化 Mat并切换成指针模式 Mat(rows,cols,type,data_ptr,step0)3将 IMAQ 的指针传递给 Mat 的 data_ptr 参数将 LineWidth 传递给 cols将 Y 分辨率 传递给 rowstype 设为CV_8U 4通道。解析IMAQ 的内存中图像每行的末尾会填充额外的像素用于存储统计数据。因此实际宽度 LineWidth 要略大于 X 分辨率。所以需要将 LineWidth 传递给 Mat 初始化的 cols 而不是将 X 分辨率传递给 cols。4使用 colRange 获取从 0 到 X 列的子矩阵从而去除 IMAQ 的右侧填充。5使用 cvtColor 将颜色空间从 BGRA 转换成 BGR至此转化完成。解析IMAQ 使用 U32 整数表示颜色从高位到低位顺序 0-R-G-B由于小端模式写入内存时的字节顺序变为 B-G-R-0这刚好与 BGRA 的颜色空间相吻合。因此只需用 cvtColor 剔除第4通道即可得到 BRG 空间的 Mat 图像。总结本系列博文作为LabVIEW工具包—OpenCV的教程将以专栏的形式陆续发布和更新。对工具包感兴趣的朋友欢迎下载试用秣厉科技 - LabVIEW工具包 - OpenCV各位看官有什么想法、建议、吐槽、批评或新奇的需求也欢迎留言讨论。