opencv 中Mat的一些操作

https://my.oschina.net/drjones/blog/312876

http://blog.sina.com.cn/s/blog_66e177dd0102w9dv.html



(1)创建矩阵

OpenCV Java中矩阵就是一个类 Mat,和它扩展出来的MatOfDouble之类的类。通常创建一个矩阵对象的方法是:

Mat A = new Mat(3, 4, CvType.CV_64FC1);

或者分两步:

Mat A = new Mat();

A.create(3,4,CvType.CV_64FC1);

矩阵使用完毕不用了,要记得销毁:

A.release();

另外还有些特殊矩阵的创建方法,这个文档里倒是有,大家可以看看。这些方法一般是静态方法,可以通过类来调用。例如:

A = Mat.eye(3,3, CvType.CV_64FC1);

A = Mat.zero(3,3,CvType.CV_64FC1);

诸如MatOfDouble之类的矩阵,还支持将矩阵转换为List或者从List(array)转换成矩阵。所以可以直接这样创建矩阵:

MatOfDouble A = new MatOfDouble(1,2,3,4,5,6,7,8,9);

或者

MatOfDouble A = new MatOfDouble();

A.fromArray(1,2,3,4,5,6,7,8,9);

注意,这样得到的矩阵实际上是一个列向量,也就是9*1的矩阵。如果想得到一个3*3的矩阵,可以用reshape,

A.reshape(1,3);

reshape这个方法的参数是很坑爹的,我好长时间都以为参数是行和列,后来翻文档才发现,第一个参数是通道数,第二参数是行数。不怪别人,是我自己想当然了。

另外,Mat还有一个方法是获得矩阵尺寸的,size()。该方法也十分坑爹,返回值居然是列*行。比方说上面那个矩阵A,

System.out.println(A.size().toString());

结果是1x9。

(2) 对矩阵进行操作是很简单的,因为OpenCV有专门的方法,其他的不说了,有一个特别要命,主要是Java开发人员特别要小心的,就是矩阵的乘法。对于C++开发者而言,矩阵乘法可以直接用*搞定,例如A=B*C。Java语言是不支持运算符重载的,因此也就不可能用这么简单的形式实现,只能用方法实现。

不过你找javadoc的时候会发现,Mat类里也提供了multi的方法,哈哈……且慢欢喜,这个不是我们说的矩阵乘法,而是矩阵对应元素的乘法,真正的矩阵乘法在Core类里,需要用Core.gemm()的形式调用。我写了一个简单那的函数实现了简单的矩阵乘法:

/**

* 计算矩阵A和B的乘,得到新的矩阵C。即 C=A*B;

* 注意:A,B,C调用前必需要初始化完毕。

* @param A 被乘矩阵

* @param B 乘矩阵

* @param C 结果矩阵

* @return 矩阵C

*/

public Mat matMul(Mat A, Mat B, Mat C)

{

Core.gemm(A, B, 1.0, Mat.zeros(A.size(), A.type()), 0.0, C);

return C;

}

这个方法是有文档的,不说啥了,目前还没有找到其他更好的方法。注意Mat类里还有dot()方法和cross()方法,都是给向量准备的,一个点乘,一个叉乘,其中叉乘还只能是三元素的向量。

(3) Java矩阵类的粗浅解析

我的理解Java矩阵实际上是两个部分。一个部分是Java的矩阵说明,包括尺寸,通道数,数据类型等;另一部分是实际存储数据的区域,在Java中这部分应该是用JNI调用其C++版本里的功能实现的,所以需要create和release。因此在做矩阵复制,赋值,转换等的各种操作的时候,有的时候是完整的创建了一个新的对象,有的时候只是创建了一个Java头,数据仍然存储在原来的地方没动,所以就有可能我们创建了好多个Mat对象,而实际存储的区域可能没那么多,会有多个Mat对象引用同一块数据存储区域。release方法实际上内部也有一个类似计数的变量,每次调用release的时候就会将这个变量减一,用这种方法来保证在合适的时候释放内存。所以这么说适时的调用release还是很重要的。但实际上什么时候应该release确实是个难题。我感觉一个标准是,谁new的对象,谁就负责release。在函数内部创建的矩阵对象,当做返回值的,必须要告诉调用者去release。

(4)矩阵元素的读取和存储

Java里读取矩阵的元素和改变某位置元素的值非常麻烦。对于C++而言,A(0,0)就可以直接取出(0,0)的值,同时也可以直接赋值。Java专门有这么两个方法,就是put()和get()。例如:

double[] x = A.get(0, 0)

这个操作可以获得(0,0)位置上的元素的值。为什么是返回的数组呢?因为OpenCV的矩阵可以是多维的,也就是在(0,0)位置上的值可以有多个通道(典型的例子是图像,其元素可能是3个值的数组(R,G,B)或者4个值的数组),所以返回值是数组。对于单通道的数据类型的矩阵而言,x[0]就是它的值。

A.put(0, 0, 1.0)

这个操作将(0,0)的值设置为1.0。当然本之上也应该是一个数组的,因为这里Java定义为可变数量参数,所以也可以只输入一个1.0。

但是这样的操作太麻烦了,大家可以想象一下最简单的常用的4*3矩阵如果这么赋起值来,那出错的概率是杠杠的。

还有一个办法就是把矩阵先转换为数组,然后进行操作,操作完毕后再转换会矩阵。也就是用数组作为中转,因为Java中操作数组还是很容易的。

Mat没有提供一个专为数组的方法,只能自己写一个了。其实也很简单,还是用的上面的两个方法。

double[] value = new double[9];

A.get(0,0, value); //从(0,0)位置开始读取数据来填充数组,一直到数组满或者矩阵结尾

或者

double[] value = new double[]{1,2,3,4,5,6,7,8,9};

A.put(0,0,value); //从(0,0)位置开始填充数组里的数据,一直到数组结束

很方便吧。注意计算好数组的大小。用这种方法也可以修改矩阵的部分数据。





---------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Mat:


静态方法:
static Mat diag(Mat d)                                                                                             // 对角矩阵 单列
static Mat eye(int rows, int cols, int type)                                 // 构造单位矩阵形状的矩阵,可以不是方阵
static Mat eye(Size size, int type)                                                           // 构造单位矩阵形状的矩阵,可以不是方阵
static Mat ones(int rows, int cols, int type)                             // 构造全是1的矩阵
static Mat ones(Size size, int type)                                                       // 构造全是1的矩阵
static Mat zeros(int rows, int cols, int type)                           // 构造全是0的矩阵
static Mat zeros(Size size, int type)                                                     // 构造全是0的矩阵

构造方法:
Mat()                                                                                                             
Mat(int rows, int cols, int type)                                                               
Mat(int rows, int cols, int type, Scalar s) 
Mat(long addr) 
Mat(Mat m, Range rowRange) 
Mat(Mat m, Range rowRange, Range colRange) 
Mat(Mat m, Rect roi) 
Mat(Size size, int type) 
Mat(Size size, int type, Scalar s)  

void create(int rows, int cols, int type)                         // 如果尺寸够,则直接返回,否则释放旧的,创建新的
void create(Size size, int type) 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值