cvmat型数据需要释放内存么

cvmat型数据需要释放内存么,第1张

关于Opencv 内存泄漏的一些总结

1、内存泄露

内存泄咐握露是说没有释放茄简陪已经不能使用的内存,这里一般指堆的内存才需要显示的释放。比如用malloc,calloc,realloc,new分配的内存是在堆上的,需要用free,delete显示的回收。内存泄露最明显的一是程序很慢,在运行程序时你可以启动任务管理器,会看到程序占用的内存一直“砰砰砰”的往上涨:最后直接崩溃,或者你关闭程序的时候也会异常退出

1)除了new的对象我们知道要delete。

OpenCV中使用颤蠢cvCreateImage()新建一个IplImage*,以及使用cvCreateMat()新建一个CvMat*,都需要cvReleaseImage() cvReleaseMat()显示的释放

[cpp] view plaincopyprint?

IplImage* subImg=cvCreateImage( cvSize((img->width)*scale,(img->height)*scale), 8, 3 )

CvMat *tempMat=cvCreateMat((img->width)*scale,(maxFace->height)*scale,CV_MAKETYPE(image->depth,image->nChannels))

cvReleaseImage(&subImg)

cvReleaseMat(&tempMat)

另外一些函数要用到 CvSeq*来存放结果(通常这些都要用cvCreateMemStorage()事先分配一块内存CvMemStorage*),都要是释放掉相应的内存,这是很难找的。

比如从二值图像中寻找轮廓的函数cvFindContours():

[cpp] view plaincopyprint?

CvMemStorage* m_storage=cvCreateMemStorage(0)

CvSeq * m_contour=0

cvFindContours( img, m_storage, &m_contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0))

//释放内存

cvReleaseMemStorage(&m_storage)

以及人脸识别中检测人脸的函数:

[cpp] view plaincopyprint?

CvMemStorage* m_storage=cvCreateMemStorage(0)

CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 )

CvSeq* faces = cvHaarDetectObjects( img, cascade, m_storage,1.1, 2, 0,cvSize(30, 30) )

//释放内存

<span style="BACKGROUND-COLOR: #ff99ff">cvReleaseMemStorage( &faces->storage)

cvReleaseHaarClassifierCascade( &cascade )</span>

注意这里我们可以使用

cvReleaseMemStorage( &faces->storage)

来释放m_storate,也可以使用:

cvReleaseMemStorage(&m_storage)// 释放内存,这是等效的,但一定不要用两次!!

2、关于cvvImage内存泄露

opencv中的CvvImage类多用在MFC中,因为有Show()这个成员函数,在MFC显示图像比IplImage要方便很多。但是同时也有容易疏忽导致内存泄漏的地方。

CvvImage::CopyOf

1

2

void CvvImage::CopyOf(CvvImage&img, intdesired_color)

void CvvImage::CopyOf(IplImage* img, intdesired_color)

从img复制图像到当前的对象中。

img

要复制的图像。

desired_color

为复制后图像的通道数, 复制后图像的像素深度为8bit。

CopyOf()函数会开辟一个新的空间存放图像,不会自动释放。

因此在使用CopyOf()函数后,必须要使用Destroy()函数手动释放内存

如:

CvvImage cimg

cimg.CopyOf(img,3) //复制为CvvImage结构

cimg.DrawToHDC(hDC,&rect) // 写到HDC中,大小为rect

cimg.Destroy()

3、CDC是Windows绘图设备的基类

其他函数中要使用CDC类,需使用GetDC函数和ReleaseDC函数,实现申请CDC类得指针和释放CDC类的指针。

CDC的使用:OnDraw(CDC* pDC),因此OnDraw中可以直接使用CDC类编写代码。

如:

CDC *pdc = GetDC()

ReleaseDC(pdc)

==================================================================

OpenCV中的内存泄露问题(有些按网上说的效果好像不起作用,内存还是在慢慢长)

1、网上说的 cvLoadImage函数:使用CvvImage类代替。并且使用CvvImage类的Load函数。(我测试后感觉没有什么改善)

使用过程大概如下:

//变量定义:

CvvImage pSrcImg

IplImag *pSrcImgCopy //使用IplImag变量做个拷贝。毕竟IplImag 类处理方便。

//获取图像:

pSrcImg.Load(str)//str为Cstring类型的图像文件名

pSrcImgCopy = pSrcImg.GetImage()//拷贝出pSrcImg的图像数据。

//释放内存

pSrcImg变量不需要每次释放,因为每次Load时是覆盖以前的内存区域。pSrcImgCopy 同样。

不过在程序结束时要释放,以免产生内存泄露或者别人以为你忘了。

cvReleaseImage(&pSrcImgCopy )

pSrcImg.Destroy()

不过要正确释放pSrcImgCopy 时,声明时必须create下:

pSrcImgCopy = cvCreateImage(cvSize(IMGWIDHT,IMGHEIGHT),IPL_DEPTH_8U, 3)

//IMGWIDHT,IMGHEIGHT为图像宽和高。

cvCloneImage函数:用cvCopy函数代替。。(我测试后感觉没有什么改善)

cvCopy(pSrcImg,pImg,NULL)//代替 pImg = cvCloneImage(pSrcImg)

pImg初始化时必须分配空间,否则上述函数不能执行。

pImg = cvCreateImage(cvSize(IMGWIDHT,IMGHEIGHT),IPL_DEPTH_8U, 3)

2. cvGetCols()、cvGetRows()

......

CvMat *srcMat = cvCreateMat(width, height, CV_8UC3) // 创建一个三通道无符号整数类型的矩阵

cvGetCols(frame,srcMat,0,width)

这里出现内存泄露,因为cvGetCols()、cvGetRows() 是为目标矩阵分配一块新的数据内存区域,如果目标矩阵的数据区域之前已经分配了内存,则会原始数据内存区域将变成内存碎片,造成内存泄露。解决方法如下:

CvMat *srcMat = cvCreateMat(width, height, CV_8UC3) // 创建一个三通道无符号整数类型的矩阵

cvReleaseData(srcMat) // 先释放目标矩阵的数据区

cvGetCols(frame,srcMat,0,width)

或者

cvCreateMatHeader(width, height, CV_8UC3)

cvGetCols(frame,srcMat,0,width)

3. IplImag*、CvMat*、CvHistogram* 等结构体指针在使用后要释放。

IplImage *frame= cvCreateImage(cvSize(width,height),8,1)

CvMat *srcMat = cvCreateMat(width, height, CV_8U)

......

CvHistogram *hist = cvCreateHist(1,&histSize,CV_HIST_ARRAY,ranges,1)

......

cvReleaseMat(&srcMat)

cvReleaseImage(&frame)

cvReleaseHist(&hist)

Mat类型对应的头文件是"highgui.h",在编译的时候仅仅加上#include "highgui.h" 这句话是不行的哪宽,得告诉系统你的作用域是什么,两种办法:

1、在程序的最开始加上: using namespace cv

2、把Mat改为 cv::Mat。

OpenCV的全称是:Open Source Computer Vision Library。OpenCV是一个基于(开源)发行的竖吵跨平台计算机视觉库,可以余缓侍运行在Linux、Windows和Mac OS *** 作系统上。

它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

开始写OpenCV这篇文章的时候,不由想到,我的大学计算机图形学的第一门实 *** 课程就是灰度转化,拉普拉斯锐化等。其中灰度图的转化,是计算机图形学基础中基础,这里就顺着OpenCV的灰度的转化,来看看OpenCV一些基础的api。配棚

本文地址: 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矩阵中的像素。其原理是对着原来的色值进行预先的变换对应(设置一个颜色通道)。用来应对设置阈值等情况。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/tougao/12134573.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存