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

news2024/11/17 10:02:46

1.使用MFC搭建框架

配置:

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

1.1 MFC项目搭建

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过这些步骤就创建了一个MFC基础项目。

1.2项目属性配置

本项目因为要使用opencv,所以就要配置以下opencv的环境
首先在opencv官网下载opencv,此次使用opencv2.4.9,下载完并且完成安装
接下来就是VS项目配置(Release)发行版
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3项目页面设计

在这里插入图片描述
在这里插入图片描述
点击左边的Toolbox(工具栏),选择相应的控件。这里我们的Win端用作服务器,界面主要显示传过来的图片,所以只需要一个Picture Control(图像控件)
可以右键单击界面三个控件,删除,然后将界面窗口右键拉到合适的大小,然后点击工具栏的控件,长按右键进行布置。
在这里插入图片描述
界面设计好后就可以进行代码的编写。

1.3代码编写

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

  1. xxxDlg.h
  2. xxxDlg.cpp

xxxDlg.h头文件编写

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

// MFCApplication1Dlg.h : 头文件
//

#pragma once
#include <opencv2\opencv.hpp>
#include "afxsock.h"
#include <winsock2.h>
#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;
		}
	}
}

最终效果演示。
在这里插入图片描述
此项目Window端

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/655056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手机连接adb 相关问题汇总

目录 关于端口占用问题1 关于修改adb 端口配置问题2 方法3 方法4 关于端口占用问题1 转载链接&#xff1a;https://www.jianshu.com/p/902a89b06271 报错信息&#xff1a; error: no device/emulators found error: device still connecting 解决方案&#xff1a; 重启…

Day_50小结

目录 一. 比较和分析各种查找算法 二. 描述各种排序算法的特点和基本思想&#xff06;比较分析各种排序算法 1. 插入排序 2. 交换排序 3. 选择排序 4. 外部排序 三. 设计一个自己的 Hash 函数和一个冲突解决机制 1. 对于哈希函数的构造&#xff1a; 2. 处理冲突的办法&#…

Mybatis持久层框架 | Lombok搭建

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Lombok Lombok项目是一个java库&#xff0c;它可以自动插入到编辑器和构建工具中&#xff0c;增强java的性能。不需要再写getter、setter或equals方法&#xff0c;只要…

易语言使用node编译的js文件

环境配置 npm install -g cnpm babel-preset-env babel-cli babel-polyfill browserifynpm install -g crypto-js nodejs转js 例如加密模块 browserify -r babel-polyfill -r crypto-js -o es6.txt browserify file.js -o es6.txt易语言 使用v8 推荐 直接生成导入js即…

LMV331TP-TR 滞后比较器实现精确电压比较与判决

文章目录 LMV331TP-TR1. 滞后比较器的基本概念和作用2. LMV331TP-TR 的特性和规格2.1 工作电压范围2.2 输入电压偏置2.3 响应时间 3. LMV331TP-TR 的工作原理3.1 内部结构3.2 滞后器功能的实现原理 4. 实现准确比较和判决的案例 LMV331TP-TR LMV331TP-TR 是一款优秀的滞后比较…

机器学习之逻辑回归模型

1 逻辑回归模型介绍 逻辑回归(Logistic Regression, LR)又称为逻辑回归分析&#xff0c;是一种机器学习算法&#xff0c;属于分类和预测算法中的一种&#xff0c;主要用于解决二分类问题。逻辑回归通过历史数据的表现对未来结果发生的概率进行预测。例如&#xff0c;我们可以将…

web存储(Storage)

目录 1、基本概念 2、功能监测 2.1 测试可用性 2、W3C标准 3、基本方法或属性 4、 Local Storage 4.1 描述 4.2 示例 5、sessionStorage 5.1 描述 5.2 示例 6、StorageEvent&#xff08;存储事件&#xff09; 6.1 构造函数 6.2 实例属性 6.3 实例方法 6.4 响应…

chatgpt赋能python:Python自动缩进详解

Python 自动缩进详解 作为一门面向对象的高级编程语言&#xff0c;Python 其中一个非常重要的特性便是自动缩进。Python 中的代码块是通过缩进来表示的&#xff0c;而不是通过括号或其他方式。这对于刚开始学习 Python 的初学者来说可能是很困难的&#xff0c;但一旦掌握了这一…

开好会议的方法 会议达成共识 明确目标,促成共识 单向会议 互动会议 会议讨论,文档先行 会前文档 会中 3D法则讨论 同步会议,跟进代办 举个栗子 企业管理

目录 开好会的方法 明确目标&#xff0c;促成共识 单向会议 互动会议 会议讨论&#xff0c;文档先行 会前文档 会中 3D法则讨论 同步会议&#xff0c;跟进代办 举个栗子 开好会的方法 会议有时候时间很长&#xff0c;很多无意义内容&#xff0c;如何开出有意义有价值…

Linux学习之权限表现

groupadd grouptest1添加一个叫grouptest1的用户组。 useradd gooduser -g grouptest1添加一个叫gooduser 的用户&#xff0c;并把它添加到grouptest1用户组里边&#xff0c;id gooduser看一下用户的信息。 接下来进行测试用户和用户组权限。 普通文件 在root账户下&#xf…

AI Chat 设计模式:2. 工厂设计模式

本文是该系列的第二篇&#xff0c;采用问答式的方式展开&#xff0c;问题由我提出&#xff0c;答案由 Chat AI 作出&#xff0c;灰色背景的文字则主要是我的旁白。 问题列表 Q.1 介绍下工厂设计模式A.1Q.2 这种设计模式有哪几种形式A.2Q.3 使用c写一个简单工厂的例子A.3Q.4 我…

操作受限的线性表——队列

本文主要内容&#xff1a;介绍了队列的基本概念和基本操作&#xff0c;详细介绍了队列的顺序存储和链式存储。并介绍了循环队列和双端队列&#xff08;以及输入/输出受限的双端队列&#xff09;&#xff0c;及其基本操作。 目录 队列一、队列的基本概念1、基本概念2、基本操作…

计算机视觉-目标检测(二):从R-FCN到YOLO-v3

文章目录 1. R-FCN1.1 动机1.2. R-FCN 网络结构1.3. R-FCN 的损失函数1.4. R-FCN的训练及性能 2. YoLO-v12.1 简介2.2 YOLO-v1网络结构2.3 目标函数2.4 YOLO-v1的优缺点 3. YOLO-v23.1 YOLO-v2相比v1的优化 4. YOLO-v3参考 1. R-FCN 论文链接&#xff1a;R-FCN:Object Detecti…

java格式化数字 NumberFormat及DecimalFormat

一、JavaAPI官方描述 1、NumberFormat NumberFormat帮助您格式化和解析任何区域设置的数字。您的代码可以完全独立于小数点&#xff0c;千位分隔符的区域设置约定&#xff0c;甚至是使用的特定十进制数字&#xff0c;或者数字格式是否为十进制。 2、 DecimalFormat Decimal…

Linux之YUM管理工具

目录 Linux之YUM管理工具 定义 实现YUM的三个机制 RHEL8中yum源变化说明 案例 示例1 --- 建立本地光盘源&#xff08;本地yum源&#xff09; 示例2 --- 配置互联网源 yum(dnf)工具管理软件包 安装软件包 module子命令 案例 yum-config-manager的使用 定义 yum-conf…

Linux系统如何配置网络

Linux系统的三种网络模式&#xff1a; 桥接&#xff1a;可以和外部设备通信&#xff0c;主机和Ubuntu分别使用不同的IP地址NAT&#xff1a;可以和外部设备通信&#xff0c;主机和Ubuntu公用一个IP地址主机&#xff1a;只能和主机通信 在此我们介绍如何配置桥接网络&#xff1…

谓词的介绍与基本使用

&#x1f6a8;谓词 &#x1f6a6;概念 1.返回类型为bool的仿函数 2.接受一个参数—一元谓词 接受一个参数—二元谓词 &#x1f680;1.一元谓词 ⛽使用方法 因为返回值为bool类型&#xff0c;所以经常会将他使用成判断关系的函数 我们使用find_if&#xff08;&#xff09;对…

HBase 2.3.7中snappy压缩配置

本文将介绍如何在HBase 2.3.7中配置snappy压缩。snappy是一种快速的数据压缩和解压缩算法&#xff0c;可以提高HBase的存储空间利用率和读写性能。本文将使用HBase 2.3.7版本&#xff0c;运行在三个Ubuntu系统的虚拟机中&#xff0c;分别作为master和slave节点。 主要步骤如下…

【SpringBoot】SpringBoot Starter 作用及原理

文章目录 前言一、什么是 Starter二、Starter 的作用三、spring 整合组件四、spring-boot 整合组件五、Starter 原理 前言 有没有在入行后直接基于 SpringBoot 开发项目&#xff0c;没有 spring、servlet 开发经历的? 有没有用 SpringBoot 开发项目&#xff0c;但是第一次听…

服务注册中心Eureka

服务注册中心Eureka Eureka介绍Eureka 环境搭建Eureka 集群配置Eureka 的自我保护模式Eureka 架构图 Eureka介绍 在微服务架构中&#xff0c;有着许许多多的微服务&#xff0c;微服务之间需要彼此进行远程调用&#xff0c;需要知道彼此的地址&#xff0c;通过人工的方式去管理…