用Opencv+树莓派+socket 实现远程监控
网上现在很多基于树莓派的远程监控都是用的ssh来完成的,但是这样不能获取实时图片数据用于后续处理,这里介绍的是一种利用socket编程通过TCP协议实现的网络传输,以实时获取画面。
材料:树莓派(我用的3b+),一个免驱摄像头,一台电脑
准备工作:树莓派安装系统,同时配置opencv,树莓派和电脑在同一局域网。
1实现原理
远程监控自然分为两端,一边是边缘端用于获取图像信息并且发送图片信息,另一边也就是接收端用于接受图像信息并显示在屏幕上。
1.1 图像传输方法
这里使用的是socket编程通过TCP协议传输图像信息,具体的socket编程相关原理这里不做详细赘述。但是有人会问,图像信息是怎么通过TCP传输的呢,这里用到了opencv自带的图像解编码函数:
cv::imencode Mat数据编码成数据流
cv::imdecode 数据流解码成Mat
通过imencode将图片信息变成数据流,用于传输,PC端接到后再用imdecode函数解码为Mat类型数据。
1.2边缘端
将摄像头插到树莓派上,并用5v,2.5A的电源给树莓派供电,使用前记得给摄像头使能。我用纸盒做了一个简单的定型。
1.3 PC端
PC端这边用的VS2013+opencv2.49,代码如下(代码中的树莓派IP可以在树莓派中输入 sudo ifconfig 里面的wlan0里面获取,注意树莓派和PC要在同一局域网下):
#include <iostream>
#include <string>
#include <WinSock2.h> //包含WinSock2.h头文件
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
#pragma comment(lib, "ws2_32.lib") //加载 ws2_32.dll
#pragma warning(disable:4996)
#define BUF_SIZE 100
int main()
{
//****初始化
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//****创建套接字
SOCKET sock = socket(PF_INET, SOCK_STREAM, 0);
//****创建sockAddr结构体
sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = PF_INET;
sockAddr.sin_port = htons(18000);
sockAddr.sin_addr.s_addr = inet_addr("192.168.1.100"); //树莓派的局域网IP
//****建立连接
connect(sock, (SOCKADDR*)& sockAddr, sizeof(SOCKADDR));
cout << "客户端发送链接请求" << endl;
char tack[20000] = { 0 };
//****接收服务器传回的数据
Mat src;
Mat test = Mat::zeros(Size(300, 300), CV_8UC1);
Mat tring = Mat::zeros(Size(300, 300), CV_8UC1);
namedWindow("src", CV_WINDOW_AUTOSIZE);
int label = 0;
Mat t;
while (1)
{
if (recv(sock, tack, 18000, NULL) != (-1)) {
cout << "等待服务端发送信息.." << endl;
//cout << tack << endl;
cout << strlen(tack) << endl;
if (strlen(tack) != 4) {
label = 0;
memset(tack, 0, 20000); //重置缓冲区
continue;
}
else {
label = 1;
}
//输出接收到的数据
if (strlen(tack) == 4 && label == 1) {
label = 1;
vector<uchar>end;
for (int i = 0; i < 18000; i++)
{
end.push_back(tack[i]);
}
src = imdecode(end, 1);
if (!src.data){
printf("no image");
src = t;
}
else{
src.copyTo(t);
}
medianBlur(src, src, 5); //去噪
imshow("src", src);
waitKey(10);
}
else {
continue;
}
memset(tack, 0, 20000); //重置缓冲区
}
}
//关闭套接字、终止使用 DLL
closesocket(sock);
WSACleanup();
return 0;
}
2 实验效果
把树莓派放在窗户边上:
先运行树莓派上的程序(我用的电脑自带的远程桌面操作),树莓派和电脑端显示如下所示: