封装的摄像头类

/*
这个类目前封装了三种采集卡的摄像头:两个模拟摄像头采集卡MV-750,MV-E8000;个数字摄像头采集卡MV-1300。
与一个学长共同完成,是完成的第一个感觉很满意的类,今天整理了一下发出来。
对外接口:载入,打开,关闭,拍照。
希望给对学习类封装的同学有点帮助。
采集卡、摄像头是北京维视的。
                          by l0g1n
CameraV1.h
*/
#pragma once

#include"stdafx.h"
#include <string>
using namespace std;
#include "HVDAILT.h"
#include "Raw2Rgb.h"
#include "HVDef.h"
#include "HVUtil.h"
#include "DVRSDK.H"
#include "DSStream.h"
#pragma comment(lib,"hvdailt.lib")
#pragma comment(lib,"raw2rgb.lib")
#pragma comment(lib,"HVUtil.lib")
#pragma comment(lib,"DVRSDK.lib")
#pragma comment(lib,"DSStream.lib")
class Camera
{
public:
	Camera():m_pWindow(NULL),m_image_buffer(NULL),m_nCameraID(-1), m_nWindowID(0)
	{}
	~Camera();
public:
	//传入参数,窗口显示所在类指针、窗口ID、摄像头通道号、摄像头名称
	void Attach(CWnd* pWnd,int nWindowID,int m_CameraID,string CameraName);
	bool open();
	void close();
	bool capture(char* s_pic_name);
	bool capture(string s_pic_name);
	bool capture(CString s_pic_name);
protected:
	CWnd* m_pWindow;
	char* m_image_buffer;
	unsigned m_nWindowID;
	int m_nCameraID;
protected:
	void InitCamera(string& CameraName);
public:
	static int CALLBACK SnapThreadCallback(HV_SNAP_INFO *pInfo);  ///English:    ///Chinese: 回调函数声明
	afx_msg LRESULT OnSnapChange(WPARAM wParam, LPARAM lParam);
	void HVGetDeviceInfo_Resolution();
	HV_BAYER_LAYOUT HVGetDeviceInfo_Bayer_Layout();
	void InitMV1300();
	void InitMV750();
	void InitMVE8000();
	bool openMV1300();
	bool openMV750();
	bool openMVE8000();
	void closeMV1300();
	void closeMV750();
	void closeMVE8000();
	bool captureMV750(char* s_pic_name);
	bool captureMV1300(char* s_pic_name);
	bool captureMVE8000(char* s_pic_name);
	
private:
	BITMAPINFO	*m_pBmpInfo;       ///English:    ///Chinese: BITMAPINFO 结构指针,显示图像时使用
	BYTE		*m_pImageBuffer;   ///English:    ///Chinese: Bayer转换后缓冲区
	BYTE		*m_pRawBuffer;     ///English:    ///Chinese: 采集图像原始数据缓冲区
	char		m_chBmpBuf[2048];  ///English:    ///Chinese: BIMTAPINFO 存储缓冲区,m_pBmpInfo即指向此缓冲区
	int m_nMaxWid;  ///English:    ///Chinese: 分辨率最大宽度
	int m_nMaxHei;  ///English:    ///Chinese: 分辨率最大高度
	/*///English:    ///Chinese: 颜色查找表*/
	BYTE		m_pLutR[256];
	BYTE		m_pLutG[256];
	BYTE		m_pLutB[256];
	HV_BAYER_LAYOUT  m_BayerType;
	HHV	      m_hhv;     ///English:    ///Chinese: 数字摄像机句柄
	HVSTATUS  status;    ///English:    ///Chinese: 设备状态
	string m_sCameraName;
};
//CameraV1.cpp
#pragma once
#include "stdafx.h"
#include "CameraV1.h"
const HV_BAYER_CONVERT_TYPE ConvertType = BAYER2RGB_NEIGHBOUR;    ///English:    ///Chinese: Raw2RGB算法
Camera::~Camera()
{
}
void Camera::InitCamera(string& CameraName)
{
	if(CameraName=="MV_1300")
	{
		m_sCameraName=CameraName;
		InitMV1300();
		return;
	}
	if(CameraName=="MV_750")
	{
		m_sCameraName=CameraName;
		InitMV750();
		return;
	}
	if(CameraName=="MV_E8000")
	{
		m_sCameraName=CameraName;
		InitMVE8000();
		return;
	}
	throw runtime_error("Camera"+CameraName+"not supported!");
}
void Camera::HVGetDeviceInfo_Resolution()  ///English:    ///Chinese: 获得摄像机分辨率
{
    int nResolution_Size; ///English:    ///Chinese: 获得DESC_RESOLUTION所需空间的大小

	status = HVGetDeviceInfo(m_hhv, DESC_RESOLUTION, NULL,&nResolution_Size);	          
	if (STATUS_OK != status)
	{
		AfxMessageBox(HVGetErrorString(status));
	}
	else
	{
		BYTE  *pbContext = NULL;
		pbContext = new BYTE[nResolution_Size];
		DWORD *pdContext = (DWORD *)pbContext;
		status = HVGetDeviceInfo(m_hhv, DESC_RESOLUTION, pdContext,&nResolution_Size);
		if (STATUS_OK != status)
		{
			if (NULL !=pbContext) {
				delete []pbContext;  ///English:    ///Chinese: 释放空间
				pbContext=NULL;
			}			
			AfxMessageBox(HVGetErrorString(status));
		}
		else
		{		
			int nWid,nHei;
			int nCon = 0;
			
			for(int i = 0;i < (nResolution_Size/8);i++) /*///English:    ///Chinese: (nResolution_Size/8)表示摄像机分辨率的数量*/
			{                                           /*///English:    ///Chinese: CCD摄像机只有一种分辨率 */
				nWid = *(pdContext + 2*nCon + 0 );
				nHei = *(pdContext + 2*nCon + 1 );
				
				m_nMaxWid = (m_nMaxWid>nWid)? m_nMaxWid:nWid;  ///English:    ///Chinese:  获得分辨率最大宽 
				m_nMaxHei = (m_nMaxHei>nHei)? m_nMaxHei:nHei;  ///English:    ///Chinese:  获得分辨率最大高
							
				nCon+=1;
			}
		}
		if (NULL !=pbContext) {
			delete []pbContext;  ///English:    ///Chinese: 释放空间
			pbContext=NULL;
		}
	}
}
HV_BAYER_LAYOUT Camera::HVGetDeviceInfo_Bayer_Layout() ///English:    ///Chinese: 获得摄像机的BAYER数据格式
{
    int nBayerLayout_Size;  ///English:    ///Chinese: 获得DESC_DEVICE_BAYER_LAYOUT所需空间的大小

	HV_BAYER_LAYOUT Layout; ///English:    ///Chinese: Bayer格式
	status = HVGetDeviceInfo(m_hhv, DESC_DEVICE_BAYER_LAYOUT, NULL,&nBayerLayout_Size);	          
    if(STATUS_OK != status)
	{
		AfxMessageBox(HVGetErrorString(status));
	}
	else
	{
		BYTE *pbBayerLayout = NULL;
		pbBayerLayout = new BYTE[nBayerLayout_Size];
		DWORD *pdBayerLayout = (DWORD *)pbBayerLayout;
        status = HVGetDeviceInfo(m_hhv, DESC_DEVICE_BAYER_LAYOUT, pdBayerLayout,&nBayerLayout_Size);
		if(STATUS_OK != status)
		{
			if (NULL != pbBayerLayout) {
				delete []pbBayerLayout; ///English:    ///Chinese: 释放空间
				pbBayerLayout=NULL;
			}
			
			AfxMessageBox(HVGetErrorString(status));
		}
		else
		{			
			Layout = (HV_BAYER_LAYOUT)*pdBayerLayout;///English:    ///Chinese: 得到具体的Bayer格式信息
		}
		
		if (NULL != pbBayerLayout) {
			delete []pbBayerLayout; ///English:    ///Chinese: 释放空间
			pbBayerLayout=NULL;
		}
	}
	return Layout;
}
int CALLBACK Camera::SnapThreadCallback(HV_SNAP_INFO *pInfo)   ///English:    ///Chinese: 回调函数
{
	Camera* pDlg=(Camera*)(pInfo->pParam);
	pDlg->OnSnapChange(NULL,NULL);	
	return 1;
}
LRESULT Camera::OnSnapChange(WPARAM wParam, LPARAM lParam)  
{	
	CRect panesize;
	CRect position;	
	//获取窗口客户区的坐标
	((CStatic*)(m_pWindow->GetDlgItem(m_nWindowID)))->GetClientRect(&panesize);
	//返回指定窗口的边框矩形的尺寸
	((CStatic*)(m_pWindow->GetDlgItem(m_nWindowID)))->GetWindowRect(&position);
	CClientDC dc(m_pWindow);
	CDC* pDC=&dc;
	UINT panewidth;	
	UINT paneheight;
	panewidth=panesize.Width();
	paneheight=panesize.Height();
	//把屏幕上指定点的屏幕坐标转换成用户坐标
	m_pWindow->ScreenToClient(&position);
	SetStretchBltMode(dc.m_hDC,COLORONCOLOR);//使图片不失真
	
	///English:    ///Chinese: 将原始图像数据进行Bayer转换,转换后为24位。
    ///English:    ///Chinese: 同时将原始数据进行上下翻转
	ConvertBayer2Rgb(m_pImageBuffer, ///English:    ///Chinese: Bayer转换后缓冲区(输出)
		m_pRawBuffer,   ///English:    ///Chinese: 原始数据缓冲区(输入)
		m_nMaxWid,      ///English:    ///Chinese: 分辨率最大宽度
		m_nMaxHei,      ///English:    ///Chinese: 分辨率最大高度
		ConvertType,    ///English:    ///Chinese: Raw2RGB算法
		m_pLutR,        ///English:    ///Chinese: 颜色查找表(红)
		m_pLutG,        ///English:    ///Chinese: 颜色查找表(绿)
		m_pLutB,        ///English:    ///Chinese: 颜色查找表(蓝)
		true,          ///English:    ///Chinese: 是否翻转
		m_BayerType     ///English:    ///Chinese: Bayer格式
		);
	///English:    ///Chinese: 在视图客户区显示图像
	StretchDIBits(pDC->GetSafeHdc(),
		position.left,						
		position.top,
		panewidth,			     ///English:    ///Chinese: 显示窗口宽度
		paneheight,			     ///English:    ///Chinese: 显示窗口高度
		0,
		0,
		m_nMaxWid,			     ///English:    ///Chinese: 图像宽度
		m_nMaxHei,			     ///English:    ///Chinese: 图像高度
		m_pImageBuffer,          ///English:    ///Chinese: 8位灰度图像数据缓冲区
		m_pBmpInfo,			     ///English:    ///Chinese: BMP图像描述信息
		DIB_RGB_COLORS,
		SRCCOPY
		);
	return 1;
}

bool Camera::open()
{
	if(m_sCameraName=="MV_1300")
		return openMV1300();
	if(m_sCameraName=="MV_750")
		return openMV750();
	if(m_sCameraName=="MV_E8000")
		return openMVE8000();

}
void Camera::close()
{
	
	if(m_sCameraName=="MV_1300")
	{
		closeMV1300();
		return;
	}
	if(m_sCameraName=="MV_750")
	{
		closeMV750();
		return;
	}
	if(m_sCameraName=="MV_E8000")
	{
		closeMVE8000();
		return;
	}
}
bool Camera::capture(char* s_pic_name)
{
	if(m_sCameraName=="MV_1300")
		return captureMV1300(s_pic_name);
	if(m_sCameraName=="MV_750")
		return captureMV750(s_pic_name);
}
bool Camera::capture(string s_pic_name)
{
	return false;
}
bool Camera::capture(CString s_pic_name)
{
	char *name = s_pic_name.GetBuffer();
	return capture(name);
}
void Camera::Attach(CWnd* pWnd,int nWindowID,int nCameraID,string CameraName)
{
	m_pWindow=pWnd;
	m_nWindowID=nWindowID;
	m_nCameraID=nCameraID;
	InitCamera(CameraName);
}
void Camera::InitMV1300()
{
	status = BeginHVDevice(m_nCameraID,&m_hhv);   ///English:    ///Chinese: 打开摄像机
	HV_VERIFY(status);

	m_pBmpInfo		= NULL;  ///English:    ///Chinese: BMP图像信息
	m_pRawBuffer	= NULL;  ///English:    ///Chinese: 原始图像数据缓冲初始化
	m_pImageBuffer	= NULL;  ///English:    ///Chinese: Bayer转换后图像数据缓冲区初始化

	m_nMaxWid = 0;
	m_nMaxHei = 0;
	
	for(int i=0;i<256;i++)   ///English:    ///Chinese: 颜色查找表初始化hao
	{
		m_pLutR[i] = i;
		m_pLutG[i] = i;
		m_pLutB[i] = i;
	}
	HVGetDeviceInfo_Resolution();  ///English:    ///Chinese: 获得摄像机分辨率
	m_BayerType = HVGetDeviceInfo_Bayer_Layout();///English:    ///Chinese: Bayer格式
	m_pBmpInfo								= (BITMAPINFO *)m_chBmpBuf;
	///English:    ///Chinese: 初始化BITMAPINFO 结构,此结构在保存bmp文件、显示采集图像时使用
	m_pBmpInfo->bmiHeader.biSize			= sizeof(BITMAPINFOHEADER);
	///English:    ///Chinese: 图像宽度,一般为输出窗口宽度
	m_pBmpInfo->bmiHeader.biWidth			= m_nMaxWid;
	///English:    ///Chinese: 图像宽度,一般为输出窗口高度
	m_pBmpInfo->bmiHeader.biHeight			= m_nMaxHei;
	m_pBmpInfo->bmiHeader.biPlanes			= 1;
	m_pBmpInfo->bmiHeader.biBitCount		= 24;
	m_pBmpInfo->bmiHeader.biCompression		= BI_RGB;
	m_pBmpInfo->bmiHeader.biSizeImage		= 0;
	m_pBmpInfo->bmiHeader.biXPelsPerMeter	= 0;
	m_pBmpInfo->bmiHeader.biYPelsPerMeter	= 0;
	m_pBmpInfo->bmiHeader.biClrUsed			= 0;
	m_pBmpInfo->bmiHeader.biClrImportant	= 0;
	/*
	///English:    ///Chinese: 分配原始图像缓冲区,一般用来存储采集图像原始数据
	///English:    ///Chinese: 一般图像缓冲区大小由输出窗口大小和视频格式确定。
	*/
	m_pRawBuffer = new BYTE[m_nMaxWid * m_nMaxHei];
	ASSERT(m_pRawBuffer);
	/*
	///English:    ///Chinese: 分配Bayer转换后图像数据缓冲
	*/
	m_pImageBuffer = new BYTE[m_nMaxWid * m_nMaxHei * 3];
	ASSERT(m_pImageBuffer);
}
void Camera::InitMV750()
{
	HxnDVR_UnInit();
	HxnDVR_Init(m_pWindow->m_hWnd);
}
bool Camera::openMV1300()
{
	// TODO: 在此添加控件通知处理程序代码
	HVSTATUS status = STATUS_OK;		
	status = HVOpenSnap(m_hhv, SnapThreadCallback, this);					
	HV_VERIFY(status);
	if (HV_SUCCESS(status))
	{
		//m_bOpen = TRUE;		///English:    ///Chinese: 标志已经打开Snap环境
	}
	// TODO: 在此添加控件通知处理程序代码
	status = STATUS_OK;	
    /*
	///English:    ///Chinese: 启动数字摄像机采集图像到内存
	*/
	BYTE *ppBuf[1];
	ppBuf[0] = m_pRawBuffer;
	status = HVStartSnap(m_hhv, ppBuf,1);
	HV_VERIFY(status);
	if (HV_SUCCESS(status)) 
	{
		return true;
	}else
		return false;
}
bool Camera::openMV750()
{
	if(!HxnDVR_ConnectDevice(m_nCameraID))
		return false;
	if(!HxnDVR_SetWindowPos(m_nCameraID,(m_pWindow->GetDlgItem(m_nWindowID))->m_hWnd, NULL))
		return false;
	return true;
}

void Camera::closeMV1300()
{
	HVSTATUS status =STATUS_OK;
	///English:    ///Chinese: 停止采集图像到内存
	status = HVStopSnap(m_hhv);
	HV_VERIFY(status);
	if (HV_SUCCESS(status)) 
	{
		//m_bStart = FALSE;
	}
	status = STATUS_OK;
	/*
	///English:    ///Chinese: 终止数字摄像机采集图像到内存,同时释放所有采集环境,
	///English:    ///Chinese: 再次启动数字摄像机采集,必须重新初始化	
	*/
	status = HVCloseSnap(m_hhv);
	HV_VERIFY(status);
	
	if (HV_SUCCESS(status))
	{
		//m_bOpen		= FALSE;
		//m_bStart	= FALSE;
	}
}
void Camera::closeMV750()
{
	HxnDVR_DisconnectDevice (m_nCameraID);
	HxnDVR_UnInit ();
}
bool Camera::captureMV750(char* s_pic_name)
{
	return HxnDVR_SaveToJpgFile(m_nCameraID, s_pic_name,100);
}
bool Camera::captureMV1300(char* s_pic_name)
{
	return HVSaveJPEG(s_pic_name, m_pImageBuffer, (int)(m_pBmpInfo->bmiHeader.biWidth), 
					(int)(m_pBmpInfo->bmiHeader.biHeight), (int)(m_pBmpInfo->bmiHeader.biBitCount), TRUE, 100);
}
bool Camera::captureMVE8000(char* s_pic_name)
{
	HRESULT hr;
	hr=DSStream_SaveToJpgFile(m_nCameraID,s_pic_name,100);
	if(FAILED(hr))
	{
		MessageBox(NULL,TEXT("MV-E8000拍照失败"),TEXT("Error"),MB_OK);
		return false;
	}
	return true;
}

void Camera::InitMVE8000()
{
	HRESULT hr;
	hr=DSStream_Initialize();
	BOOL bIsConnected=TRUE;
	int iCardNumber;
	char szDeviceName[MAX_DEVICE_NUM][MAX_DEVICE_NAME_LEN];
	const char szMV[]={"MV"};

	hr=DSStream_EnumVideoCaptureDev(szDeviceName,&iCardNumber);
	if(FAILED(hr))
	{
		MessageBox(NULL,TEXT("枚举失败"),TEXT("Error"),MB_OK);
		return;
	}
	hr=DSStream_IsConnected(m_nCameraID,&bIsConnected);
	if(FAILED(hr))
	{
		bIsConnected=TRUE;
	}
	if(bIsConnected)
	{
		MessageBox(NULL,TEXT("无可用卡"),TEXT("Error"),MB_OK);
		return;
	}
	const BOOL bOverlay=FALSE;//多个卡不能同时使用该模式
	hr=DSStream_ConnectDevice(m_nCameraID,bOverlay);
	if(FAILED(hr))
	{
		MessageBox(NULL,TEXT("连接视频卡失败"),TEXT("Error"),MB_OK);
		return;
	}
	DSStream_SetOwnerWnd(m_nCameraID,m_pWindow->m_hWnd);
}

bool Camera::openMVE8000()
{
	CRect panesize,position;
	((CStatic*)(m_pWindow->GetDlgItem(m_nWindowID)))->GetClientRect(&panesize);
	//返回指定窗口的边框矩形的尺寸
	((CStatic*)(m_pWindow->GetDlgItem(m_nWindowID)))->GetWindowRect(&position);
	m_pWindow->ScreenToClient(&position);
	DSStream_SetWindowPos(m_nCameraID,position);
	HRESULT hr;
	hr=DSStream_SetStreamStatus(m_nCameraID, RUN);
	if(FAILED(hr))
	{
		MessageBox(NULL,TEXT("MV-E8000打开摄像头失败"),TEXT("Error"),MB_OK);
		return false;
	}
	return true;
}

void Camera::closeMVE8000()
{
	DSStream_SetStreamStatus(m_nCameraID, STOP);
}


你可能感兴趣的:(封装的摄像头类)