/*************************************************
抓图片
*************************************************/
IplImage * JustCapture()
{
char imgnamesaved[100];
int send_len;
char buffer[256];
IplImage *pFrame = NULL,*img=NULL;//声明IplImage指针
CvCapture *pCapture = NULL;
/*CvCapture 是一个结构体,用来保存图像捕获所需要的信息。opencv提供两种方式从外部捕获图像:
一种是从摄像头获取,一种是通过解码视频得到图像。
两种方式都必须从第一帧开始一帧一帧的按顺序获取,因此每获取一帧后都要保存相应的状态和参数。
比如从视频文件中获取,需要保存视频文件的文件名,相应的解码器类型,下一次如果要
获取将需要解码哪一帧等。 这些信息都保存在CvCapture结构中,每获取一帧后,这些信息
都将被更新,获取下一帧需要将新信息传给获取的api接口*/
getSystemTime(imgtime);//获取系统时间,当作图片的名称
sprintf(imgname,"%s.jpg",imgtime);
sprintf(imgnamesaved,"/home/fyp/sda3/GodKnows/fromPan/capimg/%s.jpg",imgname);//图片存储位置
bzero(buffer, BUFFER_SIZE);
sprintf(buffer,"%s",imgname);
//pCapture = cvCaptureFromFile(gRtspAdd);
pCapture = cvCaptureFromAVI("20180607.mp4");// 函数cvCaptureFromAVI从摄像头或者文件中抓取一帧,然后解压并返回这一帧。
numFrames = (int)cvGetCaptureProperty(pCapture, CV_CAP_PROP_FRAME_COUNT);//设置视频获取属性,numFrames时视频文件的总帧数。
cvSetCaptureProperty(pCapture,CV_CAP_PROP_POS_FRAMES,time_frame);//设置pCapture的开始帧,第二个参数是单位为帧数的位置 从位置time_frame=0开始播放视频
while(!pCapture)
{
printf("Can not get the video stream from the camera wait 100 sec!\r\n");
sleep(100);//将程序挂起100s
pCapture = cvCaptureFromAVI("20180607.mp4");
if(!pCapture)//如果依然无法获取到视频流,继续执行循环 continue;elsebreak; } if (img==NULL) {pFrame = cvQueryFrame(pCapture);/*cvQueryFrame(pCapture)表示从摄像头或者文件中抓取并返回一帧。输入一个CvCapture 类型的指针,该函数主要功能是将视频文件的下一帧加载到内存。与cvLoadImage的不同之处是,该函数不重新分配内存空间。*///cvReleaseImage(&img); //img=cvCloneImage(pFrame);//用这一句产生内存泄漏问题,换成下面的两句img = cvCreateImage(CvSize(cvGetSize(pFrame)),IPL_DEPTH_8U, 3);cvCopy(pFrame,img,NULL);cvSaveImage(imgnamesaved,img,NULL);//保存图片sleep(sleep_first); printf("get picturename %s,sleep %d, then continue \r\n",imgname,sleep_first);send_len= send(sock_idtcp,buffer,sizeof(buffer),MSG_NOSIGNAL); //用send不成功来判断掉线,然后关闭socket,重新创建socket来连接。while(send_len< 0){perror("Send filename failed,wait 100 sec\n");close(sock_idtcp);InitTcpSocket();send_len= send(sock_idtcp,buffer,sizeof(buffer), MSG_NOSIGNAL);if (send_len< 0){sleep(30);continue;}else printf("Sending PictureName Successfully\n\n");}bzero(buffer, BUFFER_SIZE);//少写了这一句,程序运行时出错报错:*** stack smashing detected ***: ./DetectWaterDepth terminated 已放弃 (核心已转储) } cvReleaseCapture(&pCapture); //cvReleaseImage(&pFrame); return img; }
关于网上说的cvCloneImage函数:用cvCopy函数代替,我就一直纠结于把这两个换来换去,结果发现内存泄漏的真正原因不在这里。
抓图片的函数返回值是一个IplImage指针,关于函数返回值是指针的问题,转自https://blog.csdn.net/rentingting870927/article/details/5994173
先看一个例子,初学者经常碰到的问题
char *GetString(void)
{
char p[] = "hello world";
return p; //编译器一般将提出警告信息
}
void main(void)
{
char *str = NULL;
str = GetString(); //str 的内容是垃圾,得不到想要的内容
count<< str <<end;
}
函数Getstring中定义的变量p属于local,当函数结束时自动消失,所以在返回时,根本就得不到p所指的内容。解决办法有以上常见的几种
(1)可以使用全局数组,使用全局变量时,在程序结束时才释放。
(2)在函数Getstring()中使用new在堆上动态分配内存来建立数组。C语言中可以使用malloc()函数,不过不要忘记,使用完成后要进行内存释放,不然会造成内存泄漏。分别使用delete,free释放,使用delete时,会调用类的析构函数,而free则不会。
char *GetString()
{
char *p;
p = (char *)malloc(100);
return p;
}
void main()
{
char *str=NULL;
str=GetString();
strcpy(str,"Hello");
printf("%s", str);
free(str); //free memroy
} xxxx
(3)用static声明一个指针可以,但也不太好,因为如果你多次调用这个函数返回多个指针,但这几个指针实际上指向同一块地址,改变任何一个的内容将改变所有指针的内容,这样也不是很多情况所需要的。
char* GetString(void)
{
static char p[]="hello world";
return p; //p为静态创建,程序退出时才释放
}
(4)用String类型,用string 实现,是值拷贝!不存在释放内存会影响拷贝的问题。
string GetString(void)
{
char p[] = "hello world";
return p;
}
void Test4(void)
{
string str;
str = GetString();
cout<< str.c_str() << endl;
}
5)使用字符串常量,因为字符串常量存储再静态存储区域,所以一直都存在,p是临时变量,但过程结束并不 会释放这个字符串常量.而p[]就不一样了,它是一个数组,数组里面存放了字符串,这个字符串没有放在字符 串常量存储再静态存储区域,p是临时变量,跳出函数之后一般保留一步就释放了,数组的空间回收了,字符串 没有了
const char *GetString(void)
{
const char *p = "hello world";
return p;
}
char *GetString(void)
{
char *p = "hello world";
return p;
}
void GetString(char* p)
{
strcpy(p, "hello world");
}
void Test4(void)
{
char str[100];
GetString(str);
cout<< str << endl;
}
1、在栈上建立局部变量。注意,在栈上时!栈用于函数是为了返回时找得到调用点(在调用时压入栈的)
,那么,返回时要POP才能得到。函数体中建立的任何东西都消失了(返回值除外),你返回的指针指向的内
容现在不知被用作什么用途了,如果你还要修改的话,那么后果不能确定。
2、在堆中分配。返回时不会摧毁,因为堆是全局存在的。但函数的调用者要记得delete回来的指针。
2、在堆中分配。返回时不会摧毁,因为堆是全局存在的。但函数的调用者要记得delete回来的指针。
cvCloneImage()每次使用时编译器会分配新的内存空间,不会覆盖以前的内容,所以如果在循环中使用内存会迅速减小,每次用完都需要用cvRelease来释放。
解决方法是使用cvCopy函数代替。
cvCopy(pSrcImg,pImg,NULL); //代替 pImg = cvCloneImage(pSrcImg);
pImg初始化时必须分配空间,否则上述函数不能执行。
pImg = cvCreateImage(cvSize(IMGWIDHT,IMGHEIGHT),IPL_DEPTH_8U, 3);
while (1)
{
IplImage *imgDic = NULL;
imgDic = JustCapture();//调用justcapture函数
time_frame=time_frame+numFrames/20;
if(time_frame >= numFrames)
break;
Mat imgDicMat(imgDic);
cvReleaseImage(&imgDic);//最后把这个释放掉就不会有内存泄漏问题。