笔者刚开始接触计算机视觉这一个领域,在使用《学习OpenCV》这本经典著作的过程中遇到了一系列的问题,很多问题对于一名初学者来说都是共性的,因此在CSDN与大家分享、交流我遇到的问题,希望大家少走弯路,共同进步!笔者小白,若有叙述不当之处,请看客予以纠正,在此谢过。(本文代码基于VS2013+OpenCV2.4.9环境)
OpenCV 2.4.9 +VS2013 开发环境配置,可参考以下链接:
OpenCV 2.4.9 +VS2013 开发环境配置
从磁盘加载并在屏幕上显示一幅图像,程序代码如下:
#include
#include
using namespace std;
int main(int argc, char** argv) //带输入参数的main函数
{
IplImage *img = cvLoadImage(argv[1]); //加载图像至内存返回指针
cvNamedWindow("Example1", CV_WINDOW_AUTOSIZE); //创建窗口
cvShowImage("Example1", img); //窗口中显示图像
cvWaitKey(0); //等待任意按键触发
cvReleaseImage(&img); //释放图像所占内存
cvDestroyWindow("Example1"); //销毁窗口
}
带参数main函数程序的运行方法:
①在VS环境下编译生成.exe文件,并将要显示的图像文件放到.exe文件同一文件夹下
②在开始菜单搜索框输入cmd,右键以管理员身份运行
③图像文件所在盘符: 回车
④cd+“空格”+工程Debug文件夹所在路径 回车
⑤应用程序名.exe+“空格”+图像文件名.jpg 回车
为方便调试和实际调用,笔者将以上程序做了一些更改,以便能够直接实现编译调试,代码如下:
#include
#include
using namespace std;
int main(int argc, char** argv) //带输入参数的main函数
{
IplImage *img = cvLoadImage("D:\\Template\\OpenCV\\Template1_ShowImage_cmd\\3.jpg");
// IplImage *img = cvLoadImage(argv[1]); //加载图像至内存返回指针
cvNamedWindow("Example1", CV_WINDOW_AUTOSIZE); //创建窗口
cvShowImage("Example1", img); //窗口中显示图像
cvWaitKey(0); //等待任意按键触发
cvReleaseImage(&img); //释放图像所占内存
cvDestroyWindow("Example1"); //销毁窗口
}
以上代码的功能,依旧是实现对之前那张图片的调用,只不过省去了cmd调用的环节,.exe文件可直接运行。
播放视频硬盘中的视频文件的程序与显示图像类似,笔者也将其写成了通过cmd调用和直接调用的两个版本。
通过cmd调用的代码如下(调用方式见例2-1):
#include
#include
int main(int argc, char** argv) //带输入参数的main函数
{
cvNamedWindow("Example2", CV_WINDOW_AUTOSIZE); //创建窗口
CvCapture* capture = cvCreateFileCapture(argv[1]); //确定读入文件
IplImage* frame; //当前帧指针
while (1)
{
frame = cvQueryFrame(capture); //下一帧图像载入内存,填充or更新
if (!frame) break;
cvShowImage("Example2", frame);
char c = cvWaitKey(32); //等待32ms
if (c == 27) break;
}
cvReleaseCapture(&capture); //释放资源
cvDestroyWindow("Example2"); //销毁窗口
}
直接调用的代码如下(调用方式见例2-1):
#include
#include
int main(int argc, char** argv) //带输入参数的main函数
{
cvNamedWindow("Example2", CV_WINDOW_AUTOSIZE); //创建窗口
CvCapture* capture = cvCreateFileCapture("D:\\Template\\OpenCV\\Template2_ShowAVI_cmd\\Debug\\只想告诉你.avi");
IplImage* frame; //当前帧指针
while (1)
{
frame = cvQueryFrame(capture); //下一帧图像载入内存,填充or更新
if (!frame) break;
cvShowImage("Example2", frame);
char c = cvWaitKey(32); //等待32ms
if (c == 27) break;
}
cvReleaseCapture(&capture); //释放资源
cvDestroyWindow("Example2"); //销毁窗口
}
添加滚动条到基本浏览窗口的程序代码如下:
#include
#include
using namespace std;
int g_slider_position = 0; //滚动条位置全局变量
CvCapture* g_capture = NULL; //确定要读入AVI文件的指针
void onTrackbarSlide(int pos)
{
cvSetCaptureProperty(g_capture,CV_CAP_PROP_POS_FRAMES,pos); //以帧数设置读入位置
} //回调函数,滚动条被拖动时调用,位置以32位整型返回
int main(int argc, char** argv)
{
cvNamedWindow("Example3", CV_WINDOW_AUTOSIZE); //创建窗口
g_capture = cvCreateFileCapture("D:\\Template\\OpenCV\\Template2_ShowAVI_cmd\\Debug\\只想告诉你.avi");
// g_capture = cvCreateFileCapture(argv[1]); //cmd
int frames = (int)cvGetCaptureProperty(g_capture, CV_CAP_PROP_FRAME_COUNT); //获取总帧数以设定滚动条
if (frames != 0)
{
cvCreateTrackbar("Position","Example3",&g_slider_position,frames,onTrackbarSlide); //创建滚动条
} //将变量绑定到滚动条表征最大值和回调函数
IplImage* frame;
while (1)
{
frame = cvQueryFrame(g_capture);
if (!frame) break;
cvShowImage("Example3", frame);
g_slider_position++;
cvCreateTrackbar("Position", "Example3", &g_slider_position, frames, onTrackbarSlide); //滚动条随视频移动
char c = cvWaitKey(32);
if (c == 27) break;
}
cvReleaseCapture(&g_capture);
cvDestroyWindow("Example3");
return(0);
}
载入一幅图像并进行平滑处理,程序代码如下:
#include
#include
using namespace std;
void example2_4(IplImage* image)
{
cvNamedWindow("Example4-in", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Example4-out", CV_WINDOW_AUTOSIZE);
cvShowImage("Example4-in", image);
IplImage* out = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3); //(图像大小,每个像素点数据类型 ,通道数)
cvSmooth(image,out,CV_GAUSSIAN,3,3); //对3*3的区域进行高斯平滑处理
cvShowImage("Example4-out", out);
cvReleaseImage(&out);
cvReleaseImage(&image);
cvWaitKey(0);
cvDestroyWindow("Example4-in");
cvDestroyWindow("Example4-out");
}
int main(int argc, char** argv)
{
// IplImage *img = cvLoadImage(argv[1]); //cmd
IplImage *img = cvLoadImage("D:\\Template\\OpenCV\\Template4_ShowImage_Smooth\\Debug\\1.jpg"); //address
example2_4(img);
}
使用cvPyDown()创建一幅宽度和高度为输入图像一般尺寸的图像程序代码如下:
#include
#include
using namespace std;
IplImage* doPyrDown(IplImage* in, int filter = IPL_GAUSSIAN_5x5) //高斯滤波器大小,平滑作用
{
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言,图像像素必须为偶数
IplImage* out = cvCreateImage(cvSize(in->width/2, in->height/2), in->depth, in->nChannels);
cvPyrDown(in, out); //缩小图像为1/2
// cvPyrUp(in, out); //放大2倍函数
return(out);
}
void example2_5(IplImage* image)
{
cvNamedWindow("Example5-in", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Example5-out", CV_WINDOW_AUTOSIZE);
cvShowImage("Example5-in", image);
// IplImage* out = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3);
// cvSmooth(image,out,CV_GAUSSIAN,3,3);
IplImage* out = doPyrDown(image);
out = doPyrDown(out);
cvShowImage("Example5-out", out);
cvReleaseImage(&out);
cvReleaseImage(&image);
cvWaitKey(0);
cvDestroyWindow("Example5-in");
cvDestroyWindow("Example5-out");
}
int main(int argc, char** argv)
{
// IplImage *img = cvLoadImage(argv[1]); //cmd
IplImage *img = cvLoadImage("D:\\Template\\OpenCV\\Template5_Convertion_Half\\Debug\\2.jpg"); //address
example2_5(img);
}
运行结果如下:
特别提醒:
笔者在编写此段代码时忽略了一个小细节,在此处“僵持”了一段时间,出现了“R6010 -abort() has been called” 的错误,错误提示如下:
不知道大家是否注意到上面代码中的一句断言,此处很有可能导致你的程序无法编译通过。断言
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言,图像像素必须为偶数
打开的图像的宽度、高度像素点数均必须为偶数,否则断言为假,程序无法正常运行。
程序代码如下:
#include
#include
using namespace std;
IplImage* doPyrDown(IplImage* in, int filter = IPL_GAUSSIAN_5x5)
{
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言
IplImage* out = cvCreateImage(cvSize(in->width/2, in->height/2), in->depth, in->nChannels);
cvPyrDown(in, out);
return(out);
}
IplImage* doCanny(IplImage *in, double lowThresh, double highThresh, double aperture)
{
if (in->nChannels != 1)
{
cout << in->nChannels << endl;
cout << "不能输出" << endl;
return(0); //Canny只能处理灰度图像
}
IplImage* out = cvCreateImage(cvGetSize(in),IPL_DEPTH_8U, 1); //书中第一个参数为cvSize(cvGetSize(image)),程序报错
cvCanny(in, out, lowThresh, highThresh, aperture); //(输入,输出,控制边缘连接,强边缘的初始分割,Sobel算子大内核大小)
return(out);
}
void example2_6(IplImage* image)
{
cvNamedWindow("Example6-in", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Example6-out", CV_WINDOW_AUTOSIZE);
cvShowImage("Example6-in", image);
IplImage* out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
cvConvertImage(image, out, CV_BGR2GRAY); //图像强制转化为gray
out = doCanny(out, 50, 150, 3);
cvShowImage("Example6-out",out);
cvReleaseImage(&out);
cvReleaseImage(&image);
cvWaitKey(0);
cvDestroyWindow("Example6-in");
cvDestroyWindow("Example6-out");
}
int main(int argc, char** argv)
{
// IplImage *img = cvLoadImage(argv[1]); //cmd
IplImage *img = cvLoadImage("3.jpg",1); //address:D:\\Template\\OpenCV\\Template6_Convention_Canny\\Debug
example2_6(img);
}
运行效果如下:
错误更正:
笔者在调试这段代码时也遇到了不小问题,原因是Canny只能够处理灰度图像,而笔者所找到的图像基本都不是灰度图像,编译运行会出现如下错误,Canny无法输出变换后的Canny边缘检测图像。
错误如下图:
解决方案:
既然Canny需要灰度图像,笔者就为其提供灰度图像,插入以下代码,调用cvConvertImage()函数,将普通图像强制转化为gray。
cvConvertImage(image, out, CV_BGR2GRAY); //图像强制转化为gray ****
在一个简单的图像处理流程中进行两次缩放处理与Canny边缘检测,程序代码如下:
#include
#include
using namespace std;
IplImage* doPyrDown(IplImage* in, int filter = IPL_GAUSSIAN_5x5)
{
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言
IplImage* out = cvCreateImage(cvSize(in->width/2, in->height/2), in->depth, in->nChannels);
cvPyrDown(in, out);
return(out);
}
IplImage* doCanny(IplImage *in, double lowThresh, double highThresh, double aperture)
{
if (in->nChannels != 1)
{
cout << in->nChannels << endl;
cout << "不能输出" << endl;
return(0); //Canny只能处理灰度图像
}
IplImage* out = cvCreateImage(cvGetSize(in),IPL_DEPTH_8U, 1);
cvCanny(in, out, lowThresh, highThresh, aperture);
return(out);
}
void Show_Image(IplImage* image)
{
IplImage* out1 = doPyrDown(image, IPL_GAUSSIAN_5x5);
IplImage* out2 = doPyrDown(out1, IPL_GAUSSIAN_5x5); //cvCreateImage(cvGetSize(out1), IPL_DEPTH_8U, 1);
IplImage* out3 = cvCreateImage(cvGetSize(out2), IPL_DEPTH_8U, 1);
cvConvertImage(out2, out3, CV_BGR2GRAY); //图像强制转化为gray
IplImage* out4 = doCanny(out3, 10, 100, 3);
cvNamedWindow("In", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Half1", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Half2", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Gray", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Out", CV_WINDOW_AUTOSIZE);
cvShowImage("In", image);
cvShowImage("Half1", out1);
cvShowImage("Half2", out2);
cvShowImage("Gray", out3);
cvShowImage("Out", out4);
cvReleaseImage(&out1);
cvReleaseImage(&out2);
cvReleaseImage(&out3);
cvReleaseImage(&out4);
cvReleaseImage(&image);
cvWaitKey(0);
cvDestroyWindow("In");
cvDestroyWindow("Half1");
cvDestroyWindow("Half2");
cvDestroyWindow("Gray");
cvDestroyWindow("Out");
}
int main(int argc, char** argv)
{
// IplImage *img = cvLoadImage(argv[1]); //cmd
IplImage *img = cvLoadImage("D:\\Template\\OpenCV\\Template6_Convention_Canny\\Debug\\2.jpg"); //address
Show_Image(img);
}
运行截图:
特别提醒:
书中此部分中,谈到了内存空间的释放问题,这是一个在图像处理中很基础却也很容易被我们所忽略的问题。从单张图像的处理上来说,内存空间资源释放与否对程序本身的运行影响并不大,但如果实际应用中涉及到视频流的处理,将会对整个程序造成毁灭性的破坏,运算速度下降,或是溢出崩溃,因此我们必须手动释放所有我们显示分配的内存空间,关于内存空间的释放详见例2-11,此处不再赘述。
从摄像头中实时读入视频流并进行显示在窗口中,程序代码如下:
#include
#include
using namespace std;
int main(int argc, char** argv)
{
cvNamedWindow("Show_Camera", CV_WINDOW_AUTOSIZE);
CvCapture* capture;
if (argc == 1) //此处代码是做一个判断,有摄像头设备则读入摄像头的图像信息,没有则播放本地视频文件
capture = cvCreateCameraCapture(0); //参数为摄像头ID
else
capture = cvCreateFileCapture("D:\\Template\\OpenCV\\Template2_ShowAVI_cmd\\Debug\\只想告诉你.avi");
assert(capture!=NULL); //断言,视频流信息非空
IplImage* frame;
while (1)
{
frame = cvQueryFrame(capture);
if (!frame) break;
cvShowImage("Show_Camera", frame);
char c = cvWaitKey(32);
if (c == 27) break;
}
cvReleaseCapture(&capture);
cvDestroyWindow("Show_Camera");
}
运行截图如下:
错误更正:
此部分书中提到cvCreateCameraCapture()函数的参数为摄像设备ID,只有存在多个摄像设备时这个参数才起作用。默认值为-1,代表“随机选择一个”,它更适合有且仅有一个设备的情况。 经过笔记本电脑自带摄像头实际测试,笔者该描述有误,参数为-1时运行报错,出现“R6010 -abort() has been called” 的错误:
解决方案:
cvCreateCameraCapture()函数声明如下:
如果只有一个摄像机时,参数值取0。当参数被设置为-1时,OpenCV会打开一个窗口让用户选择需要使用的摄像机。cvCreateCameraCapture()函数用法
将输入视频流或者捕获的图像序列记录到输出视频流中,程序代码如下:
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
CvCapture* capture = cvCreateFileCapture("好想告诉你.avi");
if (!capture)
return -1;
IplImage* bgr_frame = cvQueryFrame(capture); //下一帧视频载入内存
double fps = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); //获取视频流属性fps
CvSize size = cvSize((int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH),
(int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT));
CvVideoWriter *writer = cvCreateVideoWriter("好想告诉你(Gray).avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, size); //视频逐真写入设备创建
IplImage* logpolar_frame = cvCreateImage(size, IPL_DEPTH_8U, 3);
while ((bgr_frame = cvQueryFrame(capture)) != NULL)
{
cvLogPolar(bgr_frame, logpolar_frame, cvPoint2D32f(bgr_frame->width / 2,bgr_frame->height / 2), 40, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS); //图像映射到极指数空间
cvWriteFrame(writer, logpolar_frame); //逐帧写入
}
cvReleaseVideoWriter(&writer);
cvReleaseImage(&logpolar_frame);
cvReleaseCapture(&capture);
return 0;
}
从摄像机读入视频数据并将缩放变换后的图像存入磁盘,并将变换结果显示在窗口中,程序代码如下:
#include
#include
using namespace std;
IplImage* doPyrDown(IplImage* in, int filter = IPL_GAUSSIAN_5x5)
{
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言
IplImage* out = cvCreateImage(cvSize(in->width / 2, in->height / 2), in->depth, in->nChannels);
cvPyrDown(in, out);
return(out);
}
int main(int argc, char* argv[])
{
IplImage* frame;
IplImage* h_frame;
CvVideoWriter *writer = NULL;
cvNamedWindow("Show_Camera", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Show_Half_Camera", CV_WINDOW_AUTOSIZE);
CvCapture* capture;
if (argc == 1)
capture = cvCreateCameraCapture(0);
else
capture = cvCreateFileCapture("D:\\Template\\OpenCV\\Template2_ShowAVI_cmd\\Debug\\只想告诉你.avi");
assert(capture != NULL);
frame = cvQueryFrame(capture);
h_frame = doPyrDown(frame);
writer = cvCreateVideoWriter("camera.avi", CV_FOURCC('X', 'V', 'I', 'D'), 15,cvSize(h_frame->width, h_frame->height));
while ((frame = cvQueryFrame(capture))!= NULL)
{
h_frame = doPyrDown(frame);
cvShowImage("Show_Camera", frame);
cvShowImage("Show_Half_Camera", h_frame);
cvWriteFrame(writer, h_frame);
cvReleaseImage(&h_frame);
if (writer)
{
cout << "video writer has created!" << endl;
}
char c = cvWaitKey(32);
if (c == 27) break;
}
cvReleaseVideoWriter(&writer);
cvReleaseImage(&h_frame);
cvReleaseCapture(&capture);
cvDestroyWindow("Show_Camera");
cvDestroyWindow("Show_Half_Camera");
return 0;
}
从摄像机读入视频数据并将缩放变换后的图像存入磁盘,并将变换结果显示在窗口中,给程序加入滚动条,使得用户可以动态调节缩放比例,缩放比例取值2~8之间,程序代码如下:
#include
#include
using namespace std;
int g_slider_position = 0;
int Override = 0; //缩放倍率
int frames = 3; //滚动条最大值
int i = 0;
IplImage* doPyrDown(IplImage* in, int filter = IPL_GAUSSIAN_5x5)
{
assert(in->width % 2 == 0 && in->height % 2 == 0); //断言
IplImage* out = cvCreateImage(cvSize(in->width / 2, in->height / 2), in->depth, in->nChannels);
cvPyrDown(in, out);
return(out);
}
void onTrackbarSlide(int pos)
{
Override = pos;
}
int main(int argc, char* argv[])
{
IplImage* frame;
IplImage* h_frame0;
IplImage* h_frame1;
IplImage* h_frame2;
CvVideoWriter *writer = NULL;
CvCapture* capture;
cvNamedWindow("Show_Camera", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Show_Half_Camera", CV_WINDOW_AUTOSIZE);
if (argc == 1)
capture = cvCreateCameraCapture(0);
else
capture = cvCreateFileCapture("D:\\Template\\OpenCV\\Template2_ShowAVI_cmd\\Debug\\只想告诉你.avi");
assert(capture != NULL);
if (frames != 0)
{
cvCreateTrackbar("Position", "Show_Camera", &g_slider_position, frames, onTrackbarSlide);
}
frame = cvQueryFrame(capture);
writer = cvCreateVideoWriter("camera.avi", CV_FOURCC('X', 'V', 'I', 'D'), 15, cvSize(frame->width, frame->height));
while ((frame = cvQueryFrame(capture))!= NULL)
{
if (Override == 0)
{
h_frame0 = frame;
cvShowImage("Show_Half_Camera", h_frame0);
cvWriteFrame(writer, h_frame0);
}
if (Override == 1)
{
h_frame0 = doPyrDown(frame);
cvShowImage("Show_Half_Camera", h_frame0);
cvWriteFrame(writer, h_frame0);
cvReleaseImage(&h_frame0);
}
if (Override == 2)
{
h_frame0 = doPyrDown(frame);
h_frame1 = doPyrDown(h_frame0);
cvShowImage("Show_Half_Camera", h_frame1);
cvWriteFrame(writer, h_frame1);
cvReleaseImage(&h_frame0);
cvReleaseImage(&h_frame1);
}
if (Override == 3)
{
h_frame0 = doPyrDown(frame);
h_frame1 = doPyrDown(h_frame0);
h_frame2 = doPyrDown(h_frame1);
cvShowImage("Show_Half_Camera", h_frame2);
cvWriteFrame(writer, h_frame2);
cvReleaseImage(&h_frame0);
cvReleaseImage(&h_frame1);
cvReleaseImage(&h_frame2);
}
cvShowImage("Show_Camera", frame);
if (writer)
{
cout << "video writer has created!" << endl;
}
char c = cvWaitKey(32);
if (c == 27) break;
}
cvReleaseVideoWriter(&writer);
cvReleaseCapture(&capture);
cvDestroyWindow("Show_Camera");
cvDestroyWindow("Show_Half_Camera");
return 0;
}
运行截图如下:
特别提醒
以上两例的编写,就涉及到了视频流的数据处理,可以看到每个运行截图中都包含了资源管理器的截图,其目的就是为了提醒各位初学者,千万要注意内存空间的分配和释放,切记在使用结束后一定要释放自己为其显示分配的内存空间,如若不然,程序随时可能面临崩溃。
例2-11中内存空间释放采用的是《学习OpenCV》一书中例2-7较为臃肿释放方式:
if (Override == 0)
{
h_frame0 = frame;
cvShowImage("Show_Half_Camera", h_frame0);
cvWriteFrame(writer, h_frame0);
}
if (Override == 1)
{
h_frame0 = doPyrDown(frame);
cvShowImage("Show_Half_Camera", h_frame0);
cvWriteFrame(writer, h_frame0);
cvReleaseImage(&h_frame0);
}
if (Override == 2)
{
h_frame0 = doPyrDown(frame);
h_frame1 = doPyrDown(h_frame0);
cvShowImage("Show_Half_Camera", h_frame1);
cvWriteFrame(writer, h_frame1);
cvReleaseImage(&h_frame0);
cvReleaseImage(&h_frame1);
}
if (Override == 3)
{
h_frame0 = doPyrDown(frame);
h_frame1 = doPyrDown(h_frame0);
h_frame2 = doPyrDown(h_frame1);
cvShowImage("Show_Half_Camera", h_frame2);
cvWriteFrame(writer, h_frame2);
cvReleaseImage(&h_frame0);
cvReleaseImage(&h_frame1);
cvReleaseImage(&h_frame2);
}
尚待解决的问题1——内存无法全部释放
笔者亦曾尝试过采用书中例2-8通过每个独立阶段来释放内存,可能因为笔者对书中代码理解不到位所致,在多次反复调用doPyrDown()函数时,只能够释放一次doPyrDown()分配的内存,在资源管理器中内存资源不断增长。
例2-8如下所示:
笔者模仿例2-8形式的释放内存代码
if (Override == 0)
{
h_frame = frame;
cvShowImage("Show_Half_Camera", h_frame);
cvWriteFrame(writer, h_frame);
}
if (Override == 1)
{
h_frame = doPyrDown(frame);
cvShowImage("Show_Half_Camera", h_frame);
cvWriteFrame(writer, h_frame);
cvReleaseImage(&h_frame);
}
运行截图:
在不进行缩放或2倍缩放时,程序的内存占用是恒定值。而进行4倍或8倍缩放时,程序所占用的内存就无法得到全部释放,内存空间占用逐步升高,代码及运行截图如下所示。
if (Override == 2)
{
h_frame = doPyrDown(frame);
h_frame = doPyrDown(h_frame);
cvShowImage("Show_Half_Camera", h_frame);
cvWriteFrame(writer, h_frame);
cvReleaseImage(&h_frame);
}
if (Override == 3)
{
h_frame = doPyrDown(frame);
h_frame = doPyrDown(h_frame);
h_frame = doPyrDown(h_frame);
cvShowImage("Show_Half_Camera", h_frame);
cvWriteFrame(writer, h_frame);
cvReleaseImage(&h_frame);
}
尚待解决的问题2——在图像缩放过程中无法继续图像视频存储
本程序中摄像头的视频流数据存储,是调用cvCreateVideoWriter()函数实现的,该函数创建了一个写入设备以便逐帧将视频流写入视频文件。
writer = cvCreateVideoWriter("camera.avi", CV_FOURCC('X', 'V', 'I', 'D'), 15, cvSize(frame->width, frame->height));
其最后一个参数规定了写入设备开辟空间的大小,但伴随图像的缩放,其图像大小亦将发生改变,这就导致图像一出现缩放其写入视频文件的动作就不再进行了,只有图像恢复原来尺寸时,视频写入动作才继续开始执行。
望已解决此问题的看客能够解惑,在此谢过~