MFC 用摄像头拍照并灰度化处理, MFC ,DirectShow,BMP图片
用摄像头拍照,把图片灰度化处理,也可以二值化处理,不过二值化后惨不忍睹,估计对特定的事物还是可以的,对一般性事物简单的处理就不适用了。
运行效果如下图:
主要的程序段:
XDShow是摄像头的接口,因为有两个摄像头,枚举后绑定了第二个。
XDShow.h
#pragma once #include <atlbase.h> #include <dshow.h> class CXDShow { public: CXDShow(void); ~CXDShow(void); public: HRESULT hr; IGraphBuilder *pGraph; ICreateDevEnum *pSysDevEnum; IEnumMoniker *pEnumCat; IMoniker*pMoniker; IMoniker*pMoniker2; ULONG cFetched; IBaseFilter *pFilter; IBaseFilter* pvideo; IMediaControl *pControl; IPin *pOut; IPin *pIn; IBasicVideo * basevideo; IVideoWindow* m_pVW; //xgz int DShowInit(); int Open(HWND hWnd); int CaptureBMP(byte* &buffer, long& bitmapsize); int SaveBMP(); };
XDShow.cpp
#include "StdAfx.h" #include "XDShow.h" #include "XGT.h" #pragma comment(lib,"Strmiids.lib") CXDShow::CXDShow(void) { } CXDShow::~CXDShow(void) { } int CXDShow::DShowInit() { PRINT(_T("\r\n CXDShow::DShowInit")); hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); //Initializes COM return 1; } int CXDShow::Open(HWND hWnd) { //PRINT(_T("\r\n CXDShow::OnTest1")); hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum); hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); hr = pEnumCat->Next(1, &pMoniker, &cFetched); //camero1 IPropertyBag *pPropBag; VARIANT varName; if(hr == S_OK) { hr=pMoniker->BindToStorage(0,0,IID_IPropertyBag,(void**)&pPropBag); VariantInit(&varName); hr=pPropBag->Read(L"FriendlyName",&varName,0); PRINT(_T("\r\n Camero Name = %s"),varName.bstrVal); } hr = pEnumCat->Next(1, &pMoniker2, &cFetched); //camero2 if(hr == S_OK) { hr=pMoniker2->BindToStorage(0,0,IID_IPropertyBag,(void**)&pPropBag); VariantInit(&varName); hr=pPropBag->Read(L"FriendlyName",&varName,0); PRINT(_T("\r\n Camero Name = %s"),varName.bstrVal); } pPropBag->Release(); //hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter); hr = pMoniker2->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter); //用 camero2 hr = pGraph->AddFilter(pFilter, L"filter1"); hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl); hr = CoCreateInstance(CLSID_VideoMixingRenderer9, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pvideo)); hr = pGraph->AddFilter(pvideo, L"video1"); IEnumPins *pEnum = 0; hr = pFilter->EnumPins(&pEnum); hr = pEnum->Next(1, &pOut, NULL); pEnum->Release(); hr = pvideo->EnumPins(&pEnum); hr = pEnum->Next(1, &pIn, NULL); pEnum->Release(); hr = pGraph->Connect(pOut, pIn); pvideo->QueryInterface(IID_IBasicVideo, (void **)&basevideo); //------------- pGraph->QueryInterface(IID_IVideoWindow, (void **)&m_pVW); m_pVW->SetWindowPosition(0, 0, 400, 300); m_pVW->put_Owner((OAHWND)hWnd); m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS); //--------- hr = pControl->Run(); return 0; } int CXDShow::CaptureBMP(byte* &buffer, long &bitmapsize) { //long bitmapsize = 0; hr = basevideo->GetCurrentImage(&bitmapsize, 0); //byte* buffer = new byte[bitmapsize]; buffer = new byte[bitmapsize]; hr = basevideo->GetCurrentImage(&bitmapsize, (long*)buffer); return 0; } int CXDShow::SaveBMP() { PRINT(_T("\r\n CXDShow::SaveBMP")); long bitmapsize = 0; hr = basevideo->GetCurrentImage(&bitmapsize, 0); byte* buffer = new byte[bitmapsize]; hr = basevideo->GetCurrentImage(&bitmapsize, (long *)buffer); BITMAPFILEHEADER hdr; LPBITMAPINFOHEADER lpbi; lpbi = (LPBITMAPINFOHEADER)buffer; int ncolors = 0; hdr.bfType = ((WORD)('M' << 8) | 'B'); hdr.bfSize = bitmapsize + sizeof(hdr); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = (DWORD)(sizeof(hdr) + lpbi->biSize + ncolors * sizeof(RGBQUAD)); FILE *fp=NULL; int len; fp=fopen("test.bmp", "wb"); if(NULL == fp) PRINT(_T("\r\n Fail fopen")); len=fwrite(&hdr, sizeof(char), sizeof(hdr),fp); len=fwrite(buffer, sizeof(char), bitmapsize,fp); PRINT(_T("\r\n write = %d"),len); fclose(fp); delete[]buffer; return 0; }
主视图显示视频,拍照后打开从视图,显示照片并处理,用同一个文档传数据。
XGTView.h
// XGTView.h : interface of the CXGTView class // #pragma once #include "XDShow.h" class CXGTView : public CScrollView { protected: // create from serialization only CXGTView(); DECLARE_DYNCREATE(CXGTView) // Attributes public: CXGTDoc* GetDocument() const; // Operations public: CXDShow m_XDShow; // Overrides public: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: virtual void OnInitialUpdate(); // called first time after construct virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); // Implementation public: virtual ~CXGTView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected: afx_msg void OnFilePrintPreview(); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); DECLARE_MESSAGE_MAP() public: afx_msg void OnTestTest1(); }; #ifndef _DEBUG // debug version in XGTView.cpp inline CXGTDoc* CXGTView::GetDocument() const { return reinterpret_cast<CXGTDoc*>(m_pDocument); } #endif
XGTView.cpp
// XGTView.cpp : implementation of the CXGTView class // #include "stdafx.h" // SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail // and search filter handlers and allows sharing of document code with that project. #ifndef SHARED_HANDLERS #include "XGT.h" #endif #include "XGTDoc.h" #include "XGTView.h" #include "MainFrm.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CXGTView IMPLEMENT_DYNCREATE(CXGTView, CScrollView) BEGIN_MESSAGE_MAP(CXGTView, CScrollView) // Standard printing commands ON_COMMAND(ID_FILE_PRINT, &CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CXGTView::OnFilePrintPreview) ON_WM_CONTEXTMENU() ON_WM_RBUTTONUP() ON_COMMAND(IDM_TEST_TEST1, &CXGTView::OnTestTest1) END_MESSAGE_MAP() // CXGTView construction/destruction CXGTView::CXGTView() { // TODO: add construction code here } CXGTView::~CXGTView() { } BOOL CXGTView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CScrollView::PreCreateWindow(cs); } // CXGTView drawing void CXGTView::OnDraw(CDC* /*pDC*/) { CXGTDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: add draw code for native data here } void CXGTView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx = sizeTotal.cy = 100; SetScrollSizes(MM_TEXT, sizeTotal); m_XDShow.DShowInit(); m_XDShow.Open(m_hWnd); } // CXGTView printing void CXGTView::OnFilePrintPreview() { #ifndef SHARED_HANDLERS AFXPrintPreview(this); #endif } BOOL CXGTView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CXGTView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CXGTView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } void CXGTView::OnRButtonUp(UINT /* nFlags */, CPoint point) { ClientToScreen(&point); OnContextMenu(this, point); } void CXGTView::OnContextMenu(CWnd* /* pWnd */, CPoint point) { #ifndef SHARED_HANDLERS theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE); #endif } // CXGTView diagnostics #ifdef _DEBUG void CXGTView::AssertValid() const { CScrollView::AssertValid(); } void CXGTView::Dump(CDumpContext& dc) const { CScrollView::Dump(dc); } CXGTDoc* CXGTView::GetDocument() const // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CXGTDoc))); return (CXGTDoc*)m_pDocument; } #endif //_DEBUG // CXGTView message handlers void CXGTView::OnTestTest1() { // TODO: Add your command handler code here PRINT("OnTestTest1"); CXGTDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; m_XDShow.CaptureBMP(pDoc->m_pbuffer, pDoc->m_bitmapsize); CMainFrame* pMainFrame = (CMainFrame*)((CXGTApp*)AfxGetApp())->m_pMainWnd; CMDIChildWnd* pActiveChild = ((CMainFrame*)pMainFrame)->MDIGetActive(); CDocument* pDocument = pActiveChild->GetActiveDocument(); //得到doc指针 CMultiDocTemplate* pDocTemplate = ((CXGTApp*)AfxGetApp())->m_pDocTemplate[1]; CFrameWnd* pFrame = pDocTemplate->CreateNewFrame(pDocument, pActiveChild); //创建窗口 pDocTemplate->InitialUpdateFrame(pFrame, pDocument); //初始视图显示窗口?? }
照片显示和处理视图
XBMPView.h
// XBMPView.h : interface of the CXBMPView class // #pragma once class CXBMPView : public CScrollView { protected: // create from serialization only CXBMPView(); DECLARE_DYNCREATE(CXBMPView) // Attributes public: CXGTDoc* GetDocument() const; // Operations public: void ShowBMP(void* Data, int Len); // Overrides public: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: virtual void OnInitialUpdate(); // called first time after construct virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); // Implementation public: virtual ~CXBMPView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected: afx_msg void OnFilePrintPreview(); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); DECLARE_MESSAGE_MAP() public: afx_msg void OnTestTest1(); }; #ifndef _DEBUG // debug version in XGTView.cpp inline CXGTDoc* CXBMPView::GetDocument() const { return reinterpret_cast<CXGTDoc*>(m_pDocument); } #endif
XBMPView.cpp
// XGTView.cpp : implementation of the CXBMPView class // #include "stdafx.h" // SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail // and search filter handlers and allows sharing of document code with that project. #ifndef SHARED_HANDLERS #include "XGT.h" #endif #include "XGTDoc.h" #include "XBMPView.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CXBMPView IMPLEMENT_DYNCREATE(CXBMPView, CScrollView) BEGIN_MESSAGE_MAP(CXBMPView, CScrollView) // Standard printing commands ON_COMMAND(ID_FILE_PRINT, &CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CXBMPView::OnFilePrintPreview) ON_WM_CONTEXTMENU() ON_WM_RBUTTONUP() ON_COMMAND(IDM_TEST_TEST1, &CXBMPView::OnTestTest1) END_MESSAGE_MAP() // CXBMPView construction/destruction CXBMPView::CXBMPView() { // TODO: add construction code here } CXBMPView::~CXBMPView() { } BOOL CXBMPView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CScrollView::PreCreateWindow(cs); } // CXBMPView drawing void CXBMPView::OnDraw(CDC* /*pDC*/) { CXGTDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: add draw code for native data here ShowBMP((void*)pDoc->m_pbuffer, (int)pDoc->m_bitmapsize); } void CXBMPView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx = sizeTotal.cy = 100; SetScrollSizes(MM_TEXT, sizeTotal); } // CXBMPView printing void CXBMPView::OnFilePrintPreview() { #ifndef SHARED_HANDLERS AFXPrintPreview(this); #endif } BOOL CXBMPView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CXBMPView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CXBMPView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } void CXBMPView::OnRButtonUp(UINT /* nFlags */, CPoint point) { ClientToScreen(&point); OnContextMenu(this, point); } void CXBMPView::OnContextMenu(CWnd* /* pWnd */, CPoint point) { #ifndef SHARED_HANDLERS theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE); #endif } // CXBMPView diagnostics #ifdef _DEBUG void CXBMPView::AssertValid() const { CScrollView::AssertValid(); } void CXBMPView::Dump(CDumpContext& dc) const { CScrollView::Dump(dc); } CXGTDoc* CXBMPView::GetDocument() const // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CXGTDoc))); return (CXGTDoc*)m_pDocument; } #endif //_DEBUG // CXBMPView message handlers void CXBMPView::OnTestTest1() { // TODO: Add your command handler code here CXGTDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; unsigned char* pData; int DataLen; DataLen = pDoc->m_bitmapsize; if (DataLen == 0) return; pData = new unsigned char[DataLen]; memcpy(pData, (void*)pDoc->m_pbuffer, DataLen); LPBITMAPINFOHEADER lpbi; unsigned char* pBmpdata = NULL; lpbi = (LPBITMAPINFOHEADER)pData; int ncolors = 0; int OffsetN14 = (DWORD)(lpbi->biSize + ncolors * sizeof(RGBQUAD)); pBmpdata = (unsigned char*)(pData + OffsetN14); //这里是没有DIB头的 int bfWidth, bfHeight; int biBitCount; int bytesPerLine; int skip; int imageSize; //DIB 数据信息 bfWidth = lpbi->biWidth; bfHeight = lpbi->biHeight; biBitCount = lpbi->biBitCount; //32位 //内存数据映射 bytesPerLine = ((bfWidth * biBitCount + 31) >> 5) << 2;//bfWidth *3+skip skip = 4 - ((bfWidth * biBitCount) >> 3) & 3; imageSize = bytesPerLine * bfHeight; int door = 120; //二值化阈值 int R, G, B, A; int Gray; //处理内存数据 for (int i = 0; i < bfHeight; i++) //高度是反的 { for (int j = 0; j < bytesPerLine; j += 4) //宽度 转换为 行(列数) { B = pBmpdata[i * bytesPerLine + j]; //xgz 2022-07-26 RGB的排列顺序是BGR,小模式 G = pBmpdata[i * bytesPerLine + j + 1]; R = pBmpdata[i * bytesPerLine + j + 2]; A = pBmpdata[i * bytesPerLine + j + 3]; Gray = (R * 19595 + G * 38469 + B * 7472) >> 16; //if (Gray > door) Gray = 255; //else Gray = 0; pBmpdata[i * bytesPerLine + j] = Gray; pBmpdata[i * bytesPerLine + j + 1] = Gray; pBmpdata[i * bytesPerLine + j + 2] = Gray; } } //pDoc->UpdateAllViews(NULL); ShowBMP(pData, DataLen); delete pData; } void CXBMPView::ShowBMP(void* Data, int Len) { unsigned char* pData; int DataLen; pData = (unsigned char*)Data; DataLen = Len; if (DataLen == 0) return; BITMAPFILEHEADER hdr; LPBITMAPINFOHEADER lpbi; BITMAPINFOHEADER bmpInfo;//信息头 memcpy(&bmpInfo, pData, 40); //没有DIB头 unsigned char* pBmpdata = NULL; lpbi = (LPBITMAPINFOHEADER)pData; //没有DIB头 int ncolors = 0; int bfOffBits = (DWORD)(14 + lpbi->biSize + ncolors * sizeof(RGBQUAD)); pBmpdata = (unsigned char*)(pData + bfOffBits -14); CSize sizeTotal; sizeTotal.cx = lpbi->biWidth; sizeTotal.cy = lpbi->biHeight; SetScrollSizes(MM_TEXT, sizeTotal); CRect rt; GetClientRect(&rt); CDC* pDC = GetDC(); pDC->SetStretchBltMode(COLORONCOLOR); StretchDIBits(pDC->GetSafeHdc(), 0, 0, rt.Width(), rt.Height(), 0, 0, lpbi->biWidth, lpbi->biHeight, pBmpdata, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS, SRCCOPY); }