做过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;
}
}