使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发

1.使用MFC搭建框架

配置:

  1. Window10
  2. VS2013
  3. opencv249
    如果VS和opencv配置不一样,让版本对应
    Opencv与VS版本

1.1 MFC项目搭建

使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第1张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第2张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第3张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第4张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第5张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第6张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第7张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第8张图片
通过这些步骤就创建了一个MFC基础项目。

1.2项目属性配置

本项目因为要使用opencv,所以就要配置以下opencv的环境
首先在opencv官网下载opencv,此次使用opencv2.4.9,下载完并且完成安装
接下来就是VS项目配置(Release)发行版
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第9张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第10张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第11张图片

1.3项目页面设计

使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第12张图片
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第13张图片
点击左边的Toolbox(工具栏),选择相应的控件。这里我们的Win端用作服务器,界面主要显示传过来的图片,所以只需要一个Picture Control(图像控件)
可以右键单击界面三个控件,删除,然后将界面窗口右键拉到合适的大小,然后点击工具栏的控件,长按右键进行布置。
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第14张图片
界面设计好后就可以进行代码的编写。

1.3代码编写

编写代码主要是以下两个文件

  1. xxxDlg.h
  2. xxxDlg.cpp

xxxDlg.h头文件编写

头文件主要引用要使用的头文件,定义socket变量,定义消息函数和消息宏

// MFCApplication1Dlg.h : 头文件
//

#pragma once
#include 
#include "afxsock.h"
#include 
#pragma comment(lib,"ws2_32.lib")
using namespace cv;

#define WM_CLIENT_READVIDEO WM_USER+103

// CMFCApplication1Dlg 对话框
class CMFCApplication1Dlg : public CDialogEx
{
// 构造
public:
	CMFCApplication1Dlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_MFCAPPLICATION1_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
    //添加代码,定义消息函数
	LRESULT OnReadVideo(WPARAM wParam, LPARAM lParam);  //自定义

public:
	//文件预留的两个按钮
	afx_msg void OnBnClickedCancel();
	afx_msg void OnBnClickedOk();


	//添加代码,接收视频socket
	SOCKET videoSock;
	SOCKADDR_IN videoSockLocal;
	SOCKADDR_IN rcv_addr;  //存放不需要的IP
	int sockLen = sizeof(SOCKADDR);
	CStatic		 m_picture;          //picture control控件
};

xxxDlg.cpp文件编写

主要就是编写MFC能够嵌入Opencv的图像,消息函数,确定和取消函数。


// MFCApplication1Dlg.cpp : 实现文件
//

#include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCApplication1Dlg 对话框



CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CMFCApplication1Dlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	//绑定变量
	DDX_Control(pDX, IDC_PIC1, m_picture);
}

BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDCANCEL, &CMFCApplication1Dlg::OnBnClickedCancel)
	ON_BN_CLICKED(IDOK, &CMFCApplication1Dlg::OnBnClickedOk)

    //添加消息
	ON_MESSAGE(WM_CLIENT_READVIDEO, &CMFCApplication1Dlg::OnReadVideo)
END_MESSAGE_MAP()


// CMFCApplication1Dlg 消息处理程序

BOOL CMFCApplication1Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO:  在此添加额外的初始化代码

	//将opencv嵌入到MFC
	CRect rect1;
	m_picture.GetWindowRect(rect1); //获取picture control控件变量的rect
	namedWindow("client", CV_WINDOW_NORMAL);//可以改变窗口大小
	resizeWindow("client", rect1.Width(), rect1.Height());//根据piccontrol的大小设置opencv窗口的大小											
	HWND hWnd = (HWND)cvGetWindowHandle("client");//嵌套opencv窗口
	HWND hParent = ::GetParent(hWnd);
	::SetParent(hWnd, GetDlgItem(IDC_PIC1)->m_hWnd);
	::ShowWindow(hParent, SW_HIDE);

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCApplication1Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

//接收视频消息函数
LRESULT CMFCApplication1Dlg::OnReadVideo(WPARAM wParam, LPARAM lParam)
{
	char rcv_video[640*480];
	switch (WSAGETSELECTEVENT(lParam))
	{
	case FD_READ:
		//定义图片数据
		Mat img_decode; // = Mat::zeros(3, 3, CV_8UC1)
		vector<uchar>img_data;
		int srcLen = recvfrom(videoSock, rcv_video, sizeof(rcv_video), 0, (SOCKADDR*)&rcv_addr, &sockLen);
		if (srcLen>0)
		{
			vector<uchar> decode(&rcv_video[0], &rcv_video[srcLen]);//直接告诉buf的地址空间  减少一次内存拷贝	
			Mat srcimg = imdecode(decode, CV_LOAD_IMAGE_COLOR);//opencv的解码函数imdecode将每一帧图片的字节序decode解码为image图片
			if (srcimg.rows != 0 && srcimg.cols != 0)
			{
				imshow("client" + 0, srcimg);//循环显示美贞图片成为视屏。
			}
		}
	}
	return 0;
}

//软件退出
void CMFCApplication1Dlg::OnBnClickedCancel()
{
	// TODO:  在此添加控件通知处理程序代码
	closesocket(videoSock);
	WSACleanup(); //释放DLL资源
	exit(0);
}

//确定开启
void CMFCApplication1Dlg::OnBnClickedOk()
{
	// TODO:  在此添加控件通知处理程序代码
	//初始化与绑定
	WSADATA wsaData;
	int iErrorCode;
	if (WSAStartup(MAKEWORD(2, 1), &wsaData))//调用Windows Socket DLL
	{
		WSACleanup();
		return;
	}
	//绑定本机IP地址
	videoSock = socket(AF_INET, SOCK_DGRAM, 0);
	videoSockLocal.sin_family = AF_INET;
	videoSockLocal.sin_addr.S_un.S_addr = INADDR_ANY;
	//确定端口,客户端也要一致
	videoSockLocal.sin_port = htons(8898);
	if (::bind(videoSock, (SOCKADDR *)&videoSockLocal, sizeof(SOCKADDR)) == SOCKET_ERROR)
	{
		WSACleanup();
		return;
	}
	else
	{
		iErrorCode = WSAAsyncSelect(videoSock, m_hWnd, WM_CLIENT_READVIDEO, FD_READ);
		if (iErrorCode == SOCKET_ERROR)
		{
			return;
		}
	}
}

最终效果演示。
使用SOCKET搭建linux和window实现实时摄像头传输(linux传输win端使用C++mfc显示)--Win端开发_第15张图片
此项目Window端

你可能感兴趣的:(随笔,mfc,c++,linux)