要入门AI,不就是眼和耳吗?所以你需要打通关键的声音采集,和图像采集。特别是编程,他的重要性不言而喻。虽然这都是玩一玩,在微软支撑下,简单,过气,但是他激发的探索和兴致(求知欲)从来不会过时,这会让你打开更加专业的basler相机,灰点(grey)相机图像采集(针对机器视觉)的大门,如果你不会对眼和耳采集的花花世界感兴趣,怎么会对算法和意识感兴趣呢?
请看整理的c#摄像头取像程序:我们给他起了一个名字叫usbcamscale(usb摄像头缩放),这里只表述图像采集代码:
第一,声明: WebCamera wc = null;
public ShowVideo.CAPDRIVERCAPS capDriverCaps;
public ShowVideo.CAPSTATUS capStatus;
public ShowVideo.CAPTUREPARMS captureparms;
第二,初始化: capDriverCaps = new ShowVideo.CAPDRIVERCAPS();
capStatus = new ShowVideo.CAPSTATUS();
captureparms = new ShowVideo.CAPTUREPARMS();
第三,取像:
wc = new WebCamera(pictureBox1.Handle, pictureBox1.Width, pictureBox1.Height);//
wc.StartWebCam();
if (!wc.capDriverConnect(wc.IwndC, 0))
{
return;
}
ShowVideo.SendMessage(wc.IwndC, ShowVideo.WM_CAP_DRIVER_GET_CAPS, ShowVideo.SizeOf(capDriverCaps), ref capDriverCaps);
if (capDriverCaps.fCaptureInitialized)
{
wc.capPreviewRate(wc.IwndC, 25);
wc.capPreview(wc.IwndC, true);//没有显示,被设置。要显示设置为WS_VISIBLE(向后看)。
}
ok,取像成功。好,这是微软给我们的便利,我们瞪大眼睛只能看着,那么如何取出一幅像呢?继续:
int mod = wc.mWidth % 4;//这是vfw模式(opencv1.0也是如此)的,在win8.1上测试通过,win10你可以想办法去通关
glob_buffer32 = new byte[640 * 480*4];//vfw模式,只能取出640*480的pixels,win8.1可以运行800*600的摄像头
glob_buffer8 = new byte[640 * 480 ];//但是取出来的仍然是640*480,所以你又需要开动脑筋通关
glob_buffer8G = new byte[640 * 480];
glob_buffer8B = new byte[640 * 480];
timer1.Start();
第四,取出一幅像:
Bitmap glob_curBitmap=null;
Bitmap transBmp = null;
private void timer1_Tick(object sender, EventArgs e)
{
if (ShowVideo.SendMessage(wc.IwndC, ShowVideo.WM_CAP_SINGLE_FRAME_OPEN, 0, 0))
{
if (ShowVideo.SendMessage(wc.IwndC, ShowVideo.WM_CAP_SINGLE_FRAME, 0, 0))
{
if (ShowVideo.SendMessage(wc.IwndC, ShowVideo.WM_CAP_SINGLE_FRAME_CLOSE, 0, 0))
{
ShowVideo.SendMessage(wc.IwndC, ShowVideo.WM_CAP_EDIT_COPY, 0, 0);
IDataObject iData = Clipboard.GetDataObject();
iData.GetDataPresent(DataFormats.Bitmap);
transBmp = (Bitmap)iData.GetData(DataFormats.Bitmap);
this.pictureBox1.Image = (Bitmap)iData.GetData(DataFormats.Bitmap);//这里显示彩色图像
Clipboard.Clear();
glob_curBitmap = (Bitmap)transBmp.Clone();
}
}
}
int ww=640;
int hh=480;
BitmapData _cutPic = glob_curBitmap.LockBits(new Rectangle(0, 0, ww, hh),//PixelFormat.Format32bppArgb
ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);//glob_curBitmap.
IntPtr ptr = _cutPic.Scan0;//得到首地址
//把cutvalues数组给ptr
Marshal.Copy(ptr, glob_buffer32, 0, 640*480* 4);
glob_curBitmap.UnlockBits(_cutPic);
for (int j = 0; j < 640; j++)
{
for (int i = 0; i < 480; i++)
{
int nn = j * 480 + i;
glob_buffer8[nn] = glob_buffer32[nn * 4+0];//这里已经取出了RGB图像放在r,g,b数组(byte【】)中
glob_buffer8G[nn] = glob_buffer32[nn * 4 + 1];//你需要想办法写入bitmap,并显示
glob_buffer8B[nn] = glob_buffer32[nn * 4 + 2];//这里的buffer8B里头存的是红色分量,发现没有?
}
}
drawload2scale(640, 480, glob_buffer8, pictureBox2);//这里显示的是灰度图像,用来可以图像处理了
}//我们把蓝色分量b数组作为灰度图像是不妥的,应该是红色0.3,绿色0.59,蓝色0.11
剩下的,就是来解释前面的关键类:第一个
class WebCamera
{
public delegate void RecievedFrameEventHandler(byte[] data);
public event RecievedFrameEventHandler RecievedFrame;
public IntPtr IwndC;
public IntPtr mControlPtr;
public int mWidth;
public int mHeight;
public ShowVideo.FrameEventHandler mFrameEventHandler;
public void FrameCallBack(IntPtr Iwnd, IntPtr lpVHdr)
{
ShowVideo.VIDEOHDR videoHeader = new ShowVideo.VIDEOHDR();
byte[] VideoData;
videoHeader = (ShowVideo.VIDEOHDR)ShowVideo.GetStructure(lpVHdr, videoHeader);
VideoData=new byte[videoHeader.dwBytesUsed];
ShowVideo.Copy(videoHeader.lpData, VideoData);
if (this.RecievedFrame != null)
{
this.RecievedFrame(VideoData);
}
}
public WebCamera(IntPtr handle, int width, int height)
{
mControlPtr = handle;
mWidth = width;
mHeight = height;
}
public void StartWebCam()
{
byte[] abc = new byte[32];
abc[0] = (byte)'u';
abc[1] = (byte)'s';
abc[2] = (byte)'b';
abc[3] = (byte)'C';
abc[4] = (byte)'a';
abc[5] = (byte)'m';
for (int i = 6; i < 32; i++)
{
abc[i] = (byte)'0';
}
// IwndC = ShowVideo.capCreateCaptureWindowA(abc, ShowVideo.WS_CHILD | ShowVideo.WS_VISIBLE, 0, 0, mWidth, mHeight, mControlPtr, 0);//要显示图像,使用此行代码
//WS_DISABLED
IwndC = ShowVideo.capCreateCaptureWindowA(abc, ShowVideo.WS_CHILD | ShowVideo.WS_DISABLED, 0, 0, mWidth, mHeight, mControlPtr, 0);//注意,这里被设置为不显示。
}
public void CloseCamera()
{
this.capDriverDisconnect(this.IwndC);
}
public bool capDriverConnect(IntPtr Iwnd, short i)
{
return ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_DRIVER_CONNECT, i, 0);
}
public bool capDriverDisconnect(IntPtr Iwnd)
{
return ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_DRIVER_DISCONNECT, 0, 0);
}
public bool capPreview(IntPtr Iwnd, bool f)
{
return ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_SET_PREVIEW, f, 0);
}
public bool capPreviewRate(IntPtr Iwnd, short wMS)
{
return ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_SET_PREVIEWRATE, wMS, 0);
}
public bool capSetVideoFormat(IntPtr hWnd, ref ShowVideo.BITMAPINFO bitmapinfo, int size)
{
//return ShowVideo.capGetVideoFormat(hWnd, bitmapinfo, size);
return ShowVideo.SendMessage(hWnd, ShowVideo.WM_CAP_SET_VIDEOFORMAT, size, ref bitmapinfo);
}
public bool capSetCallbackOnFrame(IntPtr IWnd, ShowVideo.FrameEventHandler lpProc)
{
return ShowVideo.SendMessage(IWnd, ShowVideo.WM_CAP_SET_CALLBACK_FRAME, 0, lpProc);
}
public void StartCamera()
{
byte[] lpszName = new byte[100];
byte[] lpszVer = new byte[100];
this.IwndC = ShowVideo.capCreateCaptureWindowA(lpszName, ShowVideo.WS_VISIBLE + ShowVideo.WS_CHILD,
0, 0, mWidth, mHeight, mControlPtr, 0);
}
public void caprecord(IntPtr Iwnd, string path)
{
IntPtr hBmp = Marshal.StringToHGlobalAnsi(path);
ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_FILE_SET_CAPTURE_FILEA, 0, hBmp.ToInt32());
ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_SEQUENCE, 0, 0);
}
public void caprecordstop(IntPtr Iwnd)
{
ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_STOP, 0, 0);
}
public void capsnapimage(IntPtr Iwnd, string path)
{
ShowVideo.BITMAPINFO bmpinfo = new ShowVideo.BITMAPINFO();
IntPtr hBmp = Marshal.StringToHGlobalAnsi(path);
ShowVideo.SendMessage(Iwnd, ShowVideo.WM_CAP_SAVEDIB, 0, hBmp.ToInt32());
}
}///////////////////////////////////////////////////////////////////
第二个:注意这是一个form类,你需要创建一个form窗口
public partial class ShowVideo : Form
{
public const int WS_CHILD = 0x40000000;
public const int WS_VISIBLE = 0x10000000;
public const int WS_DISABLED=0x08000000;
public const int WM_USER = 1024;
public const int WM_CAP_START = WM_USER;
public const int WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
public const int WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11;
public const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
public const int WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52;
public const int WM_CAP_SET_VIDEOFORMAT = WM_USER + 45;
public const int WM_CAP_SET_CALLBACK_FRAME = WM_USER + 5;
public const int WM_CAP_FILE_SET_CAPTURE_FILEA = WM_USER + 20;
public const int WM_CAP_SEQUENCE=WM_USER +62;
public const int WM_CAP_SAVEDIB = WM_USER + 25;
public const int WM_CAP_STOP = WM_USER + 68;
public const int WM_CAP_GET_SEQUENCE_SETUP=WM_USER+65;
public const int WM_CAP_DRIVER_GET_CAPS=WM_USER+14;
public const int WM_CAP_DRIVER_GET_STATUS = WM_USER + 54;
public delegate void FrameEventHandler(IntPtr Iwnd, IntPtr lpVHdr);
public static object GetStructure(IntPtr ptr, ValueType structure)
{
return Marshal.PtrToStructure(ptr, structure.GetType());
}
public static object GetStructure(int ptr, ValueType structure)
{
return GetStructure(new IntPtr(ptr), structure);
}
public static void Copy(IntPtr ptr, byte[] data)
{
Marshal.Copy(ptr, data, 0, data.Length);
}
public static void Copy(int ptr, byte[] data)
{
Copy(new IntPtr(ptr), data);
}
public static int SizeOf(object structer)
{
unsafe
{
return Marshal.SizeOf(structer);
}
}
[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("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, short WParam, int LParam);
[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,FrameEventHandler LParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, int WParam, ref BITMAPINFO LParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, int WParam, ref CAPDRIVERCAPS LParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, int WParam, ref CAPTUREPARMS LParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, int WParam, ref CAPSTATUS LParam);
[DllImport("User32.dll")]
public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);
[DllImport("User32.dll")]
public static extern int capGetVideoFormat(IntPtr hWnd, IntPtr psVideoFormat, int wSize);
public const int WM_CAP_SINGLE_FRAME_OPEN = WM_USER + 70;
public const int WM_CAP_SINGLE_FRAME_CLOSE = WM_USER + 71;
public const int WM_CAP_SINGLE_FRAME=WM_USER+72;
public const int WM_CAP_EDIT_COPY = (WM_USER + 30);
//[DllImport("User32.dll")]
//public static extern bool EmptyClipboard();
//[DllImport("User32.dll")]
//public static extern bool CloseClipboard();
//[DllImport("User32.dll")]
//public static extern bool OpenClipboard(IntPtr hWnd);
//[DllImport("User32.dll")]
//public static extern bool IsClipboardFormatAvailable(uint format);
//[DllImport("User32.dll")]
//public static extern IntPtr GetClipboardData(uint uFormat);
//[DllImport("User32.dll")]
//public static extern IntPtr GlobalLock(IntPtr handle);
//[DllImport("User32.dll")]
//public static extern bool GlobalUnlock(IntPtr handle);
//[DllImport("User32.dll")]
//public static extern bool CloseClipboard();
[StructLayout(LayoutKind.Sequential)]
public struct VIDEOHDR
{
[MarshalAs(UnmanagedType.I4)]
public int lpData;
[MarshalAs(UnmanagedType.I4)]
public int dwBufferLength;
[MarshalAs(UnmanagedType.I4)]
public int dwBytesUsed;
[MarshalAs(UnmanagedType.I4)]
public int dwTimeCaptured;
[MarshalAs(UnmanagedType.I4)]
public int dwUser;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER
{
[MarshalAs(UnmanagedType.I4)]
public Int32 biSize;
[MarshalAs(UnmanagedType.I4)]
public Int32 biWidth;
[MarshalAs(UnmanagedType.I4)]
public Int32 biHeight;
[MarshalAs(UnmanagedType.I2)]
public short biPlanes;
[MarshalAs(UnmanagedType.I2)]
public short biBitCount;
[MarshalAs(UnmanagedType.I4)]
public int biCompression;
[MarshalAs(UnmanagedType.I4)]
public int biSizeImage;
[MarshalAs(UnmanagedType.I4)]
public int biXpelsPerMeter;
[MarshalAs(UnmanagedType.I4)]
public int biYPelsPerMeter;
[MarshalAs(UnmanagedType.I4)]
public int biClrUsed;
[MarshalAs(UnmanagedType.I4)]
public int biClrImportant;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFO
{
[MarshalAs(UnmanagedType.Struct, SizeConst = 100)]
public BITMAPINFOHEADER bmiHeader;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
public int[] bmiColors;
}
[StructLayout(LayoutKind.Sequential)]
public struct CAPDRIVERCAPS
{
[MarshalAs(UnmanagedType.U2)]
public UInt16 wDeviceIndex;
[MarshalAs(UnmanagedType.Bool)]
public bool fHasOverlay;
[MarshalAs(UnmanagedType.Bool)]
public bool fHasDlgVideoSource;
[MarshalAs(UnmanagedType.Bool)]
public bool fHasVideoFormat;
[MarshalAs(UnmanagedType.Bool)]
public bool fHasDlgVideoDisplay;
[MarshalAs(UnmanagedType.Bool)]
public bool fCaptureInitialized;
[MarshalAs(UnmanagedType.Bool)]
public bool fDriverSuppliesPalettes;
[MarshalAs(UnmanagedType.I4)]
public int hVideoIn;
[MarshalAs(UnmanagedType.I4)]
public int hVideoOut;
[MarshalAs(UnmanagedType.I4)]
public int hVideoExtIn;
[MarshalAs(UnmanagedType.I4)]
public int hVideoExtOut;
}
[StructLayout(LayoutKind.Sequential)]
public struct CAPTUREPARMS
{
public int dwRequestMicroSecPerFrame;//默认15秒每帧
public bool fMakeUserHitOkToCapture;//开始捕获标志
public uint wPercentDropForError;//丢帧默认10
public bool fYield;//另起线程标志
public int dwIndexSize;
public uint wChunkGranularity;
public bool fUsingDOSMemory;
public uint wNumVideoRequested;//分配最大视频缓存
public bool fCaptureAudio;
public uint wNumAudioRequested;//最大数量音频缓存
public uint vKeyAbort;//终止流捕获的虚拟键盘吗
[MarshalAs(UnmanagedType.Bool)]
public bool fAbortLeftMouse;
public bool fAbortRightMouse;
public bool fLimitEnabled;//捕获操作时间限制
public uint wTimeLimit;//具体终止时间
public bool fMCIControl;
public bool fStepMCIDevicd;
public int dwMCIStartTime;
public int dwMCIStopTime;
public bool fStepCaptureAt2x;
public int wStepCaptureAverageFrames;
public int dwAudioBufferSize;//0.5s或10k字节
public int fDisableWriteCache;
public int AVStreamMaster;//音频同步标志
}
[StructLayout(LayoutKind.Sequential)]
public struct CAPSTATUS
{
public int uiImageWidth;
public int uiImageHeight;
public bool fOverlayWindow;
public bool fLiveWindow;
public bool fScale;
public Point ptScroll;
public bool fUsingDefaultPalette;
public bool fAudioHardware;
public bool fCapFileExists;
public int dwCurrentVideoFrame;
public int dwCurrentVideoFramesDropped;
public int dwCurrentWaveSamples;
public int dwCurrentTimeElapsedMS;
public IntPtr hPalCurrent;
public int dwReturn;
public bool fCapturingNow;
public int wNumVideoAllocated;
public int wNumAudioAllocated;
}
public ShowVideo()
{
InitializeComponent();
}
}
网络真是个学习的好地方,有很多的大咖需要谢谢,但更应该感谢微软!如果有想要看vc++版本的摄像头图像采集程序,请留言,或许,有对比,才能更好的学习进步,不要以为我放弃vc++了,那可是我的初心!(vc++都能搞定,C#都不是事,虽然没人教过)
待续(慢慢来!...........)每天一点小改变☺