一种windows下简单的USB摄像头图像获取方式
Abstract: Usually, the way we capture images by usb camera is not easy, either we should install some software or we should write a lot of code to make it work. Here I found a simple way to deal with it: using the library–videoInput. To introduce it to you, I write a demo program on MFC.
A simple way to capture image through USB camera on windows
随着人工智能的大火,计算机视觉(computer vision)技术也热了起来,在很多所谓的人工智能领域大放光彩,尤其是模式识别,图像分类,而这也少不了对USB摄像头的图像的获取操作,然而我在起初寻找usb摄像头图像的获取方法时竟费了一番周折,通常的做法实在是不方便。
一种常见的方法是用DirectShow, 这里有相关链接https://github.com/5455945/VideoCapture
另一种是用opencv、openGL实现的,网上也有很多相关的代码示例。
但是上面这两种都需要额外安装库,有没有能直接引用lib或者dll就能工作的“绿色”方式,当然是有的:videoinput:
http://www.muonics.net/school/spring05/videoInput/
https://github.com/ofTheo/videoInput
不过github上的demo还是有点麻烦,其实我们想用的一般很简单,就是获取图片,并没有更多的要求,这里我给出一个demo,就是获取usb摄像头的图像字节信息并绘制在对话框上。
主要代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
unsigned char *Scrbuffer; int V_W = 640; int V_H = 480; bool m_bExit; unsigned char *Buffer = new unsigned char[V_W*V_H * 3]; Scrbuffer = Buffer; videoInput video; int deviceID = 0;//the index of camera, if there is only one camera, deviceID is 0 if (!video.setupDevice(deviceID, V_W, V_H)) { CString strMsg("无法打开摄像头!"); AfxMessageBox(strMsg); } while (true) { if (video.isFrameNew(deviceID)) { video.getPixels(deviceID, Buffer, false, true);//get pixels of a frame pDlg->VdoFrameData(0, Buffer, V_W*V_H * 3, param); } } //you must stop device here before thread exit, otherwise it will cause some system problems //and the thread will not release the camera resources //which makes any other thread can't open the camera even untill the system restarts video.stopDevice(deviceID); delete[]Buffer; |
为了实际可用,demo里另开了个线程完成上述功能,完善了线程同步,如退出通知,公共变量互斥,并完成了图像绘制。
图像绘制代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
CPaintDC dc(this); CDC m_dcMem; CBitmap m_bmpMem; CBitmap * m_pOldBmp; CRect m_rtClient; GetClientRect(&m_rtClient); m_dcMem.CreateCompatibleDC(&dc); Gdiplus::Graphics m_pGraph(m_dcMem.m_hDC); m_bmpMem.CreateCompatibleBitmap(&dc, m_rtClient.Width(), m_rtClient.Height()); m_pOldBmp = m_dcMem.SelectObject(&m_bmpMem); m_pGraph.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);//抗锯齿 EnterCriticalSection(&m_csBuffer); DrawPixels(m_dcMem,Scrbuffer, V_W, V_H); LeaveCriticalSection(&m_csBuffer); dc.BitBlt(0, 0, m_rtClient.Width(), m_rtClient.Height(), &m_dcMem, 0, 0, SRCCOPY);//将内存DC上的图象拷贝到前台 m_pGraph.ReleaseHDC(dc.GetSafeHdc()); m_dcMem.SelectObject(m_pOldBmp); m_bmpMem.DeleteObject(); m_dcMem.DeleteDC(); int CUSBCameraDemoDlg::DrawPixels(CDC& m_dcMem,unsigned char* pPixels,int nWidth,int nHeight , bool bMirror=false){ CDC memDC; memDC.CreateCompatibleDC(&m_dcMem); CRect m_rtClient; GetClientRect(&m_rtClient); CBitmap bmpMem; bmpMem.CreateCompatibleBitmap(&m_dcMem, nWidth,nHeight); BITMAP bmp; bmpMem.GetBitmap(&bmp); int pixelBits = bmp.bmBitsPixel; int pixelBytes = pixelBits / 8; DWORD dwSize = bmp.bmHeight * bmp.bmWidthBytes; unsigned char* pBits = new unsigned char[dwSize]; int i, j; for (i = 0; i < bmp.bmHeight; i++){ for (j = 0; j < bmp.bmWidth; j++){ //24bits format: BGR //32bits format: BGRA unsigned char * pPixelStart = pBits + i*bmp.bmWidthBytes + j* pixelBytes; unsigned char * pSrcStart = pPixels + i* bmp.bmWidth*3 + (bMirror?(bmp.bmWidth - j):j)*3; pPixelStart[0] = pSrcStart[0]; pPixelStart[1] = pSrcStart[1]; pPixelStart[2] = pSrcStart[2]; pPixelStart[3] = 0; } } bmpMem.SetBitmapBits(dwSize,pBits); CBitmap* pOldBmp = memDC.SelectObject(&bmpMem); m_dcMem.StretchBlt(0, 0, m_rtClient.Width(), m_rtClient.Height(), &memDC,0,0,nWidth ,nHeight,SRCCOPY); memDC.SelectObject(pOldBmp); delete[] pBits; bmpMem.DeleteObject(); memDC.DeleteDC(); //DrawImage("Capture1.jpg", m_rtClient); //m_dcMem.SetBkColor(RGB(0, 255, 255)); return 0; } |
demo示意图:
下载demo请到:
或者:
https://github.com/atp798/BlogStraka/tree/master/USBCameraDemo