python opencv camera2.0多摄像头捕捉方法 使用cvCreateCameraCaputure(X)获取。 参数X=Y+Z。 Y=摄

Wikipedia,自由的百科全书
您也可使用编写的
本文档介绍的CCameraDS类调用采集函数可直接返回IplImage,使用更方便,且集成了DirectShow,勿需安装庞大的DirectX/Platform SDK。
本类只在Visual C++ 6.0下进行了测试
[]可能存在的缺陷
在vc6.0中测试将此例程移植到mfc下时(特别是显示到控件上时),性能不如CvCapture;mfc下显示使用CvvImage对象的DrawToHDC方法。最明显的差别在cpu使用率上,即使都开到多线程中,DirectShow采集图像的方法仅仅显示cpu使用率就高达60%,拖动时能高达80%,且资源释放缓慢;但是采用CvCapture,即使带上一些图像处理步骤,cpu使用率也基本在50%以下。
CCameraDS中有如下函数:
CCameraDS()构造函数
CCameraDS()析构函数
bool OpenCamera(int nCamID, bool bDisplayProperties=true)打开摄像头,nCamID指定打开哪个摄像头,取值可以为0,1,2,...。bDisplayProperties指示是否自动弹出摄像头属性页。
bool OpenCamera(int nCamID, bool bDisplayProperties=true, int nWidth=320, int nHeight=240)打开摄像头,nCamID指定打开哪个摄像头,取值可以为0,1,2,...。bDisplayProperties指示是否自动弹出摄像头属性页。nWidth和nHeight设置的摄像头的宽和高,如果摄像头不支持所设定的宽度和高度,则返回false
void CloseCamera()关闭摄像头,析构函数会自动调用这个函数
static int CameraCount()返回摄像头的数目。可以不用创建CCameraDS实例,采用int c=CCameraDS::CameraCount();得到结果。
static int CameraName(int nCamID, char* sName, int nBufferSize);
根据摄像头的编号返回摄像头的名字
nCamID: 摄像头编号
sName: 用于存放摄像头名字的数组
nBufferSize: sName的大小
可以不用创建CCameraDS实例,采用CCameraDS::CameraName();得到结果。
int GetWidth()返回图像宽度。
int GetHeight()返回图像高度
IplImage * QueryFrame()抓取一帧,返回的IplImage不可手动释放!返回图像数据的为BGR模式的Top-down(第一个字节为左上角像素),即IplImage::origin=0(IPL_ORIGIN_TL)
//////////////////////////////////////////////////////////////////////
// Video Capture using DirectShow
// Author: Shiqi Yu (shiqi.)
// Thanks to:
HardyAI@OpenCV China
flymanbox@OpenCV China (for his contribution to function CameraName, and frame width/height setting)
// Last modification: April 9, 2009
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// 使用说明:
1. 将CameraDS.h CameraDS.cpp以及目录DirectShow复制到你的项目中
2. 菜单 Project-&Settings-&Settings for:(All configurations)-&C/C++-&Category(Preprocessor)-&Additional include directories
设置为 DirectShow/Include
3. 菜单 Project-&Settings-&Settings for:(All configurations)-&Link-&Category(Input)-&Additional library directories
设置为 DirectShow/Lib
在vc++2005开发环境下的使用说明:
1.将CameraDS.h CameraDS.cpp复制到你的项目中
2.将DirectShow复制到你的opencv根目录下,菜单 工具-&选项-&项目和解决方案-&vc++目录,把..(你的opencv安装目录)/DirectShow/Include添加到
“引用文件”中$(VCInstallDir)PlatformSDK\include和$(FrameworkSDKDir)include下面任意位置
3.菜单 工具-&选项-&项目和解决方案-&vc++目录,把..(你的opencv安装目录)/DirectShow/Lib添加到“库文件”下面。也可参考使用说明3。
//////////////////////////////////////////////////////////////////////
#include &camerads.h&
#include &highgui.h&
#include &stdio.h&
int main()
int cam_count;
//仅仅获取摄像头数目
cam_count = CCameraDS::CameraCount();
(&There are %d cameras.\n&, cam_count);
//获取所有摄像头的名称
for(int i=0; i & cam_count; i++)
char camera_name&#91;<span style="color: #&#93;;
int retval = CCameraDS::CameraName&#40;i, camera_name, sizeof&#40;camera_name&#41; &#41;;
if&#40;retval &0&#41;
&#40;&Camera #%d's Name is '%s'.\n&, i, camera_name&#41;;
&#40;&Can not get Camera #%d's name.\n&, i&#41;;
if&#40;cam_count==0&#41;
return -1;
CCameraDS camera;
//打开第一个摄像头
//if(! camera.OpenCamera(0, true)) //弹出属性选择窗口
if&#40;! camera.OpenCamera&#40;0, false, <span style="color: #,<span style="color: #&#41;&#41; //不弹出属性选择窗口,用代码制定图像宽和高
fprintf&#40;stderr, &Can not open camera.\n&&#41;;
return -1;
cvNamedWindow&#40;&camera&&#41;;
while&#40;1&#41;
//获取一帧
IplImage *pFrame = camera.QueryFrame&#40;&#41;;
cvShowImage&#40;&camera&, pFrame&#41;;
if &#40;cvWaitKey&#40;20&#41; == 'q'&#41;
camera.CloseCamera&#40;&#41;; //可不调用此函数,CCameraDS析构时会自动关闭摄像头
cvDestroyWindow&#40;&camera&&#41;;
Personal tools
最后更改13:50 日.
本页面已经被浏览134,598次。
本网站由赞助主机和网络。8375人阅读
Opencv(3)
作者:咕唧咕唧liukun321来自:http://blog.csdn.net/liukun321本质上说一张图像就是由数值组成的矩阵。Opencv 2.x由 cv::Mat 这个数据结构来表示一张图像。矩阵的每一个元素代表了一个像素。对于彩色图像而言矩阵的元素是一个三元数。对图像有了这个新的认识,下面可以试着借助opencv处理图像了。先来看一下今天要处理的图像:今天的主题是存取像素,首先来看一下如何存取像素值。其实对于像素值的操作都可以由cv::Mat类中成员直接或间接实现,cv::Mat有若干成员函数可以获取图像的数据及属性。&操作单个像素方法:at(int y, int x)cv::mat的成员函数: at(int y, int x)可以用来存取图像中对应坐标为(x,y)的元素坐标。但是在使用它时要注意,在编译期必须要已知图像的数据类型,这是因为cv::mat可以存放任意数据类型的元素。因此at方法的实现是用模板函数来实现的。使用方法:假设提前已知一幅图像img的数据类型为 unsigned char型灰度图(单通道),要对坐标为(10,12)的像素重新赋值为128,则对应操作如下:img.at&uchar&(12,10) = 128;如果要操作的图片img是一幅数据类型同样为unsigned char的彩色图片,再次要求将坐标(10,12)的像素赋值为128。这个操作跟上面的就有点区别了,需要对这个像素三个通道的每个对应元素赋值,Opencv中图像三原色在内存中的排列顺序为B-G-R(见下面注释),操作过程如下:img.at&cv::Vec3b&(12,10) [0]= 128;//B
img.at& cv::Vec3b &(12,10) [1]= 128;//G
img.at& cv::Vec3b &(12,10) [2]= 128;//R
了解了at方法的用法,下面就尝试一下使用at方法对刚才的图片做一个简单的处理(将图像中加入椒盐噪点)。椒盐噪点是一种特殊的噪点,是随机的将图像的部分像素设置为黑色或白色。既然灰度图与彩色图像对单个元素的操作方式不同,这就需要有一个图像类型判断的过程。cv::Mat image = cv::imread(&test.jpg&);
if(image.channles() == 1)
清楚了这些过程,下面就来看看添加椒盐噪点函数的实现过程:#include &opencv2/opencv.hpp&
#include&cstdlib&
void salt(Mat &img,int saltNum)
for(i = 0;i & saltN i++)
x = rand()%img.
y = rand()%img.
if(img.channels() == 1)
img.at&uchar&(y,x) = 255;
}else if(img.channels() == 3)
img.at&Vec3b&(y,x)[0] = 255;
img.at&Vec3b&(y,x)[1] = 255;
img.at&Vec3b&(y,x)[2] = 255;
int main()
Mat image = imread(&../test.jpg&);
result = image.clone();
salt(result,3000);
namedWindow(&src(http://blog.csdn.net/liukun321)& , CV_WINDOW_AUTOSIZE);
imshow(&src(http://blog.csdn.net/liukun321)&, image);
imshow(&dst(http://blog.csdn.net/liukun321)&, result);
waitKey();
程序运行后的效果图:
原图&加入椒盐噪声后效果&其实除了at方法操作像素,还可以使用opencv提供的类cv::Mat_ &&来实现。cv::Mat_是一个模板子类。这个类定义了很多额外的方法,但是没有提供公共的成员变量。如果已知了矩阵的类型,使用cv::Mat_会带来很多便利。它的使用方法如下:cv::Mat_&uchar&
img = imread(&test.jpg&);
img(10,12) = 128;//10行 12列
还有一种操作像素的方法:使用Mat类的ptr()方法配合cols 、rows、step、elemSize等成员变量,直接进行指针操作。下面先来说说这几个成员变量cols代表图像的列数rows代表图像的高度step 代表以字节为单位的图像宽度elemSize 代表像素的大小 (比如一个三通道uchar 型矩阵,返回值为3)&prt()方法同样是个模板类,需要编译期已知像素点的类型:cv::Mat_&uchar&
img = imread(&test.jpg&);
uchar* addr =
img.ptr&uchar&(10);//返回10行的地址
addr +=12;//单通道灰度图
*addr = 128;
同样完成了对第10行第12列像素的操作。若图象为三通道彩色图:cv::Mat_&uchar&
img = imread(&test.jpg&);
uchar* addr =
img.ptr&uchar&(10);//返回10行的地址
addr +=12* img.elemSize;//单通道灰度图
*addr = 128;
addr +=12* img.elemSize是因为彩色图象在内存中的存储方式:图像缓冲区中的前三个字节对应图像左上角第一个像素的三个通道值,接下来的三个字节对应第一行的第二个像素,以此类推。而且注意Opencv默认是使用BGR的通道顺序。到此已经介绍了3中操作图像中像素的方法。除这三种以外还有一种使用迭代器的操作。今天就不再介绍了。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1009795次
积分:10406
积分:10406
排名:第1146名
原创:164篇
转载:132篇
评论:431条
由于发现原创文章,在未署名作者及出处的情况下被转载。在以后所有的原创文章开头我都会写明作者和出处。希望朋友们以后在转载本博客原创博文时注意标明文章作者及出处。
练武不练功,到老一场空
欢迎大家加入LINUX讨论群 群号
文章:10篇
阅读:87339
(2)(1)(1)(2)(3)(2)(1)(2)(3)(3)(4)(1)(2)(1)(5)(3)(2)(11)(2)(3)(8)(1)(2)(5)(1)(4)(3)(2)(6)(11)(6)(8)(11)(20)(6)(4)(17)(14)(2)(2)(1)(4)(4)(2)(23)(74)(2)双摄像头测距的OpenCV实现(转) - 精诚缕缕 - 上海大学乐乎博客--思考,交流,分享,行动,成长,快乐
我爱。。。
& 双摄像头测距的OpenCV实现(转)
15:21:01&|&双摄像头测距的OpenCV实现(转)
&虽然最近注意力已经不可遏制地被神经科学、大脑记忆机制和各种毕业活动吸引过去了,但是还是觉得有必要把这段时间双目视觉方面的进展总结一下。毕竟从上一篇博文发表之后,很多同仁发E-mail来与我讨论,很多原来的疑团,也在讨论和一步步的试验中逐渐解决了。&&开篇之前,首先要感谢maxwellsdemon和wobject,没有和你们的讨论,也就没有此篇的成文。说到双摄像头测距,首先要复习一下测距原理,把Learning OpenCV翻到416和418页,可以看到下面两幅图图1. 双摄像头模型俯视图图2, 双摄像头模型立体视图图1解释了双摄像头测距的原理,书中Z的公式如下:&在OpenCV中,f的量纲是像素点,Tx的量纲由定标棋盘格的实际尺寸和用户输入值确定,一般总是设成毫米,当然为了精度提高也可以设置为0.1毫米量级,d=xl-xr的量纲也是像素点。因此分子分母约去,z的量纲与Tx相同&图2解释了双摄像头获取空间中某点三维坐标的原理。&可以看到,实际的坐标计算利用的都是相似三角形的原理,其表达式就如同Q矩阵所示。&&空间中某点的三维坐标就是(X/W, Y/W, Z/W)。&因此,为了精确地求得某个点在三维空间里的距离,我们需要获得的参数有焦距f、视差d、摄像头中心距Tx。如果还需要获得X坐标和Y坐标的话,那么还需要额外知道左右像平面的坐标系与立体坐标系中原点的偏移cx和cy。其中f, Tx, cx和cy可以通过立体标定获得初始值,并通过立体校准优化,使得两个摄像头在数学上完全平行放置,并且左右摄像头的cx, cy和f相同(也就是实现图2中左右视图完全平行对准的理想形式)。而立体匹配所做的工作,就是在之前的基础上,求取最后一个变量:视差d(这个d一般需要达到亚像素精度)。从而最终完成求一个点三维坐标所需要的准备工作。&在清楚了上述原理之后,我们也就知道了,所有的这几步:标定、校准和匹配,都是围绕着如何更精确地获得f, d, Tx, cx和cy而设计的。&双目测距的原理就说到这里,为了避免大家看到大段纯叙述性的文字头晕,下面的行文将会以FAQ的形式围绕着实现双摄像头测距过程中碰到的几点疑惑展开。当然,其中的解答也只是我的个人理解,如有不当,敬请指正。Q1:标定时棋盘格的大小如何设定,对最后结果有没有影响?A:当然有。在标定时,需要指定一个棋盘方格的长度,这个长度(一般以毫米为单位,如果需要更精确可以设为0.1毫米量级)与实际长度相同,标定得出的结果才能用于实际距离测量。一般如果尺寸设定准确的话,通过立体标定得出的Translation的向量的第一个分量Tx的绝对值就是左右摄像头的中心距。一般可以用这个来验证立体标定的准确度。比如我设定的棋盘格大小为270 (27mm),最终得出的Tx大小就是602.8 (60.28mm),相当精确。&Q2:通过立体标定得出的Tx符号为什么是负的?A:这个其实我也不是很清楚。个人的解释是,立体标定得出的T向量指向是从右摄像头指向左摄像头(也就是Tx为负),而在OpenCV坐标系中,坐标的原点是在左摄像头的。因此,用作校准的时候,要把这个向量的三个分量符号都要换一下,最后求出的距离才会是正的。但是这里还有一个问题,就是Learning OpenCV中Q的表达式,第四行第三列元素是-1/Tx,而在具体实践中,求出来的实际值是1/Tx。这里我和maxwellsdemon讨论下来的结果是,估计书上Q表达式里的这个负号就是为了抵消T向量的反方向所设的,但在实际写OpenCV代码的过程中,那位朋友却没有把这个负号加进去。(一家之言,求更详细的解释)&Q3:cvFindStereoCorrespondenceBM的输出结果好像不是以像素点为单位的视差?A:在OpenCV2.0中,BM函数得出的结果是以16位符号数的形式的存储的,出于精度需要,所有的视差在输出时都扩大了16倍(2^4)。其具体代码表示如下:dptr[y*dstep] = (short)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*128/d : 0) + 15) && 4);可以看到,原始视差在左移8位(256)并且加上一个修正值之后又右移了4位,最终的结果就是左移4位因此,在实际求距离时,cvReprojectTo3D出来的X/W,Y/W,Z/W都要乘以16 (也就是W除以16),才能得到正确的三维坐标信息Q4:利用双摄像头进行测距的时候世界坐标的原点究竟在哪里?&A:世界坐标系的原点是左摄像头凸透镜的光心。说起这个,就不得不提到针孔模型。如图3所示,针孔模型是凸透镜成像的一种简化模型。当物距足够远时(远大于两倍焦距),凸透镜成像可以看作是在焦距处的小孔成像。(ref: .cn/2/lib//.htm)图3. 针孔模型在实际计算过程中,为了计算方便,我们将像平面翻转平移到针孔前,从而得到一种数学上更为简单的等价形式(方便相似三角形的计算),如图4所示。图4. 针孔模型的数学等价形式&&因此,对应图2就可以知道,世界坐标系原点就是左摄像头针孔模型的针孔,也就是左摄像头凸透镜的光心&Q5:f和d的单位是像素,那这个像素到底表示什么,它与毫米之间又是怎样换算的?A:这个问题也与针孔模型相关。在针孔模型中,光线穿过针孔(也就是凸透镜中心)在焦距处上成像,因此,图3的像平面就是摄像头的CCD传感器的表面。每个CCD传感器都有一定的尺寸,也有一定的分辨率,这个就确定了毫米与像素点之间的转换关系。举个例子,CCD的尺寸是8mm X 6mm,分辨率是640X480,那么毫米与像素点之间的转换关系就是80pixel/mm。在实际运用中,我们在数学上将这个像平面等效到小孔前(图4),这样就相当于将在透镜中心点之前假设了一块虚拟的CCD传感器。&Q6:为什么cvStereoRectify求出的Q矩阵cx, cy, f都与原来的不同?A:这个在前文有提到过。在实际测量中,由于摄像头摆放的关系,左右摄像头的f, cx, cy都是不相同的。而为了使左右视图达到完全平行对准的理想形式从而达到数学上运算的方便,立体 校准所做的工作事实上就是在左右像重合区域最大的情况下,让两个摄像头光轴的前向平行,并且让左右摄像头的f, cx, cy相同。因此,Q矩阵中的值与两个instrinsic矩阵的值不一样就可以理解了。实验结果:实验下来,虽然Block Matching算法本身对精度有所限制,但测距基本能达到能让人接受的精度,结果如下图5所示图5. OpenCV双摄像头测距结果上图中,中、左、右三个物体分别被放在离摄像头50cm, 75cm和90cm的位置。可以看出测距的结果相当不错。当然,上面这幅图是比较好的结果。由于BM算法的限制,同一点云中相同距离的点一般会有正负2厘米之内的误差。图6是利用双目摄像头测物体长宽的结果,可以看出结果似乎不太准确。。。图6. OpenCV双摄像头测边长结果其中,物体宽为117-88=29mm,但实际宽度为5.2cm,物体高位71-13=58mm,但实际高度为13cm。这方面的误差还是比较难以理解此外,还有一个问题至今尚未完全理解,就是双目摄像头的中心距,为什么采用Tx而不是T向量的长度。因为如果要左右视图重合区域最大化的话两个摄像头的光轴都要与T垂直才是(如图7),这样的话,校正后两个摄像头的中心距应该是T才对。不知道我这样的理解对不对?图7. 双摄像头立体校准俯视图&|&&相关文章<div class="votes" id="Score
(不得超过 50 个汉字) (输入完内容可以直接按Ctrl+Enter提交)

我要回帖

更多关于 opencv oncameraframe 的文章

 

随机推荐