2015-12-08 19:00:02 waeceo 阅读数 14849
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    13985 人正在学习 去看看 张建飞

硕士研三找完工作后就开始投入紧张忙碌的论文生涯,现在我在忙大论文的工程。前期好多的实验和理论,头都大了,好在通过搞这些东西,收获了不少心得。

写一下在用C#读取摄像头并做处理的Demo心得吧。

如果我们需要读取摄像头,并且还要对其中的某帧图像进行处理,比如说取出其中的某个像素点坐标的对应的像素色彩值,RGB或者灰度值。有以下几种方法:

(1)我们第一个想到的就是使用大名鼎鼎的Opencv。确实Opencv非常好用,但是对于一些对于C++一知半解的人来说,要有界面程序的话还得学Qt,哇,Qt配置Opencv可麻烦了,以前做的时候用过,也配置过,可以说非常麻烦,网上众说纷纭,各种版本的配置,基本上没有一个版本能够不出问题的配置好,还是我参考了各个版本后,自己想出的配置方法,也写在我以前的博客里了,如果需要的话,可以上下捣一捣翻一翻,准能找到。我这一次做为啥不用以前的程序了呢?就是因为我刚把环境卸掉了,不想再装了,所以问题来了,想偷懒,就得有其他办法做。如下的方法(2)

(2)好多人说,opencv也可以配置在C#上啊,对,没错,大牛应该能用的了,搞得动。为什么这么说?我问了一下度娘,她说,你必须学习EmguCV才行啊,说这是microsoft吸取了opencv的精华,而后又加入了很多高级功能之后的版本。高大上啊,然后我又开始搜EmguCV,大概的资料在下面两个链接上:

http://www.opencv.org.cn/forum.php?mod=viewthread&tid=32710
http://wenku.baidu.com/link?url=DIvhesSEe7CjxWPtX2YH-HOVciLereVfNVfd-OSZRlcpCGENlYyRO7wdSlbcqkueLRGlqT-UkswmKOKeMbAN6SrJJJb1sE2ic4ukwrcWvoK

资料很少,用的人也不多,所以,给那些刚涉入程序员行列不久的人一条靠谱的建议:我们在做一个工程的时候,网上一搜,会有很多种办法解决,但是,我们不要随便找一个就开始干,这是蛮干,开始的时候可能还没啥难度,网上的资料也够用,但是越往后做,难度越大,网上的资料可以用的资料就越少了,那就要看你的功底了;所以对于内功修为不够的人,千万不要随便学一门武功,容易走火入魔惊恐!这样做是非常浪费时间的,如果你在公司这么干的话,是会有致命后果的。所以公司的人在做一个工程前,首先都会论证网上的各种技术,做法,选一个比较成熟的技术来做,这样的话,节省时间,而且也不容易出现大的错误。我算是记住了!所以这个方案对于我的工程来说也就pass掉了。
换下一话题,大笑,方法(3)
(3)起初为了完成某个短期的目标就慌不择路的选择了该方法,结果越陷越深啊,幸好,我还有点内功,能够控制住自己,没有走火入魔。很心酸。该方法就是本文主要讲的方法
AVICap;avicap32.dll;
百度一搜avicap的话会有不少的资料,不过有很多资料都是重复的,你copy我的,我copy你的,真正的有几篇写的还可以的,链接如下:

http://blog.chinaunix.net/uid-20594503-id-1619859.html
http://blog.csdn.net/laolei1986/article/details/5730245
还有一些百度文档和博客上的程序,基本上都是一个样的,他们的程序我就不贴了,网上可以搜到的,基本功能就是打开视频,保存bmp格式的图片,录制avi格式的视频并保存;
而我的功能需求是这样的,(1)可以打开视频;(2)能够在视频现实中抓取一帧图片并且把图片转换成bmp格式;(3)分析这帧图片,找出某像素点的RGB值;(4)最后用Graphics绘图把RGB值根据大小画到picbox上,二维图像这样的,横轴是像素数(图片中某一行的第多少个像素点),纵轴是R值;
现把各个功能模块的程序帖上来:
先附上一张图吧:

做完后基本是这个效果,左侧的图片是640*480的,右侧是点击图片中的某一列之后的480个像素点对应的R值,0-255;
程序如下:包括功能(1)和功能(2)的程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Drawing;

namespace Test
{
    class VideoWork
    {
        private const int WM_USER = 0x400;
        private const int WS_CHILD = 0x40000000;
        private const int WS_VISIBLE = 0x10000000;
        private const int WM_CAP_START = WM_USER;
        private const int WM_CAP_STOP = WM_CAP_START + 68;
        private const int WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
        private const int WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11;
        private const int WM_CAP_SAVEDIB = WM_CAP_START + 25;//保存文件
        private const int WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
        private const int WM_CAP_SEQUENCE = WM_CAP_START + 62;
        private const int WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20;//设置捕获文件
        public const int WM_CAP_FILE_GET_CAPTURE_FILE = WM_CAP_START + 21;//获得捕获文件
        private const int WM_CAP_SEQUENCE_NOFILE = WM_CAP_START + 63;
        private const int WM_CAP_SET_OVERLAY = WM_CAP_START + 51;
        private const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;//50
        private const int WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START + 6;
        private const int WM_CAP_SET_CALLBACK_ERROR = WM_CAP_START + 2;
        private const int WM_CAP_SET_CALLBACK_STATUSA = WM_CAP_START + 3;
        private const int WM_CAP_SET_CALLBACK_FRAME = WM_CAP_START + 5;
        private const int WM_CAP_SET_SCALE = WM_CAP_START + 53;
        private const int WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52;
        //private IntPtr hWndC;
        public static IntPtr hWndC;

        private bool bWorkStart = false;
        private IntPtr mControlPtr;
        private int mWidth;
        private int mHeight;
        private int mLeft;
        private int mTop;
                   /// <summary>
                /// 初始化显示图像
                /// </summary>
                /// <param name= “handle “> 控件的句柄 </param>
                /// <param name= “left “> 开始显示的左边距 </param>
                /// <param name= “top “> 开始显示的上边距 </param>
                /// <param name= “width “> 要显示的宽度 </param>
                /// <param name= “height “> 要显示的长度 </param>
                public VideoWork(IntPtr handle, int left, int top, int width, int height)
                {
                mControlPtr = handle;
                mWidth = width;
                mHeight = height;
                mLeft = left;
                mTop = top;
                }
                [DllImport("avicap32.dll ")]
private static extern IntPtr capCreateCaptureWindowA(byte[] lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int nID);

                [DllImport("avicap32.dll ")]
                private static extern int capGetVideoFormat(IntPtr hWnd, IntPtr psVideoFormat, int wSize);

                //
                //这里特别注意,因为WinAPI中的long为32位,而C#中的long为64wei,所以需要将lParam该为int
                //
                [DllImport("User32.dll ")]
                private static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);

                /// <summary>
                /// 开始显示图像
                /// </summary>
                public void Start()
                {
                    if (bWorkStart)
                        return;

                    bWorkStart = true;
                    byte[] lpszName = new byte[100];

                    hWndC = capCreateCaptureWindowA(lpszName, WS_CHILD | WS_VISIBLE, mLeft, mTop, mWidth, mHeight, mControlPtr, 0);

                    if (hWndC.ToInt32() != 0)
                    {
                        SendMessage(hWndC, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0);
                        SendMessage(hWndC, WM_CAP_SET_CALLBACK_ERROR, 0, 0);
                        SendMessage(hWndC, WM_CAP_SET_CALLBACK_STATUSA, 0, 0);
                        SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0, 0);
                        SendMessage(hWndC, WM_CAP_SET_SCALE, 1, 0);//打开预览视频的缩放比例
                        SendMessage(hWndC, WM_CAP_SET_PREVIEWRATE, 66, 0);//66ms,视频刷新频率
                        SendMessage(hWndC, WM_CAP_SET_OVERLAY, 1, 0);//启用叠加 注:据说启用此项可以加快渲染速度    
                        SendMessage(hWndC, WM_CAP_SET_PREVIEW, 1, 0);//设置显示图像启动预览模式 PREVIEW
                    }
                    return;

                }

                /// <summary>
                /// 停止显示
                /// </summary>
                public void Stop()
                {
                    SendMessage(hWndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
                    bWorkStart = false;
                }

                /// <summary>
                /// 抓图
                /// </summary>
                /// <param name= “path “> 要保存bmp文件的路径 </param>
                public void GrabImage()//string path
                {
                    IntPtr hBmp = Marshal.StringToHGlobalAnsi(@"G:\c.bmp");//正确@"G:\c.bmp"   正确Application.StartupPath+".bmp"
                    SendMessage(hWndC, WM_CAP_SAVEDIB, 0, hBmp.ToInt32());
                }
    }
}
比较简单,因为网上都有,但关键点比较难,就是我没有办法从正在播放的视频中抓取一帧直接保存成bmp格式的图片直接分析,取而代之的方法是,先把其中抓获的一帧图片保存到本地磁盘,然后,另外一个picbox在一个定时器中不停的读取本地磁盘保存的bmp格式的图片,然后再绘图类中,我们在从该picbox中读取bitmap格式的图片,总之绕了一大圈,很费劲,不过总算功能实现了,但是,说实话,我不满意!以上功能再绘图类中,如下:
class Draw
    {
        public static double startPixel = 0;
        public static double endPixel = 480;
        public static double startGray = 0;
        public static double endGray = 255;

        private Graphics glight;//灰度值
        public void draw(PaintEventArgs e, PictureBox pictureBox3)
        {
            glight = e.Graphics;
            Pen p = new Pen(Color.Black, 2);

            //画标题
            Font fii = new Font("Tahoma",15, FontStyle.Regular);
            //以下两个for循环是画网格
            for (int i = 0; i < 6; i++)
            {
                glight.DrawLine(p, 70, i * 102, 550, i * 102);//横轴
            }
            for (int i = 0; i < 6; i++)
            {
                glight.DrawLine(p, 70 + i * 96, 0, 70 + i * 96, 512);
            }
            //画纵坐标
            for (int i = 0; i < 6; i++)
            {
                glight.DrawString((startGray + i * ((endGray - startGray) / 5)).ToString(), fii, new SolidBrush(Color.Red), 20, 505 - i * 102);
            }
            //画横坐标
            for (int i = 0; i < 6; i++)
            {
                glight.DrawString((startPixel + i * ((endPixel - startPixel) / 5)).ToString(), fii, new SolidBrush(Color.Red), 50+ i * 96, 520);
            }

            //画波形图
            double perPixel = 480 / (endPixel - startPixel);//每个点占多少像素
            double perGray = 512 / (endGray - startGray);//每个灰度值占多少像素

            //画点
            Pen point = new Pen(Color.Red, 3);
            Bitmap bmp;
            bmp = (Bitmap)pictureBox3.Image;
            if (bmp == null)
                bmp = new Bitmap(@"G:\c.bmp");

            int begin=0;
            for (double i = 0; i < endPixel - startPixel; i=i+1)
            {
                //bmp.GetPixel(Form1.clickpixel, (int)i);
                begin=Convert.ToInt32(bmp.GetPixel(Form1.clickpixel,(int)(startPixel + i)).R);
                if (begin>= startGray &&begin<= endGray)
                    glight.DrawEllipse(point, 70 + (int)(perPixel * (i + 1)), 512 - (int)((begin - startGray) * perGray), 1, 1);//画椭圆 420 - x * 100, 610 - y * 100, 1, 1
            }
        }
    }
貌似都完成了,但是还有一个令我百思不得其解的问题,以前graphics绘图,刷新的时候就直接在定时器中用invalidate就可以搞定了,一般在定时器中首先调用抓图函数并保存到本地,然后另外一个picturebox在读取本地的图片就OK了,但是该实验这么做就就不行,在获取了图片之后,就直接刷新是不行的,在绘图中会报错,解决方法是在用一个定时器,在另外一个定时器中定时刷新就可以了,如下程序:
    private void timer1_Tick(object sender, EventArgs e)
                {
                    wv.GrabImage();
                    this.pictureBox3.ImageLocation = @"G:\c.bmp";
                }

我 2015/12/8 20:27:13

                private void timer2_Tick(object sender, EventArgs e)
                {
                    this.pictureBox2.Invalidate();//代表每隔多长时间就重绘一次
                }

至此,该工程基本完成了,但是效率很低,因为抓帧后保存本地---picbox从本地读取----bitmap从picbox读取,所以绕了很多弯子,动态显示的时候,鼠标都在抖动,说明很差啊,不过也算是用该方法完成了这个功能了吧,因为我实在不知道该如何从视频中直接抓取一帧bitmap的图像直接处理。有知道的大神,可以写评论啊,谢谢!

2017-03-23 19:42:01 liyuqian199695 阅读数 15292
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    13985 人正在学习 去看看 张建飞

C#中打开摄像头(Halcon)

1、halcon中打开摄像头

通过“助手”菜单打开“Image Acquisition”,如图所示,选择“DirectShow”表示普通USB摄像头。


通过“连接、拍照、视频”可以检测是否已经打开。

可以看到图像窗口中已经有视频可以显示,如图


可以选择代码生成,选择插入代码,可以看到在程序编辑区,代码已经插入。


这里是为了在C#中打开摄像头,下面选择代码导出:“文件---->导出”。


打开image_acp.cs代码如下:

//
//  File generated by HDevelop for HALCON/DOTNET (C#) Version 12.0
//

using HalconDotNet;

public partial class HDevelopExport
{
#if !(NO_EXPORT_MAIN || NO_EXPORT_APP_MAIN)
  public HDevelopExport()
  {
    // Default settings used in HDevelop 
    HOperatorSet.SetSystem("width", 512);
    HOperatorSet.SetSystem("height", 512);
    if (HalconAPI.isWindows)
      HOperatorSet.SetSystem("use_window_thread","true");
    action();
  }
#endif

#if !NO_EXPORT_MAIN
  // Main procedure 
  private void action()
  {



    // Local iconic variables 

    HObject ho_Image=null;

    // Local control variables 

    HTuple hv_AcqHandle = null;
    // Initialize local and output iconic variables 
    HOperatorSet.GenEmptyObj(out ho_Image);
    //Image Acquisition 01: Code generated by Image Acquisition 01
    HOperatorSet.OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "rgb", 
        -1, "false", "default", "[0] USB2.0 PC CAMERA", 0, -1, out hv_AcqHandle);
    HOperatorSet.GrabImageStart(hv_AcqHandle, -1);
    while ((int)(1) != 0)
    {
      ho_Image.Dispose();
      HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);
      //Image Acquisition 01: Do something
    }
    HOperatorSet.CloseFramegrabber(hv_AcqHandle);
    ho_Image.Dispose();

  }

#endif



}
#if !(NO_EXPORT_MAIN || NO_EXPORT_APP_MAIN)
public class HDevelopExportApp
{
  static void Main(string[] args)
  {
    new HDevelopExport();
  }
}
#endif

2、C#中打开摄像头

(1)新建一个C#---WINFORM程序,在窗体上添加Halcon的HWindowControl控件(参照博客:C#(VS2010)调用HALCON12),两个按钮


(2)Form1.cs代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HalconDotNet;//添加Halcon空间

using System.Threading;

namespace 打开摄像头
{
    public partial class Form1 : Form
    {
        //halcon导出的变量
        HObject ho_Image = null;
        HTuple hv_AcqHandle = null;

        public Form1()
        {
            InitializeComponent();
        }
        //定义一个线程
        Thread dispig;
        private void button1_Click(object sender, EventArgs e)
        {//图像采集
            dispig = new Thread(getin);
            dispig.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {//停止
            dispig.Abort();
            HOperatorSet.CloseFramegrabber(hv_AcqHandle);
        }
        void getin()
        {
            HOperatorSet.GenEmptyObj(out ho_Image);
            HOperatorSet.OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "rgb",
                            -1, "false", "default", "[0] USB2.0 PC CAMERA", 0, -1, out hv_AcqHandle);
            HOperatorSet.GrabImageStart(hv_AcqHandle, -1);
            while(true)
            {
                HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);

                HOperatorSet.DispObj(ho_Image, hWindowControl1.HalconWindow);
                ho_Image.Dispose();
            }
            
        }
    }

}

(3)效果如下:


如果视频正在采集中,直接关闭窗体,程序会报错,其实是由于线程正在运行的问题(参照之前的博客:C#----多线程)。为窗体添加一个“FromClosing”事件即可,代码如下:

  private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  {
      if (dispig != null)
      {
           dispig.Abort(); //结束这个线程
      }
  }

到此,程序完全可以正常运行。

其全部代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HalconDotNet;//添加Halcon空间

using System.Threading;

namespace 打开摄像头
{
    public partial class Form1 : Form
    {
        //halcon导出的变量
        HObject ho_Image = null;
        HTuple hv_AcqHandle = null;

        public Form1()
        {
            InitializeComponent();
        }
        //定义一个线程
        Thread dispig;
        private void button1_Click(object sender, EventArgs e)
        {//图像采集
            dispig = new Thread(getin);
            dispig.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {//停止
            dispig.Abort();
            HOperatorSet.CloseFramegrabber(hv_AcqHandle);
        }
        void getin()
        {
            HOperatorSet.GenEmptyObj(out ho_Image);
            HOperatorSet.OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "rgb",
                            -1, "false", "default", "[0] USB2.0 PC CAMERA", 0, -1, out hv_AcqHandle);
            HOperatorSet.GrabImageStart(hv_AcqHandle, -1);
            while(true)
            {
                HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);

                HOperatorSet.DispObj(ho_Image, hWindowControl1.HalconWindow);
                ho_Image.Dispose();
            }
            
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (dispig != null)
            {
                dispig.Abort(); //结束这个线程
            }
        }
    }



}
2017-06-10 11:56:07 shenshendeai 阅读数 776
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    13985 人正在学习 去看看 张建飞

问题描述见下面图

用AForge 写程序,在做界面时发现打开程序后打开界面能连接摄像头,然后关闭再打开就一直连接状态,是因为关闭时没有关闭摄像头,只关闭了界面。


 VideoCaptureDevice videoSource;

只需在关闭时加入 videoSource.Stop();即可解决该问题

  private void FrmGetPic_FormClosing(object sender, EventArgs e)
        {
            if (videoDevices == null || videoDevices.Count == 0)
            {
                return;
            }
            videoSource.Stop();

        }

第一次打开


第二次打开


类中定义:

FilterInfoCollection videoDevices;
        VideoCaptureDevice videoSource;

 private void FrmGetPic_Load(object sender, EventArgs e)
        {

  try
            {
                // 枚举所有视频输入设备
                videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
                //  MessageBox.Show(videoDevices.Count.ToString());
                if (videoDevices.Count == 0)
                    throw new ApplicationException();


                foreach (FilterInfo device in videoDevices)
                {
                    this.cb_SPDriver.Items.Add(device.Name);
                }


                cb_SPDriver.SelectedIndex = 0;
               // CameraConn();
              
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                this.cb_SPDriver.Items.Add("未找到驱动设备");
                videoDevices = null;
            }

}


    private void CameraConn()
        {
            //VideoCaptureDevice videoSource = new VideoCaptureDevice(videoDevices[tscbxCameras.SelectedIndex].MonikerString);
            //videoSource.DesiredFrameSize = new Size(320, 240);
            //videoSource.DesiredFrameRate = 1;

            //videPlayer.VideoSource = videoSource;
            //videPlayer.Start();
            if (videoDevices == null || videoDevices.Count == 0) return;


            videoSourcePlayer1.SignalToStop();
            videoSourcePlayer1.WaitForStop();


            videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            selectedDeviceIndex = cb_SPDriver.SelectedIndex;
            videoSource = new VideoCaptureDevice(videoDevices[selectedDeviceIndex].MonikerString);//连接摄像头。
            videoSource.VideoResolution = videoSource.VideoCapabilities[selectedDeviceIndex];
            videoSourcePlayer1.VideoSource = videoSource;
            // set NewFrame event handler
            videoSourcePlayer1.Start();


        }

2014-01-11 12:46:03 yal179 阅读数 2008
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    13985 人正在学习 去看看 张建飞

从网上找的C#的打开本地摄像头的代码,在我的台式机上运行没有问题,在笔记本上运行,第一次就会出现视频源的选择窗口,确定了之后无法开始视频,后来终于找到了个解决办法,可以通过更新摄像头驱动来解决。

我先后试了360驱动大师,驱动精灵、万能摄像头驱动2011,驱动人生,后来装了驱动人生就好了。

2014-02-26 23:24:06 whw8007 阅读数 734
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    13985 人正在学习 去看看 张建飞

作者:沐海

转自:http://www.cnblogs.com/mahaisong/p/3284314.html


复制代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;


namespace MyVideoService
{
    class Program
    {
        
        static void Main(string[] args)
        {
            cVideo video = new cVideo(Process.GetCurrentProcess().MainWindowHandle, 379, 316);
            video.StartWebCam();
            video.GrabImage(Process.GetCurrentProcess().MainWindowHandle, "d:\\b.jpg");
            video.CloseWebcam();
        }
    }
}
复制代码

 

复制代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.Drawing;
using System.IO;

namespace MyVideoService
{
    public class VideoAPI  //视频API类
    {
        //  视频API调用
        [DllImport("avicap32.dll")]
        public static extern IntPtr capCreateCaptureWindowA(byte[] lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int nID);
        [DllImport("avicap32.dll")]
        public static extern bool capGetDriverDescriptionA(short wDriver, byte[] lpszName, int cbName, byte[] lpszVer, int cbVer);
        [DllImport("User32.dll")]
        public static extern bool SendMessage(IntPtr hWnd, int wMsg, bool wParam, int lParam);
        [DllImport("User32.dll")]
        public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, int lParam);
        //  常量
        public const int WM_USER = 0x400;
        public const int WS_CHILD = 0x40000000;
        public const int WS_VISIBLE = 0x10000000;
        public const int SWP_NOMOVE = 0x2;
        public const int SWP_NOZORDER = 0x4;
        public const int WM_CAP_DRIVER_CONNECT = WM_USER + 10;
        public const int WM_CAP_DRIVER_DISCONNECT = WM_USER + 11;
        public const int WM_CAP_SET_CALLBACK_FRAME = WM_USER + 5;
        public const int WM_CAP_SET_PREVIEW = WM_USER + 50;
        public const int WM_CAP_SET_PREVIEWRATE = WM_USER + 52;
        public const int WM_CAP_SET_VIDEOFORMAT = WM_USER + 45;
        public const int WM_CAP_START = WM_USER;
        public const int WM_CAP_SAVEDIB = WM_CAP_START + 25;
    }
    public class cVideo     //视频类
    {
        private IntPtr lwndC;       //保存无符号句柄
        private IntPtr mControlPtr; //保存管理指示器
        private int mWidth;
        private int mHeight;
        public cVideo(IntPtr handle, int width, int height)
        {
            mControlPtr = handle; //显示视频控件的句柄
            mWidth = width;      //视频宽度
            mHeight = height;    //视频高度
        }
        /// <summary>
        /// 打开视频设备
        /// </summary>
        public void StartWebCam()
        {
            byte[] lpszName = new byte[100];
            byte[] lpszVer = new byte[100];
            VideoAPI.capGetDriverDescriptionA(0, lpszName, 100, lpszVer, 100);
            this.lwndC = VideoAPI.capCreateCaptureWindowA(lpszName, VideoAPI.WS_CHILD | VideoAPI.WS_VISIBLE, 0, 0, mWidth, mHeight, mControlPtr, 0);
            if (VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_DRIVER_CONNECT, 0, 0))
            {
                VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SET_PREVIEWRATE, 100, 0);
                VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SET_PREVIEW, true, 0);
            }
        }
        /// <summary>
        /// 关闭视频设备
        /// </summary>
        public void CloseWebcam()
        {
            VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_DRIVER_DISCONNECT, 0, 0);
        }
        ///   <summary>   
        ///   拍照
        ///   </summary>   
        ///   <param   name="path">要保存jpeg文件的路径</param>   
        public void GrabImage(IntPtr hWndC, string path)
        {
            IntPtr hBmp = Marshal.StringToHGlobalAnsi(path);

            VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SAVEDIB, 0, hBmp.ToInt32());

            Bitmap image = new Bitmap(path);
            if (path.Contains("bmp"))
            {
                image.Save(path.Replace("bmp", "jpg"), ImageFormat.Jpeg);
                image.Dispose();
                if (System.IO.File.Exists(path))
                {
                    try
                    {
                        System.IO.File.Delete(path);
                    }
                    catch (System.IO.IOException e)
                    {
                        return;
                    }
            }
            else {
                image.Save(path, ImageFormat.Jpeg);
                image.Dispose();
            }
            
            }



        }
    }

}
复制代码

 

补上这一个,是因为在VFW的系列教程中有人反映截图的问题。 我原来的方案是btye转换。 现在通过dll直接做byte的图片输入。 更方便。

            VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SAVEDIB, 0, hBmp.ToInt32());

这个文章来源: 开源中国。 转帖是北洋螃蟹
本人声明: 个人主页:沐海(http://www.cnblogs.com/mahaisong) 以上文章都是经过本人设计实践和阅读其他文档得出。如果需要探讨或指教可以留言或加我QQ!欢迎交流!

没有更多推荐了,返回首页