捕获摄像头的每一帧图像

lizhengnan 2009-02-05 10:29:19
我现在想用捕获摄像头的每一帧图像.

用DirectShow的ISampleGrabber可以,但我又不太会用.
现在写了点代码,但不好使.可以帮我看一下.
或都有别的方法也可以.


public void CaptureVideo()
{
int hr = 0;
IBaseFilter sourceFilter = null;

try
{
// Get DirectShow interfaces
GetInterfaces();

// Attach the filter graph to the capture graph
hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
DsError.ThrowExceptionForHR(hr);

// Use the system device enumerator and class enumerator to find
// a video capture/preview device, such as a desktop USB video camera.
sourceFilter = FindCaptureDevice();

ISampleGrabber sampGrabber = new SampleGrabber() as ISampleGrabber;

hr = sampGrabber.SetOneShot(false);
hr = sampGrabber.SetBufferSamples(true);
DsError.ThrowExceptionForHR(hr);
ConfigureSampleGrabber(sampGrabber);
IBaseFilter baseGrabFlt = sampGrabber as IBaseFilter;

// Add Capture filter to our graph.
hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
DsError.ThrowExceptionForHR(hr);
hr = this.graphBuilder.AddFilter(baseGrabFlt, "SampleGrabber");
DsError.ThrowExceptionForHR(hr);

// Render the preview pin on the video capture filter
// Use this instead of this.graphBuilder.RenderFile
     // 在这会返回一个错误,hr的值为262782.不知道如果解决.
hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, baseGrabFlt, null);

DsError.ThrowExceptionForHR(hr);

// Now that the filter has been added to the graph and we have
// rendered its stream, we can release this reference to the filter.
Marshal.ReleaseComObject(sourceFilter);

// Set video window style and position
SetupVideoWindow();

// Add our graph to the running object table, which will allow
// the GraphEdit application to "spy" on our graph
rot = new DsROTEntry(this.graphBuilder);

// Start previewing video data
hr = this.mediaControl.Run();
DsError.ThrowExceptionForHR(hr);

// Remember current state
this.currentState = PlayState.Running;
}
catch
{
MessageBox.Show("An unrecoverable error has occurred.");
}
}
/// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
{
Graphics g;
String s;
float sLeft;
float sTop;
SizeF d;

g = Graphics.FromImage(bitmapOverlay);
g.Clear(System.Drawing.Color.Transparent);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

// Prepare to put the specified string on the image
g.DrawRectangle(System.Drawing.Pens.Blue, 0, 0, this.Width - 1, this.Height - 1);
g.DrawRectangle(System.Drawing.Pens.Blue, 1, 1, this.Width - 3, this.Height - 3);

d = g.MeasureString(m_String, fontOverlay);

sLeft = (this.Width - d.Width) / 2;
sTop = (this.Height - d.Height) / 2;

g.DrawString(m_String, fontOverlay, System.Drawing.Brushes.Red,
sLeft, sTop, System.Drawing.StringFormat.GenericTypographic);

// Add a frame number in the bottom right
s = "Frame " + m_Count.ToString();
d = g.MeasureString(s, transparentFont);
sLeft = (this.Width - d.Width) - 10;
sTop = (this.Height - d.Height) - 10;

g.DrawString(s, transparentFont, transparentBrush, sLeft, sTop,
System.Drawing.StringFormat.GenericTypographic);
g.Dispose();

// need to flip the bitmap so it's the same orientation as the
// video buffer
bitmapOverlay.RotateFlip(RotateFlipType.RotateNoneFlipY);

// create and copy the video's buffer image to a bitmap
Bitmap v;
v = new Bitmap(this.Width , this.Height , m_stride, PixelFormat.Format32bppArgb, pBuffer);
g = Graphics.FromImage(v);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

// draw the overlay bitmap over the video's bitmap
g.DrawImage(bitmapOverlay, 0, 0, bitmapOverlay.Width, bitmapOverlay.Height);

// dispose of the various objects
g.Dispose();
v.Dispose();

// Increment frame number. Done this way, frame are zero indexed.
m_Count++;

return 0;
}

/// <summary> Set the options on the sample grabber </summary>
private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
{
AMMediaType media;
int hr;

// Set the media type to Video/RBG24
media = new AMMediaType();
media.majorType = MediaType.Video;
media.subType = MediaSubType.ARGB32;
media.formatType = FormatType.VideoInfo;

hr = sampGrabber.SetMediaType(media);
DsError.ThrowExceptionForHR(hr);

DsUtils.FreeAMMediaType(media);
media = null;

hr = sampGrabber.SetCallback(this, 1);
DsError.ThrowExceptionForHR(hr);
}

void SetupBitmap()
{
int fSize;

// scale the font size in some portion to the video image
fSize = 9 * (this.Width / 64);
bitmapOverlay = new Bitmap(this.Width , this.Height ,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
fontOverlay = new Font("Times New Roman", fSize, System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point);

// scale the font size in some portion to the video image
fSize = 5 * (this.Width / 64);
transparentFont = new Font("Tahoma", fSize, System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point);
transparentBrush = new SolidBrush(Color.FromArgb(96, 0, 0, 255));
}
...全文
1219 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
lzgzzy 2011-08-17
  • 打赏
  • 举报
回复
楼主能把完整的代码发给我吗?谢谢,156860596.qq.com
Jimmy.Chiang 2010-10-08
  • 打赏
  • 举报
回复
关注研究~
avermedia 2010-09-17
  • 打赏
  • 举报
回复
楼主能不能把完整的代码传给我一份,不胜感激 895652159@qq.com
寒冰沁狐兰 2010-08-06
  • 打赏
  • 举报
回复
求知中呀。我也正在做这样程序,就是不知道怎么动态的视频中的图片。。急急。。。。
_skyfish 2009-02-18
  • 打赏
  • 举报
回复
我最近也在用directshow开发视频相关软件,也碰到了一个跟您相同的问题就是hr出现一个很大的负值,一直不知道怎么解决不知道您解决没有,怎么解决的?谢谢。
空心兜兜 2009-02-05
  • 打赏
  • 举报
回复
很专业的问题
lizhengnan 2009-02-05
  • 打赏
  • 举报
回复
装的是9.0C.

//加上这段。
IBaseFilter videoRenderer = (IBaseFilter) new VideoRenderer();
graphBuilder.AddFilter(videoRenderer, "VideoRenderer");

// Render the preview pin on the video capture filter
// Use this instead of this.graphBuilder.RenderFile
// 在这会返回一个错误,hr的值为262782.不知道如果解决.
hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, baseGrabFlt, videoRenderer);

加上上面的也不行,还是一样的错误.
liujiayu10 2009-02-05
  • 打赏
  • 举报
回复
DirectX是不是版本不新
fskang 2009-02-05
  • 打赏
  • 举报
回复
开始运行,dxdiag。看了下,还有你的Graph好像没有输出啊,不知道有没有影响。我的DirectShow也是半吊子。。。


//加上这段。
IBaseFilter videoRenderer = (IBaseFilter) new VideoRenderer();
graphBuilder.AddFilter(videoRenderer, "VideoRenderer");

// Render the preview pin on the video capture filter
// Use this instead of this.graphBuilder.RenderFile
// 在这会返回一个错误,hr的值为262782.不知道如果解决.
hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, baseGrabFlt, videoRenderer);


lizhengnan 2009-02-05
  • 打赏
  • 举报
回复
我装的Direct几我也不知道,
不是用的采集卡,我用的是摄像头
Mike老羊 2009-02-05
  • 打赏
  • 举报
回复
学习
fskang 2009-02-05
  • 打赏
  • 举报
回复
如果是按照例子改的话,问题应该不大的。还有就是你装了DirectX9吗?用的是采集卡吗?你的采集卡支持DirectShow吗?
eynStudio 2009-02-05
  • 打赏
  • 举报
回复
关注!
lizhengnan 2009-02-05
  • 打赏
  • 举报
回复
是可以的,不过我这里现在出错呀.

hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, baseGrabFlt, null);

在这里会出现一个错误.hr的值为262782

我现在就是不知道怎么把ISAMPLEGRABBER加进去呀
fskang 2009-02-05
  • 打赏
  • 举报
回复
你用的DirectShow.net吧。可以的,注意坐标转换就可以了。下面是叠加字符的方法。改改就行了。

/// <summary>
/// buffer callback, COULD BE FROM FOREIGN THREAD.
/// </summary>
/// <param name="SampleTime">The sample time.</param>
/// <param name="pBuffer">The p buffer.</param>
/// <param name="BufferLen">The buffer len.</param>
/// <returns></returns>
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
{
// Note that we depend on only being called once per call to Click. Otherwise
// a second call can overwrite the previous image.
Debug.Assert(BufferLen == Math.Abs(stride)*videoHeight, "Incorrect buffer length");

if (imageLogo != null || stringLogo != null)
{
//获取帧图片。
Bitmap frameImage = new Bitmap(videoWidth, videoHeight, stride, PixelFormat.Format24bppRgb, pBuffer);
Graphics g = Graphics.FromImage(frameImage);
g.SmoothingMode = SmoothingMode.AntiAlias;

//帧图片的坐标原点为左下角,GDI+的坐标原点为左上角,需要变换全局坐标系。
System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix(1, 0, 0, -1, 0, 0);
g.Transform = matrix;
g.TranslateTransform(0, -videoHeight);

//设置字符所处的位置。
if (imageLogo != null)
{
g.DrawImage(imageLogo, imagePosition.X, imagePosition.Y);
}
if (stringLogo != null)
{
g.DrawImage(stringLogo, stringPosition.X, stringPosition.Y);
}
//释放设备管理器和帧图片的内存。
g.Dispose();
frameImage.Dispose();
}
return 0;
}
fskang 2009-02-05
  • 打赏
  • 举报
回复
呵呵,不客气。
lizhengnan 2009-02-05
  • 打赏
  • 举报
回复
非常感谢fskang,

换成media.subType = MediaSubType.RGB24

好使了,呵呵

说实话我不知道这个参数的意义是什么,只是看例子是这么写的,我就拷过来了.

呵呵,非常感谢.
fuyonggao 2009-02-05
  • 打赏
  • 举报
回复
你要的效果是不是象:
http://download.csdn.net/source/385366
那样?
megerisin 2009-02-05
  • 打赏
  • 举报
回复
关注一下哈
fskang 2009-02-05
  • 打赏
  • 举报
回复
http://groups.google.com/group/microsoft.public.smartphone.developer/browse_thread/thread/c9a4b3a393d4aa8a/9a025c9c22b01105?lnk=st&q=CNullRend&rnum=1

HResult 0x0004027e is not an error code, it's a success indicating that the
preview was rendered through the smart tee. Your camera driver is a two pin
driver and therefore the preview is rendered from the capture pin through
the smart tee. Only HRESULTs starting with 0x8xxxx are failure codes, the
rest are success codes indicating additional information.

貌似这个不算个错误。。。你检查下你枚举的设备是不是那个摄像头,另外在运行时检查下baseGrabFlt是不是空值,还有 media.subType = MediaSubType.ARGB32;换成media.subType = MediaSubType.RGB24再试试。

111,130

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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