本文地址: https://www.jianshu.com/p/7963c7dbaf92
先来看看OpenCV,基础对象Mat,矩阵。什么是矩阵,实际上没有必要解释,一般人都能够明白数学意义上矩阵的含义。
OpenCV把每一个M * N的宽高图像,看成M*N的矩阵。矩阵的每一个单元就对应着图像中像素的每一个点。
我们如果放大图中某个部分,就会发现如下情况
图像实际上就如同矩阵一样每个单元由一个像素点构成。
因为OpenCV的Mat每一个像素点,包含的数据不仅仅只有一个单纯的数字。每一个像素点中包含着颜色通道数据。
稍微解释一下颜色通道,我们可以把世间万物肉眼能识别的颜色由3种颜色(R 红色,G 绿色,B 蓝色)经过调节其色彩饱和度组成的。也就是说通过控制RGB三种的色值大小(0~255)来调配新的颜色。
当我们常见的灰度图,一般是单个颜色通道,因为只用黑白两种颜色。我们常见的图片,至少是三色通道,因为需要RGB三种颜色通道。
我们常见Android的Bitmap能够设置ARGB_8888的标志位就是指能够通过A(透明通道),R,G,B来控制图片加载的颜色通道。
OpenCV为了更好的控制这些数据。因此采用了数学上的矩阵的概念。当OpenCV要控制如RGB三色通道的Mat,本质上是一个M * N * 3的三维矩阵。
但是实际上,我们在使用OpenCV的Mat的时候,我们只需要关注每个图片的像素,而每个像素的颜色通道则是看成Mat中每个单元数据的内容即可
我们先来看看Mat的构造方法
现阶段,实际上我们值得我们注意的是构造函数:
举个例子:
这个mat矩阵将会制造一个高20,宽30,一个1字节的颜色通道(也是Mat中每一个像素数据都是1字节的unchar类型的数据),同时颜色是白色的图片。
在这里面我们能够看到一个特殊的宏CV_8UC1。实际上这是指代OpenCV中图片带的是多少颜色通道的意思。
这4个宏十分重要,要时刻记住。
当我们需要把Mat 中的数据拷贝一份出来,我们应该调用下面这个api:
这样就能拷贝一份像素数据到新的Mat中。之后 *** 作新的Mat就不会影响原图。
实际上,在本文中,我们能够看到OpenCV是这么调用api读取图片的数据转化为Mat矩阵。
OpenCV会通过imread去读图片文件,并且转化为Mat矩阵。
能看见imread,是调用imread_把图片中的数据拷贝的img这个Mat对象中。接着会做一次图片的颠倒。这个方面倒是和Glide很相似。
文件:modules/imgcodecs/src/loadsave.cpp
这里面做了几个事情,实际上和FFmpge的设计十分相似。
其核心也是 *** 作Mat中的像素指针,找到颜色通道,确定指针移动的步长,赋值图片的数据到Mat矩阵中。核心如下:
其中还涉及到jpeg的哈夫曼算法之类的东西,这里就不深入源码。毕竟这是基础学习。
什么是灰度图,灰度度图实际上我们经常见到那些灰白的也可以纳入灰度图的范畴。实际上在计算机图形学有这么一个公式:
将RGB的多颜色图,通过 的算法,将每一个像素的图像的三颜色通道全部转化为为一种色彩,通过上面的公式转为为一种灰色的颜色。
一旦了解了,我们可以尝试编写灰度图的转化。我们通过矩阵的at方法访问每一个像素中的数据。
为了形象表示矩阵指针,指向问题,可以把RGB在OpenCV的Mat看成如下分布:
记住OpenCV的RGB的顺序和Android的不一样,是BGRA的顺序。和我们Android开发颠倒过来。
因此,我们可以得到如下的例子
我们经过尝试之后,确实能够把一个彩色的图片转化一个灰色图片。但是这就是
这里介绍一下Mat的一个api:
实际上OpenCV,内置了一些 *** 作,可以把RGB的图像数据转化灰度图。
我们看看OpenCV实际上的转化出来的灰度图大小。我们通过自己写的方法,转化出来的灰度图是119kb,而通过cvtColor转化出来的是44kb。
问题出在哪里?还记得吗?因为只有灰白两种颜色,实际上只需要一种颜色通道即可,而这边还保留了3个颜色通道,也就说图片的每一个像素点中的数据出现了没必要的冗余。
这样就是44kb的大小。把三颜色通道的数据都设置到单颜色通道之后,就能进一步缩小其大小。
实际上在Android中的ColorMatrix中也有灰度图转化的api。
对画笔矩阵进行一次,矩阵变化 *** 作。
实际上就是做了一次矩阵运算。绘制灰度的时候相当于构建了这么一个矩阵
接着通过矩阵之间的相乘,每一行的 0.213f,0.715f,0.072f控制像素的每个通道的色值。
对于Java来说,灰度转化的算法是: ,把绿色通道的比例调大了。
在OpenCV中有这么两个API,add和addWidget。两者都是可以把图像混合起来。
add和addWidget都是将像素合并起来。但是由于是像素直接相加的,所以容易造成像素接近255,让整个像素泛白。
而权重addWeighted,稍微能减轻一点这种问题,本质上还是像素相加,因此打水印一般不是使用这种办法。
等价于
saturate_cast这个是为了保证计算的值在0~255之间,防止越界。
饱和度,图片中色值更加大,如红色,淡红,鲜红
对比度:是指图像灰度反差。相当于图像中最暗和最亮的对比
亮度:暗亮度
控制对比度,饱和度的公式: , ,
因此当我们想要控制三通道的饱和度时候,可以通过alpha来控制色值成比例增加,beta控制一个色值线性增加。
如下:
在这里,看到了OpenCV会把所有的图片看成Mat矩阵。从本文中,能看到Mat的像素 *** 作可以能看到有两种,一种是ptr像素指针,一种是at。ptr是OpenCV推荐的更加效率的访问速度。
当然还有一种LUT的核心函数,用来极速访问Mat矩阵中的像素。其原理是对着原来的色值进行预先的变换对应(设置一个颜色通道)。用来应对设置阈值等情况。
最近在写性能优化专题相关文章,依次写了“Android电量优化全解析”、“Android性能优化全解析”、“Android渲染优化解析”、“Android计算优化解析”。文章中有提到许多性能优化的工具,但由于文章重点都是如何分析性能相关的论述,对工具的使用介绍大都是简单略过,下面简单介绍下性能优化工具-MAT(Memory Analyzer Tool)使用,介绍的顺序为:
MAT工具全称为Memory Analyzer Tool,一款详细分析Java堆内存的工具,该工具非常强大,为了使用该工具,我们需要hprof文件。但是该文件不能直接被MAT使用,需要进行一步转化,可以使用hprof-conv命令来转化,但是Android Studio可以直接转化,转化方法如下:
1.选择一个hprof文件,点击右键选择Export to standard .hprof选项。
2.填写更改后的文件名和路径。
点击OK按钮后,MAT工具所需的文件就生成了!
下面我们用MAT来打开转换后的doctorq.hprof文件:
1.打开MAT后选择File->Open File选择我们刚才生成的doctorq.hprof文件
2.选择该文件后,MAT会有几秒种的时间解析该文件,有的hprof文件可能过大,会有更长的时间解析,解析后,展现在我们的面前的界面如下:
这是个总览界面,会大体给出一些分析后初步的结论。
该视图会首页总结出当前这个Heap dump占用了多大的内存,其中涉及的类有多少,对象有多少,类加载器,如果有没有回收的对象,会有一个连接,可以直接参看(图中的Unreachable Objects Histogram)。
比如该例子中显示了Heap dump占用了41M的内存,5400个类,96700个对象,6个类加载器, 然后还会有各种分类信息。
会列举出Retained Size值最大的几个值,你可以将鼠标放到饼图中的扇叶上,可以在右侧看出详细信息:
图中灰色区域,并不是我们需要关心的,他是除了大内存对象外的其他对象,我们需要关心的就是图中彩色区域,比如图中2.4M的对象,我们来看看该对象到底是啥
该对象是一个Bitmap对象,你如果想知道该对象到底是什么图片,可以使用图片工具gimp工具浏览该对象。
histogram视图主要是查看某个类的实例个数,比如我们在检查内存泄漏时候,要判断是否频繁创建了对象,就可以来看对象的个数来看。也可以通过排序看出占用内存大的对象:
默认是类名形式展示,你也可以选择不同的显示方式,有以下四种方式:
下面来演示一下:
该视图会以占用总内存的百分比来列举所有实例对象,注意这个地方是对象而不是类了,这个视图是用来发现大内存对象的。这些对象都可以展开查看更详细的信息,可以看到该对象内部包含的对象:
这个视图会展示一些可能的内存泄漏的点,比如上图上图显示有3个内存泄漏可疑点,我们以Problem Suspect 1为例来理解该报告,首先我们来看该可疑点详细信息:
上面信息显示ImageCahe类的一个实例0xa50819f8占用了14.19%的内存,具体值为5147200字节(5147200/1024/1024=4.9M),并存放在LinkedHashMap这个集合中,然后我们点击Details跳转到更详细的页面:
这样我们就能找到在我们的app源码中造成该泄漏可疑点的地方,很容易去定位问题。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)