opencv3.3.0播放avi文件时内存不断上涨

red-fly 2018-03-29 11:27:09
加精
从网上下载了opencv3.3.0,然后自己用vs2015编译后用来开发

现在要播放一个avi文件,结果内存不断上涨,虽然上涨 不是太快(大约1MB/分钟),但上涨大约10MB时,程序就无响应了

环境:vs2015 MFC,调用opencv3.3.0库播放avi,其实只调用了几个接口,另外从网上找了CvvImage类加入到了工程中,方便把avi的图像画到自己指定的mfc控件上

代码的大致流程:
设置定时器为40ms一次,每次读取一帧然后画到一个指定的static控件上,当到达最后一帧时,再返回到第一帧。


/*
本函数在定时器中每40ms调用一次
在类的头文件中定义
CvCapture *m_cvCapture;
CvvImage m_cimg;
CStatic m_stVideo; 控件,用于显示图像
*/
void CShowVideoView::PlayFile()
{
if (m_isPause)
{
DrawPicture(m_cimg);
return;
}

IplImage* img = NULL;
m_playPos += 1;
img = cvQueryFrame(m_cvCapture);
if (img == NULL)
{
// 已经到最后了,要回到开始的位置
cvSetCaptureProperty(m_cvCapture, CV_CAP_PROP_POS_FRAMES, 0);
m_playPos = 0;
return;
}

m_cimg.CopyOf(img);
DrawPicture(m_cimg);
}

void CShowVideoView::DrawPicture(CvvImage &cimg)
{
CDC *pDC = m_stVideo.GetDC();
if (pDC == NULL)
{
return;
}
HDC hDc = pDC->m_hDC;
CRect rect;
m_stVideo.GetClientRect(&rect);
cimg.DrawToHDC(hDc, &rect);
}


这个流程也很简单,就是读取一帧,然后显示,到最后一帧的时候就返回到第一帧继续
另外对于网上下载的这个CvvImage类,其CopyOf()接口中,我看只有create()的调用,而没有销毁,所以我就在这个接口里添加了个destroy的调用,修改后的代码如下:

void CvvImage::CopyOf(IplImage* img, int desired_color)
{
if (HG_IS_IMAGE(img))
{
int color = desired_color;
CvSize size = cvGetSize(img);

if (color < 0)
color = img->nChannels > 1;

// 这两行是新添加的
if (m_img)
Destroy();

if (Create(size.width, size.height,
(!color ? 1 : img->nChannels > 1 ? img->nChannels : 3) * 8,
img->origin))
{
cvConvertImage(img, m_img, 0);
}
}
}


如果我只读取一帧,然后每次都显示这同一帧,上涨的速度就慢很多,如果只是读取而不显示,同样也还是会上涨
...全文
3511 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
Creâplus 2021-07-27
  • 打赏
  • 举报
回复

楼主表现$$的非常棒~

adsl6656336987365 2018-05-10
  • 打赏
  • 举报
回复
自己解决了问题,楼主很不错,点个赞!
red-fly 2018-04-12
  • 打赏
  • 举报
回复
引用 11 楼 hjgzj 的回复:
自己解决了问题,楼主很不错,点个赞!
还是自己的问题,以前似乎没有这样用过,所以也没有暴漏出过这个问题,真是要不断地一直学习才好
xq3707qq 2018-04-12
  • 打赏
  • 举报
回复
自己解决了问题,楼主很不错,点个赞!
  • 打赏
  • 举报
回复
自己解决了问题,楼主很不错,点个赞!
qq_21443615 2018-04-04
  • 打赏
  • 举报
回复
支持一下 感谢分享
wuhui420 2018-04-02
  • 打赏
  • 举报
回复
好用吧支持下
red-fly 2018-03-31
  • 打赏
  • 举报
回复
引用 6 楼 robertbo 的回复:
难道说在显示的时候GetDC()这个值不是唯一的?之前都是用CvvImage类解决的显示问题,你可以逐行注释掉试试,看看是哪一行的代码导致的内存不释放。
刚开始我也是下载了一个CvvImage的代码用它来画的,只是后来出现了内存上涨而且过一会儿程序无响应的问题,在找这个问题的过程中,就又找了一下其它的画图方式。这个过程不影响其实的情况,发现的问题仅仅是GetDC()后没有释放。 后来在释放获取的DC后,程序运行正常了,但是内存还是会上涨,不过上涨的慢,测试了大约2个小时,上涨了大约15MB的内存,降了这个情况之外,其它看上去是一切正常。这似乎是一个问题,但程序可以不需要长时间连续运行,所以暂时先不管这个情况了,以后如果有时间,再仔细查查究竟是哪里导致的
red-fly 2018-03-30
  • 打赏
  • 举报
回复
引用 3 楼 robertbo 的回复:
你的CDC *pDC = m_stVideo.GetDC();必须每次都重新GetDC吗,为什么不可以在外面把pDC初始化为与m_stVideo同样生命周期的变量呢,这样就不用每次都初始化和释放了。 再有,DrawMat里面pDC->GetSafeHdc()也是一个同样没有释放的句柄吧。
刚才试了两种情况,在类中声明全局的 CDC *m_pDcVideo: 1. 在程序启动时获取DC:m_pDcVideo = m_stVideo.GetDC(); 这个结果不为空,说明正常,在后面采用此dc画图时,没有任何显示。 2. 在程序启动时置 m_pDcVideo = NULL,在画图时判断如果为NULL,就获取,否则就不再获取: if (m_pDcVideo == NULL) m_pDcVideo = m_stVideo.GetDC(); ... // 画图 结果只显示第一张图片,后面的都不显示 注:两种情况都不即时销毁m_pDcVideo,而是在程序退出时如果其不为NULL就销毁
red-fly 2018-03-30
  • 打赏
  • 举报
回复
引用 3 楼 robertbo 的回复:
你的CDC *pDC = m_stVideo.GetDC();必须每次都重新GetDC吗,为什么不可以在外面把pDC初始化为与m_stVideo同样生命周期的变量呢,这样就不用每次都初始化和释放了。 再有,DrawMat里面pDC->GetSafeHdc()也是一个同样没有释放的句柄吧。
csdn上没有说GetSafeHdc要释放,贴子 https://bbs.csdn.net/topics/340265147 上也说不用额外释放
robertbo 2018-03-30
  • 打赏
  • 举报
回复
你的CDC *pDC = m_stVideo.GetDC();必须每次都重新GetDC吗,为什么不可以在外面把pDC初始化为与m_stVideo同样生命周期的变量呢,这样就不用每次都初始化和释放了。 再有,DrawMat里面pDC->GetSafeHdc()也是一个同样没有释放的句柄吧。
robertbo 2018-03-30
  • 打赏
  • 举报
回复
[b[/b]
引用 5 楼 jszj 的回复:
[quote=引用 3 楼 robertbo 的回复:] 你的CDC *pDC = m_stVideo.GetDC();必须每次都重新GetDC吗,为什么不可以在外面把pDC初始化为与m_stVideo同样生命周期的变量呢,这样就不用每次都初始化和释放了。 再有,DrawMat里面pDC->GetSafeHdc()也是一个同样没有释放的句柄吧。
刚才试了两种情况,在类中声明全局的 CDC *m_pDcVideo: 1. 在程序启动时获取DC:m_pDcVideo = m_stVideo.GetDC(); 这个结果不为空,说明正常,在后面采用此dc画图时,没有任何显示。 2. 在程序启动时置 m_pDcVideo = NULL,在画图时判断如果为NULL,就获取,否则就不再获取: if (m_pDcVideo == NULL) m_pDcVideo = m_stVideo.GetDC(); ... // 画图 结果只显示第一张图片,后面的都不显示 注:两种情况都不即时销毁m_pDcVideo,而是在程序退出时如果其不为NULL就销毁[/quote] 难道说在显示的时候GetDC()这个值不是唯一的?之前都是用CvvImage类解决的显示问题,你可以逐行注释掉试试,看看是哪一行的代码导致的内存不释放。
red-fly 2018-03-29
  • 打赏
  • 举报
回复
观察了一会儿,应该是解决了,还是自己的问题,要对GetDC()的返回值进行释放:

void CShowVideoView::DrawPicture()
{
    CDC *pDC = m_stVideo.GetDC();
    if (pDC == NULL)
    {
        return;
    }
 
    CRect rect;
    m_stVideo.GetClientRect(&rect);
    DrawMat(pDC, m_matImg, rect);
    ReleaseDC(pDC);   // 加了这一行
}
虽然内存还是会上涨,但是慢了,而且一段时间后基本上就不再上涨了,也不会出现无响应的情况了,程序也没有其它异常了,一切都正常了
red-fly 2018-03-29
  • 打赏
  • 举报
回复
了解到 IplImage被抛弃,VideoCapture才是推荐的新接口,所以就对代码做了少许修改:

/*
cv::VideoCapture m_cvCapture;
cv::Mat			m_matImg;
//*/
if (!m_cvCapture.read(m_matImg))
{
	// 已经到最后了,要回到开始的位置
	GotoVideoStart();
	m_isFramed = false;
	return;
}
DrawPicture();
...

void CShowVideoView::DrawPicture()
{
	CDC *pDC = m_stVideo.GetDC();
	if (pDC == NULL)
	{
		return;
	}

	CRect rect;
	m_stVideo.GetClientRect(&rect);
	DrawMat(pDC, m_matImg, rect);
}
其中 DrawMat() 用的是 // https://blog.csdn.net/carotong/article/details/48497495 的代码,看起来也很简单 这样修改后,下载的CvvImage类就没有再用了 然而仍然会不断上涨这个内存

4,246

社区成员

发帖
与我相关
我的任务
社区描述
OpenCV相关技术交流专区
计算机视觉人工智能opencv 技术论坛(原bbs) 广东省·深圳市
社区管理员
  • OpenCV
  • 幻灰龙
  • OpenCV中国团队
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

OpenCV中国团队官方博客:https://blog.csdn.net/opencvchina

试试用AI创作助手写篇文章吧