python实现windows同屏捕捉

Python使用OpenCV播放mss截取的桌面屏幕(包含本机和他机环境)

效果展示

python实现windows同屏捕捉

先上代码

本机环境 不区分服务器和用户端,便于理解基础运行原理
他机环境 区分服务器和用户端,额外需要理解网络传输的相关知识

原理

  1. 截屏获取当前桌面图像,参考python捕捉windows桌面
  2. 使用OpenCV显示图像,图像展示不全参考python-openCV展示图像不全的问题
with mss.mss() as sct:
    frame = sct.grab(monitor)
    cv2.imshow("Video", np.array(frame))
  1. 重复执行1~2,实现帧序列转视频
  2. 他机环境则需要搭建socket通道
  • 服务器
# 监听地址和端口
server_address = ("127.0.0.1", 8080)
# 创建TCP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定到指定地址和端口
sock.bind(server_address)
# 开始监听
sock.listen(1)
  • 用户端
# 远程服务器的地址和端口
server_address = ("127.0.0.1", 8080)
# 创建TCP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(server_address)
  1. 通过socket传输图像数据,首先需要客户端将图像转换成字节,服务器接收字节数据,再将字节转换成图像并展示
# 将图像转换为字节流
_, img_encoded = cv2.imencode(".png", frame)
img_bytes = img_encoded.tobytes()
#......
# 传输过程见下文
# ......
# 将字节流转换成图像
frame_cv = cv2.imdecode(np.frombuffer(img_bytes, np.uint8), cv2.IMREAD_UNCHANGED)
  1. socket传输过程,需要注意不同的图像由于像素差异,字节大小会变化,因此需要明确每张图片的数据读取边界,所以通常会在发送的图片数据前加一个消息头,用于存储图片大小等信息
  • 用户端
# 发送图像大小
size = len(img_bytes)
sock.sendall(size.to_bytes(4, byteorder="big"))
# 发送图像数据
sock.sendall(img_bytes)
  • 服务器
# 接收图像大小
size_bytes = conn.recv(4)
size = int.from_bytes(size_bytes, byteorder="big")
# 接收图像数据
img_bytes = b""
while len(img_bytes) < size:
    packet = conn.recv(size - len(img_bytes))
    if not packet:
        break
    img_bytes += packet

本机环境

按q键停止播放

import cv2
import mss
import numpy as np
import time

# 获取屏幕尺寸
with mss.mss() as sct:
    monitor = sct.monitors[0]
    screen_width = monitor["width"]
    screen_height = monitor["height"]

# 设置捕获区域(这里设置为整个屏幕)
monitor = {"top": 0, "left": 0, "width": screen_width, "height": screen_height}

# 设置帧速率(每秒30帧)
frame_rate = 30
with mss.mss() as sct:
    while True:
        begin = time.time()
        # 获取屏幕截图
        frame = sct.grab(monitor)
        # 显示帧
        cv2.namedWindow("Video", cv2.WINDOW_GUI_NORMAL)
        cv2.imshow("Video", np.array(frame))
        # 检测键盘输入
        key = cv2.waitKey(int(1000 / frame_rate)) & 0xFF

        # 如果按下 'q' 键,退出循环
        if key == ord("q"):
            break
        end = time.time()
        # 打印帧数
        print(1 / (end - begin))

cv2.destroyAllWindows()


他机环境

服务端

import cv2
import numpy as np
import threading
import socket
import time

frames = []


def initSocket():
    # 监听地址和端口
    server_address = ("", 8080)
    # 创建TCP套接字
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定到指定地址和端口
    sock.bind(server_address)
    # 开始监听
    sock.listen(1)
    print("等待连接...")
    while True:
        # 接受连接
        conn, addr = sock.accept()
        print("连接来自:", addr)
        try:
            while True:
                # 接收图像大小
                size_bytes = conn.recv(4)
                size = int.from_bytes(size_bytes, byteorder="big")
                # 接收图像数据
                frame = b""
                while len(frame) < size:
                    packet = conn.recv(size - len(frame))
                    if not packet:
                        break
                    frame += packet
                # 将字节流转换成图像
                frame_cv = cv2.imdecode(np.frombuffer(frame, np.uint8), cv2.IMREAD_UNCHANGED)
                # 展示图像
                frames.append(frame_cv)
        finally:
            conn.close()


def show():
    global frames
    # 设置最大帧速率
    frame_rate = 60
    while True:
        if len(frames) > 0:
            begin=time.time()
            frame = frames.pop(0)
            cv2.namedWindow("image", cv2.WINDOW_GUI_NORMAL)
            cv2.imshow("image", frame)
            cv2.waitKey(int(1000 / frame_rate))
            end=time.time()
            # 打印帧数
            print(1 / (end - begin))


if __name__ == "__main__":
    thread1 = threading.Thread(target=show)
    thread2 = threading.Thread(target=initSocket)
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()

用户端

import cv2
import mss
import numpy as np
import time
import socket


# 获取屏幕尺寸
with mss.mss() as sct:
    monitor = sct.monitors[0]
    screen_width = monitor["width"]
    screen_height = monitor["height"]

# 设置捕获区域(这里设置为整个屏幕)
monitor = {"top": 0, "left": 0, "width": screen_width, "height": screen_height}

# 远程服务器的地址和端口
server_address = ("127.0.0.1", 8080)
# 创建TCP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(server_address)
with mss.mss() as sct:
    while True:
        begin = time.time()
        # 获取屏幕截图
        frame = sct.grab(monitor)
        # 转换成OpenCV对象
        frame_cv = np.array(frame)
        # 将图像转换为字节流
        _, img_encoded = cv2.imencode(".png", frame_cv)
        img_bytes = img_encoded.tobytes()
        # 发送图像大小
        size = len(img_bytes)
        sock.sendall(size.to_bytes(4, byteorder="big"))
        # 发送图像数据
        sock.sendall(img_bytes)
        end = time.time()
        # 打印帧数
        print(1 / (end - begin))

cv2.destroyAllWindows()

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值