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);

}

 

posted @ 2022-07-24 21:02  XGZ21  阅读(336)  评论(0编辑  收藏  举报