做过opencv方面的人都知道,在项目中经常需要自动要输出几帧图片,但是好像每次都要手动去改储存图片的名字,如果不这样,虽然程序执行了,但是因为名字相同,还是会覆盖前面的几帧。
cvSaveImage函数中的图片名字是个字符串,不可能在程序中每次自动更改,那我们用什么方法呢?我们需要在这个字符串上做手脚。大家知道,C++中并没有字符串类型,我们用的,都可以认为是字符数组。那么这个地址值其实也就是一个指向特殊字符串地址的指针。
于是,用分解的方法就可以实现这个目的。例如地址为“E:/test/i.jpg”。我们不可以直接改变i的值,那么我们就可以分为:“E:/test/“,i,”.jpg“三个字符串。可能就有人要问了:i不是for循环中定义的整形数么?(for(int i=0;i<10;i++))。对,确实是这样,但是在头文件<stdlib.h>下,我们有一些可以进行数据类型转换的函数。我们这里用到了itoa函数。
先看看定义:char *itoa(int value,char *string,int radix) 将整数value转换成字串存入string,radix为转换所用基数.。最终我们得到的还是一个指向字符串的指针,那么就ok了。
接下来我们直接看看代码和实现:
#include "camera.h" #include <highgui.h> #include <stdio.h> #include<iostream> #include "string.h" #include<stdlib.h> using namespace std; using namespace cv; int main() { int cam_count; //仅仅获取摄像头数目 cam_count = CCamera::CameraCount(); printf("There are %d cameras.\n", cam_count); //获取所有摄像头的名称 for(int i=1; i <= cam_count; i++) { char camera_name[1024]; CCamera::CameraName(i, camera_name, sizeof(camera_name) ); printf("Camera #%d's Name is '%s'.\n", i, camera_name); } if(cam_count==0) return -1; CCamera camera1; CCamera camera2; //打开第一个摄像头,检查第二个摄像头 if(! camera1.OpenCamera(1, 10000,10000)) //用代码制定图像宽和高 { fprintf(stderr, "Can not open camera1.\n"); return -1; } cvNamedWindow("camera1"); //Sleep(100); if (cam_count>1) { if(! camera2.OpenCamera(1)) // if(! camera2.OpenCamera(1, 2048,1536)) //用代码制定图像宽和高 { fprintf(stderr, "Can not open camera2.\n"); return -1; } cvNamedWindow("camera2"); } IplImage *pFrame1 = 0; IplImage *pFrame2 = 0; if (cam_count==1)//连续采集 { while(1) { //获取帧 for(int i=0;i<10;i++){ pFrame1 = camera1.QueryFrame(); //显示 //char *arr1 = new char[]; char arr1[] = "E:/test/"; char *arr2 = new char[]; itoa(i,arr2,10); char arr3[] = ".jpg"; strcat(arr1,arr2); strcat(arr1,arr3); cout<<arr1<<endl; cout<<"true"<<endl; //cvShowImage("camera1", pFrame1); cvSaveImage(arr1, pFrame1 ); } break; if (cvWaitKey(20) == 'q')//不懂,这是检测什么? break; } } else { while(1) { //获取一帧 pFrame1 = camera1.QueryFrame(); //显示 cvShowImage("camera1", pFrame1); pFrame2 = camera2.QueryFrame(); cout<<"false"<<endl; //显示 cvShowImage("camera2", pFrame2); if (cvWaitKey(20) == 'q') break; } } camera1.CloseCamera(); //可不调用此函数,CCamera析构时会自动关闭摄像头 cvDestroyWindow("camera1"); if (cam_count>1) { camera2.CloseCamera(); //可不调用此函数,CCamera析构时会自动关闭摄像头 cvDestroyWindow("camera2"); } return 0; }
if (cam_count==1)//连续采集 { while(1) { //获取帧 for(int i=0;i<10;i++){ pFrame1 = camera1.QueryFrame(); //显示 //char *arr1 = new char[]; char arr1[] = "E:/test/"; char *arr2 = new char[]; itoa(i,arr2,10); char arr3[] = ".jpg"; strcat(arr1,arr2); strcat(arr1,arr3); cout<<arr1<<endl; cout<<"true"<<endl; //cvShowImage("camera1", pFrame1); cvSaveImage(arr1, pFrame1 ); } break; if (cvWaitKey(20) == 'q')//不懂,这是检测什么? break; } }注意在cvSaveImage中arr1本身就是个字符串数组,不需要再加引号。这样,就完美的实现了用不同的名称储存多帧图像。
但是还是存在一些问题就是arr1的内存会崩溃,不知道是不是因为在后面多次使用字符串连接函数。待解决。
我们再附上常用的数据类型转换函数:
char *ultoa(unsigned long value,char *string,int radix)
将无符号整型数value转换成字符串并返回该字符串,radix为转换时所用基数
char *ltoa(long value,char *string,int radix)
将长整型数value转换成字符串并返回该字符串,radix为转换时所用基数
char *itoa(int value,char *string,int radix)
将整数value转换成字串存入string,radix为转换所用基数.
double atof(char *nptr)
将字符串nptr转换成双精度数,并返回这个数,错误返回0
int atoi(char *nptr)
将字符串nptr转换成整型数, 并返回这个数,错误返回0
long atol(char *nptr)
将字符串nptr转换成长整型数,并返回这个数,错误返回0
double strtod(char *str,char **endptr)
将字符串str转换成双精度数,并返回这个数,
long strtol(char *str,char **endptr,int base)
将字符串str转换成长整型数, 并返回这个数,
我们来看另一种形式的实现:
#include<iostream> #include<sstream> #include<string> using namespace std; double sciToDub(const string&str){ stringstream ss(str); double d=0; ss>>d; if(ss.fail()){ string s="unable to format"; s+=str; s+="as a number!"; throw(s); } return (d); } int main(){ try{ cout<<sciToDub("1.234e5")<<endl; cout<<sciToDub("6.02e-2")<<endl; cout<<sciToDub("asdf")<<endl; } catch(string &e){ cerr<<"whoops:"<<e<<endl; } }