计算机视觉——利用openCV与Socket结合进行远程摄像头实时视频传输并保存图片数据

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文的内容是利用openCV与Socket结合进行远程摄像头实时视频传输并保存图片数据,其原理是由Client客户端采集摄像头图像后经Socket传输到Server服务器端再显示出来。同时服务器端可通过键盘按动截图并保存。

本文内容参考自:

https://blog.csdn.net/qq_43665891/article/details/104362386
https://blog.csdn.net/u012736685/article/details/77131633


一、TCP协议通信步骤

首先了解一下TCP协议的一般通信步骤。

客户端:
1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt();* 可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
  4、设置要连接的对方的IP地址和端口等属性;
  5、连接服务器,用函数connect();
  6、收发数据,用函数send()和recv(),或者read()和write();
  7、关闭网络连接;

服务器端:
1、创建一个socket,用函数socket();
  2、设置socket属性,用函数setsockopt(); * 可选
  3、绑定IP地址、端口等信息到socket上,用函数bind();
  4、开启监听,用函数listen();
  5、接收客户端上来的连接,用函数accept();
  6、收发数据,用函数send()和recv(),或者read()和write();
  7、关闭网络连接;
  8、关闭监听;

二、代码实现

1.客户端

代码如下(示例):

import socket
import struct
import time
import traceback

import cv2
import numpy


class Client(object):
    """客户端"""

    def __init__(self, addr_port=('192.168.29.1', 11000)):
        # 连接的服务器的地址
        # 连接的服务器的端口
        self.addr_port = addr_port
        # 创建套接字
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 地址端口可以复用
        self.client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # 分辨率
        self.resolution = (640, 480)


    def connect(self):
        """链接服务器"""
        try:
            self.client.connect(self.addr_port)
            return True
        except Exception as e:
            traceback.print_exc()  # 打印原始的异常信息
            print('连接失败')
            return False

    def send2server(self):
        """读摄像头数据 发送给服务器"""
        camera = cv2.VideoCapture(0)  # 摄像头对象
        print('isOpened:', camera.isOpened())

        while camera.isOpened():

            try:
                # 获取摄像头数据
                ret, frame = camera.read()
                # 对每一帧图片做大小处理 和大小的压缩
                frame = cv2.resize(frame, self.resolution)
                # 参1图片后缀名 参2 原图片的数据 参3图片质量 0-100 越大越清晰
                ret, img = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 100])
                # img 是被压缩后的数据 无法正常显示
                print(img)
                print('-------------')
                print(img.tostring())

                # 转换为numpy格式数据
                img_code = numpy.array(img)

                # 转为二进制数据
                img = img_code.tostring()

                # 获取数据长度
                length = len(img)

                # 发送的数据  大小 宽 高 图片数据

                # 数据打包变为二进制
                # pack方法参数1 指定打包数据的数据大小  i 4字节 h代表2字节
                all_data = struct.pack('ihh', length, self.resolution[0], self.resolution[1]) + img

                self.client.send(all_data)
                time.sleep(0.01)
            except:
                camera.release()  # 释放摄像头
                traceback.print_exc()
                return


if __name__ == '__main__':
    client = Client()
    if client.connect():
        client.send2server()

客户端说明

1 init方法完成套接字的初始化,传入地址和端口,设置视频的分辨率
2 connect方法 利用客户端的socket对象的connect方法 连接服务器
3 send方法 读取摄像头拍摄的数据, ( socekt对象只发送二进制的数据 ) 把数据处理成二进制 , struct包的pack方法把里面的参数打包好自动转成二进制 , 再利用send发送出去

2.服务端

代码如下(示例):

import socket
import struct
import threading
import cv2
import numpy
import os

class Server:
    def __init__(self):
        # 设置tcp服务端的socket
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置重复使用
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 绑定地址和端口
        self.server.bind(('192.168.29.1', 11000))
        # 设置被动监听
        self.server.listen(128)

    def run(self):
        while True:
            print('等待客户端连接')
            # 等待客户端连接
            client, addr = self.server.accept()
            ProcessClient(client).start()


class ProcessClient(threading.Thread):

    def __init__(self, client):
        super().__init__()
        self.client = client
		
		# 以下内容作用是根据文件夹的图片序号规定'i'的初值,方便下一次保存图片时使用
        self.i=0        
        path = "F:/sample"
        for root, dirs, files in os.walk(path, topdown=False):
            print(root)
            print(dirs)
            print(files)

        file_list = []
        for file in files:
            file = int(file.split('.')[0])
            file_list.append(file)

        if len(file_list) == 0:
            self.i = 0
        else:
            file_list.sort()
            self.i = file_list[-1] + 1


    def run(self):
        while True:
            data = self.client.recv(8)
            if not data:
                break
            # 图片的长度 图片的宽高
            length, width, height = struct.unpack('ihh', data)

            imgg = b''  # 存放最终的图片数据
            while length:
                # 接收图片
                temp_size = self.client.recv(length)
                length -= len(temp_size)  # 每次减去收到的数据大小
                imgg += temp_size  # 每次收到的数据存到img里

            # 把二进制数据还原
            data = numpy.fromstring(imgg, dtype='uint8')

            # 还原成矩阵数据
            image = cv2.imdecode(data, cv2.IMREAD_UNCHANGED)
            print(image)
          
          
            cv2.imshow('capture', image)
                # 保存图片
            k = cv2.waitKey(1)
            if k == ord('k'):
                cv2.imwrite(r"F:\sample\\" + str(self.i) + ".jpg", image) #存储路径
                self.i = self.i + 1
                print(self.i)
                # time.sleep(5)

            if k == ord('q'):
                break


if __name__ == '__main__':
    server = Server()
    server.run()

服务端说明:将服务端接受到的视频数据逆操作,即可得到原来的视频,然后用cv2.imshow显示视频。

三、IP设置方法

  1. 服务端cmd输入ipconfig查看ip地址
    在这里插入图片描述
    2.找到当前使用网络的ipv4地址,将服务端与客户端都设置成该地址,例如:本机现在使用的WIFI
    在这里插入图片描述
    那就将ip地址设置成如上ipv4地址(远程传输服务端需要申请公网ip)。

四、效果演示

切记先打开服务端,再打开客户端。
在这里插入图片描述
在这里插入图片描述
按’k’截图保存在本地,按‘q’关闭cv。

  • 12
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值