Mat类及常用数据结构
一、Mat类简介
Mat是矩阵类(Matrix)的缩写,Mat由矩阵头(Header)和数据两部分组成。
1.1、矩阵头
矩阵头中包含了矩阵尺寸、存储方法,存储地址等信息。
java
public class MatDemo {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
Mat m = Mat.zeros(2, 3, CvType.CV_8UC1);
//打印矩阵信息
System.out.println(m);
}
}
java
Mat [ 2*3*CV_8UC1, isCont=true, isSubmat=false, nativeObj=0x600003f8f060, dataAddr=0x7f7c923071c0 ]
- 23CV_8UC1:矩阵尺寸是2*3,数据类型是CV_8UC1
- isCont=true:是否连续存储
- isSubmat=false:是否为子矩阵(子矩阵指矩阵的一个子区域,子矩阵可以像矩阵一样进行处理和保存,但是对子矩阵的任何修改都会同时影响原来的矩阵)
- nativeObj=0x600003f8f060:本地对象地址
- dataAddr=0x7f7c923071c0:存储的图片的地址
1.2、矩阵的数据类型
以CV_8UC3为例:
- CV表示OpenCV
- 下划线后由四部分组成:
- 第一部分表示数据位数,8表示8位,16表示16位,32表示32位,64表示64位
- 第二部分表示数据类型,U代表无符号整型,S代表有符号整型,F代表浮点类型
- 第三部分C代表通道
- 第四部分为通道数:1表示1通道,2表示2通道,3表示3通道
图像深度 | 数字值 | 具体描述 | 取值范围 |
---|---|---|---|
CV_8U | 0 | 8位无符号整数 | 0~255 |
CV_8S | 1 | 8位有符号整数 | -128~127 |
CV_16U | 2 | 16位无符号整数 | 0~65535 |
CV_16S | 3 | 16位有符号整数 | -32768~32767 |
CV_32S | 4 | 32位有符号整数 | -2147483~2147483647 |
CV_32F | 5 | 32位浮点数 | - |
CV_64F | 6 | 64位浮点数 | - |
1.3、Mat的子类
Mat类可以存储哥哥不同的数据类型。根据数据类型的不同,Mat类又派生出多个子类。
二、矩阵数据的存储
2.1、单通道
Mat类存储图像数据时,可以看做按照栅格扫描顺序存储的数组。单通道的灰度图中数据的排列顺序如下:
java
1行1列的灰度值 1行2列的灰度值 1行3列的灰度值...
2行1列的灰度值 2行2列的灰度值 2行3列的灰度值...
3行1列的灰度值 3行2列的灰度值 3行3列的灰度值...
...
举例,3*3大小8位1通道的灰度图存储如下
java
public class MatDemo {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
Mat m = Mat.zeros(3, 3, CvType.CV_8UC1);
//打印矩阵内部存储
System.out.println(m.dump());
}
}
java
1通道,所以同一行1个值表示1个像素点
[ 0, 0, 0;
0, 0, 0;
0, 0, 0]
2.2、多通道
灰度图因为只有一个通道,所以相对简单,3个通道的RGB彩色图像在OpenCV中颜色是按B(蓝色)、G(绿色)、R(红色)的顺序排列的。3*3大小8位3通道的存储如下:
java
public class MatDemo {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
Mat m = Mat.zeros(3, 3, CvType.CV_8UC3);
//打印矩阵内部存储
System.out.println(m.dump());
}
}
java
3通道,所以1行3个值表示一个像素点
第一行 第二行 第三行
[ 0(B),0(G),0(R), 0, 0, 0, 0, 0, 0; 第一列
0, 0, 0, 0, 0, 0, 0, 0, 0; 第二列
0, 0, 0, 0, 0, 0, 0, 0, 0] 第三列
三、创建矩阵的方法
3.1、静态方法创建
java
public class CreateMat {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
//创建2*3全为0的矩阵
Mat m1 = Mat.zeros(2, 3, CvType.CV_8UC1);
System.out.println(m1.dump());
//创建2*3全为1的矩阵
Mat m2 = Mat.ones(2, 3, CvType.CV_8UC1);
System.out.println(m2.dump());
//创建3*3的矩阵,当行号等于列号时值为1,其余值为0
Mat m3 = Mat.eye(3, 3, CvType.CV_8UC1);
System.out.println(m3.dump());
//需要注意的是,如果通道数大于1,则onces()创建的Mat类只有第一个通道的值为1
Mat m4 = Mat.ones(3, 3, CvType.CV_8UC3);
System.out.println(m4.dump());
}
}
java
[ 0, 0, 0;
0, 0, 0]
[ 1, 1, 1;
1, 1, 1]
[ 1, 0, 0;
0, 1, 0;
0, 0, 1]
[ 1, 0, 0, 1, 0, 0, 1, 0, 0;
1, 0, 0, 1, 0, 0, 1, 0, 0;
1, 0, 0, 1, 0, 0, 1, 0, 0]
3.2、构造方法创建

这14种方法大多类似,下面介绍最常用的几种:
java
//构造方式创建
//方法一
Mat mat1 = new Mat();
mat1.create(3, 3, CvType.CV_8UC1);
//方法二
Mat src = Mat.ones(2, 2, CvType.CV_8UC1);
Mat dst = new Mat();
src.copyTo(dst);//将src复制到dst
//方法三
//大小为100*100,8位3通道蓝色
Mat mat = new Mat(100, 100, CvType.CV_8UC3, new Scalar(255, 0, 0));
3.3、读取图像文件创建
java
//读取文件创建
Mat fish = Imgcodecs.imread("/Users/acton_zhang/J2EE/MavenWorkSpace/opencv_demo/src/main/java/demo1/fish.png");
//在频幕显示图像
HighGui.imshow("fish", fish);
//按任意键退出
HighGui.waitKey();
3.4、克隆创建
java
Mat src = Mat.ones(2, 2, CvType.CV_8UC1);
Mat dst - src.clone();
四、获取矩阵信息
java
public class GetMatInfo {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
Mat fish = Imgcodecs.imread("/Users/acton_zhang/J2EE/MavenWorkSpace/opencv_demo/src/main/java/demo1/fish.png");
//获取矩阵头
System.out.println(fish);
//获取矩阵行数
System.out.println(fish.rows());
//获取矩阵列数
System.out.println(fish.cols());
//获取矩阵维度,2*3为二维,3*3*5为3维
System.out.println(fish.dims());
//获取矩阵通道数
System.out.println(fish.channels());
//获取矩阵的深度
System.out.println(fish.depth());
//获取矩阵的尺寸
System.out.println(fish.size());
//获取矩阵的数据类型
System.out.println(fish.type());
//获取矩阵元素个数,等于行*列
System.out.println(fish.total());
//获取矩阵数据
//System.out.println(fish.dump());
}
}
java
Mat [ 750*998*CV_8UC3, isCont=true, isSubmat=false, nativeObj=0x6000025045a0, dataAddr=0x7fbf66a4b000 ]
750
998
2
3
0
998x750
16
748500
五、矩阵相关操作
5.1、获取/修改像素值
获取像素值使用get方法:
- int Mat.get(int row, int col, byte[] data)
- int Mat.get(int row, int col, short[] data)
- int Mat.get(int row, int col, int[] data)
- int Mat.get(int row, int col, float[] data)
- int Mat.get(int row, int col, double[] data)
注意:当row和col为0时表示第一行第一列。Java中的byte类型取值范围为-128~127,如果矩阵数据类型为CV_8U,则二者取值范围并不一致。
修改像素值使用put方法:
- int Mat.put(int row, int col, byte[] data)
- int Mat.put(int row, int col, short[] data)
- int Mat.put(int row, int col, int[] data)
- int Mat.put(int row, int col, float[] data)
- int Mat.put(int row, int col, double[] data)
java
public class MatPixel {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
Mat m = Mat.eye(3, 3, CvType.CV_8UC1);
//输出修改前的矩阵数据
System.out.println(m.dump());
System.out.println();
//将第二行第二列值改为9
m.put(1, 1, 9);
//输出修改后的矩阵数据
System.out.println(m.dump());
System.out.println();
//获取第二行第二列的像素值,存储在data数组中
byte[] data = new byte[1];//单通道,所以数组长度为1即可
m.get(1, 1, data);
//输出像素值
System.out.println(data[0]);
}
}
java
[ 1, 0, 0;
0, 1, 0;
0, 0, 1]
[ 1, 0, 0;
0, 9, 0;
0, 0, 1]
9
上述程序有个潜在问题,矩阵m的数据类型和data数组的数据类型并不匹配。如果put(1,1, 255),则超过了byte的上限,修改后代码如下:
java
public class MatPixel {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
Mat m = Mat.eye(3, 3, CvType.CV_32SC1);//修改为32位整型
//输出修改前的矩阵数据
System.out.println(m.dump());
System.out.println();
//将第二行第二列值改为9
m.put(1, 1, 255);
//输出修改后的矩阵数据
System.out.println(m.dump());
System.out.println();
//获取第二行第二列的像素值,存储在data数组中
int[] data = new int[1];//单通道,所以数组长度为1即可
m.get(1, 1, data);
//输出像素值
System.out.println(data[0]);
}
}
java
[1, 0, 0;
0, 1, 0;
0, 0, 1]
[1, 0, 0;
0, 255, 0;
0, 0, 1]
255
看上去问题得到了解决,但是实际上还存在一个问题,矩阵的数据类型为CV_32SC1,不是希望的CV_8UC1。要彻底解决这个问题,需要调用Mat类的convertTo()方法。
5.2、批量获取/修改像素值
如果将get/put方法的行号和列号都置为0,同时第三个参数数组足够大,则可以用于批量获取或修改数据。
java
public class MatPixel {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
Mat m = Mat.eye(2, 2, CvType.CV_32SC3);
//将矩阵数据存放在数据data中
int[] data = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 200, 255};
//批量修改矩阵数据
m.put(0, 0, data);
//查看矩阵数据
System.out.println(m.dump());
System.out.println();
//转化矩阵数据类型
Mat mat = new Mat();
m.convertTo(mat, CvType.CV_8SC3);
//获取矩阵的所有数据
int[] i = new int[12];
//获取所有数据
m.get(0, 0, i);
//查看mat的矩阵头
System.out.println(mat);
System.out.println();
//查看矩阵数据
System.out.println(mat.dump());
System.out.println();
//查看数组i的数据
for (int n = 0; n < i.length; n++) {
System.out.print(i[n] + ",");
}
}
}
java
[1, 2, 3, 4, 5, 6;
7, 8, 9, 128, 200, 255]
Mat [ 2*2*CV_8SC3, isCont=true, isSubmat=false, nativeObj=0x600002436d00, dataAddr=0x7fc463805040 ]
[ 1, 2, 3, 4, 5, 6;
7, 8, 9, 127, 127, 127]
1,2,3,4,5,6,7,8,9,128,200,255,
六、常用数据结构
6.1、Point类(点)
Point类用于表示二维坐标系中的一个点。成员变量为x,y。
java
Point(double x, double y)
x:点的x坐标
y:点的y坐标
6.2、Rect类(矩形)
Rect类用于表示一个矩形,成员变量为x,y,width和height。
java
Rect(int x, int y, int width, int height)
x:左上角顶点x坐标
y:左上角顶点y坐标
width:矩形宽度
height:矩形高度
6.3、Size类(尺寸)
Size类用于表示尺寸,成员变量为width,height。
java
Size(double width, double height)
width:宽度
height:高度
6.4、Scalar类(颜色)
Scalar表示具有4个元素的数组,在OpenCV中被用来传递颜色值,如RGB的色彩值。Scalar表示颜色时的顺序是B(蓝色)、G(绿色)、R(红色),如果是四通道,则在后面跟透明度。
java
Scalar(double v0)
通常用于构造灰度图像
v0:灰度值
Scalar(double v0, double v1, double v2);
通常用于三通道图像
v0:B值
v1:G值
v2:R值
Scalar(double v0, double v1, double v2, double v3);
通常用于四通道图像
v0:B值
v1:G值
v2:R值
v3:透明度值
6.5、示例
java
public class BaseStructure {
static {
OpenCV.loadLocally(); // 自动下载并加载本地库
}
public static void main(String[] args) {
//创建Point
Point p = new Point(10, 20);
System.out.println(p);
System.out.println(p.x + "," + p.y);
System.out.println();
//创建Rect
Rect r = new Rect(10, 20, 50, 100);
System.out.println(r);
System.out.println(r.x + "," + r.y + "," + r.width + "," + r.height);
System.out.println();
//创建Size
Size s = new Size(50, 100);
System.out.println(s);
System.out.println(s.width + "," + s.height);
System.out.println();
//创建Scalar
Scalar red = new Scalar(0, 0, 255);
System.out.println(red);
System.out.println();
}
}
java
{10.0, 20.0}
10.0,20.0
{10, 20, 50x100}
10,20,50,100
50x100
50.0,100.0
[0.0, 0.0, 255.0, 0.0]