精华内容
下载资源
问答
  • openCv java Mat和MatOfByte的之间的相互转换 (4)
    千次阅读
    2020-08-28 14:46:35

    因为opecncv是和图片打交道的,我个人觉得图片在计算机中存储的方式一般都是字节,Opecv中图片和矩阵之间是通过对象Mat产生的关联

    我们很容易将图片转换成为Mat

    	Mat src = Imgcodecs.imread(path, 0);

    这个是一种方式

    如何将字节转换成为Mat

    首先我们获取一个图片并且将图片转换成为byte

    	File file = new File("D:\\svnp\\MyYan\\res\\drawable\\chessboard.jpg");
    
    		FileInputStream fis = new FileInputStream(file);
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		int len;
    		byte[] buffer = new byte[1024];
    		while ((len = fis.read(buffer)) != -1) {
    			baos.write(buffer, 0, len);
    		}
    		byte[] data = baos.toByteArray();
    		fis.close();
    		baos.close();

     有了byte [] data 这个字节数组

    我们能不能直接转换成为Mat

    我们可以先转换成MatOfByte

    MatOfByte matb = new MatOfByte(data);

     我们获取到了MatOfByte的对象

    Mat mat = Imgcodecs.imdecode(matb, Imgcodecs.IMREAD_UNCHANGED);

    从MatOfByte转换为Mat,因为最初是一张图片,我们可以显示出来

    HighGui.imshow("ces", mat);
    HighGui.waitKey(5);

     

    上面是从MatOfByte 转换为Mat

    那么如何从Mat转换为MatOfByte

    Mat mat2 = Imgcodecs.imdecode(mata, Imgcodecs.IMREAD_UNCHANGED);

    当然从MatOfByte就可以转换为最开始的状态byte

    byte [] b=mata.toArray();

    刚开始学习opencv 基础做点笔记

    希望对你有所帮助

     

    更多相关内容
  • java结合OpenCV实现Mat与BufferedImage互相转换
  • 然后通过一系列的图像识别操作,最后得到的图像是Mat的格式,但是在javaFx中只能通过ImageView显示图片,那就转化呗! 例如一个颜色筛选操作: //颜色筛选 public static void colorFilter() { /** * Image...

    做课设的时候遇到一个问题,因为我们想做的是一个关于图像识别的程序。就像这样:
    在这里插入图片描述然后通过一系列的图像识别操作,最后得到的图像是Mat的格式,但是在javaFx中只能通过ImageView显示图片,那就转化呗!

    例如一个颜色筛选操作:

      //颜色筛选
        public static void colorFilter() {
        	/**
        	 * ImageProcessing.orangeImage 为颜色筛选图像的Mat对象
        	 * toBufferedImage 将Mat类型的图像转化为java.awt中的BufferedImage类型。
        	 * showImage 将java.awt中的BUfferedImage类型转化为javaFx中的ImageView类型,用于直接显示图像。
        	 */
        	BufferedImage image = toBufferedImage(ImageProcessing.orangeImage);
        	showImage(image);
        }
    
    private static BufferedImage toBufferedImage(Mat matrix) { 
    		int type = BufferedImage.TYPE_BYTE_GRAY;
    		if (matrix.channels() > 1) { 
    			type = BufferedImage.TYPE_3BYTE_BGR;
    			} 
    		int bufferSize = matrix.channels() * matrix.cols() * matrix.rows(); 
    		byte[] buffer = new byte[bufferSize];
    		matrix.get(0, 0, buffer); 
    		// 获取所有的像素点
    		BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
    		final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); 
    		System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
    		return image; 
    		}
    
     public static void showImage(BufferedImage image) {
        	WritableImage wr = null;
        	if (image != null) {
        		wr = new WritableImage(image.getWidth(), image.getHeight());
        		PixelWriter pw = wr.getPixelWriter();
        		for (int x = 0; x < image.getWidth(); x++) {
        			for (int y = 0; y < image.getHeight(); y++) {
        				pw.setArgb(x, y, image.getRGB(x, y));
        			}
        		}
        	}
    	    ImageView imageView = new ImageView(wr);
    	    imageView.setFitHeight(700);
    	    imageView.setFitWidth(600);
    	    imageView.setPreserveRatio(true);
    	    //用于返回图像,作为界面组件BorderPane形式显示。
    	    getImage.setCenter(imageView); 
        }
    

    后面两段代码均是我在网上找的,忘记留下出处了。

    展开全文
  • MAT 文件库 (MFL) 是一个 Java 库,用于读取和写入与 MATLAB 的 MAT 文件格式兼容的 MAT 文件。 它的总体设计目标是: * 提供符合 MATLAB 语义行为的用户友好 API *支持在堆受限或分配受限的环境中处理大量数据* ...
  • Mat类概述、Mat对象的构造方法、Mat对象常用方法、int depth()、void copyTo(Mat mat)、void convertTo(Mat dst,int type)、Mat clone()、void create(xxx)、int channels()、int rows()、int cols()、头部信息、...

    概述

           Mat对象是一个用于OpenCV中用于存储图像的数据结构自动分配内存,即根据所读入的图片为其分配相应大小的内存空间,不存在内存泄露问题,是面向对象的数据结构。它分为头部数据部分
    使用Mat存储这样一张图片
    在这里插入图片描述
    代码

    public class DemoMat {
        static{
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        }
        public static void main(String[] args) {
            Mat src= Imgcodecs.imread("aa.jpg");//使用Imgcodecs类的imread读取一张图片
            System.out.println(src);//打印src的头部信息
        }
    }
    

    我们直接输出Mat的一个实例,可以看到如下信息。
    在这里插入图片描述

    头部信息

    400×266×CV_8UC3:400像素×266像素×数据类型

    isCont:是否联系存储

    isSubmat:是否为子矩阵

    nativeObj:本地对象地址

    dataAddr:存储的图片的地址

    数据类型

           上面的CV_8UC3,下划线后的数字表示位数、数字后的第一个符号表示用于储存像素的类型、后面的符号表示通道数。

    U:unsigned int ,无符号整型

    S:signed int ,有符号整型

    F:float,单精度浮点型,float类型本身即有符号

    Cx:图像的通道数

    各种数据类型所对应的整数
    在这里插入图片描述

    数据部分

           dataAddr所指向的内存空间即为数据部分,也就是图片所存储的地方。

    数据部分一个多维矩阵。
    代码

    public class DemoMat {
        static{
            System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        }
        public static void main(String[] args) {
            Mat src= Imgcodecs.imread("aa.jpg");//读取图片
            byte [] b= new byte[3];//定义存放通道元素的数组(本例采用三通道)
            for (int i=0;i<src.rows();i++){//遍历行、列
                for (int j=0;j<src.cols();j++){
                    src.get(i,j,b);//获取每个运算,并存储在b数组中
                    System.out.print(Arrays.toString(b));
                }
                System.out.println();
            }java
        }
    }
    

    执行结果
    在这里插入图片描述
    含义

           上面的输出结果是一个三维数组,可以看成一个二维数组的元素是一个维数组,而二维数组的行和列的个数就代表图片的大小(以像素为单位),而其元素一位数组代表所使用的数据类型,如上数据类型为三通道。通道的存储顺序为B、G、R。
           下图代表二维数组的元素一维数组。OpenCV中通道存储是按照B、G、R的顺序存储的。
    在这里插入图片描述
    下图表示一个张图片的存储结构。
    在这里插入图片描述

    Mat对象的构造方法

    Mat()

    创建一个空的mat实例。
    代码

    Mat mat = new Mat();
    System.out.println(mat);
    

    执行结果
    在这里插入图片描述

    Mat(long addr)

    传入地址后复制一个Mat实例。
    代码

            Mat src= Imgcodecs.imread("aa.jpg");
            System.out.println(src);
            Mat mat = new Mat(src.nativeObj);//传入地址
            System.out.println(mat);
            System.out.println(mat==src);
    

    执行结果
    在这里插入图片描述

    Mat(int row,int cols,int type)

    传入行、列以及数据类型进行实例化。
    代码

    //Mat mat=new Mat(5,5,16);
    Mat mat=new Mat(5,5, CvType.CV_8UC3);//5行5列CV_8UC3类型
    System.out.println(mat);
    

    执行结果
    在这里插入图片描述

    Mat(Size size,int type)

    将构造函数Mat(int row,int cols,int type)中的行和列用Size对象所替代了。
    代码

    Mat mat=new Mat(new Size(5,5),CvType.CV_8UC3);
    System.out.println(mat);
    

    执行结果
    在这里插入图片描述

    Mat(int rows,int cols,int type,Scalar s)

    rows:行

    cols:列

    type:数据类型

    s:颜色
    代码

    Mat mat=new Mat(50,50,CvType.CV_8UC3,new Scalar(0,0,255));
    HighGui.imshow("标题",mat);
    HighGui.waitKey(0);
    

    执行结果
    在这里插入图片描述

    Mat(Size size,int type,Scalar s)

    将构造函数Mat(int rows,int cols,int type,Scalar s)的行和列用Size对象代替。

    Mat对象常用方法

    int depth()

    返回通道的数据类型,即返回,CV_8UC3中下划线的前3位。
    对应整型。

    CV_8U = 0,
    CV_8S = 1,
    CV_16U = 2,
    CV_16S = 3,
    CV_32S = 4,
    CV_32F = 5,
    CV_64F = 6,
    CV_16F = 7;
    

    代码

    Mat mat01=new Mat(5,5,CvType.CV_8UC3);
    Mat mat02=new Mat(5,5,CvType.CV_16U);
    System.out.println("CV_8U:"+mat01.depth()+"\n"+"CV_16U:"+mat02.depth());
    

    执行结果
    在这里插入图片描述

    void copyTo(Mat mat)

    复制自己到mat。
    代码

    Mat src= Imgcodecs.imread("aa.jpg");
    Mat s=new Mat();
    src.copyTo(s);//复制到s
    System.out.println(src);
    System.out.println(s);
    System.out.println(s==src);//用于验证是否相等
    

    执行结果
    在这里插入图片描述

    void convertTo(Mat dst,int type)

    dst:复制到的Mat实例
    type:数据类型
    convertTo:可以改变Mat的深度,例如可以把Mat的type从CV_8UC3改为CV_16SC3

    convertTo:不可以改变Mat的通道数,例如不可以把Mat的type从CV_8UC3改为CV_8UC1,即使你填入的转换类型通道数不同,输出的通道数还是与输入的通道数相同
    代码

    Mat src= Imgcodecs.imread("aa.jpg");
    Mat mat=new Mat();
    src.convertTo(mat,CvType.CV_8U);//不可转换
    System.out.println(src);
    System.out.println(mat);
    src.convertTo(mat,CvType.CV_16FC3);//可转换
    System.out.println(src);
    System.out.println(mat);
    

    执行结果
    在这里插入图片描述

    Mat clone()

    返回一个复制的Mat对象。

    代码

    Mat src= Imgcodecs.imread("aa.jpg");
      Mat mat=new Mat();
      mat=src.clone();
    System.out.println(src);
    System.out.println(mat);
    

    执行结果
    在这里插入图片描述

    void create(xxx)

    在这里插入图片描述
    create对象可改变图像的大小、类型,作用于调用此函数的实例。
    代码

    Mat src= Imgcodecs.imread("aa.jpg");
    src.create(400,400,CvType.CV_8U);
    HighGui.imshow("标题",src);//使用HighGui类的imshow()方法展示图片
    HighGui.waitKey(0);
    

    原图
    在这里插入图片描述
    执行结果
    在这里插入图片描述

    int channels()、int rows()、int cols()

    获取图像的

    channels():通道数

    rows():行数

    cols():列数
    代码

    Mat src= Imgcodecs.imread("aa.jpg");
    System.out.println("行:"+src.rows()+"\n"+"列:"+src.cols()+"\n"+"通道数:"+src.channels());
    

    执行结果
    在这里插入图片描述

    展开全文
  • JVM MAT使用分析详解

    2021-03-15 10:24:35
    一般说来,这些内存信息包含:所有的对象信息,包括对象实例、成员变量、存储于栈中的基本类型值和存储于堆中的其他对象的引用值。所有的类信息,包括classloader、类名称、父类、静态变量等...

    MAT简介

    MAT是一款非常强大的内存分析工具,在Eclipse中有相应的插件,同时也有单独的安装包。在进行内存分析时,只要获得了反映当前设备内存映像的hprof文件,通过MAT打开就可以直观地看到当前的内存信息。一般说来,这些内存信息包含:所有的对象信息,包括对象实例、成员变量、存储于栈中的基本类型值和存储于堆中的其他对象的引用值。

    所有的类信息,包括classloader、类名称、父类、静态变量等

    GCRoot到所有的这些对象的引用路径

    线程信息,包括线程的调用栈及此线程的线程局部变量(TLS)

    MAT支持将这些信息通过我们需要的方式归纳和显示,这样,整个内存信息就一览无余地显示在了我们的面前。

    虽然MAT有如此强大的功能,但是内存分析也没有简单到一键完成的程度,很多内存问题还是需要我们从MAT展现给我们的信息当中通过经验和直觉来判断才能发现。下面,我们就先介绍一下MAT的一些功能。

    调用jdk工具jps查看当前的java进程

    C:/>jps

    3504 Jps

    3676 Bootstrap

    3496 org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar

    调用jmap工具得到信息

    C:/>jmap -dump:format=b,file=heap.bin 3676

    Dumping heap to C:/heap.bin ...

    Heap dump file created

    这时,我们的C盘根目录,就生成了heap.bin文件,用eclipse的file---->open打开这个文件,首先是一个启动图:

    0_13017267038hni.gif

    这里可以选择查看

    1、内存泄露报表,自动检查可能存在内存泄露的对象,通过报表展示存活的对象以及为什么他们没有被垃圾收集;

    2、对象报表,对可颖对象的分析,如字符串是否定义重了,空的collection、finalizer以及弱引用等

    Overview

    用MAT打开一个hprof文件后一般会进入如下的overview界面,或者和这个界面类似的leak suspect界面,overview界面会以饼图的方式显示当前消耗内存最多的几类对象,可以使我们对当前内存消耗有一个直观的印象。但是,除非你的程序内存泄漏特别明显或者你正好在生成hprof文件之前复现了程序的内存泄漏场景,你才可能通过这个界面猜到程序出问题的地方。

    618b4b6f3e1efcb6bd6e5fde3f118d88.png

    Dorminator Tree(支配树)

    支配树可以直观地反映一个对象的retained heap,这里我们首先要了解两个概念,shallow heap和retained heap:shallow heap:指的是某一个对象所占内存大小。

    retained heap:指的是一个对象的retained set所包含对象所占内存的总大小。

    retained set指的是这个对象本身和他持有引用的对象和这些对象的retained set所占内存大小的总和,用官方的一张图来解释如下:

    df4201f0f72e7d103e3c0453d06bd9b9.png

    虽然说MAT定义的支配树和上图中的引用树稍有不同,但是二者的本质都可以反映一个对象如果被回收,有多少内存可以同时得到释放,只不过支配树的定义下可以更精确地反映这个数量。如果你感兴趣,可以继续看我之后的对支配树的概念解释,如果一时理解不过来可以跳过,把支配树简单想象成引用树即可。

    实际上支配树就是从引用树演化而来。所谓支配,例如x对象支配y对象,就是在引用树当中,一条到y的路径必然会经过x;所谓直接支配,例如x直接支配y,指的是在所有支配y的对象中,x是y最近的一个对象。支配树就是反映的这种直接支配关系,在支配树种,父节点必然是子节点的直接支配对象,下图就是一个从引用树到支配树的转换示意图:

    0d6ca1f32a32e89caeb01c40ca8349a4.png

    上面这幅图右边就是从左边转换而来形成的支配树,这里特别对C节点形成的子树做一下说明。CDE及DF、EG的关系就不用多说,从引用树和我们刚才对支配概念的阐述可以直接得出结论,关键是H节点,H节点在支配树种既不是D的子节点也不是E的子节点是因为,在引用树当中,能够到达H的路径有两条,DEFG节点都不是到达它的路径上必须经过的节点,符合这个条件的只有C节点,因此在支配树中H是C的子节点。现在仔细观察支配树可以发现,一个节点的子树正好就是这个节点对应的retained set。比如,如果D节点被回收,那么就可以释放DF对象所占的内存,但是H所占的内存还不能得到释放,因为可能G还在引用着H,这也是为什么在支配树中H是C节点的子节点的原因,只有C节点被回收了才一定能够回收H节点所占的内存。

    说了这么多,MAT中Dorminator Tree到底能够用到什么上面?我认为,它主要可以用于诊断一个对象所占内存为什么会不断膨胀,一个对象膨胀,就说明它对应到支配树中的子树就越来越庞大,只要分析这个对象对应的子树,确定那些对象是不应该出现在子树中就可以对问题手到病除。下面举一个实例进行简单分析。

    在android中ListView对象是可以不断对其子view进行服用来达到提高内存使用效率的目的,ListView的这一特性依赖于List Adapter的getView的实现,我们通过如下代码来故意使ListView无法服用其子view,从而模拟对象膨胀的情况,代码如下:public class LeakedListviewExample extends Activity {

    private ListView mLeakedListview;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.leaked_listview);

    mLeakedListview = (ListView) findViewById(R.id.leaked_listview);

    mLeakedListview.setAdapter(new LeakedAdapter());

    }

    private class LeakedAdapter extends BaseAdapter {

    @Override

    public int getCount() {

    return 1000;

    }

    @Override

    public Object getItem(int position) {

    return String.valueOf(position);

    }

    @Override

    public long getItemId(int position) {

    return position;

    }

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

    // 不复用convertView,每次都new一个新的对象

    TextView leakedView = new TextView(LeakedListviewExample.this);

    leakedView.setText(String.valueOf(position));

    return leakedView;

    }

    }

    }

    在运行代码的设备多次上下滑动这个ListView后,可以观察这个应用程序所占内存越来越大,每次手动GC后效果也不明显,说明出现了内存泄漏的现象,于是我们通过MAT dump出内存,切换到Dorminator Tree后可以看到如下的情况:

    10f758a6a6d6c1ca82bf7fcda534e36e.png

    首先就可以看到ListView的shallow heap和retained heap是非常不成比例的,这说明这个ListView持有了大量对象的引用,正常情况下ListView是不会出现此现象。于是我们根据retained heap的大小逐步对ListView的支配树进行展开可以发现,Recycle Bin下面持有大量的TextView的引用,数量高达2500多个,而在正常情况下,ListView会复用Recycle Bin当中type类型相同的view,其中的对象个数不可能如此庞大,因此,从这里就可以断定ListView使用不当出现了内存泄漏。

    Histogram

    以直方图的方式来显示当前内存使用情况可能更加适合较为复杂的内存泄漏分析,它默认直接显示当前内存中各种类型对象的数量及这些对象的shallow heap和retained heap。结合MAT提供的不同显示方式,往往能够直接定位问题,还是以上面的代码为例,当我们切换到histogram视图下时,可以看到:

    f1aa84fb65452d7153bdd2c3f4e11c51.png

    根据retained heap进行排序后可见,TextView存在2539个对象,消耗的内存也比较靠前,由于TextView属于布局中的组件,一般来说应用程序界面不能复杂到有这么多的TextView的存在,因此这其中必定存在问题。那么又如何来确定到底是谁在持有这些对象而导致内存没有被回收呢?有两种方式,第一就是右键选择List Objects -> with incoming reference,这可以列出所有持有这些TextView对象的引用路径,如图

    53c538d8ba0cbc357037a030e71564d0.png

    从中可以看出几乎所有的TextView对象都被ListView持有,因此基本可以断定出现了ListView没有复用view的情况;第二种方式就更直接粗暴,但是非常有效果,那就是借助我们刚才说的dorminator tree,右键选择Immediate Dorminator后就可以看到如下结果

    4294ccda4926ba7b8273d87fa75b3c17.png

    从中可以看到,有2508个TextView对象都被ListView的RecycleBin持有,原因自然就很明确了。

    MAT的查询选项

    上面主要介绍的是MAT的两个结果分析界面,其实,配合不同的查询选项,可以将它们的威力最大化。MAT中常用的查询选项集合都在顶部以图标的方式进行了显示

    2b3a7ea65bb818dae4566c050ed1427d.png

    从左到右依次为:显示Overview视图,显示Histogram视图,显示Dorminator Tree视图,使用OQL语言对结果进行查询,显示线程信息,结果智能分析,自定义查询选项集合,根据地址查询对象,结果分组,计算retained heap等。前三项就不再多说,分别对应之前我们介绍的三个结果分析结果显示方式,剩余的我挑选一些常用的选项结合一些实例进行说明。

    OQL(Object Query Language)

    在MAT中支持对象查询语句,这是一个类似于SQL语句的查询语言,能够用来查询当前内存中满足指定条件的所有的对象。OQL将内存中的每一个不同的类当做一个表,类的对象则是这表中的一条记录,每个对象的成员变量则对应着表中的一列。

    OQL的基本语法和SQL相似,语句的基本组成如下SELECT * FROM [ INSTANCEOF ] [ WHERE ]

    所以,当你输入select * from instanceof android.app.Activity

    的时候,就会将当前内存中所有Activity及其之类都显示出来。但是OQL也有一些特别的用法。下面简单介绍一下OQL各部分的基本组成(更详细的可以参看这里)。

    FROM部分

    首先是OQL的from部分,指明了需要查询的对象,可以是如下的这些类型:一个类的完整名称,例如select * from com.example.leakdemo.LisenerLeakedActivity

    正则表达式,例如SELECT * FROM "java\.lang\..*"

    基本类型数组或者对象数组,例如int[]或者java.io.File[]select * from java.io.File[]

    对象的地址,例如0x2b7468c8select * from 0x2b7468c8, 0x2b7468dd

    对象的id,例如20815select * from 66888

    甚至可以是另外一个OQL的查询结果,以实现级联查询。SELECT * FROM (SELECT * FROM java.lang.Class c WHERE c implements org.eclipse.mat.snapshot.model.IClass )

    from部分还可以用如下两个关键词进行修饰INSTANCEOF : 用来包含查询指定类的子类进行查询,否则只查询和from部分完全匹配的类,例如:SELECT * FROM INSTANCEOF android.app.Activity

    OBJECTS : 修饰后最多只会返回一条结果,指明查询结果对应的类信息,而不是对象信息,例如:SELECT * FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity

    返回的就是LisenerLeakedActivity对应的类的信息,而不是内存中存在的ListenerLeakedActivity对象。

    from部分还能为查询指定别名,以便提高可读性。例如SELECT result.mType FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity result

    这里的result即是我们指定的别名,在我们不指定的情况下OQL默认别名为空,如下语句和上面语句效果是相同的SELECT .mType FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity

    SELECT部分

    这部分和WHERE部分只最灵活也是最复杂的部分,但是大部分情况下我认为在这里使用“*”最好,因为一般这样我们的结果里面的信息是最全。不过如果你不想被结果中的其他信息干扰,可以自定义这部分的内容来实现。

    OQL可以通过自定义select来实现对内存中对象或者类的各种属性及方法结果等进行查询,这主要通过以下三种表达方式来实现。访问查询对象的属性的表达式为:[ . ] . .

    其中alias代表别名,是在from部分中定义的,可以省略;field就是对象中定义的属性。这种方式能够访问到查询对象的属性值,例如:SELECT result.mType FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity result

    能够展现出LisenerLeakedActivity.mType组成的查询结果。

    查询访问Java Bean及该对象在MAT中的属性,需要的表达式为:[ . ] @

    通过这种方式能够查询到的内容比较多,我们可以通过使用MAT中对OQL的自动补全功能(点这里查看)来选择需要查询的内容,例如:SELECT result.@clazz AS "class", result.@displayName AS "display name" FROM com.example.leakdemo.LisenerLeakedActivity result

    就可以得到对象对应的class信息和对象在heap dump中的显示名称。

    查询访问一些底层对象的Java方法的返回结果。MAT可以通过反射来调用当前查询对象的底层类的Java方法,从而得到这些方法的执行结果。其表达式为:[ . ] @( [ , ] ) ...

    注意method后面的括号是必不可少的,否则OQL会认为这是一个属性名称。”@”符号在新版本的OQL已经可以不需要了,例如:SELECT result.@clazz.hasSuperClass(), result.getField("mType") FROM com.example.leakdemo.LisenerLeakedActivity result

    可以得到当前对象是否有基类,以及对象中的mType属性的值是多少。

    不仅如此,select部分还支持很多有用的内建函数,这里就不一一介绍了,大家可以戳这里查看。

    关于select部分的更多信息还可以到这里具体查看。

    WHERE部分

    灵活设置where参数可以为我们排除很大一部分的干扰信息,这部分对于属性和方法的支持和select部分相同,支持的运算符号和关键字有:<=, >=, >,

    相信大家都清楚这些关键值的意义,举一个简单例子SELECT * FROM com.example.leakdemo.LisenerLeakedActivity result where result.mType = 1

    上面那个查询语句可以查询到所有LisenerLeakedActivity.mType为1的对象。关于where部分的相信介绍可以参考这里。

    OQL可以用来排查缓慢内存泄漏的情况,这种形式的内存泄漏只有程序长时间运行才会造成OOM,在排查阶段由于泄漏不严重而不能够在Dominator Tree或者Histogram中明显表现出来,但是如果你清楚在当前阶段程序中的一些重要对象的大概数量的话,则可以通过OQL来查询验证。这种方式对于在Android中排查Activity泄漏十分有用,例如有下面的代码:public class LisenerLeakedActivity extends Activity {

    private static final String TYPE_KEY = "type_key";

    private DemoListener mListener;

    private int mType = -1;

    public static void startListenerLeakedActivity(Context context, int actiivtyType) {

    Intent intent = new Intent(context, LisenerLeakedActivity.class);

    intent.putExtra(TYPE_KEY, actiivtyType);

    context.startActivity(intent);

    }

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    mType = getIntent().getIntExtra(TYPE_KEY, -1);

    mListener = new InnerListener();

    DemoListenerManager.getInstance().registerListener(mListener);

    }

    public int getActivityType() {

    return mType;

    }

    @Override

    protected void onDestroy() {

    super.onDestroy();

    // 故意制造泄漏

    // if (null != mListener) {

    // DemoListenerManager.getInstance().unregisterListener(mListener);

    // }

    }

    private class InnerListener implements DemoListener {

    @Override

    public void nothingToHandle() {

    // nothing to do

    }

    }

    }

    上面Activity会在onCreate中向DemoListenerManager注册一个Listener,而这个Listener是Activity的内部类,因此它持有这个Activity的引用,如果在Activity的onDestroy阶段没有及时的反注册,那么这个Activity就泄漏了。现在随着多次启动和关闭这个Activity,我们可以发现gc后的内存总是不断增长,这是一个内存泄漏的特征,于是我们dump出当前内存,但是在其中的Dorminator Tree和Histogram中都不能很明确地得出问题所在,于是我们只能按照经验使用OQL来排查。假设你对Activity的泄漏有所怀疑,通过简单输入:select * from instanceof android.app.Activity

    可以得到如下结果:

    b34d5ffef816dfcb58b6a5075134ca62.png

    从结果当中可以看到,当前内存中存在多个ListenerLeakActivity,而按照我们的原则,离开一个Activity就应该及时销毁和释放改Activity的资源,因此这就说明了Activity的泄漏是造成泄漏的原因之一。

    自定义查询选项集合

    这部分的功能其实和在显示列表中点击右键得到的菜单相同,如下所示:

    72065b3bc8c1587df23d5fd21d6b03cc.png

    下面挑选比较重要的几个选项来说明。

    List Objects

    有两个选项:with incoming refrences和with outcoming refreences,分别会罗列出选定对象在引用树中的父节点和子节点,可以作为为什么当前对象还保留在内存中的基本依据。在平时的排查过程中,此功能还是比较常用,因为可以顺着罗列出的引用路径一步步分析内存泄漏的具体原因,例如如下是上面Demo中针对ListenerLeakedActivity的一个with incoming reference的结果,从这个结果中可以逐步展开,最后得到是因为DemoListenerManager的单例仍然持有ListenerLeakedActivity的InnerListener造成泄漏的结论。

    e895f24a0cd21b5fcea1c33fd16a6f60.png注意,如果你选择with incoming references得到的每个结果展开后仍然是针对选择展开的内容的with incoming references,对于with outcoming references也一样。因此,如果两个对象存在循环引用,你需要仔细分析,排除循环引用的路径。例如上图中就不能再展开引用源:ListenerLeakedActivity的mListener进行分析,因为ListenerLeakedActivity本身就和InnerListner存在相互引用关系,展开就又得到了ListenerLeakedActivity的incoming references结果,和一级列表结果是一样的,一直这样展开下去就真是子子孙孙无穷匮也了。

    Show objects by class

    和List Objects相似,也可以罗列出当前选中对象在引用树种的上下级关系,只是这个选项会将结果中类型相同的对象进行归类,比如结果中有多个String类型的对象,List Objects会将它们分别显示出来,而Show objects by class会将它们统一归类为java.lang.String。虽然相对来说结果显示简洁了,但是我个人在平时分析的过程中一般较少使用到这个功能。

    Merge Shortest Path To GC Roots

    这是快速分析的一个常用功能,它能够从当前内存映像中找到一条指定对象所在的到GC Root的最短路径。这个功能还附带了其他几个选项,这几个选项分别指明了计算最短路径的时候是否是需要排除弱引用、软引用及影子引用等,一般来说这三种类型的引用都不会是造成内存泄漏的原因,因为JVM迟早是会回收只存在这三种引用的资源的,所以在dump内存映像之前我们都会手动触发一次gc,同时在找最短引用路径的时候也会选择上exclude all phantom/weak/soft etc. references选项,排除来自这三种引用的干扰。如下是针对ListenerLeakedActivity的一次Merge Shortest Path To GC Roots的结果,从图中可以明显地看到一条从sInstance->mListener->array->ListenerLeakedActivity的引用路径,这个结果已经足以定位Demo中内存泄漏的原因了。

    c06ca75866da1dc4d0f2fa228303e085.png

    Java Basics

    这个选项并不是很常用,这里只简单介绍一下其中的Class Loader Explorer子选项,它可以用来查看一些和选定对象的class loader相关的特性,包括这个class loader的名称、继承关系和它所加载的所有类型,如果你的程序当中应用到了自定义class loader或者osgi相关的特性,这个选项会为你分析问题提供一定程度的帮助。如下是我们通过Demo中的ListenerLeakedActivity的Class Loader Explorer可以看到如下结果。结果表明ListenerLeakedActivity是由PathClassLoader加载的,同时罗列了由这个class loader加载的其他8个类型以及这些类型目前在内存中的实例数量。

    f9e8ce171fbe2b31ae41c8b3a14b22b9.png

    Java Collections

    这块的功能平时确实少有用到,对其中的功能应用不太了解,大家有兴趣可以参考这里。也欢迎大家帮助我补充一下这块的功能应用。

    Immidiate Dominators

    这是一个非常有用的功能,它的作用就是找出选择对象在Dominator Tree中的父节点。根据我们之前对Dominator Tree的阐述,就是找到一个对此对象存在于内存中负直接责任的对象,这个方法一般和List Objects或者Merge Shortest Path To GC Roots相互结合使用,共同定位或相互佐证。因为去掉了一个节点在引用树中的一个父节点并不一定能保证这个对象会被回收,但是如果去掉了它的Immediate Dominator,那这个对象一定会被回收掉;但同时,有时候一个对象的Immidate Dominator计算出来是GC Roots,因为它处在引用树中的路径没有一个非GC Roots的共同点,这个时候我们直接用Immidiate Dominators就不太好分析,而需要借助List Objects或者Merge Shortest Path To GC Roots的功能。因此,这几个方法需要相互配合使用。

    Show Retained Set

    这个功能简单来说就是显示选定对象对应在Dominator Tree中的子节点集合,所有这些子节点所占空间大小对应于它的retained heap。可以用来判断当一个对象被回收的话有多少其他类型的对象会被同时回收掉,例如,我们上面的Demo中,因为InnerListener同时被ListenerLeakedActivity和DemoListenerManager所持有,因此它不在这两个对象任何一个的retained set中,而是在这两个对象的公共节点GC Roots的retained set中,但是如果我们没有向DemoListenerManager中注册过InnerListener,那么它会出现在ListenerLeakedActivity的retained set中。

    结果分组

    这个选项支持将列表显示的结果按照继承关系、包名或者class loader进行分组,默认情况下我们结果显示是不分组的,例如Histogram和Dominator Tree的查询结果只是将对应引用树和Dominator Tree中的各个节点罗列出来,这样就包含了很多系统中的其他我们不关注的信息,使用分组的方法就可以方便聚焦到我们关注的内容之中。例如,下面分别是我们对Demo的Histogram视图结果进行按照包名和继承关系进行分组的结果显示。从中看到按照包名排序的方式方便我们着重关注那些我们自己实现的类在内存中的情况,因为毕竟一般情况下出现泄漏问题的是我们自己的代码;而按照继承关系的方式进行分类我们可以直接看到当前内存中到底有多少个Activity的子类及其对象存在,方便我们重点排查某些类。

    49a531be19df023c467d132aab0db358.png

    f865a02863afeb088c1cd07f16de7b3a.png

    计算retained heap

    在我们一开始选择Histogram或者Dominator Tree视图查询结果的时候,MAT并没有立即开始为我们计算对应各个节点的Rtained Heap大小,此时我们可以用这个功能来进行计算,以方便我们进行泄漏的判断。这个选项又包含两个算法,一个是quick approx的方式,即快速估算,这个算法特点是速度快,能够快速计算出罗列各项Retained Heap所占的最小内存,所以你用这个方式计算后看到的Rtained Heap都是带有”>=”标志的;如果你想精确地了解各项对应Retained Heap的大小,可以选择使用Calculate Precise Retained Size,但是根据当前内存映像大小和复杂度的不同,计算过程耗时也不相同,但一般都比第一种方式慢得多。

    结束语

    还是花了不少时间来写这篇博客,中间参考了不少其他同行的劳动成果,也不知道是否后面能否完全一一列举,但更多的是自己的总结。在写这篇博客之前自己也使用过一段MAT,但并不是每个功能都使用到了,所以如果其中有什么地方理解有误还望各位读者留言指正。

    关于Android内存泄漏检测的一个神器LeakCanary,大家可以参考我之前写的另外一篇博客

    参考:

    1.LeakCanary简介

    目前Java程序最常用的内存分析工具应该是MAT(Memory Analyzer Tool),它是一个Eclipse插件,同时也有单独的RCP客户端,也可以通过官网的SVN下载到它的源码(具体见另一篇《compile-MAT》)并编译成jar包。LeakCanary本质上就是一个基于MAT进行Android应用程序内存泄漏自动化检测的的开源工具,通过集成这个工具代码到自己的Android工程当中就能够在程序调试开发过程中通过一个漂亮的界面(如下图)随时发现和定位内存泄漏问题,而不用每次在开发流程中都抽出专人来进行内存泄漏问题检测,极大地方便了Android应用程序的开发。

    c90f65c7bea0c322644b7d2c42f458f5.png

    总的来说,LeakCanary有如下几个明显优点:针对Android Activity组件完全自动化的内存泄漏检查。

    可定制一些行为(dump文件和leaktrace对象的数量、自定义例外、分析结果的自定义处理等)。

    集成到自己工程并使用的成本很低。

    友好的界面展示和通知。

    假如你现在想集成LeakCanary到自己的工程中,那么你只需要做以下工作: 1. 导入leakcanary的jar包到自己工程(下载链接:leakcanary.zip) 2. 在4.0以上,只需要在工程的Application的onCreate函数中按照如下的方式加入一行代码:

    public class ExampleApplication extends Application {

    @Override

    public void onCreate() {

    super.onCreate();

    LeakCanary.install(this);

    }

    }

    4.0以下在需要进行内存泄漏监控的Activity的onDestroy方法中按如下加入代码:

    protected void onDestroy() {

    super.onDestroy();

    // start watch

    HeapDump.Listener heapDumpListener =

    new ServiceHeapDumpListener(this, listenerServiceClass);

    DebuggerControl debuggerControl = new AndroidDebuggerControl();

    AndroidHeapDumper heapDumper = new AndroidHeapDumper();

    heapDumper.cleanup();

    ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults().build();

    RefWatcher refWatcher = new RefWatcher(new AndroidWatchExecutor(), debuggerControl, GcTrigger.DEFAULT,

    heapDumper, heapDumpListener, excludedRefs);

    }   第二种情况下,在有多个Activity需要检测的情况看起来稍显繁琐,实际上可以用以上方法实现一个基类Activity,之后需要内存泄漏检测的Activity直接继承这个基类Activity就不需要每次都重复处理oonDestroy方法了。并且以上代码只作为示例,实际上每次watch的时候并不需要重新new一个RefWatcher对象,因为这个对象是可以重复使用的。

    完成了以上两个步骤后,LeakCanary就可以为你的工程服务了,这之中需要我们自己处理的工作很少,相比较我们自己手工用MAT进行内存泄漏检测而言,确实方便了很多。 ## 2.LeakCanary原理分析 ## 这么强大的工具,它是如何实现的呢,引用LeakCanary中文使用说明,它的基本工作原理如下:RefWatcher.watch() 创建一个 KeyedWeakReference 到要被监控的对象。

    然后在后台线程检查引用是否被清除,如果没有,调用GC。

    如果引用还是未被清除,把 heap 内存 dump 到 APP 对应的文件系统中的一个 .hprof 文件中。

    在另外一个进程中的 HeapAnalyzerService 有一个 HeapAnalyzer 使用HAHA 解析这个文件。

    得益于唯一的 reference key, HeapAnalyzer 找到 KeyedWeakReference,定位内存泄漏。

    HeapAnalyzer 计算 到 GC roots 的最短强引用路径,并确定是否是泄漏。如果是的话,建立导致泄漏的引用链。

    引用链传递到 APP 进程中的 DisplayLeakService, 并以通知的形式展示出来。

    但事实上一切并没那么简单,LeakCanary的设计者在实现的时候实际上为我们考虑了很多细节。可以通过源码分析来走一遍一次内存泄漏检查的流程。 在一个Activity生命周期结束调用oonDestroy方法的时候会触发LeakCanary进行一次内存泄漏检查,LeakCanary开始进行检查的入口函数实际上是RefWatcher类的,watch方法,其源码如下:

    public void watch(Object watchedReference, String referenceName) {

    ...

    String key = UUID.randomUUID().toString();

    retainedKeys.add(key);

    final KeyedWeakReference reference = new KeyedWeakReference(watchedReference, key, referenceName, queue);

    watchExecutor.execute(new Runnable() {

    @Override

    public void run() {

    ensureGone(reference, watchStartNanoTime);

    }

    });

    } 这个函数做的主要工作就是为需要进行泄漏检查的Activity创建一个带有唯一key标志的弱引用,并将这个弱引用key保存至retainedKeys中,然后将后面的工作交给watchExecutor来执行。这个watchExecutor在LeakCanary中是AndroidWatchExecutor的实例,调用它的execute方法实际上就是向主线程的消息队列中插入了一个IdleHandler消息,这个消息只有在对应的消息队列为空的时候才会去执行,因此RefWatcher的watch方法就保证了在主线程空闲的时候才会去执行ensureGone方法,防止因为内存泄漏检查任务而严重影响应用的正常执行。ensureGone的主要源码如下:

    void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {

    ...

    removeWeaklyReachableReferences();

    if (gone(reference) || debuggerControl.isDebuggerAttached()) {

    return;

    }

    gcTrigger.runGc(); // 手动执行一次gc

    removeWeaklyReachableReferences();

    if (!gone(reference)) {

    long startDumpHeap = System.nanoTime();

    long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);

    File heapDumpFile = heapDumper.dumpHeap();

    if (heapDumpFile == null) {

    // Could not dump the heap, abort.

    Log.d(TAG, "Could not dump the heap, abort.");

    return;

    }

    long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);

    heapdumpListener.analyze(new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs,

    watchDurationMs, gcDurationMs, heapDumpDurationMs));

    }

    } 因为这个方法是在主线程中执行的,因此一般执行到这个方法中的时候之前被destroy的那个Activity的资源应该被JVM回收了,因此这个方法首先调用removeWeaklyReachableReferences方法来将引用队列中存在的弱引用从retainedKeys中删除掉,这样,retainedKeys中保留的就是还没有被回收对象的弱引用key。之后再用gone方法来判断我们需要检查的Activity的弱引用是否在retainedKeys中,如果没有,说明这个Activity对象已经被回收,检查结束。否则,LeakCanary主动触发一次gc,再进行以上两个步骤,如果发现这个Activity还没有被回收,就认为这个Activity很有可能泄漏了,并dump出当前的内存文件供之后进行分析。

    之后的工作就是对内存文件进行分析,由于这个过程比较耗时,因此最终会把这个工作交给运行在另外一个进程中的HeapAnalyzerService来执行。HeapAnalyzerService通过调用HeapAnalyzer的checkForLeak方法进行内存分析,其源码如下:

    public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {

    ...

    ISnapshot snapshot = null;

    try {

    snapshot = openSnapshot(heapDumpFile);

    IObject leakingRef = findLeakingReference(referenceKey, snapshot);

    // False alarm, weak reference was cleared in between key check and heap dump.

    if (leakingRef == null) {

    return noLeak(since(analysisStartNanoTime));

    }

    String className = leakingRef.getClazz().getName();

    AnalysisResult result =

    findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, true);

    if (!result.leakFound) {

    result = findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, false);

    }

    return result;

    } catch (SnapshotException e) {

    return failure(e, since(analysisStartNanoTime));

    } finally {

    cleanup(heapDumpFile, snapshot);

    }

    }

    这个方法进行的第一步就是利用HAHA将之前dump出来的内存文件解析成Snapshot对象,其中调用到的方法包括SnapshotFactory的parse和HprofIndexBuilder的fill方法。解析得到的Snapshot对象直观上和我们使用MAT进行内存分析时候罗列出内存中各个对象的结构很相似,它通过对象之间的引用链关系构成了一棵树,我们可以在这个树种查询到各个对象的信息,包括它的Class对象信息、内存地址、持有的引用及被持有的引用关系等。到了这一阶段,HAHA的任务就算完成,之后LeakCanary就需要在Snapshot中找到一条有效的到被泄漏对象之间的引用路径。首先它调用findLeakTrace方法来从Snapshot中找到被泄漏对象,源码如下:

    private IObject findLeakingReference(String key, ISnapshot snapshot) throws SnapshotException {

    Collection refClasses =

    snapshot.getClassesByName(KeyedWeakReference.class.getName(), false);

    if (refClasses.size() != 1) {

    throw new IllegalStateException(

    "Expecting one class for " + KeyedWeakReference.class.getName() + " in " + refClasses);

    }

    IClass refClass = refClasses.iterator().next();

    int[] weakRefInstanceIds = refClass.getObjectIds();

    for (int weakRefInstanceId : weakRefInstanceIds) {

    IObject weakRef = snapshot.getObject(weakRefInstanceId);

    String keyCandidate =

    PrettyPrinter.objectAsString((IObject) weakRef.resolveValue("key"), 100);

    if (keyCandidate.equals(key)) { // 匹配key

    return (IObject) weakRef.resolveValue("referent"); // 定位泄漏对象

    }

    }

    throw new IllegalStateException("Could not find weak reference with key " + key);

    }

    为了能够准确找到被泄漏对象,LeakCanary通过被泄漏对象的弱引用来在Snapshot中定位它。因为,如果一个对象被泄漏,一定也可以在内存中找到这个对象的弱引用,再通过弱引用对象的referent就可以直接定位被泄漏对象。 下一步的工作就是找到一条有效的到被泄漏对象的最短的引用,这通过findLeakTrace来实现,实际上寻找最短路径的逻辑主要是封装在PathsFromGCRootsComputerImpl这个类的getNextShortestPath和processCurrentReferrefs这两个方法当中,其源码如下:

    public int[] getNextShortestPath() throws SnapshotException {

    switch (state) {

    case 0: // INITIAL

    {

    ...

    }

    case 1: // FINAL

    return null;

    case 2: // PROCESSING GC ROOT

    {

    ...

    }

    case 3: // NORMAL PROCESSING

    {

    int[] res;

    // finish processing the current entry

    if (currentReferrers != null) {

    res = processCurrentReferrefs(lastReadReferrer + 1);

    if (res != null) return res;

    }

    // Continue with the FIFO

    while (fifo.size() > 0) {

    currentPath = fifo.getFirst();

    fifo.removeFirst();

    currentId = currentPath.getIndex();

    currentReferrers = inboundIndex.get(currentId);

    if (currentReferrers != null) {

    res = processCurrentReferrefs(0);

    if (res != null) return res;

    }

    }

    return null;

    }

    default:

    ...

    }

    }

    private int[] processCurrentReferrefs(int fromIndex) throws SnapshotException {

    GCRootInfo[] rootInfo = null;

    for (int i = fromIndex; i < currentReferrers.length; i++) {

    ...

    }

    for (int referrer : currentReferrers) {

    if (referrer >= 0 && !visited.get(referrer) && !roots.containsKey(referrer)) {

    if (excludeMap == null) {

    fifo.add(new Path(referrer, currentPath));

    visited.set(referrer);

    } else {

    if (!refersOnlyThroughExcluded(referrer, currentId)) {

    fifo.add(new Path(referrer, currentPath));

    visited.set(referrer);

    }

    }

    }

    }

    return null;

    }

    }

    为了是逻辑更清晰,在这里省略了对GCRoot的处理。这个类将整个内存映像信息抽象成了一个以GCRoot为根的树,getNextShortestPath的状态3是对一般节点的处理,由于之前已经定位了被泄漏的对象在这棵树中的位置,为了找到一条到GCRoot最短的路径,PathsFromGCRootsComputerImpl采用的方法是类似于广度优先的搜索策略,在getNextShortestPath中从被泄漏的对象开始,调用一次processCurrentReferrefs将持有它引用的节点(父节点),加入到一个FIFO队列中,然后依次再调用getNextShortestPath和processCurrentReferrefs来从FIFO中取节点及将这个节点的父节点再加入FIFO队列中,一层一层向上寻找,哪条路径最先到达GCRoot就表示它应该是一条最短路径。由于FIFO保存了查询信息,因此如果要找次最短路径只需要再调用一次getNextShortestPath触发下一次查找即可,其算法原理如下图所示。

    289869045287d267ede143ff840fe7b1.png

    至此,主要的工作就完成了,后面就是调用buildLeakTrace构建查询结果,这个过程相对简单,仅仅是将之前查找的最短路径转换成最后需要显示的LeakTrace对象,这个对象中包括了一个由路径上各个节点LeakTraceElement组成的链表,代表了检查到的最短泄漏路径。最后一个步骤就是将这些结果封装成AnalysisResult对象然后交给DisplayLeakService进行处理。这个service主要的工作是将检查结果写入文件,以便之后能够直接看到最近几次内存泄露的分析结果,同时以notification的方式通知用户检测到了一次内存泄漏。使用者还可以继承这个service类来并实现afterDefaultHandling来自定义对检查结果的处理,比如将结果上传刚到服务器等。

    以上就是对LeakCanary源码的分析,中间省略了一些细节处理的说明,但不得不提的是LeakCanary支持自定义泄漏豁对象ExcludedRefs的集合,这些豁免对象一般都是一些已知的系统泄漏问题或者自己工程中已知但又需要被排除在检查之外的泄漏问题构成的。LeakCanary在findLeakTrace方法中如果发现这个集合中的对象存在于泄漏路径上,就会排除掉这条泄漏路径并尝试寻找下一条。

    展开全文
  • Java opencv把mat还原成图片

    千次阅读 2020-10-27 10:39:50
    背景:代码的原理是opencv连接摄像头,捕获到帧数据mat(矩阵),将其转成byte数组然后进行base64编码,把数据与帧的其他信息(宽、高、通道数、时间戳)写入到json对象中,Kafka把json对象以字符串是方式发送出去;...
  • 思路:先将BufferedImage统一转化为RGB格式,再将其转换为Mat类型
  • java opencv byte[] 转Mat类型遇到的坑

    千次阅读 2022-02-09 21:05:52
    Mat mat = new Mat(1024,1024,CV_8UC1); byte[] arr = new byte[64]; Arrays.fill(arr,(byte)0xff); //实际需要覆盖多个小图像,这里为简化需求将左上角覆盖一白色方块 for(int i=0;i<64;i++){ mat.put(i,0...
  • Java内存分析利器MAT使用详解

    千次阅读 2021-03-04 10:04:39
    这是一篇阅读MAT helper的笔记。Heap dump是java进程在特定时间的一个内存快照。通常在触发heap dump之前会进行一次full gc,这样dump出来的内容就包含的是被gc后的对象。dump文件包含的内容:1,全部的对象:类,域...
  • 使用MAT分析Java内存

    2021-02-12 13:26:21
    OverviewMAT(Memory Analyzer Tool) 是一个JAVA Heaper分析器,可以用来分析内存泄露和减少内存消耗。分析Process showmap中的/dev/ashmem/dalvik-heap(deleted)一项所占用的Memory.可以参考我写的使用showmap分析...
  • 入门级Matjava版)

    千次阅读 2022-01-15 15:36:39
    第一二个参数是行列数,第三个参数是mat类型。这里32SC3表示一个像素用了32位,S代表signed int,C3代表通道数是3。 即 创建一个3X2的矩阵,此矩阵具有3通道。每个点能保存int类型数据 未带通道数的默认是1。例如...
  • 前言调试程序的过程中,opencv创建矩阵之后对其赋值出现错误:Mat m = Mat::zeros(1, featureLen, CV_32FC1);Mat data = Mat::zeros(testCount, featureLen, CV_32FC1);//Mat res = Mat::zeros(testCount, 1, CV_32...
  • 1内存泄漏的排查方法Dalvik Debug Monitor Server (DDMS)是ADT插件的一部分,其中有两项功能可用于内存检查:·...Eclipse Memory Analysis Tools (MAT)是一个分析Java堆数据的专业工具,用它可以定位内存泄漏的原...
  • // Create a Matrix the same size of image Mat image = new Mat(im.getHeight(), im.getWidth(), CvType.CV_8UC3); // Fill Matrix with image values image.put(0, 0, pixels); return image; } 解决方案 You ...
  • 使用MATjava内存分析

    2021-02-12 13:26:19
    这是一篇阅读MAT helper的笔记。Heap dump是java进程在特定时间的一个内存快照。通常在触发heap dump之前会进行一次full gc,这样dump出来的内容就包含的是被gc后的对象。dump文件包含的内容:1,全部的对象:类,域...
  • Mat类型(type)

    2021-03-13 11:55:20
    问题:如果Mat 中想存小数,那么声明是就要用CV_32FC1等浮点数的类型,并且在访问像素的时候,指向每一行(i行)的指针:不再是: uchar *data=src.ptr(i); 了 (uchar 是0~255的无符号整数)而是用:float *data =src....
  • Java内存分析工具MAT(Memory Analyzer Tool)的介绍与使用

    千次阅读 多人点赞 2021-06-25 08:45:22
    详细介绍了Java内存分析工具MAT(Memory Analyzer Tool)的常见使用方法,MAT可以帮助Java程序员快速进行内存分析,定位问题。
  • MAT 不是一个万能工具,它并不能处理所有类型的堆存储文件。但是比较主流的厂家和格式,例如 Sun, HP, SAP 所采用的 HPROF 二进制堆存储文件,以及 IBM 的 PHD 堆存储文件等都能被很好的解析。下面来看看要怎么做呢...
  • mat转换png

    2021-08-07 12:33:27
    ) with h5py.File(dataFile, 'r') as f: f = h5py.File(dataFile, 'r') print(f.keys()) # 此处的keys返回的是view-like objects ,不是list # print(f['x'][:]) # 由于导入的mat文件是structure类型的,所以需要...
  • 可以在java部分创建一个Mat,用于保存图像处理结果图像,获取Mat 的本地地址传入jni函数中: // java Mat res = new Mat(); jni_fun(res.getNativeObjAddr()); c++部分新建Mat指针指向java传入的内存区域,将处理后...
  • opencv中对图像的处理是最基本...Mat类型较CvMat和IplImage有更强的矩阵运算能力,支持常见的矩阵运算(参照Matlab中的各种矩阵运算),所以将IplImage类型和CvMat类型转换为Mat类型更易于数据处理。Mat类型可用于直接...
  • Java与C++传opencv Mat

    千次阅读 2019-01-10 14:44:52
    java端: File file = new File(&quot;1.jpg&quot;); BufferedImage bi = null; try { bi = ImageIO.read(file); } catch (Exception e) { e.printStackTrace(); ...
  • JMatIO 是一个 JAVA 库,用于使用 Matlab 的二进制 MAT 文件进行读/写/操作。 目前支持的数据类型有: + 双阵列+ UInt8, Int8 数组+ UInt64, Int64 数组+ 字符数组+ 结构+ 元胞数组+ 稀疏数组 这个项目也可以在...
  • java OpenCv Mat 类的基本操作(3)

    千次阅读 2020-08-27 10:21:10
    人脸识别opencv还支持DNN,但是我在使用pb模型的时候,最后forward输出的矩阵我并不知道怎么处理来显示出来图像,所以不得用时间将基础做好,opencv java里面有一个重要的类是Mat,那么我们先看看如何创建 废话少说...
  • I am trying to convert a C++ method from a previous answer I received using OpenCV to Java using OpenCV Java bindings我正在尝试将以前使用OpenCV得到的答案转换为使用OpenCV Java绑定的JavaC++ code:c++代码...
  • OpenCV Mat 类型定义和赋值

    千次阅读 2020-12-24 10:47:26
    1.一般的Mat定义方法:cv::Mat M(height,width,),例:cv::Mat M(480,640,CV_8UC3); 表示定义了一个480行640列的矩阵,矩阵的每个单元的由三个(C3:3 Channel)8位无符号整形(U Unsigned U8 8位)构成。2.将已有数组赋...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,627
精华内容 6,250
关键字:

java mat类型

java 订阅