问题描述
正如我在Python文档中所见,
https://docs.python.org/3/library/mmap.html。
Linux中的Python可以完全支持内存映射文件。但是,当我尝试将此想法应用于我的应用程序时。我无法运行该示例。
我的应用程序是将帧从Python文件(客户端)发送到另一个Python文件(服务器)。
客户代码
import mmap
import time
import os
import cv2 as cv
print("opening camera...")
cap = cv.VideoCapture('/home/hunglv/Downloads/IMG_8442.MOV')
mm = None
try:
while True:
ret,img = cap.read()
if not ret:
break
if mm is None:
mm = mmap.mmap(-1,img.size,mmap.MAP_SHARED,mmap.PROT_WRITE)
# write image
start = time.time()
buf = img.tobytes()
mm.seek(0)
mm.write(buf)
mm.flush()
stop = time.time()
print("Writing Duration:",(stop - start) * 1000,"ms")
except KeyboardInterrupt:
pass
print("Closing resources")
cap.release()
mm.close()
服务器代码
import mmap
import time
import os
import cv2 as cv
import numpy as np
shape = (1080,1920,3)
n = np.prod(shape)
mm = mmap.mmap(-1,n)
while True:
# read image
print (mm)
start = time.perf_counter()
mm.seek(0)
buf = mm.read(12)
img = np.frombuffer(buf,dtype=np.uint8).reshape(shape)
stop = time.perf_counter()
print("Reading Duration:","ms")
cv.imshow("img",img)
key = cv.waitKey(1) & 0xFF
key = chr(key)
if key.lower() == "q":
break
cv.destroyAllWindows()
mm.close()
在服务器端,我将内存索引设置为0,并尝试从内存中读取字节。但是,似乎服务器无法从客户端正确读取数据。
[已更新] 我试图在服务器端读取前12个字节。该值是常量,不再更改。
b'\ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00 \ x00'
此外, 随机帧的前12个字节是
b'\ xf5 \ xff \ xff \ xf0 \ xfa \ xfe \ xdf \ xe9 \ xed \ xd2 \ xdc \ xe0'
解决方法
首先,我发现了一个可能可行的示例,但是它使用了tagName
(对于客户端和服务器来说都是相同的),这意味着它仅适用于Window:
接下来,我发现了可以在Linux上运行的代码:
Sharing Python data between processes using mmap。
它将在磁盘上创建真实文件,将其调整为图像大小,然后在fd
中使用其mmap()
我使用网络摄像头进行测试。
服务器
import mmap
import time
import os
import cv2
print("Opening camera...")
cap = cv2.VideoCapture(0)
#print(cap.get(cv.CAP_PROP_FRAME_WIDTH)) # 640
#print(cap.get(cv.CAP_PROP_FRAME_HEIGHT)) # 480
shape = (480,640,3)
n = (480*640*3)
fd = os.open('/tmp/mmaptest',os.O_CREAT | os.O_TRUNC | os.O_RDWR)
#os.write(fd,b'\x00' * n) # resize file
os.truncate(fd,n) # resize file
mm = None
try:
while True:
ret,img = cap.read()
if not ret:
break
if mm is None:
mm = mmap.mmap(fd,n,mmap.MAP_SHARED,mmap.PROT_WRITE) # it has to be only for writing
# write image
start = time.perf_counter()
buf = img.tobytes()
mm.seek(0)
mm.write(buf)
mm.flush()
stop = time.perf_counter()
print("Writing Duration:",(stop - start) * 1000,"ms")
except KeyboardInterrupt:
pass
print("Closing resources")
cap.release()
mm.close()
客户
import mmap
import time
import os
import cv2
import numpy as np
shape = (480,os.O_RDONLY)
mm = mmap.mmap(fd,mmap.PROT_READ) # it has to be only for reading
while True:
# read image
start = time.perf_counter()
mm.seek(0)
buf = mm.read(n)
img = np.frombuffer(buf,dtype=np.uint8).reshape(shape)
stop = time.perf_counter()
print("Reading Duration:","ms")
cv2.imshow("img",img)
key = cv2.waitKey(1) & 0xFF
key = chr(key)
if key.lower() == "q":
break
cv2.destroyAllWindows()
mm.close()
顺便说一句::mmap()
与-1
(无需在磁盘上创建文件)可能可以与线程(或派生)一起使用,因为它们共享相同的内存。