新手求助:关于图像采集问题

snowflier 2003-08-07 09:26:49
各位大侠:
我是新手。老板让将图像采集做到软件中,我对于用vc做视频采集一窍不通,请问有没有相关资料,可以让我学习,最后有例子。
...全文
117 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
windows_editor 2003-08-20
  • 打赏
  • 举报
回复
有采集卡SDK最好了 没有的话用windows标准vfw也行呀
lizhuohua 2003-08-18
  • 打赏
  • 举报
回复
d
AthlonxpX86 2003-08-16
  • 打赏
  • 举报
回复
看你的驱动程序是哪一种了,如果是windows标准的数据采集卡驱动可以用echeng192的方法,如果不是标准的,就需要用厂家提供的SDK,就是你说的.OCX,按照说明做就行了,
snowflier 2003-08-15
  • 打赏
  • 举报
回复
我找到了采集卡的驱动,并且将其.OCX文件加入到vc中,这样就够了吗
zlj617 2003-08-11
  • 打赏
  • 举报
回复
u-p!!
首先,一般情况下,采集卡厂商都会提供他买的采集卡的lib文件,或是dll文件,你直接调用就是了!
飞不动 2003-08-08
  • 打赏
  • 举报
回复
directshow 提供了用应用程序从适当的硬件中捕捉和预览音/视频的能力。数据源包括:vcr,camera,tv tuner,microphone,或其他的数据源。一个应用程序可以立刻显示捕捉的数据(预览),或是保存到一个文件中。

在这个例子中,icapturegraphbuilder 接口是处理捕捉工作的主要接口。你可以在你自己的捕捉程序中使用同样的方法和接口。在这里主要讨论icapturegraphbuilder 如何执行音/视频的捕捉。我们假设你已经熟悉了directshow的filter graph的体系和一般的capture filter graph的结构(可以参考directshow基础指南)。

icapturegraphbuilder 接口提供了一个filter graph builder对象,让你的应用程序在建立capture filter graph时,省去处理很多单调乏味的工作,集中精力于捕捉中。他提供的方法满足了基本的捕捉和预览功能的要求。

方法findinterface ,在filter graph中查找一个于捕捉有关的详细的接口。使的你可以访问一个详细接口的功能,而不需要你去列举在filter graph中的pins 和 filters。
方法renderstream ,连接源过滤器和渲染过滤器,选择添加一些中间的过滤器。
方法controlstream ,独立的精确的控制graph的开始和结束帧。

既然是硬件捕捉,当然要和硬件打交道,接着介绍设备列举和捕捉接口。
通过icreatedevenum::createclassenumerator方法列举捕捉系统中的设备。之后,实例化一个directshow的filter去使用这个设备。接着用icapturegraphbuilder::findinterface去获得于捕捉相关的接口指针iamdroppedframes, iamvideocompression, iamstreamconfig, and iamvfwcapturedialogs 。因为设备列举和捕捉接口比较长,放在这会打乱结构,所有专门写了一篇(参考设备列举和捕捉接口)。

note:
1.这个示例是directshow自带的例子。你可以在directshow sdk的目录sample\ds\caputre看这个例子代码(amcap.cpp)。这里只是他的一些片断代码。可以说是他的中文模块的说明。
2.amcap例子中,把所有的接口指针和一些成员变量保存在一个全局结构gcap中了。
定义如下:
struct _capstuff {
char szcapturefile[_max_path];
word wcapfilesize; // size in meg
icapturegraphbuilder *pbuilder;
ivideowindow *pvw;
imediaeventex *pme;
iamdroppedframes *pdf;
iamvideocompression *pvc;
iamvfwcapturedialogs *pdlg;
iamstreamconfig *pasc; // for audio cap
iamstreamconfig *pvsc; // for video cap
ibasefilter *prender;
ibasefilter *pvcap, *pacap;
igraphbuilder *pfg;
ifilesinkfilter *psink;
iconfigavimux *pconfigavimux;
int imasterstream;
bool fcapturegraphbuilt;
bool fpreviewgraphbuilt;
bool fcapturing;
bool fpreviewing;
bool fcapaudio;
int ivideodevice;
int iaudiodevice;
double framerate;
bool fwantpreview;
long lcapstarttime;
long lcapstoptime;
char achfriendlyname[120];
bool fusetimelimit;
dword dwtimelimit;
} gcap;
当不在需要保存在gcap中的接口指针是,一定要释放这些接口指针,一般是在程序的析构函数中,或是在别的同等功能函数中。如下:
if (gcap.pbuilder)
gcap.pbuilder->release();
gcap.pbuilder = null;
if (gcap.psink)
gcap.psink->release();
gcap.psink = null;
if (gcap.pconfigavimux)
gcap.pconfigavimux->release();
gcap.pconfigavimux = null;
if (gcap.prender)
gcap.prender->release();
gcap.prender = null;
if (gcap.pvw)
gcap.pvw->release();
gcap.pvw = null;
if (gcap.pme)
gcap.pme->release();
gcap.pme = null;
if (gcap.pfg)
gcap.pfg->release();
gcap.pfg = null;


设置文件名
使用普通的openfile dialog获得捕捉文件的信息。通过调用alloccapturefile 函数为捕捉文件分配空间。这一点是重要的,因为这是个巨大的空间。这样可以提高捕捉操作的速度。icapturegraphbuilder::alloccapfile 执行实际的文件分配,ifilesinkfilter::setfilename 指示file writer filter使用用户选择的文件名保存数据。icapturegraphbuilder::setoutputfilename 把file writer filter加入filter graph(后面会介绍,他是icapturegraphbuilderd自代的)。

setcapturefile 和 alloccapturefile 函数如下:
/*
* put up a dialog to allow the user to select a capture file.
*/
bool setcapturefile(hwnd hwnd)
{
if (openfiledialog(hwnd, gcap.szcapturefile, _max_path)) {
ofstruct os;

// we have a capture file name

/*
* if this is a new file, then invite the user to
* allocate some space
*/
if (openfile(gcap.szcapturefile, &os, of_exist) == hfile_error) {

// bring up dialog, and set new file size
bool f = alloccapturefile(hwnd);
if (!f)
return false;
}
} else {
return false;
}

setappcaption(); // need a new app caption

// tell the file writer to use the new file name
if (gcap.psink) {
wchar wach[_max_path];
multibytetowidechar(cp_acp, mb_precomposed, gcap.szcapturefile, -1,
wach, _max_path);
gcap.psink->setfilename(wach, null);
}

return true;
}

// preallocate the capture file
//
bool alloccapturefile(hwnd hwnd)
{
// we'll get into an infinite loop in the dlg proc setting a value
if (gcap.szcapturefile[0] == 0)
return false;

/*
* show the allocate file space dialog to encourage
* the user to pre-allocate space
*/
if (dodialog(hwnd, idd_alloccapfilespace, alloccapfileproc, 0)) {

// ensure repaint after dismissing dialog before
// possibly lengthy operation
updatewindow(ghwndapp);

// user has hit ok. alloc requested capture file space
bool f = makebuilder();
if (!f)
return false;
wchar wach[_max_path];
multibytetowidechar(cp_acp, mb_precomposed, gcap.szcapturefile, -1,
wach, _max_path);
if (gcap.pbuilder->alloccapfile(wach,
gcap.wcapfilesize * 1024l * 1024l) != noerror) {
messageboxa(ghwndapp, "error",
"failed to pre-allocate capture file space",
mb_ok | mb_iconexclamation);
return false;
}
return true;
} else {
return false;
}
}

建立graph builder对象

amcap的 makebuilder函数建立了一个capture graph builer对象,通过调用cocreateinstance获得了icapturegraphbuilder 接口指针。amcap把他存储到gcap结构的pbuilder中。
// make a graph builder object we can use for capture graph building
//
bool makebuilder()
{
// we have one already
if (gcap.pbuilder)
return true;

hresult hr = cocreateinstance((refclsid)clsid_capturegraphbuilder,
null, clsctx_inproc, (refiid)iid_icapturegraphbuilder,
(void **)&gcap.pbuilder);
return (hr == noerror) ? true : false;
}


建立graph的渲染部分,并告诉他写文件(用先前决定的文件)

这包括一个multiplexer filter 和 file writer。directshow 提供了一个avi mux(multiplexer)filter。
在这里icapturegraphbuilder::setoutputfilename 是一个关键的方法。他把multiplexer 和 file writer添加到filter graph中,连接他们,并设置文件的名字。第一个参数mediasubtype_avi,指出capture graph builder 对象将插入一个avi multiplexer filter,因此,file writer将以avi文件格式记录捕捉的数据。第二个参数(wach)是文件名。最后的两个参数指出multiplexer filter (gcap.prender) 和file writer filter (gcap.psink),这两个是通过setoutputfilename 函数初始化的。amcap存储这些指针到全局结构gcap中。capture graph builder 对象建立了一个filter graph对象(igraphbuilder),把这两个filter加入到filter graph中去。他告诉file writer使用指定的文件保存数据。下面的例子演示了如何调用setoutputfilename。
//
// we need a rendering section that will write the capture file out in avi
// file format
//

wchar wach[_max_path];
multibytetowidechar(cp_acp, mb_precomposed, gcap.szcapturefile, -1, wach,
_max_path);
guid guid = mediasubtype_avi;
hr = gcap.pbuilder->setoutputfilename(&guid, wach, &gcap.prender,
&gcap.psink);
if (hr != noerror) {
errmsg("error %x: cannot set output file", hr);
goto setupcapturefail;
}


获得当前的filter graph

飞不动 2003-08-08
  • 打赏
  • 举报
回复
现在需要实际的设备了,调用ienummoniker::next ,然后用得到的指针pm调用imoniker::bindtoobject,绑定filter到设备。如果你不想建立联合的filter,使用imoniker::bindtostorage 代替imoniker::bindtoobject。


ulong cfetched;
imoniker *pm; // this will access the actual devices
gcap.pvcap = null;
while(hr = pem->next(1, &pm, &cfetched), hr==s_ok)
{
if ((int)uindex == gcap.ivideodevice) { // this is the one we want. instantiate it.
hr = pm->bindtoobject(0, 0, iid_ibasefilter, (void**)&gcap.pvcap);
pm->release(); // we don't need the moniker pointer anymore
break;
}
pm->release();
uindex++;
}
pem->release(); // we've got the device; don't need the
enumerator anymore


当有了设备后,通过接口指针去测量帧数,得到driver的名字,得到捕捉的尺寸(size)。在例子中,把每个指针都存储才gcap全局结构中了。
, and get the capture size. amcap stores each pointer in the gcap global structure.

// we use this interface to get the number of captured and dropped frames
gcap.pbuilder->findcaptureinterface(gcap.pvcap,
iid_iamdroppedframes, (void **)&gcap.pdf);

// we use this interface to get the name of the driver
gcap.pbuilder->findcaptureinterface(gcap.pvcap,
iid_iamvideocompression, (void **)&gcap.pvc);

// we use this interface to set the frame rate and get the capture size
gcap.pbuilder->findcaptureinterface(gcap.pvcap,
iid_iamvideostreamconfig, (void **)&gcap.pvsc);

然后得到媒体的类型和显示窗口的大小去匹配视频格式的尺寸。

am_media_type *pmt;
gcap.pvsc->getformat(&pmt); // current capture format

resizewindow(header(pmt->pbformat)->biwidth,
header(pmt->pbformat)->biheight);
deletemediatype(pmt);


现在,已经有了视频设备和他的相关信息,重复这个过程,得到音频设和他的信息并存储到全局机构中去。注意,这次是用参数clsid_audioinputdevicecategory 调用icreatedevenum::createclassenumerator 。

hr = cocreateinstance(clsid_systemdeviceenum, null, clsctx_inproc_server,
iid_icreatedevenum, (void**)&pcreatedevenum);
uindex = 0;
hr = pcreatedevenum->createclassenumerator(clsid_audioinputdevicecategory,
&pem, 0);
pcreatedevenum->release();

pem->reset();
gcap.pacap = null;
while(hr = pem->next(1, &pm, &cfetched), hr==s_ok)
{
if ((int)uindex == gcap.iaudiodevice) { // this is the one we want
hr = pm->bindtoobject(0, 0, iid_ibasefilter, (void**)&gcap.pacap);
pm->release();
break;
}
pm->release();
uindex++;
}
pem->release();

amcap also repeats the process of retrieving the format interface, this time for the audio device.

hr = gcap.pbuilder->findcaptureinterface(gcap.pacap,
iid_iamaudiostreamconfig, (void **)&gcap.pasc);
}



如何保持directshow filter (properties) 道具

ipropertybag 和 ipersistpropertybag 接口存储和返回properties的"bags"组。通过这些接口存储的properties是可以持久保持的。同一个对象在不同的实例之间,他们保持一致。filter可以存储他们的properties(clsid, friendlyname, and devicepath)。当一个filter存储完他的properties之后,实例一个filter时,directshow会自动得到他们。添加功能到你的filter中,执行ipersistpropertybag接口和他的方法。你可以用ipropertybag::read 方法装载filter properties 到win32 variant 变量中,然后初始化输入输出pin。


下面的代码演示directshow的vfwcapture filter如何执行ipersistpropertybag::load方法的。记住:在执行期间,你的filter必须提供一个有效的ipropertybag指针。


stdmethodimp cvfwcapture::load(lppropertybag ppropbag, lperrorlog perrorlog)
{
hresult hr;
cautolock cobjectlock(m_plock); // locks the object; automatically unlocks it in the destructor.

if (m_pstream) // if the filter already exists for this stream
return e_unexpected;

variant var; // variant from platform sdk
var.vt = vt_i4; // four-byte integer (long)
hr = ppropbag->read(l"vfwindex", &var, 0); // vfwindex is the private name used by the vidcap class manager to refer to the vfw capture filter
if(succeeded(hr)) // if it read the properties successfully
{
hr = s_ok; // defaults return value to s_ok
m_ivideoid = var.lval; // stores the specified hardware device number
createpins(&hr); // inits the pins, replacing the return value if necessary
}
return hr; // returns s_ok or an error value, if createpins failed
飞不动 2003-08-08
  • 打赏
  • 举报
回复
找到的一些资料,共享一下
这篇解释和示例如何通过directshow的接口去初始化和访问系统的硬件设备。代表性的,directshow应用程序使用下面类型的硬件。

音/视频捕捉卡
音频或视频回放卡
音频或视频压缩或解压卡(象mpeg解码器)
下面将以av设备作参考。


如何列举设备

包括在directshow sdk中的接口,类,和例子提供了音/视频捕捉和回放的功能。因为文件源过滤器和filter graph manager处理了内在的工作,所有,添加捕捉功能到一个应用程序中,只需添加很少的代码。你可以通过列举系统硬件设备和得到设备列表完成特别的任务(例如:所有的视频捕捉卡的列表)。directshow自动为win32和video for windows 设备实例化过滤器。

要av设备工作,首先,你必须检测当前系统存在的设备。icreatedevenum接口建立指定类型的列表。提供你需要的检测和设置硬件的功能。访问一个指定的设备有三步,详细的说明和代码如下:

建立系统硬件设备的列表
首先,申明一个列表指针,然后通过 cocreateinstance 建立。clsid_systemdeviceenum是我们想建立对象的类型,iid_icreatedevenum是接口的guid。

icreatedevenum *pcreatedevenum ;
cocreateinstance(clsid_systemdeviceenum, null, clsctx_inproc_server,
iid_icreatedevenum, (void**)&pcreatedevenum) ;


其次,建立一个特别类型的硬件设备的列表(例如视频捕捉卡)
申明一个ienummoniker接口,并把他传给icreatedevenum::createclassenumerator 方法。你就可以使用他访问新得到的列表了。

ienummoniker *penummon ;
pcreatedevenum->createclassenumerator(
[specify device guid here]
&penummon, 0);

最后,列举列表直到你得到你想要的设备为止。
如果先前的createclassenumerator调用成功了,你可以用ienummoniker::next得到设备。调用imoniker::bindtoobject建立一个和选择的device联合的filter,并且装载filter的属性(clsid,friendlyname, and devicepath)。不需要为if语句的(1 == cfetched) 困惑,在测试合法性之前,penummon->next(1, &pmon, &cfetched)方法会设置他为返回对象的数字(如果成功了为1)。

ulong cfetched = 0;
imoniker *pmon ;

if (s_ok == (penummon->next(1, &pmon, &cfetched)) && (1 == cfetched))
{
pmon->bindtoobject(0, 0, iid_ibasefilter, (void **)&[desired interface here]) ;

好,现在你有了一个imoniker指针,你可以添加设备的filter到filter graph。一旦你添加了filter,你就不需要imoniker指针,设备列表,或系统设备列表。

pgraph->addfilter([desired interface here], l"[filter name here]") ;
pmon->release() ; // release moniker
}
penummon->release() ; // release the class enumerator
}
pcreatedevenum->release();



实例:amcap中的设备列表代码

amcap例子中,把所有的接口指针和一些成员变量保存在一个全局结构gcap中了。
定义如下:
struct _capstuff {
char szcapturefile[_max_path];
word wcapfilesize; // size in meg
icapturegraphbuilder *pbuilder;
ivideowindow *pvw;
imediaeventex *pme;
iamdroppedframes *pdf;
iamvideocompression *pvc;
iamvfwcapturedialogs *pdlg;
iamstreamconfig *pasc; // for audio cap
iamstreamconfig *pvsc; // for video cap
ibasefilter *prender;
ibasefilter *pvcap, *pacap;
igraphbuilder *pfg;
ifilesinkfilter *psink;
iconfigavimux *pconfigavimux;
int imasterstream;
bool fcapturegraphbuilt;
bool fpreviewgraphbuilt;
bool fcapturing;
bool fpreviewing;
bool fcapaudio;
int ivideodevice;
int iaudiodevice;
double framerate;
bool fwantpreview;
long lcapstarttime;
long lcapstoptime;
char achfriendlyname[120];
bool fusetimelimit;
dword dwtimelimit;
} gcap;


例子用uindex变量循环列举系统的硬件设备。
bool initcapfilters()
{
hresult hr;
bool f;
uint uindex = 0;

makebuilder函数建立了一个filter graph builder(参考建立一个捕捉程序)。

f = makebuilder();

建立设备列表对象,得到icreatedevenum接口

icreatedevenum *pcreatedevenum;
hr = cocreateinstance(clsid_systemdeviceenum, null, clsctx_inproc_server,
iid_icreatedevenum, (void**)&pcreatedevenum);

建立一个特别类型的硬件设备的列表,类的id是clsid_videoinputdevicecategory。现在有了一个ienummoniker指针,可以访问捕捉设备的列表了。

ienummoniker *pem;
hr = pcreatedevenum->createclassenumerator(clsid_videoinputdevicecategory, &pem, 0);
pcreatedevenum->release(); // we don't need the device enumerator anymore
pem->reset(); // go to the start of the
enumerated list






snowflier 2003-08-08
  • 打赏
  • 举报
回复
我做的是应用程序,需要在软件中实现采集功能,有点类似于photoshop中可以扫描图像一样
飞不动 2003-08-08
  • 打赏
  • 举报
回复
我需要的是做应用程序,把视频采卡捕捉的视频在程序中放出来
一个实时的监控程序!
请大家给点思路,解决了我可以放高分!!
谢谢!!
AthlonxpX86 2003-08-07
  • 打赏
  • 举报
回复
做什么程序?驱动还是应用程序
DDK中有现成的视频采集驱动的例子,应用方面,需要会用DX
晨星 2003-08-07
  • 打赏
  • 举报
回复
难道你用的板卡没有API吗?
如果有,直接调用就可以了。不过这样等你把软件做好,交付使用,你会发现自己还是不懂视频采集。:)
Pipi0714 2003-08-07
  • 打赏
  • 举报
回复
用采集卡就可以了我又现城的代码,我们可以谈谈。我卖你卡给你源程序
snowflier 2003-08-07
  • 打赏
  • 举报
回复
to 晨星:
请问有没有相关资料,采集卡的驱动中饱和有链接库文件,怎样嵌入vc调用,希望能详细一点,谢谢
飞不动 2003-08-07
  • 打赏
  • 举报
回复
我也很需要这方面的知识

2,640

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 硬件/系统
社区管理员
  • 硬件/系统社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧