前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python udp发送数据(http视频传输)

python udp发送数据(http视频传输)

作者头像
全栈程序员站长
发布2022-07-28 21:30:32
2.2K0
发布2022-07-28 21:30:32
举报

大家好,又见面了,我是你们的朋友全栈君。

一、前言

最近想写一个实时的视频传输程序,然后上网找了很久没有找到合适的

我想用OpenCV 进行图像采集,然后用pygame 将视频信号转化为可通过UDP 网络传输的字符流,然后到达终端后再通过pygame 对字符流进行解析,进而将图像显示出来

之所以使用UDP 传输而不是TCP 传输,是因为UDP 在视频传输方面拥有快速、无需连接等优点,适合密集传送大量信息的场合 但UDP 传输有一个问题,就是一次传输量有限,这就直接导致后续传输的视频信号需要进行一定压缩

所以我就开始自己捣鼓了 😃

本文内容若有不懂可查阅如下教程: Windows 安装pygame 模块 树莓派 与 Xbox360手柄 基于pygame 的一次邂逅 树莓派Camera 的使用 【手把手教学—超简单】树莓派安装OpenCV 3 Python + OpenCV 学习笔记(二)>>> 加载视频流 Python >>> UDP 网络编程

我是用树莓派作为视频采集端,然后笔记本作为信号接收端的

注意:PC端需关闭防火墙后方可成功接收数据!

在这里插入图片描述
在这里插入图片描述

二、开始

1)整体思路

  1. 在发送端使用OpenCV 打开摄像头采集视频帧信号;
  2. 将视频帧信号输出为jpg 图片文件;
  3. pygame 模块将该jpg 图片转化为字符流;
  4. 将该字符流通过UDP 传输到接收端;
  5. 接收端同样使用pygame 对字符流进行解析,最终即可获得图像信息。

2)摄像头采集视频帧

代码语言:javascript
复制
import cv2 as cv

capture = cv.VideoCapture(0)
while True:
	# 获得图像帧
	ret, frame = capture.read()
	# 图像翻转
	frame = cv.flip(frame, -1)
	# 将图像尺寸缩小,便于传输
	frame = cv.resize(frame, (160, 120))

3)将图像帧输出为图片

代码语言:javascript
复制
cv.imwrite("test.jpg", frame)

4)将图片转化为字符流

代码语言:javascript
复制
# 加载图片
Img = pygame.image.load('/home/pi/test.jpg')
# 图片转化字符串
string = pygame.image.tostring(Img, "RGB")

5)通过UDP 传输字符流

我创建了一个进程用于传输数据:

代码语言:javascript
复制
def mythread(sock, data, addr):
        sock.sendto(data, addr)
        print("已发送 " + str(len(data)) + " bytes")
        sock.close()

# socket.SOCK_DGRAM 代表是使用UDP协议
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
t = threading.Thread(target=mythread, args=(sock, string, ('192.168.0.196', 9999)))
t.start()

注意:当发送密集数据时,如图像数据等。需要控制图像大小(例如160*120),不然发不出去。

6)接收端接收数据并解析

代码语言:javascript
复制
# 创建连接
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口
s.bind(('192.168.0.196', 9999))
# 接收数据
data, addr = s.recvfrom(60000)

# 字符串再转化为图片
img = pygame.image.frombuffer(data, (180, 160), "RGB")

7)将图像显示出来

代码语言:javascript
复制
# 窗口内设置白色底色和图片,并更新显示
gameDisplay.fill(WHITE)
gameDisplay.blit(img, (0, 0))
pygame.display.update()

三、完整程序

1)发送端

代码语言:javascript
复制
#coding:utf-8
import pygame
import cv2 as cv
from picamera import PiCamera
import time
import threading
import socket

pygame.init()

# 传输视频信号的UDP 连接进程
def mythread(sock, data, addr):
        sock.sendto(data, addr)
        print("已发送 " + str(len(data)) + " bytes")
        sock.close()

def main():
        print("begin")
        start = time.clock()
        capture = cv.VideoCapture(0)
        while True:
                ret, frame = capture.read()
                frame = cv.flip(frame, -1)
                frame = cv.resize(frame, (160, 120))
                cv.imwrite("test.jpg", frame)
                # 加载图片
                Img = pygame.image.load('/home/pi/test.jpg')
                # 图片转化字符串
                string = pygame.image.tostring(Img, "RGB")
                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                t = threading.Thread(target=mythread, args=(sock, string, ('192.168.0.196', 9999)))
                t.start()
                if cv.waitKey(10) & 0xff == ord('q'):
                        break

main()
cv.destroyAllWindows()

2)接收端

代码语言:javascript
复制
#coding=utf-8
import socket
import time
import threading
import pygame

# 颜色
WHITE = (255,255,255)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 128)
BLACK = ( 0, 0, 0)

# 创建连接
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口
s.bind(('192.168.0.196', 9999))

print('Waiting for connection...')

pygame.init()

# 设置标题
pygame.display.set_caption('UDP 视频传输')

# 开启窗口
display_width = 300
display_height = 200
gameDisplay = pygame.display.set_mode((display_width,display_height))

# 判断是否结束pygame
gamefinish = False
# 帧率
frame_rate = 0

# 通过字体文件获得字体对象
fontObj = pygame.font.Font('C:/Windows/Fonts/comici.ttf', 20)
# 配置要显示的文字
textSurfaceObj = fontObj.render('FPS', True, BLACK, WHITE)
# 获得要显示的对象的rect
textRectObj = textSurfaceObj.get_rect()
# 设置显示对象的坐标
textRectObj.center = (200, 10)

# 用于视频显示delay
clock = pygame.time.Clock()
# 用于帧率计算
start = time.perf_counter()

while not gamefinish:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gamefinish = True
            print(event)

    # 无数据接收则线程挂起,等待数据
    data, addr = s.recvfrom(60000)
    frame_rate = frame_rate + 1
    if time.perf_counter() - start > 1:
        start = time.perf_counter()
        # 配置要显示的文字
        textSurfaceObj = fontObj.render(("FPS: " + str(frame_rate)), True, BLACK, WHITE)
        frame_rate = 0

    print('Received from %s:%s.' % addr)

    # 字符串再转化为图片
    img = pygame.image.frombuffer(data, (160, 120), "RGB")

    # 窗口内设置白色底色和图片,并更新显示
    gameDisplay.fill(WHITE)
    gameDisplay.blit(img, (0, 0))
    gameDisplay.blit(textSurfaceObj, textRectObj)
    pygame.display.update()
    clock.tick(60)

pygame.quit()

四、结果

在实际测试中,我发现160*120的分辨率对网络要求较高,而当分辨率降为80*60时则效果好一点(帧率基本在30左右): 当然,这样的话视频窗口显得很小。

在这里插入图片描述
在这里插入图片描述

我们可以在接收端对图像进行放大: (成像质量下降)

代码语言:javascript
复制
# 指定size 放大
img = pygame.transform.scale(img, (160, 120))
# 直接放大两倍
img = pygame.transform.scale2x(img)
在这里插入图片描述
在这里插入图片描述

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/128978.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年4月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、开始
    • 1)整体思路
      • 2)摄像头采集视频帧
        • 3)将图像帧输出为图片
          • 4)将图片转化为字符流
            • 5)通过UDP 传输字符流
              • 6)接收端接收数据并解析
                • 7)将图像显示出来
                • 三、完整程序
                  • 1)发送端
                    • 2)接收端
                    • 四、结果
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档