如何有效地压缩内存中的帧?

问题描述

我正在测试 Python 中的屏幕投射。客户端和服务器的代码都比较简单。

总而言之,我之前做的是:

  • 在服务器上:
    • 使用 mss 抓取屏幕
    • 使用 pickle 进行序列化
    • 发送数据
    • 对每一帧重复
  • 在客户端:
    • 使用 pickle 接收数据并反序列化
    • 通过CV2运行接收到的numpy数组显示

我在本地进行了测试,结果证明效果很好。然而,一旦我开始在我的网络(台式机和笔记本电脑之间)内进行测试,问题就迅速激增。质量很棒,但非常滞后,FPS 低得难以置信。

我意识到帧可能太大了,所以我决定将重点转向压缩,我已经搜索并尝试了几个小时但无济于事。经过一段时间的搜索,我在 SO 上遇到了一些使用 zlib用户,所以我决定做同样的事情,尽管在序列化和发送(在服务器上)以及反序列化和反序列化之前压缩(zlib.compress(frame))解压缩 (zlib.decompress(frame))(在客户端上)我无法将数据转回 numpy 数组,因此 CV2 会崩溃,并说出 TypeError: Expected Ptr<cv::UMat> for argument 'src' 之类的内容

除了知道如何有效地压缩帧之外,我还非常想知道是什么导致了我的代码变慢,因为我不完全确定问题出在帧大小上。我很感激在这主题上的任何帮助以及任何提示、技巧或批评,因为我在这主题上绝对没有经验。

服务器代码

import sys,socket as s
import pickle
import struct        
import cv2
import numpy as np
from mss import mss
from PIL import Image
import time

HOST = ''  

if len(sys.argv) > 1:  
    PORT = int(sys.argv[1]) 
else:  
    PORT = 9999  
    
sock = s.socket(s.AF_INET,s.soCK_STREAM) 
sock.setsockopt(s.soL_SOCKET,s.so_REUSEADDR,1)  

sock.bind((HOST,PORT)) 
sock.listen(1)  

(conn_sock,addr) = sock.accept()


bounding_Box = {'top': 0,'left': 0,'width': 1920,'height':1080}

sct = mss()
sct.compression_level = 9

while True:
    try:

        frame = np.array(sct.grab(bounding_Box))
        
        msg_bytes = pickle.dumps(frame,-1)
        size_bytes = struct.pack('i',len(msg_bytes))

        # Sending size bytes before actual data
        conn_sock.sendall(size_bytes)
        conn_sock.sendall(msg_bytes)


    except Exception as e:   
        print(e)
        conn_sock.close()

        break

cv2.destroyAllWindows()

客户端代码

import sys,socket as s
import pickle
import struct
import cv2
import numpy as np
from sock_utils import receive_all


if len(sys.argv) > 1:
    HOST = sys.argv[1]   
    PORT = int(sys.argv[2]) 

else:   
    HOST = '127.0.0.1'   
    PORT = 9999  


conn_sock = s.socket(s.AF_INET,s.soCK_STREAM)   
conn_sock.connect((HOST,PORT))   
    
while True:   
    
    # Getting size of bytes to receive
    size_bytes = conn_sock.recv(4)
    size = struct.unpack('i',size_bytes)[0]

    # Getting frame bytes
    msg_bytes = receive_all(conn_sock,size)

    # Deserializing frame
    frame = pickle.loads(msg_bytes)


    # Showing output
    cv2.namedWindow("Screencasting",cv2.WINDOW_norMAL)

    cv2.imshow("Screencasting",frame)

    # Checking for 'q' key if pressed
    key = cv2.waitKey(1) & 0xFF
    if key == ord("q"):
        break



conn_sock.close()

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)